diff --git a/python/requirements.txt b/python/requirements.txt index 11d7910b94d..162e68787d1 100644 --- a/python/requirements.txt +++ b/python/requirements.txt @@ -5,7 +5,7 @@ blessings == 1.6 mach == 0.6.0 mozdebug == 0.1 mozinfo == 0.8 -mozlog == 3.5 +mozlog == 3.6 setuptools == 18.5 toml == 0.9.2 diff --git a/python/servo/lints/wpt_lint.py b/python/servo/lints/wpt_lint.py index b1b98eec97a..a1c7e528c77 100644 --- a/python/servo/lints/wpt_lint.py +++ b/python/servo/lints/wpt_lint.py @@ -36,6 +36,6 @@ class Lint(LintRunner): from tools.lint import lint sys.path.remove(wpt_working_dir) file_dir = os.path.abspath(os.path.join(WPT_PATH, suite)) - returncode = lint.lint(file_dir, list(files), output_format="json", css_mode=False) + returncode = lint.lint(file_dir, list(files), output_format="json") if returncode: yield ("WPT Lint Tool", "", "lint error(s) in Web Platform Tests: exit status %s" % returncode) diff --git a/tests/wpt/include.ini b/tests/wpt/include.ini index de71a08fec6..2b197be5984 100644 --- a/tests/wpt/include.ini +++ b/tests/wpt/include.ini @@ -93,7 +93,7 @@ skip: true skip: false [performance-timeline] skip: false -[quirks-mode] +[quirks] skip: false [referrer-policy] skip: false diff --git a/tests/wpt/metadata/2dcontext/imagebitmap/createImageBitmap-invalid-args.html.ini b/tests/wpt/metadata/2dcontext/imagebitmap/createImageBitmap-invalid-args.html.ini index 02038e45fee..e1fe300a6b9 100644 --- a/tests/wpt/metadata/2dcontext/imagebitmap/createImageBitmap-invalid-args.html.ini +++ b/tests/wpt/metadata/2dcontext/imagebitmap/createImageBitmap-invalid-args.html.ini @@ -1,5 +1,6 @@ [createImageBitmap-invalid-args.html] type: testharness + expected: TIMEOUT [createImageBitmap with a HTMLImageElement source and sw set to 0 rejects with a RangeError.] expected: FAIL @@ -84,3 +85,9 @@ [createImageBitmap with an undecodable blob source rejects with an InvalidStateError.] expected: FAIL + [createImageBitmap with a broken image source rejects with an InvalidStateError.] + expected: FAIL + + [createImageBitmap with an available but undecodable image source rejects with an InvalidStateError.] + expected: TIMEOUT + diff --git a/tests/wpt/metadata/FileAPI/blob/Blob-Request-revoke-fetch.html.ini b/tests/wpt/metadata/FileAPI/blob/Blob-Request-revoke-fetch.html.ini new file mode 100644 index 00000000000..ea8d27f50c0 --- /dev/null +++ b/tests/wpt/metadata/FileAPI/blob/Blob-Request-revoke-fetch.html.ini @@ -0,0 +1,4 @@ +[Blob-Request-revoke-fetch.html] + [Revoke blob URL after creating Request, will fetch] + expected: FAIL + diff --git a/tests/wpt/metadata/FileAPI/blob/Blob-constructor-endings.html.ini b/tests/wpt/metadata/FileAPI/blob/Blob-constructor-endings.html.ini new file mode 100644 index 00000000000..53c933ca61f --- /dev/null +++ b/tests/wpt/metadata/FileAPI/blob/Blob-constructor-endings.html.ini @@ -0,0 +1,4 @@ +[Blob-constructor-endings.html] + [Blob constructor: endings option] + expected: FAIL + diff --git a/tests/wpt/metadata/FileAPI/blob/Blob-constructor.html.ini b/tests/wpt/metadata/FileAPI/blob/Blob-constructor.html.ini index 99cce5caae3..193d306bf54 100644 --- a/tests/wpt/metadata/FileAPI/blob/Blob-constructor.html.ini +++ b/tests/wpt/metadata/FileAPI/blob/Blob-constructor.html.ini @@ -32,3 +32,6 @@ expected: FAIL bug: https://github.com/servo/servo/issues/10911 + [options properties should be accessed in lexicographic order.] + expected: FAIL + diff --git a/tests/wpt/metadata/FileAPI/file/File-constructor-endings.html.ini b/tests/wpt/metadata/FileAPI/file/File-constructor-endings.html.ini new file mode 100644 index 00000000000..6f01cc277ba --- /dev/null +++ b/tests/wpt/metadata/FileAPI/file/File-constructor-endings.html.ini @@ -0,0 +1,4 @@ +[File-constructor-endings.html] + [File constructor: endings option] + expected: FAIL + diff --git a/tests/wpt/metadata/FileAPI/file/File-constructor.html.ini b/tests/wpt/metadata/FileAPI/file/File-constructor.html.ini index 1134394834f..3e76435960d 100644 --- a/tests/wpt/metadata/FileAPI/file/File-constructor.html.ini +++ b/tests/wpt/metadata/FileAPI/file/File-constructor.html.ini @@ -12,3 +12,12 @@ expected: FAIL bug: https://github.com/servo/servo/issues/10911 + [HTMLDocument in fileBits] + expected: FAIL + + [Invalid bits argument: "hello"] + expected: FAIL + + [Using object fileName] + expected: FAIL + diff --git a/tests/wpt/metadata/FileAPI/file/send-file-form-iso-2022-jp.tentative.html.ini b/tests/wpt/metadata/FileAPI/file/send-file-form-iso-2022-jp.tentative.html.ini new file mode 100644 index 00000000000..384ddd6aef8 --- /dev/null +++ b/tests/wpt/metadata/FileAPI/file/send-file-form-iso-2022-jp.tentative.html.ini @@ -0,0 +1,4 @@ +[send-file-form-iso-2022-jp.tentative.html] + [Upload files in ISO-2022-JP form (tentative)] + expected: FAIL + diff --git a/tests/wpt/metadata/FileAPI/file/send-file-form-utf-8.html.ini b/tests/wpt/metadata/FileAPI/file/send-file-form-utf-8.html.ini new file mode 100644 index 00000000000..66bd7e9ed4b --- /dev/null +++ b/tests/wpt/metadata/FileAPI/file/send-file-form-utf-8.html.ini @@ -0,0 +1,4 @@ +[send-file-form-utf-8.html] + [Upload files in UTF-8 form] + expected: FAIL + diff --git a/tests/wpt/metadata/FileAPI/file/send-file-form-windows-1252.tentative.html.ini b/tests/wpt/metadata/FileAPI/file/send-file-form-windows-1252.tentative.html.ini new file mode 100644 index 00000000000..d022b9dc34f --- /dev/null +++ b/tests/wpt/metadata/FileAPI/file/send-file-form-windows-1252.tentative.html.ini @@ -0,0 +1,4 @@ +[send-file-form-windows-1252.tentative.html] + [Upload files in Windows-1252 form (tentative)] + expected: FAIL + diff --git a/tests/wpt/metadata/FileAPI/file/send-file-form-x-user-defined.tentative.html.ini b/tests/wpt/metadata/FileAPI/file/send-file-form-x-user-defined.tentative.html.ini new file mode 100644 index 00000000000..bb7738135d3 --- /dev/null +++ b/tests/wpt/metadata/FileAPI/file/send-file-form-x-user-defined.tentative.html.ini @@ -0,0 +1,4 @@ +[send-file-form-x-user-defined.tentative.html] + [Upload files in x-user-defined form (tentative)] + expected: FAIL + diff --git a/tests/wpt/metadata/FileAPI/file/send-file-form.html.ini b/tests/wpt/metadata/FileAPI/file/send-file-form.html.ini new file mode 100644 index 00000000000..464056abd50 --- /dev/null +++ b/tests/wpt/metadata/FileAPI/file/send-file-form.html.ini @@ -0,0 +1,4 @@ +[send-file-form.html] + [Upload ASCII-named file in UTF-8 form] + expected: FAIL + diff --git a/tests/wpt/metadata/FileAPI/unicode.html.ini b/tests/wpt/metadata/FileAPI/unicode.html.ini new file mode 100644 index 00000000000..bb84bb80b87 --- /dev/null +++ b/tests/wpt/metadata/FileAPI/unicode.html.ini @@ -0,0 +1,4 @@ +[unicode.html] + [Blob/Unicode interaction: normalization and encoding] + expected: FAIL + diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json index af456269a80..baaa27bed20 100644 --- a/tests/wpt/metadata/MANIFEST.json +++ b/tests/wpt/metadata/MANIFEST.json @@ -7315,12 +7315,6 @@ {} ] ], - "css/css-block/cursor-applies-to-011.xht": [ - [ - "/css/css-block/cursor-applies-to-011.xht", - {} - ] - ], "css/css-counter-styles/arabic-indic/css3-counter-styles-101.html": [ [ "/css/css-counter-styles/arabic-indic/css3-counter-styles-101.html", @@ -8263,6 +8257,12 @@ {} ] ], + "css/css-display/run-in/cursor-applies-to-011.xht": [ + [ + "/css/css-display/run-in/cursor-applies-to-011.xht", + {} + ] + ], "css/css-flexbox/css-flexbox-height-animation-stretch.html": [ [ "/css/css-flexbox/css-flexbox-height-animation-stretch.html", @@ -12139,6 +12139,12 @@ {} ] ], + "fullscreen/model/move-to-fullscreen-iframe-manual.html": [ + [ + "/fullscreen/model/move-to-fullscreen-iframe-manual.html", + {} + ] + ], "fullscreen/model/move-to-iframe-manual.html": [ [ "/fullscreen/model/move-to-iframe-manual.html", @@ -12187,6 +12193,12 @@ {} ] ], + "fullscreen/rendering/ua-style-iframe-manual.html": [ + [ + "/fullscreen/rendering/ua-style-iframe-manual.html", + {} + ] + ], "gamepad/events-manual.html": [ [ "/gamepad/events-manual.html", @@ -12235,6 +12247,12 @@ {} ] ], + "geolocation-sensor/GeolocationSensor_onerror-manual.https.html": [ + [ + "/geolocation-sensor/GeolocationSensor_onerror-manual.https.html", + {} + ] + ], "gyroscope/Gyroscope_onerror-manual.https.html": [ [ "/gyroscope/Gyroscope_onerror-manual.https.html", @@ -14497,9 +14515,9 @@ {} ] ], - "quirks-mode/active-and-hover-manual.html": [ + "quirks/active-and-hover-manual.html": [ [ - "/quirks-mode/active-and-hover-manual.html", + "/quirks/active-and-hover-manual.html", {} ] ], @@ -17701,6 +17719,12 @@ {} ] ], + "uievents/mouse/layout_change_should_fire_mouseover-manual.html": [ + [ + "/uievents/mouse/layout_change_should_fire_mouseover-manual.html", + {} + ] + ], "uievents/mouse/mouseevent_move_button-manual.html": [ [ "/uievents/mouse/mouseevent_move_button-manual.html", @@ -19255,6 +19279,12 @@ {} ] ], + "wake-lock/wakelock-applicability-manual.https.html": [ + [ + "/wake-lock/wakelock-applicability-manual.https.html", + {} + ] + ], "web-nfc/nfc_hw_disabled-manual.https.html": [ [ "/web-nfc/nfc_hw_disabled-manual.https.html", @@ -48549,6 +48579,18 @@ {} ] ], + "css/CSS2/fonts/font-148.xht": [ + [ + "/css/CSS2/fonts/font-148.xht", + [ + [ + "/css/CSS2/fonts/font-148-ref.xht", + "==" + ] + ], + {} + ] + ], "css/CSS2/fonts/font-applies-to-001.xht": [ [ "/css/CSS2/fonts/font-applies-to-001.xht", @@ -50457,6 +50499,42 @@ {} ] ], + "css/CSS2/generated-content/after-inheritable-001.xht": [ + [ + "/css/CSS2/generated-content/after-inheritable-001.xht", + [ + [ + "/css/CSS2/generated-content/after-inheritable-001-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/after-inheritable-002.xht": [ + [ + "/css/CSS2/generated-content/after-inheritable-002.xht", + [ + [ + "/css/CSS2/generated-content/after-inheritable-002-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/after-location-001.xht": [ + [ + "/css/CSS2/generated-content/after-location-001.xht", + [ + [ + "/css/CSS2/generated-content/after-location-001-ref.html", + "==" + ] + ], + {} + ] + ], "css/CSS2/generated-content/before-after-001.xht": [ [ "/css/CSS2/generated-content/before-after-001.xht", @@ -50469,6 +50547,18 @@ {} ] ], + "css/CSS2/generated-content/before-after-002.xht": [ + [ + "/css/CSS2/generated-content/before-after-002.xht", + [ + [ + "/css/CSS2/generated-content/content-003-ref.html", + "==" + ] + ], + {} + ] + ], "css/CSS2/generated-content/before-after-011.xht": [ [ "/css/CSS2/generated-content/before-after-011.xht", @@ -50817,12 +50907,456 @@ {} ] ], + "css/CSS2/generated-content/before-inheritable-001.xht": [ + [ + "/css/CSS2/generated-content/before-inheritable-001.xht", + [ + [ + "/css/CSS2/generated-content/after-inheritable-001-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/before-inheritable-002.xht": [ + [ + "/css/CSS2/generated-content/before-inheritable-002.xht", + [ + [ + "/css/CSS2/generated-content/after-inheritable-002-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/before-location-001.xht": [ + [ + "/css/CSS2/generated-content/before-location-001.xht", + [ + [ + "/css/CSS2/generated-content/before-location-001-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/bidi-generated-content-001.xht": [ + [ + "/css/CSS2/generated-content/bidi-generated-content-001.xht", + [ + [ + "/css/CSS2/generated-content/bidi-generated-content-001-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/bidi-generated-content-002.xht": [ + [ + "/css/CSS2/generated-content/bidi-generated-content-002.xht", + [ + [ + "/css/CSS2/generated-content/bidi-generated-content-002-ref.html", + "==" + ] + ], + {} + ] + ], "css/CSS2/generated-content/content-001.xht": [ [ "/css/CSS2/generated-content/content-001.xht", [ [ - "/css/CSS2/reference/no-red-on-blank-page-ref.xht", + "/css/CSS2/generated-content/content-001-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-002.xht": [ + [ + "/css/CSS2/generated-content/content-002.xht", + [ + [ + "/css/CSS2/generated-content/content-001-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-003.xht": [ + [ + "/css/CSS2/generated-content/content-003.xht", + [ + [ + "/css/CSS2/generated-content/content-003-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-004.xht": [ + [ + "/css/CSS2/generated-content/content-004.xht", + [ + [ + "/css/reference/ref-filled-green-100px-square-only.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-005.xht": [ + [ + "/css/CSS2/generated-content/content-005.xht", + [ + [ + "/css/CSS2/generated-content/content-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-006.xht": [ + [ + "/css/CSS2/generated-content/content-006.xht", + [ + [ + "/css/CSS2/generated-content/content-006-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-007.xht": [ + [ + "/css/CSS2/generated-content/content-007.xht", + [ + [ + "/css/CSS2/generated-content/content-007-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-009.xht": [ + [ + "/css/CSS2/generated-content/content-009.xht", + [ + [ + "/css/CSS2/generated-content/content-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-010.xht": [ + [ + "/css/CSS2/generated-content/content-010.xht", + [ + [ + "/css/CSS2/generated-content/content-010-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-011.xht": [ + [ + "/css/CSS2/generated-content/content-011.xht", + [ + [ + "/css/CSS2/generated-content/content-011-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-012.xht": [ + [ + "/css/CSS2/generated-content/content-012.xht", + [ + [ + "/css/CSS2/generated-content/content-012-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-013.xht": [ + [ + "/css/CSS2/generated-content/content-013.xht", + [ + [ + "/css/CSS2/generated-content/content-013-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-014.xht": [ + [ + "/css/CSS2/generated-content/content-014.xht", + [ + [ + "/css/CSS2/generated-content/content-014-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-015.xht": [ + [ + "/css/CSS2/generated-content/content-015.xht", + [ + [ + "/css/CSS2/generated-content/content-015-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-016.xht": [ + [ + "/css/CSS2/generated-content/content-016.xht", + [ + [ + "/css/CSS2/generated-content/content-016-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-017.xht": [ + [ + "/css/CSS2/generated-content/content-017.xht", + [ + [ + "/css/CSS2/generated-content/content-017-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-018.xht": [ + [ + "/css/CSS2/generated-content/content-018.xht", + [ + [ + "/css/CSS2/generated-content/content-014-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-019.xht": [ + [ + "/css/CSS2/generated-content/content-019.xht", + [ + [ + "/css/CSS2/generated-content/content-015-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-020.xht": [ + [ + "/css/CSS2/generated-content/content-020.xht", + [ + [ + "/css/CSS2/generated-content/content-001-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-021.xht": [ + [ + "/css/CSS2/generated-content/content-021.xht", + [ + [ + "/css/CSS2/generated-content/content-021-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-022.xht": [ + [ + "/css/CSS2/generated-content/content-022.xht", + [ + [ + "/css/CSS2/generated-content/content-022-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-023.xht": [ + [ + "/css/CSS2/generated-content/content-023.xht", + [ + [ + "/css/CSS2/generated-content/content-023-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-025.xht": [ + [ + "/css/CSS2/generated-content/content-025.xht", + [ + [ + "/css/CSS2/generated-content/content-021-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-026.xht": [ + [ + "/css/CSS2/generated-content/content-026.xht", + [ + [ + "/css/CSS2/generated-content/content-026-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-027.xht": [ + [ + "/css/CSS2/generated-content/content-027.xht", + [ + [ + "/css/CSS2/generated-content/content-027-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-028.xht": [ + [ + "/css/CSS2/generated-content/content-028.xht", + [ + [ + "/css/CSS2/generated-content/content-028-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-029.xht": [ + [ + "/css/CSS2/generated-content/content-029.xht", + [ + [ + "/css/CSS2/generated-content/content-029-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-030.xht": [ + [ + "/css/CSS2/generated-content/content-030.xht", + [ + [ + "/css/CSS2/generated-content/content-030-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-031.xht": [ + [ + "/css/CSS2/generated-content/content-031.xht", + [ + [ + "/css/CSS2/generated-content/content-031-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-032.xht": [ + [ + "/css/CSS2/generated-content/content-032.xht", + [ + [ + "/css/CSS2/generated-content/content-032-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-033.xht": [ + [ + "/css/CSS2/generated-content/content-033.xht", + [ + [ + "/css/CSS2/generated-content/content-033-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-034.xht": [ + [ + "/css/CSS2/generated-content/content-034.xht", + [ + [ + "/css/CSS2/generated-content/content-030-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-035.xht": [ + [ + "/css/CSS2/generated-content/content-035.xht", + [ + [ + "/css/CSS2/generated-content/content-031-ref.html", "==" ] ], @@ -50834,7 +51368,499 @@ "/css/CSS2/generated-content/content-036.xht", [ [ - "/css/CSS2/reference/no-red-on-blank-page-ref.xht", + "/css/CSS2/generated-content/content-001-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-037.xht": [ + [ + "/css/CSS2/generated-content/content-037.xht", + [ + [ + "/css/CSS2/generated-content/content-037-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-038.xht": [ + [ + "/css/CSS2/generated-content/content-038.xht", + [ + [ + "/css/CSS2/generated-content/content-003-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-039.xht": [ + [ + "/css/CSS2/generated-content/content-039.xht", + [ + [ + "/css/CSS2/generated-content/content-003-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-040.xht": [ + [ + "/css/CSS2/generated-content/content-040.xht", + [ + [ + "/css/CSS2/generated-content/content-040-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-041.xht": [ + [ + "/css/CSS2/generated-content/content-041.xht", + [ + [ + "/css/CSS2/generated-content/content-041-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-042.xht": [ + [ + "/css/CSS2/generated-content/content-042.xht", + [ + [ + "/css/CSS2/generated-content/content-042-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-043.xht": [ + [ + "/css/CSS2/generated-content/content-043.xht", + [ + [ + "/css/CSS2/generated-content/content-043-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-046.xht": [ + [ + "/css/CSS2/generated-content/content-046.xht", + [ + [ + "/css/CSS2/generated-content/content-037-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-047.xht": [ + [ + "/css/CSS2/generated-content/content-047.xht", + [ + [ + "/css/CSS2/generated-content/content-047-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-048.xht": [ + [ + "/css/CSS2/generated-content/content-048.xht", + [ + [ + "/css/CSS2/generated-content/content-048-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-050.xht": [ + [ + "/css/CSS2/generated-content/content-050.xht", + [ + [ + "/css/CSS2/generated-content/content-050-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-052.xht": [ + [ + "/css/CSS2/generated-content/content-052.xht", + [ + [ + "/css/CSS2/generated-content/content-052-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-053.xht": [ + [ + "/css/CSS2/generated-content/content-053.xht", + [ + [ + "/css/CSS2/generated-content/content-053-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-054.xht": [ + [ + "/css/CSS2/generated-content/content-054.xht", + [ + [ + "/css/CSS2/generated-content/content-003-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-056.xht": [ + [ + "/css/CSS2/generated-content/content-056.xht", + [ + [ + "/css/CSS2/generated-content/content-003-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-057.xht": [ + [ + "/css/CSS2/generated-content/content-057.xht", + [ + [ + "/css/CSS2/generated-content/content-003-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-063.xht": [ + [ + "/css/CSS2/generated-content/content-063.xht", + [ + [ + "/css/CSS2/generated-content/content-063-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-065.xht": [ + [ + "/css/CSS2/generated-content/content-065.xht", + [ + [ + "/css/CSS2/generated-content/content-053-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-067.xht": [ + [ + "/css/CSS2/generated-content/content-067.xht", + [ + [ + "/css/CSS2/generated-content/content-047-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-068.xht": [ + [ + "/css/CSS2/generated-content/content-068.xht", + [ + [ + "/css/CSS2/generated-content/content-068-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-070.xht": [ + [ + "/css/CSS2/generated-content/content-070.xht", + [ + [ + "/css/CSS2/generated-content/content-070-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-072.xht": [ + [ + "/css/CSS2/generated-content/content-072.xht", + [ + [ + "/css/CSS2/generated-content/content-072-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-073.xht": [ + [ + "/css/CSS2/generated-content/content-073.xht", + [ + [ + "/css/CSS2/generated-content/content-073-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-075.xht": [ + [ + "/css/CSS2/generated-content/content-075.xht", + [ + [ + "/css/CSS2/generated-content/content-075-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-076.xht": [ + [ + "/css/CSS2/generated-content/content-076.xht", + [ + [ + "/css/CSS2/generated-content/content-003-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-077.xht": [ + [ + "/css/CSS2/generated-content/content-077.xht", + [ + [ + "/css/CSS2/generated-content/content-041-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-080.xht": [ + [ + "/css/CSS2/generated-content/content-080.xht", + [ + [ + "/css/CSS2/generated-content/content-080-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-081.xht": [ + [ + "/css/CSS2/generated-content/content-081.xht", + [ + [ + "/css/CSS2/generated-content/content-081-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-082.xht": [ + [ + "/css/CSS2/generated-content/content-082.xht", + [ + [ + "/css/CSS2/generated-content/content-082-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-083.xht": [ + [ + "/css/CSS2/generated-content/content-083.xht", + [ + [ + "/css/CSS2/generated-content/content-083-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-085.xht": [ + [ + "/css/CSS2/generated-content/content-085.xht", + [ + [ + "/css/CSS2/generated-content/content-047-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-086.xht": [ + [ + "/css/CSS2/generated-content/content-086.xht", + [ + [ + "/css/CSS2/generated-content/content-041-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-089.xht": [ + [ + "/css/CSS2/generated-content/content-089.xht", + [ + [ + "/css/CSS2/generated-content/content-089-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-090.xht": [ + [ + "/css/CSS2/generated-content/content-090.xht", + [ + [ + "/css/CSS2/generated-content/content-090-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-091.xht": [ + [ + "/css/CSS2/generated-content/content-091.xht", + [ + [ + "/css/CSS2/generated-content/content-091-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-096.xht": [ + [ + "/css/CSS2/generated-content/content-096.xht", + [ + [ + "/css/CSS2/generated-content/content-096-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-097.xht": [ + [ + "/css/CSS2/generated-content/content-097.xht", + [ + [ + "/css/CSS2/generated-content/content-097-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-099.xht": [ + [ + "/css/CSS2/generated-content/content-099.xht", + [ + [ + "/css/CSS2/generated-content/content-041-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-100.xht": [ + [ + "/css/CSS2/generated-content/content-100.xht", + [ + [ + "/css/CSS2/generated-content/content-100-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-103.xht": [ + [ + "/css/CSS2/generated-content/content-103.xht", + [ + [ + "/css/CSS2/generated-content/content-103-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-105.xht": [ + [ + "/css/CSS2/generated-content/content-105.xht", + [ + [ + "/css/reference/only_pass_parens_semicolon.html", "==" ] ], @@ -50865,6 +51891,18 @@ {} ] ], + "css/CSS2/generated-content/content-109.xht": [ + [ + "/css/CSS2/generated-content/content-109.xht", + [ + [ + "/css/reference/only_pass_parens_semicolon.html", + "==" + ] + ], + {} + ] + ], "css/CSS2/generated-content/content-110.xht": [ [ "/css/CSS2/generated-content/content-110.xht", @@ -50901,6 +51939,18 @@ {} ] ], + "css/CSS2/generated-content/content-113.xht": [ + [ + "/css/CSS2/generated-content/content-113.xht", + [ + [ + "/css/CSS2/generated-content/content-113-ref.html", + "==" + ] + ], + {} + ] + ], "css/CSS2/generated-content/content-114.xht": [ [ "/css/CSS2/generated-content/content-114.xht", @@ -50985,6 +52035,306 @@ {} ] ], + "css/CSS2/generated-content/content-122.xht": [ + [ + "/css/CSS2/generated-content/content-122.xht", + [ + [ + "/css/CSS2/generated-content/content-113-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-123.xht": [ + [ + "/css/CSS2/generated-content/content-123.xht", + [ + [ + "/css/CSS2/generated-content/content-047-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-126.xht": [ + [ + "/css/CSS2/generated-content/content-126.xht", + [ + [ + "/css/CSS2/generated-content/content-126-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-127.xht": [ + [ + "/css/CSS2/generated-content/content-127.xht", + [ + [ + "/css/CSS2/generated-content/content-126-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-129.xht": [ + [ + "/css/CSS2/generated-content/content-129.xht", + [ + [ + "/css/CSS2/generated-content/content-053-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-131.xht": [ + [ + "/css/CSS2/generated-content/content-131.xht", + [ + [ + "/css/CSS2/generated-content/content-047-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-132.xht": [ + [ + "/css/CSS2/generated-content/content-132.xht", + [ + [ + "/css/CSS2/generated-content/content-132-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-135.xht": [ + [ + "/css/CSS2/generated-content/content-135.xht", + [ + [ + "/css/CSS2/generated-content/content-135-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-136.xht": [ + [ + "/css/CSS2/generated-content/content-136.xht", + [ + [ + "/css/CSS2/generated-content/content-136-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-138.xht": [ + [ + "/css/CSS2/generated-content/content-138.xht", + [ + [ + "/css/CSS2/generated-content/content-003-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-141.xht": [ + [ + "/css/CSS2/generated-content/content-141.xht", + [ + [ + "/css/CSS2/generated-content/content-141-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-143.xht": [ + [ + "/css/CSS2/generated-content/content-143.xht", + [ + [ + "/css/CSS2/generated-content/content-143-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-144.xht": [ + [ + "/css/CSS2/generated-content/content-144.xht", + [ + [ + "/css/CSS2/generated-content/content-144-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-145.xht": [ + [ + "/css/CSS2/generated-content/content-145.xht", + [ + [ + "/css/CSS2/generated-content/content-091-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-146.xht": [ + [ + "/css/CSS2/generated-content/content-146.xht", + [ + [ + "/css/CSS2/generated-content/content-003-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-147.xht": [ + [ + "/css/CSS2/generated-content/content-147.xht", + [ + [ + "/css/CSS2/generated-content/content-147-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-149.xht": [ + [ + "/css/CSS2/generated-content/content-149.xht", + [ + [ + "/css/CSS2/generated-content/content-149-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-150.xht": [ + [ + "/css/CSS2/generated-content/content-150.xht", + [ + [ + "/css/CSS2/generated-content/content-150-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-152.xht": [ + [ + "/css/CSS2/generated-content/content-152.xht", + [ + [ + "/css/CSS2/generated-content/content-047-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-153.xht": [ + [ + "/css/CSS2/generated-content/content-153.xht", + [ + [ + "/css/CSS2/generated-content/content-091-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-155.xht": [ + [ + "/css/CSS2/generated-content/content-155.xht", + [ + [ + "/css/CSS2/generated-content/content-155-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-156.xht": [ + [ + "/css/CSS2/generated-content/content-156.xht", + [ + [ + "/css/CSS2/generated-content/content-156-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-157.xht": [ + [ + "/css/CSS2/generated-content/content-157.xht", + [ + [ + "/css/CSS2/generated-content/content-156-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-158.xht": [ + [ + "/css/CSS2/generated-content/content-158.xht", + [ + [ + "/css/CSS2/generated-content/content-158-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-159.xht": [ + [ + "/css/CSS2/generated-content/content-159.xht", + [ + [ + "/css/CSS2/generated-content/content-159-ref.html", + "==" + ] + ], + {} + ] + ], "css/CSS2/generated-content/content-171.xht": [ [ "/css/CSS2/generated-content/content-171.xht", @@ -51057,6 +52407,54 @@ {} ] ], + "css/CSS2/generated-content/content-attr-001.xht": [ + [ + "/css/CSS2/generated-content/content-attr-001.xht", + [ + [ + "/css/CSS2/reference/ref-nothing-below.xht", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-attr-case-001.html": [ + [ + "/css/CSS2/generated-content/content-attr-case-001.html", + [ + [ + "/css/reference/pass_if_pass_below.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-attr-case-002.xht": [ + [ + "/css/CSS2/generated-content/content-attr-case-002.xht", + [ + [ + "/css/CSS2/reference/no-red-on-blank-page-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-auto-reset-001.xht": [ + [ + "/css/CSS2/generated-content/content-auto-reset-001.xht", + [ + [ + "/css/CSS2/generated-content/content-auto-reset-001-ref.html", + "==" + ] + ], + {} + ] + ], "css/CSS2/generated-content/content-counter-000.xht": [ [ "/css/CSS2/generated-content/content-counter-000.xht", @@ -51273,6 +52671,150 @@ {} ] ], + "css/CSS2/generated-content/content-newline-001.xht": [ + [ + "/css/CSS2/generated-content/content-newline-001.xht", + [ + [ + "/css/CSS2/generated-content/content-newline-001-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-white-space-001.xht": [ + [ + "/css/CSS2/generated-content/content-white-space-001.xht", + [ + [ + "/css/CSS2/generated-content/content-white-space-001-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-white-space-002.xht": [ + [ + "/css/CSS2/generated-content/content-white-space-002.xht", + [ + [ + "/css/CSS2/generated-content/content-white-space-002-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-white-space-003.xht": [ + [ + "/css/CSS2/generated-content/content-white-space-003.xht", + [ + [ + "/css/CSS2/generated-content/content-white-space-003-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/content-white-space-004.xht": [ + [ + "/css/CSS2/generated-content/content-white-space-004.xht", + [ + [ + "/css/CSS2/generated-content/content-white-space-004-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/counters-hidden-000.xht": [ + [ + "/css/CSS2/generated-content/counters-hidden-000.xht", + [ + [ + "/css/CSS2/generated-content/counters-hidden-000-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/counters-hidden-001.xht": [ + [ + "/css/CSS2/generated-content/counters-hidden-001.xht", + [ + [ + "/css/CSS2/generated-content/counters-hidden-000-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/counters-hidden-002.xht": [ + [ + "/css/CSS2/generated-content/counters-hidden-002.xht", + [ + [ + "/css/CSS2/generated-content/counters-hidden-002-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/counters-multi-000.xht": [ + [ + "/css/CSS2/generated-content/counters-multi-000.xht", + [ + [ + "/css/CSS2/generated-content/counters-multi-000-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/counters-multi-001.xht": [ + [ + "/css/CSS2/generated-content/counters-multi-001.xht", + [ + [ + "/css/CSS2/generated-content/counters-multi-000-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/counters-order-000.xht": [ + [ + "/css/CSS2/generated-content/counters-order-000.xht", + [ + [ + "/css/CSS2/generated-content/counters-order-000-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/generated-content/counters-root-000.xht": [ + [ + "/css/CSS2/generated-content/counters-root-000.xht", + [ + [ + "/css/CSS2/generated-content/counters-root-000-ref.html", + "==" + ] + ], + {} + ] + ], "css/CSS2/generated-content/multiple-content-values-001.xht": [ [ "/css/CSS2/generated-content/multiple-content-values-001.xht", @@ -52749,6 +54291,18 @@ {} ] ], + "css/CSS2/linebox/line-height-oof-descendants-001.html": [ + [ + "/css/CSS2/linebox/line-height-oof-descendants-001.html", + [ + [ + "/css/CSS2/linebox/line-height-oof-descendants-001-ref.html", + "==" + ] + ], + {} + ] + ], "css/CSS2/linebox/vertical-align-004.xht": [ [ "/css/CSS2/linebox/vertical-align-004.xht", @@ -94341,6 +95895,66 @@ {} ] ], + "css/CSS2/visudet/content-height-001.html": [ + [ + "/css/CSS2/visudet/content-height-001.html", + [ + [ + "/css/CSS2/visudet/reference/content-height-001-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/visudet/content-height-002.html": [ + [ + "/css/CSS2/visudet/content-height-002.html", + [ + [ + "/css/CSS2/visudet/reference/content-height-002-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/visudet/content-height-003.html": [ + [ + "/css/CSS2/visudet/content-height-003.html", + [ + [ + "/css/CSS2/visudet/reference/content-height-003-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/visudet/content-height-004.html": [ + [ + "/css/CSS2/visudet/content-height-004.html", + [ + [ + "/css/CSS2/visudet/reference/content-height-004-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/visudet/content-height-005.html": [ + [ + "/css/CSS2/visudet/content-height-005.html", + [ + [ + "/css/CSS2/visudet/reference/content-height-005-ref.html", + "!=" + ] + ], + {} + ] + ], "css/CSS2/visudet/height-applies-to-010a.xht": [ [ "/css/CSS2/visudet/height-applies-to-010a.xht", @@ -94401,6 +96015,78 @@ {} ] ], + "css/CSS2/visudet/line-height-201.html": [ + [ + "/css/CSS2/visudet/line-height-201.html", + [ + [ + "/css/CSS2/visudet/reference/line-height-201-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/visudet/line-height-202.html": [ + [ + "/css/CSS2/visudet/line-height-202.html", + [ + [ + "/css/CSS2/visudet/reference/line-height-202-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/visudet/line-height-203.html": [ + [ + "/css/CSS2/visudet/line-height-203.html", + [ + [ + "/css/CSS2/visudet/reference/line-height-203-ref.html", + "!=" + ] + ], + {} + ] + ], + "css/CSS2/visudet/line-height-204.html": [ + [ + "/css/CSS2/visudet/line-height-204.html", + [ + [ + "/css/CSS2/visudet/reference/line-height-202-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/visudet/line-height-205.html": [ + [ + "/css/CSS2/visudet/line-height-205.html", + [ + [ + "/css/CSS2/visudet/reference/line-height-202-ref.html", + "==" + ] + ], + {} + ] + ], + "css/CSS2/visudet/line-height-206.html": [ + [ + "/css/CSS2/visudet/line-height-206.html", + [ + [ + "/css/CSS2/visudet/reference/line-height-206-ref.html", + "!=" + ] + ], + {} + ] + ], "css/CSS2/visufx/clip-001.xht": [ [ "/css/CSS2/visufx/clip-001.xht", @@ -96009,18 +97695,6 @@ {} ] ], - "css/compositing/mix-blend-mode/mix-blend-mode-transition.html": [ - [ - "/css/compositing/mix-blend-mode/mix-blend-mode-transition.html", - [ - [ - "/css/compositing/mix-blend-mode/reference/mix-blend-mode-transition-ref.html", - "==" - ] - ], - {} - ] - ], "css/compositing/mix-blend-mode/mix-blend-mode-video-sibling.html": [ [ "/css/compositing/mix-blend-mode/mix-blend-mode-video-sibling.html", @@ -96129,6 +97803,18 @@ {} ] ], + "css/css-animations/animation-delay-011.html": [ + [ + "/css/css-animations/animation-delay-011.html", + [ + [ + "/css/css-animations/animation-common-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-backgrounds/background-334.html": [ [ "/css/css-backgrounds/background-334.html", @@ -96513,6 +98199,42 @@ {} ] ], + "css/css-backgrounds/background-color-body-propagation-001.html": [ + [ + "/css/css-backgrounds/background-color-body-propagation-001.html", + [ + [ + "/css/css-backgrounds/background-color-body-propagation-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-backgrounds/background-color-body-propagation-002.html": [ + [ + "/css/css-backgrounds/background-color-body-propagation-002.html", + [ + [ + "/css/css-backgrounds/background-color-body-propagation-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-backgrounds/background-color-body-propagation-003.html": [ + [ + "/css/css-backgrounds/background-color-body-propagation-003.html", + [ + [ + "/css/css-backgrounds/background-color-body-propagation-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-backgrounds/background-image-001.html": [ [ "/css/css-backgrounds/background-image-001.html", @@ -96621,6 +98343,18 @@ {} ] ], + "css/css-backgrounds/background-image-none-gradient-repaint.html": [ + [ + "/css/css-backgrounds/background-image-none-gradient-repaint.html", + [ + [ + "/css/css-backgrounds/background-clip-color-repaint-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-backgrounds/background-origin-002.html": [ [ "/css/css-backgrounds/background-origin-002.html", @@ -100557,1602 +102291,6 @@ {} ] ], - "css/css-block/counter-increment-applies-to-011.xht": [ - [ - "/css/css-block/counter-increment-applies-to-011.xht", - [ - [ - "/css/reference/pass_if_number_5.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/counter-reset-applies-to-011.xht": [ - [ - "/css/css-block/counter-reset-applies-to-011.xht", - [ - [ - "/css/reference/pass_if_number_5.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/font-style-applies-to-004.xht": [ - [ - "/css/css-block/font-style-applies-to-004.xht", - [ - [ - "/css/reference/pass_if_filler_text_slanted.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/font-variant-applies-to-004.xht": [ - [ - "/css/css-block/font-variant-applies-to-004.xht", - [ - [ - "/css/reference/pass_if_filler_text_match_smallcaps.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/font-weight-applies-to-004.xht": [ - [ - "/css/css-block/font-weight-applies-to-004.xht", - [ - [ - "/css/reference/pass_if_filler_text_match_bold.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/height-applies-to-011.xht": [ - [ - "/css/css-block/height-applies-to-011.xht", - [ - [ - "/css/reference/pass_if_square_96px_black.html", - "==" - ] - ], - {} - ] - ], - "css/css-block/letter-spacing-applies-to-004.xht": [ - [ - "/css/css-block/letter-spacing-applies-to-004.xht", - [ - [ - "/css/reference/black_box_ends_when_blue_box_ends_6_boxes_ahem.html", - "==" - ] - ], - {} - ] - ], - "css/css-block/list-style-applies-to-011.xht": [ - [ - "/css/css-block/list-style-applies-to-011.xht", - [ - [ - "/css/reference/single_square_list_marker.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/list-style-type-applies-to-011.xht": [ - [ - "/css/css-block/list-style-type-applies-to-011.xht", - [ - [ - "/css/reference/single_square_list_marker.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/max-height-applies-to-011.xht": [ - [ - "/css/css-block/max-height-applies-to-011.xht", - [ - [ - "/css/reference/pass_if_square_96px_black.html", - "==" - ] - ], - {} - ] - ], - "css/css-block/max-width-applies-to-011.xht": [ - [ - "/css/css-block/max-width-applies-to-011.xht", - [ - [ - "/css/reference/pass_if_square_96px_black.html", - "==" - ] - ], - {} - ] - ], - "css/css-block/min-height-applies-to-011.xht": [ - [ - "/css/css-block/min-height-applies-to-011.xht", - [ - [ - "/css/reference/pass_if_square_96px_black.html", - "==" - ] - ], - {} - ] - ], - "css/css-block/min-width-applies-to-011.xht": [ - [ - "/css/css-block/min-width-applies-to-011.xht", - [ - [ - "/css/reference/pass_if_square_96px_black.html", - "==" - ] - ], - {} - ] - ], - "css/css-block/quotes-applies-to-011.xht": [ - [ - "/css/css-block/quotes-applies-to-011.xht", - [ - [ - "/css/reference/pass_if_pass_below.html", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-abspos-between-001.xht": [ - [ - "/css/css-block/run-in-abspos-between-001.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-abspos-between-002.xht": [ - [ - "/css/css-block/run-in-abspos-between-002.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-abspos-between-003.xht": [ - [ - "/css/css-block/run-in-abspos-between-003.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-basic-001.xht": [ - [ - "/css/css-block/run-in-basic-001.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-basic-002.xht": [ - [ - "/css/css-block/run-in-basic-002.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-basic-003.xht": [ - [ - "/css/css-block/run-in-basic-003.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-basic-004.xht": [ - [ - "/css/css-block/run-in-basic-004.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-basic-005.xht": [ - [ - "/css/css-block/run-in-basic-005.xht", - [ - [ - "/css/css-block/run-in-block-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-basic-006.xht": [ - [ - "/css/css-block/run-in-basic-006.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-basic-007.xht": [ - [ - "/css/css-block/run-in-basic-007.xht", - [ - [ - "/css/css-block/run-in-basic-007-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-basic-008.xht": [ - [ - "/css/css-block/run-in-basic-008.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-basic-009.xht": [ - [ - "/css/css-block/run-in-basic-009.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-basic-010.xht": [ - [ - "/css/css-block/run-in-basic-010.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-basic-011.xht": [ - [ - "/css/css-block/run-in-basic-011.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-basic-012.xht": [ - [ - "/css/css-block/run-in-basic-012.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-basic-013.xht": [ - [ - "/css/css-block/run-in-basic-013.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-basic-014.xht": [ - [ - "/css/css-block/run-in-basic-014.xht", - [ - [ - "/css/css-block/run-in-pre-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-basic-015.xht": [ - [ - "/css/css-block/run-in-basic-015.xht", - [ - [ - "/css/css-block/run-in-pre-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-basic-016.xht": [ - [ - "/css/css-block/run-in-basic-016.xht", - [ - [ - "/css/css-block/run-in-pre-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-basic-017.xht": [ - [ - "/css/css-block/run-in-basic-017.xht", - [ - [ - "/css/css-block/run-in-pre-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-basic-018.xht": [ - [ - "/css/css-block/run-in-basic-018.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-block-between-001.xht": [ - [ - "/css/css-block/run-in-block-between-001.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-block-between-002.xht": [ - [ - "/css/css-block/run-in-block-between-002.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-block-between-003.xht": [ - [ - "/css/css-block/run-in-block-between-003.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-breaking-001.xht": [ - [ - "/css/css-block/run-in-breaking-001.xht", - [ - [ - "/css/css-block/run-in-breaking-001-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-breaking-002.xht": [ - [ - "/css/css-block/run-in-breaking-002.xht", - [ - [ - "/css/css-block/run-in-breaking-002-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-clear-001.xht": [ - [ - "/css/css-block/run-in-clear-001.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-clear-002.xht": [ - [ - "/css/css-block/run-in-clear-002.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-abspos-001.xht": [ - [ - "/css/css-block/run-in-contains-abspos-001.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-block-001.xht": [ - [ - "/css/css-block/run-in-contains-block-001.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-block-002.xht": [ - [ - "/css/css-block/run-in-contains-block-002.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-block-003.xht": [ - [ - "/css/css-block/run-in-contains-block-003.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-block-004.xht": [ - [ - "/css/css-block/run-in-contains-block-004.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-block-005.xht": [ - [ - "/css/css-block/run-in-contains-block-005.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-block-inside-inline-001.xht": [ - [ - "/css/css-block/run-in-contains-block-inside-inline-001.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-block-inside-inline-002.xht": [ - [ - "/css/css-block/run-in-contains-block-inside-inline-002.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-block-inside-inline-003.xht": [ - [ - "/css/css-block/run-in-contains-block-inside-inline-003.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-float-001.xht": [ - [ - "/css/css-block/run-in-contains-float-001.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-inline-001.xht": [ - [ - "/css/css-block/run-in-contains-inline-001.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-inline-002.xht": [ - [ - "/css/css-block/run-in-contains-inline-002.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-inline-003.xht": [ - [ - "/css/css-block/run-in-contains-inline-003.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-inline-004.xht": [ - [ - "/css/css-block/run-in-contains-inline-004.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-inline-005.xht": [ - [ - "/css/css-block/run-in-contains-inline-005.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-inline-006.xht": [ - [ - "/css/css-block/run-in-contains-inline-006.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-inline-007.xht": [ - [ - "/css/css-block/run-in-contains-inline-007.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-inline-block-001.xht": [ - [ - "/css/css-block/run-in-contains-inline-block-001.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-inline-table-001.xht": [ - [ - "/css/css-block/run-in-contains-inline-table-001.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-relpos-block-001.xht": [ - [ - "/css/css-block/run-in-contains-relpos-block-001.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-relpos-block-002.xht": [ - [ - "/css/css-block/run-in-contains-relpos-block-002.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-relpos-block-003.xht": [ - [ - "/css/css-block/run-in-contains-relpos-block-003.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-run-in-001.xht": [ - [ - "/css/css-block/run-in-contains-run-in-001.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-run-in-002.xht": [ - [ - "/css/css-block/run-in-contains-run-in-002.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-run-in-003.xht": [ - [ - "/css/css-block/run-in-contains-run-in-003.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-table-001.xht": [ - [ - "/css/css-block/run-in-contains-table-001.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-table-002.xht": [ - [ - "/css/css-block/run-in-contains-table-002.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-table-003.xht": [ - [ - "/css/css-block/run-in-contains-table-003.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-table-caption-001.xht": [ - [ - "/css/css-block/run-in-contains-table-caption-001.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-table-cell-001.xht": [ - [ - "/css/css-block/run-in-contains-table-cell-001.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-table-column-001.xht": [ - [ - "/css/css-block/run-in-contains-table-column-001.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-table-column-group-001.xht": [ - [ - "/css/css-block/run-in-contains-table-column-group-001.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-table-inside-inline-001.xht": [ - [ - "/css/css-block/run-in-contains-table-inside-inline-001.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-table-inside-inline-002.xht": [ - [ - "/css/css-block/run-in-contains-table-inside-inline-002.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-table-inside-inline-003.xht": [ - [ - "/css/css-block/run-in-contains-table-inside-inline-003.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-table-row-001.xht": [ - [ - "/css/css-block/run-in-contains-table-row-001.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-contains-table-row-group-001.xht": [ - [ - "/css/css-block/run-in-contains-table-row-group-001.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-display-none-between-001.xht": [ - [ - "/css/css-block/run-in-display-none-between-001.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-display-none-between-002.xht": [ - [ - "/css/css-block/run-in-display-none-between-002.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-display-none-between-003.xht": [ - [ - "/css/css-block/run-in-display-none-between-003.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-fixedpos-between-001.xht": [ - [ - "/css/css-block/run-in-fixedpos-between-001.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-fixedpos-between-002.xht": [ - [ - "/css/css-block/run-in-fixedpos-between-002.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-fixedpos-between-003.xht": [ - [ - "/css/css-block/run-in-fixedpos-between-003.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-float-between-001.xht": [ - [ - "/css/css-block/run-in-float-between-001.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-float-between-002.xht": [ - [ - "/css/css-block/run-in-float-between-002.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-float-between-003.xht": [ - [ - "/css/css-block/run-in-float-between-003.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-inherit-001.xht": [ - [ - "/css/css-block/run-in-inherit-001.xht", - [ - [ - "/css/css-block/run-in-inherit-001-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-inline-between-001.xht": [ - [ - "/css/css-block/run-in-inline-between-001.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-inline-between-002.xht": [ - [ - "/css/css-block/run-in-inline-between-002.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-inline-between-003.xht": [ - [ - "/css/css-block/run-in-inline-between-003.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-inline-block-between-001.xht": [ - [ - "/css/css-block/run-in-inline-block-between-001.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-inline-block-between-002.xht": [ - [ - "/css/css-block/run-in-inline-block-between-002.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-inline-block-between-003.xht": [ - [ - "/css/css-block/run-in-inline-block-between-003.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-inline-table-between-001.xht": [ - [ - "/css/css-block/run-in-inline-table-between-001.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-inline-table-between-002.xht": [ - [ - "/css/css-block/run-in-inline-table-between-002.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-inline-table-between-003.xht": [ - [ - "/css/css-block/run-in-inline-table-between-003.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-listitem-between-001.xht": [ - [ - "/css/css-block/run-in-listitem-between-001.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-listitem-between-002.xht": [ - [ - "/css/css-block/run-in-listitem-between-002.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-listitem-between-003.xht": [ - [ - "/css/css-block/run-in-listitem-between-003.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-relpos-between-001.xht": [ - [ - "/css/css-block/run-in-relpos-between-001.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-relpos-between-002.xht": [ - [ - "/css/css-block/run-in-relpos-between-002.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-relpos-between-003.xht": [ - [ - "/css/css-block/run-in-relpos-between-003.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-replaced-001.xht": [ - [ - "/css/css-block/run-in-replaced-001.xht", - [ - [ - "/css/css-block/run-in-replaced-001-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-restyle-001.xht": [ - [ - "/css/css-block/run-in-restyle-001.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-restyle-002.xht": [ - [ - "/css/css-block/run-in-restyle-002.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-restyle-003.xht": [ - [ - "/css/css-block/run-in-restyle-003.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-run-in-between-001.xht": [ - [ - "/css/css-block/run-in-run-in-between-001.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-run-in-between-002.xht": [ - [ - "/css/css-block/run-in-run-in-between-002.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-run-in-between-003.xht": [ - [ - "/css/css-block/run-in-run-in-between-003.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-run-in-between-004.xht": [ - [ - "/css/css-block/run-in-run-in-between-004.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-run-in-between-005.xht": [ - [ - "/css/css-block/run-in-run-in-between-005.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-run-in-between-006.xht": [ - [ - "/css/css-block/run-in-run-in-between-006.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-run-in-between-007.xht": [ - [ - "/css/css-block/run-in-run-in-between-007.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-run-in-between-008.xht": [ - [ - "/css/css-block/run-in-run-in-between-008.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-table-between-001.xht": [ - [ - "/css/css-block/run-in-table-between-001.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-table-between-002.xht": [ - [ - "/css/css-block/run-in-table-between-002.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-table-between-003.xht": [ - [ - "/css/css-block/run-in-table-between-003.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-table-cell-between-001.xht": [ - [ - "/css/css-block/run-in-table-cell-between-001.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-table-cell-between-002.xht": [ - [ - "/css/css-block/run-in-table-cell-between-002.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-table-cell-between-003.xht": [ - [ - "/css/css-block/run-in-table-cell-between-003.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-table-row-between-001.xht": [ - [ - "/css/css-block/run-in-table-row-between-001.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-table-row-between-002.xht": [ - [ - "/css/css-block/run-in-table-row-between-002.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-table-row-between-003.xht": [ - [ - "/css/css-block/run-in-table-row-between-003.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-text-between-001.xht": [ - [ - "/css/css-block/run-in-text-between-001.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-text-between-002.xht": [ - [ - "/css/css-block/run-in-text-between-002.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-text-between-003.xht": [ - [ - "/css/css-block/run-in-text-between-003.xht", - [ - [ - "/css/css-block/run-in-text-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-text-between-004.xht": [ - [ - "/css/css-block/run-in-text-between-004.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/run-in-text-between-005.xht": [ - [ - "/css/css-block/run-in-text-between-005.xht", - [ - [ - "/css/css-block/run-in-basic-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-block/text-decoration-applies-to-004.xht": [ - [ - "/css/css-block/text-decoration-applies-to-004.xht", - [ - [ - "/css/reference/pass_if_filler_text_underlined.html", - "==" - ] - ], - {} - ] - ], - "css/css-block/text-transform-applies-to-004.xht": [ - [ - "/css/css-block/text-transform-applies-to-004.xht", - [ - [ - "/css/reference/pass_if_letter_uppercase.html", - "==" - ] - ], - {} - ] - ], - "css/css-block/width-applies-to-011.xht": [ - [ - "/css/css-block/width-applies-to-011.xht", - [ - [ - "/css/reference/pass_if_square_96px_black.html", - "==" - ] - ], - {} - ] - ], "css/css-cascade/all-prop-001.html": [ [ "/css/css-cascade/all-prop-001.html", @@ -102314,7 +102452,7 @@ "/css/css-color/currentcolor-001.html", [ [ - "/css/css-color/greentext-ref.html", + "/css/css-color/greensquare-ref.html", "==" ] ], @@ -102326,7 +102464,7 @@ "/css/css-color/currentcolor-002.html", [ [ - "/css/css-color/greentext-ref.html", + "/css/css-color/greensquare-ref.html", "==" ] ], @@ -102357,6 +102495,222 @@ {} ] ], + "css/css-color/hex-003.html": [ + [ + "/css/css-color/hex-003.html", + [ + [ + "/css/css-color/hex-003-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/hex-004.html": [ + [ + "/css/css-color/hex-004.html", + [ + [ + "/css/css-color/hex-003-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/hsl-001.html": [ + [ + "/css/css-color/hsl-001.html", + [ + [ + "/css/css-color/greentext-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/hsl-002.html": [ + [ + "/css/css-color/hsl-002.html", + [ + [ + "/css/css-color/greentext-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/hsl-003.html": [ + [ + "/css/css-color/hsl-003.html", + [ + [ + "/css/css-color/greentext-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/hsl-004.html": [ + [ + "/css/css-color/hsl-004.html", + [ + [ + "/css/css-color/greentext-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/hsl-005.html": [ + [ + "/css/css-color/hsl-005.html", + [ + [ + "/css/css-color/greentext-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/hsl-006.html": [ + [ + "/css/css-color/hsl-006.html", + [ + [ + "/css/css-color/greentext-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/hsl-007.html": [ + [ + "/css/css-color/hsl-007.html", + [ + [ + "/css/css-color/greentext-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/hsl-008.html": [ + [ + "/css/css-color/hsl-008.html", + [ + [ + "/css/css-color/greentext-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/hsla-001.html": [ + [ + "/css/css-color/hsla-001.html", + [ + [ + "/css/css-color/greentext-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/hsla-002.html": [ + [ + "/css/css-color/hsla-002.html", + [ + [ + "/css/css-color/greentext-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/hsla-003.html": [ + [ + "/css/css-color/hsla-003.html", + [ + [ + "/css/css-color/greentext-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/hsla-004.html": [ + [ + "/css/css-color/hsla-004.html", + [ + [ + "/css/css-color/greentext-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/hsla-005.html": [ + [ + "/css/css-color/hsla-005.html", + [ + [ + "/css/css-color/greentext-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/hsla-006.html": [ + [ + "/css/css-color/hsla-006.html", + [ + [ + "/css/css-color/greentext-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/hsla-007.html": [ + [ + "/css/css-color/hsla-007.html", + [ + [ + "/css/css-color/greentext-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/hsla-008.html": [ + [ + "/css/css-color/hsla-008.html", + [ + [ + "/css/css-color/greentext-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-color/lab-001.html": [ [ "/css/css-color/lab-001.html", @@ -102753,6 +103107,66 @@ {} ] ], + "css/css-color/t32-opacity-basic-0.0-a.xht": [ + [ + "/css/css-color/t32-opacity-basic-0.0-a.xht", + [ + [ + "/css/css-color/t32-opacity-basic-0.0-a-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/t32-opacity-basic-1.0-a.xht": [ + [ + "/css/css-color/t32-opacity-basic-1.0-a.xht", + [ + [ + "/css/css-color/t32-opacity-basic-1.0-a-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/t32-opacity-clamping-0.0-b.xht": [ + [ + "/css/css-color/t32-opacity-clamping-0.0-b.xht", + [ + [ + "/css/css-color/t32-opacity-basic-0.0-a-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/t32-opacity-clamping-1.0-b.xht": [ + [ + "/css/css-color/t32-opacity-clamping-1.0-b.xht", + [ + [ + "/css/css-color/t32-opacity-clamping-1.0-b-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/t32-opacity-offscreen-b.xht": [ + [ + "/css/css-color/t32-opacity-offscreen-b.xht", + [ + [ + "/css/css-color/t32-opacity-offscreen-b-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-color/t32-opacity-offscreen-multiple-boxes-1-c.xht": [ [ "/css/css-color/t32-opacity-offscreen-multiple-boxes-1-c.xht", @@ -102777,6 +103191,42 @@ {} ] ], + "css/css-color/t32-opacity-offscreen-with-alpha-c.xht": [ + [ + "/css/css-color/t32-opacity-offscreen-with-alpha-c.xht", + [ + [ + "/css/css-color/t32-opacity-offscreen-with-alpha-c-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/t41-html4-keywords-a.xht": [ + [ + "/css/css-color/t41-html4-keywords-a.xht", + [ + [ + "/css/css-color/t41-html4-keywords-a-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/t421-rgb-clip-outside-gamut-b.xht": [ + [ + "/css/css-color/t421-rgb-clip-outside-gamut-b.xht", + [ + [ + "/css/css-color/t421-rgb-clip-outside-gamut-b-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-color/t421-rgb-func-int-a.xht": [ [ "/css/css-color/t421-rgb-func-int-a.xht", @@ -102861,6 +103311,30 @@ {} ] ], + "css/css-color/t421-rgb-values-meaning-b.xht": [ + [ + "/css/css-color/t421-rgb-values-meaning-b.xht", + [ + [ + "/css/css-color/t421-rgb-values-meaning-b-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/t422-rgba-a0.0-a.xht": [ + [ + "/css/css-color/t422-rgba-a0.0-a.xht", + [ + [ + "/css/css-color/t32-opacity-basic-0.0-a-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-color/t422-rgba-a1.0-a.xht": [ [ "/css/css-color/t422-rgba-a1.0-a.xht", @@ -102981,6 +103455,18 @@ {} ] ], + "css/css-color/t422-rgba-values-meaning-b.xht": [ + [ + "/css/css-color/t422-rgba-values-meaning-b.xht", + [ + [ + "/css/css-color/t422-rgba-values-meaning-b-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-color/t423-transparent-1-a.xht": [ [ "/css/css-color/t423-transparent-1-a.xht", @@ -103029,6 +103515,18 @@ {} ] ], + "css/css-color/t424-hsl-h-rotating-b.xht": [ + [ + "/css/css-color/t424-hsl-h-rotating-b.xht", + [ + [ + "/css/css-color/t424-hsl-h-rotating-b-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-color/t424-hsl-parsing-f.xht": [ [ "/css/css-color/t424-hsl-parsing-f.xht", @@ -103233,6 +103731,30 @@ {} ] ], + "css/css-color/t425-hsla-h-rotating-b.xht": [ + [ + "/css/css-color/t425-hsla-h-rotating-b.xht", + [ + [ + "/css/css-color/t425-hsla-h-rotating-b-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-color/t425-hsla-onscreen-b.xht": [ + [ + "/css/css-color/t425-hsla-onscreen-b.xht", + [ + [ + "/css/css-color/t422-rgba-onscreen-b-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-color/t425-hsla-onscreen-multiple-boxes-c.xht": [ [ "/css/css-color/t425-hsla-onscreen-multiple-boxes-c.xht", @@ -103269,6 +103791,18 @@ {} ] ], + "css/css-color/t43-svg-keywords-a.xht": [ + [ + "/css/css-color/t43-svg-keywords-a.xht", + [ + [ + "/css/css-color/t43-svg-keywords-a-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-color/t44-currentcolor-background-b.xht": [ [ "/css/css-color/t44-currentcolor-background-b.xht", @@ -103797,6 +104331,18 @@ {} ] ], + "css/css-contain/contain-style-counters.html": [ + [ + "/css/css-contain/contain-style-counters.html", + [ + [ + "/css/css-contain/contain-style-counters-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-display/display-contents-alignment-001.html": [ [ "/css/css-display/display-contents-alignment-001.html", @@ -103845,6 +104391,18 @@ {} ] ], + "css/css-display/display-contents-before-after-003.html": [ + [ + "/css/css-display/display-contents-before-after-003.html", + [ + [ + "/css/css-display/display-contents-pass-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-display/display-contents-block-001.html": [ [ "/css/css-display/display-contents-block-001.html", @@ -103869,6 +104427,30 @@ {} ] ], + "css/css-display/display-contents-button.html": [ + [ + "/css/css-display/display-contents-button.html", + [ + [ + "/css/css-display/display-contents-pass-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-display/display-contents-details.html": [ + [ + "/css/css-display/display-contents-details.html", + [ + [ + "/css/css-display/display-contents-pass-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-display/display-contents-dynamic-before-after-001.html": [ [ "/css/css-display/display-contents-dynamic-before-after-001.html", @@ -104049,6 +104631,18 @@ {} ] ], + "css/css-display/display-contents-dynamic-pseudo-insertion-001.html": [ + [ + "/css/css-display/display-contents-dynamic-pseudo-insertion-001.html", + [ + [ + "/css/css-display/display-contents-dynamic-pseudo-insertion-001-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-display/display-contents-dynamic-table-001-inline.html": [ [ "/css/css-display/display-contents-dynamic-table-001-inline.html", @@ -104097,6 +104691,18 @@ {} ] ], + "css/css-display/display-contents-fieldset.html": [ + [ + "/css/css-display/display-contents-fieldset.html", + [ + [ + "/css/css-display/display-contents-pass-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-display/display-contents-first-letter-001.html": [ [ "/css/css-display/display-contents-first-letter-001.html", @@ -104109,6 +104715,18 @@ {} ] ], + "css/css-display/display-contents-first-letter-002.html": [ + [ + "/css/css-display/display-contents-first-letter-002.html", + [ + [ + "/css/css-display/display-contents-pass-green-no-red-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-display/display-contents-first-line-001.html": [ [ "/css/css-display/display-contents-first-line-001.html", @@ -104121,6 +104739,18 @@ {} ] ], + "css/css-display/display-contents-first-line-002.html": [ + [ + "/css/css-display/display-contents-first-line-002.html", + [ + [ + "/css/css-display/display-contents-pass-green-no-red-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-display/display-contents-flex-001.html": [ [ "/css/css-display/display-contents-flex-001.html", @@ -104193,6 +104823,18 @@ {} ] ], + "css/css-display/display-contents-line-height.html": [ + [ + "/css/css-display/display-contents-line-height.html", + [ + [ + "/css/css-display/display-contents-line-height-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-display/display-contents-list-001.html": [ [ "/css/css-display/display-contents-list-001.html", @@ -104241,18 +104883,6 @@ {} ] ], - "css/css-display/display-contents-replaced-001.html": [ - [ - "/css/css-display/display-contents-replaced-001.html", - [ - [ - "/css/css-display/display-contents-replaced-001-ref.html", - "==" - ] - ], - {} - ] - ], "css/css-display/display-contents-state-change-001.html": [ [ "/css/css-display/display-contents-state-change-001.html", @@ -104265,6 +104895,18 @@ {} ] ], + "css/css-display/display-contents-svg-elements.html": [ + [ + "/css/css-display/display-contents-svg-elements.html", + [ + [ + "/css/css-display/display-contents-svg-elements-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-display/display-contents-table-001.html": [ [ "/css/css-display/display-contents-table-001.html", @@ -104301,6 +104943,18 @@ {} ] ], + "css/css-display/display-contents-text-inherit.html": [ + [ + "/css/css-display/display-contents-text-inherit.html", + [ + [ + "/css/css-display/display-contents-text-inherit-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-display/display-contents-text-only-001.html": [ [ "/css/css-display/display-contents-text-only-001.html", @@ -104325,6 +104979,18 @@ {} ] ], + "css/css-display/display-contents-unusual-html-elements-none.html": [ + [ + "/css/css-display/display-contents-unusual-html-elements-none.html", + [ + [ + "/css/css-display/display-contents-pass-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-display/display-flow-root-001.html": [ [ "/css/css-display/display-flow-root-001.html", @@ -104337,6 +105003,1602 @@ {} ] ], + "css/css-display/run-in/counter-increment-applies-to-011.xht": [ + [ + "/css/css-display/run-in/counter-increment-applies-to-011.xht", + [ + [ + "/css/reference/pass_if_number_5.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/counter-reset-applies-to-011.xht": [ + [ + "/css/css-display/run-in/counter-reset-applies-to-011.xht", + [ + [ + "/css/reference/pass_if_number_5.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/font-style-applies-to-004.xht": [ + [ + "/css/css-display/run-in/font-style-applies-to-004.xht", + [ + [ + "/css/reference/pass_if_filler_text_slanted.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/font-variant-applies-to-004.xht": [ + [ + "/css/css-display/run-in/font-variant-applies-to-004.xht", + [ + [ + "/css/reference/pass_if_filler_text_match_smallcaps.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/font-weight-applies-to-004.xht": [ + [ + "/css/css-display/run-in/font-weight-applies-to-004.xht", + [ + [ + "/css/reference/pass_if_filler_text_match_bold.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/height-applies-to-011.xht": [ + [ + "/css/css-display/run-in/height-applies-to-011.xht", + [ + [ + "/css/reference/pass_if_square_96px_black.html", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/letter-spacing-applies-to-004.xht": [ + [ + "/css/css-display/run-in/letter-spacing-applies-to-004.xht", + [ + [ + "/css/reference/black_box_ends_when_blue_box_ends_6_boxes_ahem.html", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/list-style-applies-to-011.xht": [ + [ + "/css/css-display/run-in/list-style-applies-to-011.xht", + [ + [ + "/css/reference/single_square_list_marker.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/list-style-type-applies-to-011.xht": [ + [ + "/css/css-display/run-in/list-style-type-applies-to-011.xht", + [ + [ + "/css/reference/single_square_list_marker.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/max-height-applies-to-011.xht": [ + [ + "/css/css-display/run-in/max-height-applies-to-011.xht", + [ + [ + "/css/reference/pass_if_square_96px_black.html", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/max-width-applies-to-011.xht": [ + [ + "/css/css-display/run-in/max-width-applies-to-011.xht", + [ + [ + "/css/reference/pass_if_square_96px_black.html", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/min-height-applies-to-011.xht": [ + [ + "/css/css-display/run-in/min-height-applies-to-011.xht", + [ + [ + "/css/reference/pass_if_square_96px_black.html", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/min-width-applies-to-011.xht": [ + [ + "/css/css-display/run-in/min-width-applies-to-011.xht", + [ + [ + "/css/reference/pass_if_square_96px_black.html", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/quotes-applies-to-011.xht": [ + [ + "/css/css-display/run-in/quotes-applies-to-011.xht", + [ + [ + "/css/reference/pass_if_pass_below.html", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-abspos-between-001.xht": [ + [ + "/css/css-display/run-in/run-in-abspos-between-001.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-abspos-between-002.xht": [ + [ + "/css/css-display/run-in/run-in-abspos-between-002.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-abspos-between-003.xht": [ + [ + "/css/css-display/run-in/run-in-abspos-between-003.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-basic-001.xht": [ + [ + "/css/css-display/run-in/run-in-basic-001.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-basic-002.xht": [ + [ + "/css/css-display/run-in/run-in-basic-002.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-basic-003.xht": [ + [ + "/css/css-display/run-in/run-in-basic-003.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-basic-004.xht": [ + [ + "/css/css-display/run-in/run-in-basic-004.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-basic-005.xht": [ + [ + "/css/css-display/run-in/run-in-basic-005.xht", + [ + [ + "/css/css-display/run-in/run-in-block-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-basic-006.xht": [ + [ + "/css/css-display/run-in/run-in-basic-006.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-basic-007.xht": [ + [ + "/css/css-display/run-in/run-in-basic-007.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-007-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-basic-008.xht": [ + [ + "/css/css-display/run-in/run-in-basic-008.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-basic-009.xht": [ + [ + "/css/css-display/run-in/run-in-basic-009.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-basic-010.xht": [ + [ + "/css/css-display/run-in/run-in-basic-010.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-basic-011.xht": [ + [ + "/css/css-display/run-in/run-in-basic-011.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-basic-012.xht": [ + [ + "/css/css-display/run-in/run-in-basic-012.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-basic-013.xht": [ + [ + "/css/css-display/run-in/run-in-basic-013.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-basic-014.xht": [ + [ + "/css/css-display/run-in/run-in-basic-014.xht", + [ + [ + "/css/css-display/run-in/run-in-pre-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-basic-015.xht": [ + [ + "/css/css-display/run-in/run-in-basic-015.xht", + [ + [ + "/css/css-display/run-in/run-in-pre-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-basic-016.xht": [ + [ + "/css/css-display/run-in/run-in-basic-016.xht", + [ + [ + "/css/css-display/run-in/run-in-pre-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-basic-017.xht": [ + [ + "/css/css-display/run-in/run-in-basic-017.xht", + [ + [ + "/css/css-display/run-in/run-in-pre-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-basic-018.xht": [ + [ + "/css/css-display/run-in/run-in-basic-018.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-block-between-001.xht": [ + [ + "/css/css-display/run-in/run-in-block-between-001.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-block-between-002.xht": [ + [ + "/css/css-display/run-in/run-in-block-between-002.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-block-between-003.xht": [ + [ + "/css/css-display/run-in/run-in-block-between-003.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-breaking-001.xht": [ + [ + "/css/css-display/run-in/run-in-breaking-001.xht", + [ + [ + "/css/css-display/run-in/run-in-breaking-001-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-breaking-002.xht": [ + [ + "/css/css-display/run-in/run-in-breaking-002.xht", + [ + [ + "/css/css-display/run-in/run-in-breaking-002-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-clear-001.xht": [ + [ + "/css/css-display/run-in/run-in-clear-001.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-clear-002.xht": [ + [ + "/css/css-display/run-in/run-in-clear-002.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-abspos-001.xht": [ + [ + "/css/css-display/run-in/run-in-contains-abspos-001.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-block-001.xht": [ + [ + "/css/css-display/run-in/run-in-contains-block-001.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-block-002.xht": [ + [ + "/css/css-display/run-in/run-in-contains-block-002.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-block-003.xht": [ + [ + "/css/css-display/run-in/run-in-contains-block-003.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-block-004.xht": [ + [ + "/css/css-display/run-in/run-in-contains-block-004.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-block-005.xht": [ + [ + "/css/css-display/run-in/run-in-contains-block-005.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-block-inside-inline-001.xht": [ + [ + "/css/css-display/run-in/run-in-contains-block-inside-inline-001.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-block-inside-inline-002.xht": [ + [ + "/css/css-display/run-in/run-in-contains-block-inside-inline-002.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-block-inside-inline-003.xht": [ + [ + "/css/css-display/run-in/run-in-contains-block-inside-inline-003.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-float-001.xht": [ + [ + "/css/css-display/run-in/run-in-contains-float-001.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-inline-001.xht": [ + [ + "/css/css-display/run-in/run-in-contains-inline-001.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-inline-002.xht": [ + [ + "/css/css-display/run-in/run-in-contains-inline-002.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-inline-003.xht": [ + [ + "/css/css-display/run-in/run-in-contains-inline-003.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-inline-004.xht": [ + [ + "/css/css-display/run-in/run-in-contains-inline-004.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-inline-005.xht": [ + [ + "/css/css-display/run-in/run-in-contains-inline-005.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-inline-006.xht": [ + [ + "/css/css-display/run-in/run-in-contains-inline-006.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-inline-007.xht": [ + [ + "/css/css-display/run-in/run-in-contains-inline-007.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-inline-block-001.xht": [ + [ + "/css/css-display/run-in/run-in-contains-inline-block-001.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-inline-table-001.xht": [ + [ + "/css/css-display/run-in/run-in-contains-inline-table-001.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-relpos-block-001.xht": [ + [ + "/css/css-display/run-in/run-in-contains-relpos-block-001.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-relpos-block-002.xht": [ + [ + "/css/css-display/run-in/run-in-contains-relpos-block-002.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-relpos-block-003.xht": [ + [ + "/css/css-display/run-in/run-in-contains-relpos-block-003.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-run-in-001.xht": [ + [ + "/css/css-display/run-in/run-in-contains-run-in-001.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-run-in-002.xht": [ + [ + "/css/css-display/run-in/run-in-contains-run-in-002.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-run-in-003.xht": [ + [ + "/css/css-display/run-in/run-in-contains-run-in-003.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-table-001.xht": [ + [ + "/css/css-display/run-in/run-in-contains-table-001.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-table-002.xht": [ + [ + "/css/css-display/run-in/run-in-contains-table-002.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-table-003.xht": [ + [ + "/css/css-display/run-in/run-in-contains-table-003.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-table-caption-001.xht": [ + [ + "/css/css-display/run-in/run-in-contains-table-caption-001.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-table-cell-001.xht": [ + [ + "/css/css-display/run-in/run-in-contains-table-cell-001.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-table-column-001.xht": [ + [ + "/css/css-display/run-in/run-in-contains-table-column-001.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-table-column-group-001.xht": [ + [ + "/css/css-display/run-in/run-in-contains-table-column-group-001.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-table-inside-inline-001.xht": [ + [ + "/css/css-display/run-in/run-in-contains-table-inside-inline-001.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-table-inside-inline-002.xht": [ + [ + "/css/css-display/run-in/run-in-contains-table-inside-inline-002.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-table-inside-inline-003.xht": [ + [ + "/css/css-display/run-in/run-in-contains-table-inside-inline-003.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-table-row-001.xht": [ + [ + "/css/css-display/run-in/run-in-contains-table-row-001.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-contains-table-row-group-001.xht": [ + [ + "/css/css-display/run-in/run-in-contains-table-row-group-001.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-display-none-between-001.xht": [ + [ + "/css/css-display/run-in/run-in-display-none-between-001.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-display-none-between-002.xht": [ + [ + "/css/css-display/run-in/run-in-display-none-between-002.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-display-none-between-003.xht": [ + [ + "/css/css-display/run-in/run-in-display-none-between-003.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-fixedpos-between-001.xht": [ + [ + "/css/css-display/run-in/run-in-fixedpos-between-001.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-fixedpos-between-002.xht": [ + [ + "/css/css-display/run-in/run-in-fixedpos-between-002.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-fixedpos-between-003.xht": [ + [ + "/css/css-display/run-in/run-in-fixedpos-between-003.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-float-between-001.xht": [ + [ + "/css/css-display/run-in/run-in-float-between-001.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-float-between-002.xht": [ + [ + "/css/css-display/run-in/run-in-float-between-002.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-float-between-003.xht": [ + [ + "/css/css-display/run-in/run-in-float-between-003.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-inherit-001.xht": [ + [ + "/css/css-display/run-in/run-in-inherit-001.xht", + [ + [ + "/css/css-display/run-in/run-in-inherit-001-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-inline-between-001.xht": [ + [ + "/css/css-display/run-in/run-in-inline-between-001.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-inline-between-002.xht": [ + [ + "/css/css-display/run-in/run-in-inline-between-002.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-inline-between-003.xht": [ + [ + "/css/css-display/run-in/run-in-inline-between-003.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-inline-block-between-001.xht": [ + [ + "/css/css-display/run-in/run-in-inline-block-between-001.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-inline-block-between-002.xht": [ + [ + "/css/css-display/run-in/run-in-inline-block-between-002.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-inline-block-between-003.xht": [ + [ + "/css/css-display/run-in/run-in-inline-block-between-003.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-inline-table-between-001.xht": [ + [ + "/css/css-display/run-in/run-in-inline-table-between-001.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-inline-table-between-002.xht": [ + [ + "/css/css-display/run-in/run-in-inline-table-between-002.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-inline-table-between-003.xht": [ + [ + "/css/css-display/run-in/run-in-inline-table-between-003.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-listitem-between-001.xht": [ + [ + "/css/css-display/run-in/run-in-listitem-between-001.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-listitem-between-002.xht": [ + [ + "/css/css-display/run-in/run-in-listitem-between-002.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-listitem-between-003.xht": [ + [ + "/css/css-display/run-in/run-in-listitem-between-003.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-relpos-between-001.xht": [ + [ + "/css/css-display/run-in/run-in-relpos-between-001.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-relpos-between-002.xht": [ + [ + "/css/css-display/run-in/run-in-relpos-between-002.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-relpos-between-003.xht": [ + [ + "/css/css-display/run-in/run-in-relpos-between-003.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-replaced-001.xht": [ + [ + "/css/css-display/run-in/run-in-replaced-001.xht", + [ + [ + "/css/css-display/run-in/run-in-replaced-001-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-restyle-001.xht": [ + [ + "/css/css-display/run-in/run-in-restyle-001.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-restyle-002.xht": [ + [ + "/css/css-display/run-in/run-in-restyle-002.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-restyle-003.xht": [ + [ + "/css/css-display/run-in/run-in-restyle-003.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-run-in-between-001.xht": [ + [ + "/css/css-display/run-in/run-in-run-in-between-001.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-run-in-between-002.xht": [ + [ + "/css/css-display/run-in/run-in-run-in-between-002.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-run-in-between-003.xht": [ + [ + "/css/css-display/run-in/run-in-run-in-between-003.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-run-in-between-004.xht": [ + [ + "/css/css-display/run-in/run-in-run-in-between-004.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-run-in-between-005.xht": [ + [ + "/css/css-display/run-in/run-in-run-in-between-005.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-run-in-between-006.xht": [ + [ + "/css/css-display/run-in/run-in-run-in-between-006.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-run-in-between-007.xht": [ + [ + "/css/css-display/run-in/run-in-run-in-between-007.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-run-in-between-008.xht": [ + [ + "/css/css-display/run-in/run-in-run-in-between-008.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-table-between-001.xht": [ + [ + "/css/css-display/run-in/run-in-table-between-001.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-table-between-002.xht": [ + [ + "/css/css-display/run-in/run-in-table-between-002.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-table-between-003.xht": [ + [ + "/css/css-display/run-in/run-in-table-between-003.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-table-cell-between-001.xht": [ + [ + "/css/css-display/run-in/run-in-table-cell-between-001.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-table-cell-between-002.xht": [ + [ + "/css/css-display/run-in/run-in-table-cell-between-002.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-table-cell-between-003.xht": [ + [ + "/css/css-display/run-in/run-in-table-cell-between-003.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-table-row-between-001.xht": [ + [ + "/css/css-display/run-in/run-in-table-row-between-001.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-table-row-between-002.xht": [ + [ + "/css/css-display/run-in/run-in-table-row-between-002.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-table-row-between-003.xht": [ + [ + "/css/css-display/run-in/run-in-table-row-between-003.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-text-between-001.xht": [ + [ + "/css/css-display/run-in/run-in-text-between-001.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-text-between-002.xht": [ + [ + "/css/css-display/run-in/run-in-text-between-002.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-text-between-003.xht": [ + [ + "/css/css-display/run-in/run-in-text-between-003.xht", + [ + [ + "/css/css-display/run-in/run-in-text-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-text-between-004.xht": [ + [ + "/css/css-display/run-in/run-in-text-between-004.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/run-in-text-between-005.xht": [ + [ + "/css/css-display/run-in/run-in-text-between-005.xht", + [ + [ + "/css/css-display/run-in/run-in-basic-ref.xht", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/text-decoration-applies-to-004.xht": [ + [ + "/css/css-display/run-in/text-decoration-applies-to-004.xht", + [ + [ + "/css/reference/pass_if_filler_text_underlined.html", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/text-transform-applies-to-004.xht": [ + [ + "/css/css-display/run-in/text-transform-applies-to-004.xht", + [ + [ + "/css/reference/pass_if_letter_uppercase.html", + "==" + ] + ], + {} + ] + ], + "css/css-display/run-in/width-applies-to-011.xht": [ + [ + "/css/css-display/run-in/width-applies-to-011.xht", + [ + [ + "/css/reference/pass_if_square_96px_black.html", + "==" + ] + ], + {} + ] + ], "css/css-exclusions/css3-exclusions/exclusions-wrap-flow-01.xht": [ [ "/css/css-exclusions/css3-exclusions/exclusions-wrap-flow-01.xht", @@ -104673,6 +106935,78 @@ {} ] ], + "css/css-flexbox/anonymous-flex-item-001.html": [ + [ + "/css/css-flexbox/anonymous-flex-item-001.html", + [ + [ + "/css/css-flexbox/anonymous-flex-item-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-flexbox/anonymous-flex-item-002.html": [ + [ + "/css/css-flexbox/anonymous-flex-item-002.html", + [ + [ + "/css/css-flexbox/anonymous-flex-item-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-flexbox/anonymous-flex-item-003.html": [ + [ + "/css/css-flexbox/anonymous-flex-item-003.html", + [ + [ + "/css/css-flexbox/anonymous-flex-item-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-flexbox/anonymous-flex-item-004.html": [ + [ + "/css/css-flexbox/anonymous-flex-item-004.html", + [ + [ + "/css/css-flexbox/anonymous-flex-item-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-flexbox/anonymous-flex-item-005.html": [ + [ + "/css/css-flexbox/anonymous-flex-item-005.html", + [ + [ + "/css/css-flexbox/anonymous-flex-item-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-flexbox/anonymous-flex-item-006.html": [ + [ + "/css/css-flexbox/anonymous-flex-item-006.html", + [ + [ + "/css/css-flexbox/anonymous-flex-item-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-flexbox/auto-margins-001.html": [ [ "/css/css-flexbox/auto-margins-001.html", @@ -108429,6 +110763,18 @@ {} ] ], + "css/css-flexbox/percentage-heights-004.html": [ + [ + "/css/css-flexbox/percentage-heights-004.html", + [ + [ + "/css/css-flexbox/percentage-heights-004-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-flexbox/percentage-widths-001.html": [ [ "/css/css-flexbox/percentage-widths-001.html", @@ -108453,6 +110799,30 @@ {} ] ], + "css/css-flexbox/table-as-item-narrow-content.html": [ + [ + "/css/css-flexbox/table-as-item-narrow-content.html", + [ + [ + "/css/reference/ref-filled-green-100px-square-only.html", + "==" + ] + ], + {} + ] + ], + "css/css-flexbox/table-as-item-wide-content.html": [ + [ + "/css/css-flexbox/table-as-item-wide-content.html", + [ + [ + "/css/reference/ref-filled-green-100px-square-only.html", + "==" + ] + ], + {} + ] + ], "css/css-flexbox/ttwf-reftest-flex-align-content-center.html": [ [ "/css/css-flexbox/ttwf-reftest-flex-align-content-center.html", @@ -108633,6 +111003,158 @@ {} ] ], + "css/css-fonts/first-available-font-001.html": [ + [ + "/css/css-fonts/first-available-font-001.html", + [ + [ + "/css/css-fonts/first-available-font-001-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-fonts/first-available-font-002.html": [ + [ + "/css/css-fonts/first-available-font-002.html", + [ + [ + "/css/css-fonts/first-available-font-002-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-fonts/first-available-font-003.html": [ + [ + "/css/css-fonts/first-available-font-003.html", + [ + [ + "/css/css-fonts/first-available-font-003-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-fonts/first-available-font-004.html": [ + [ + "/css/css-fonts/first-available-font-004.html", + [ + [ + "/css/css-fonts/first-available-font-003-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-fonts/first-available-font-005.html": [ + [ + "/css/css-fonts/first-available-font-005.html", + [ + [ + "/css/css-fonts/first-available-font-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-fonts/first-available-font-006.html": [ + [ + "/css/css-fonts/first-available-font-006.html", + [ + [ + "/css/css-fonts/first-available-font-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-fonts/first-available-font-007.html": [ + [ + "/css/css-fonts/first-available-font-007.html", + [ + [ + "/css/css-fonts/first-available-font-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-fonts/font-default-01.html": [ + [ + "/css/css-fonts/font-default-01.html", + [ + [ + "/css/css-fonts/font-default-01-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-fonts/font-default-02.html": [ + [ + "/css/css-fonts/font-default-02.html", + [ + [ + "/css/css-fonts/font-default-02-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-fonts/font-default-03.html": [ + [ + "/css/css-fonts/font-default-03.html", + [ + [ + "/css/css-fonts/font-default-03-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-fonts/font-default-04.html": [ + [ + "/css/css-fonts/font-default-04.html", + [ + [ + "/css/css-fonts/font-default-04-a-ref.html", + "==" + ], + [ + "/css/css-fonts/font-default-04-b-ref.html", + "==" + ], + [ + "/css/css-fonts/font-default-04-c-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-fonts/font-display/font-display-change.html": [ + [ + "/css/css-fonts/font-display/font-display-change.html", + [ + [ + "/css/css-fonts/font-display/font-display-change-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-fonts/font-display/font-display.html": [ [ "/css/css-fonts/font-display/font-display.html", @@ -111357,6 +113879,18 @@ {} ] ], + "css/css-grid/grid-items/explicitly-sized-grid-item-as-table.html": [ + [ + "/css/css-grid/grid-items/explicitly-sized-grid-item-as-table.html", + [ + [ + "/css/reference/ref-filled-green-100px-square-only.html", + "==" + ] + ], + {} + ] + ], "css/css-grid/grid-items/grid-inline-items-001.html": [ [ "/css/css-grid/grid-items/grid-inline-items-001.html", @@ -112905,6 +115439,54 @@ {} ] ], + "css/css-lists/counter-increment-inside-display-contents.html": [ + [ + "/css/css-lists/counter-increment-inside-display-contents.html", + [ + [ + "/css/css-lists/counter-7-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-lists/counter-reset-increment-display-contents.html": [ + [ + "/css/css-lists/counter-reset-increment-display-contents.html", + [ + [ + "/css/css-lists/counter-7-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-lists/counter-reset-increment-display-none.html": [ + [ + "/css/css-lists/counter-reset-increment-display-none.html", + [ + [ + "/css/css-lists/counter-7-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-lists/counter-reset-inside-display-contents.html": [ + [ + "/css/css-lists/counter-reset-inside-display-contents.html", + [ + [ + "/css/css-lists/counter-7-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-logical/cascading-001.html": [ [ "/css/css-logical/cascading-001.html", @@ -114854,7 +117436,7 @@ "/css/css-multicol/multicol-br-inside-avoidcolumn-001.xht", [ [ - "/css/css-multicol/multicol-br-inside-avoidcolumn-ref.xht", + "/css/reference/ref-filled-green-200px-square.html", "==" ] ], @@ -115089,30 +117671,6 @@ {} ] ], - "css/css-multicol/multicol-count-computed-001.xht": [ - [ - "/css/css-multicol/multicol-count-computed-001.xht", - [ - [ - "/css/css-multicol/multicol-count-computed-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-multicol/multicol-count-computed-002.xht": [ - [ - "/css/css-multicol/multicol-count-computed-002.xht", - [ - [ - "/css/css-multicol/multicol-count-computed-2-ref.xht", - "==" - ] - ], - {} - ] - ], "css/css-multicol/multicol-count-computed-003.xht": [ [ "/css/css-multicol/multicol-count-computed-003.xht", @@ -115149,30 +117707,6 @@ {} ] ], - "css/css-multicol/multicol-count-large-001.xht": [ - [ - "/css/css-multicol/multicol-count-large-001.xht", - [ - [ - "/css/css-multicol/multicol-count-large-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-multicol/multicol-count-large-002.xht": [ - [ - "/css/css-multicol/multicol-count-large-002.xht", - [ - [ - "/css/css-multicol/multicol-count-large-2-ref.xht", - "==" - ] - ], - {} - ] - ], "css/css-multicol/multicol-count-negative-001.xht": [ [ "/css/css-multicol/multicol-count-negative-001.xht", @@ -115317,18 +117851,6 @@ {} ] ], - "css/css-multicol/multicol-fill-auto.xht": [ - [ - "/css/css-multicol/multicol-fill-auto.xht", - [ - [ - "/css/css-multicol/multicol-fill-ref.xht", - "==" - ] - ], - {} - ] - ], "css/css-multicol/multicol-fill-balance-001.xht": [ [ "/css/css-multicol/multicol-fill-balance-001.xht", @@ -115401,6 +117923,18 @@ {} ] ], + "css/css-multicol/multicol-gap-fraction-002.html": [ + [ + "/css/css-multicol/multicol-gap-fraction-002.html", + [ + [ + "/css/reference/nothing.html", + "==" + ] + ], + {} + ] + ], "css/css-multicol/multicol-gap-large-001.xht": [ [ "/css/css-multicol/multicol-gap-large-001.xht", @@ -115497,18 +118031,6 @@ {} ] ], - "css/css-multicol/multicol-inherit-004.xht": [ - [ - "/css/css-multicol/multicol-inherit-004.xht", - [ - [ - "/css/css-multicol/multicol-inherit-4-ref.xht", - "==" - ] - ], - {} - ] - ], "css/css-multicol/multicol-list-item-001.xht": [ [ "/css/css-multicol/multicol-list-item-001.xht", @@ -116025,54 +118547,6 @@ {} ] ], - "css/css-multicol/multicol-rule-style-groove-001.xht": [ - [ - "/css/css-multicol/multicol-rule-style-groove-001.xht", - [ - [ - "/css/css-multicol/multicol-rule-style-groove-001-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-multicol/multicol-rule-style-inset-001.xht": [ - [ - "/css/css-multicol/multicol-rule-style-inset-001.xht", - [ - [ - "/css/css-multicol/multicol-rule-style-ridge-001-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-multicol/multicol-rule-style-outset-001.xht": [ - [ - "/css/css-multicol/multicol-rule-style-outset-001.xht", - [ - [ - "/css/css-multicol/multicol-rule-style-groove-001-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-multicol/multicol-rule-style-ridge-001.xht": [ - [ - "/css/css-multicol/multicol-rule-style-ridge-001.xht", - [ - [ - "/css/css-multicol/multicol-rule-style-ridge-001-ref.xht", - "==" - ] - ], - {} - ] - ], "css/css-multicol/multicol-shorthand-001.xht": [ [ "/css/css-multicol/multicol-shorthand-001.xht", @@ -116145,30 +118619,6 @@ {} ] ], - "css/css-multicol/multicol-span-all-child-001.xht": [ - [ - "/css/css-multicol/multicol-span-all-child-001.xht", - [ - [ - "/css/css-multicol/multicol-span-all-child-001-ref.xht", - "==" - ] - ], - {} - ] - ], - "css/css-multicol/multicol-span-all-child-002.xht": [ - [ - "/css/css-multicol/multicol-span-all-child-002.xht", - [ - [ - "/css/css-multicol/multicol-span-all-child-002-ref.xht", - "==" - ] - ], - {} - ] - ], "css/css-multicol/multicol-span-all-margin-001.xht": [ [ "/css/css-multicol/multicol-span-all-margin-001.xht", @@ -116229,18 +118679,6 @@ {} ] ], - "css/css-multicol/multicol-span-all-margin-nested-003.xht": [ - [ - "/css/css-multicol/multicol-span-all-margin-nested-003.xht", - [ - [ - "/css/css-multicol/multicol-span-all-margin-nested-3-ref.xht", - "==" - ] - ], - {} - ] - ], "css/css-multicol/multicol-span-all-margin-nested-firstchild-001.xht": [ [ "/css/css-multicol/multicol-span-all-margin-nested-firstchild-001.xht", @@ -116361,6 +118799,18 @@ {} ] ], + "css/css-multicol/multicol-width-ch-001.xht": [ + [ + "/css/css-multicol/multicol-width-ch-001.xht", + [ + [ + "/css/css-multicol/multicol-width-ch-ref.xht", + "==" + ] + ], + {} + ] + ], "css/css-multicol/multicol-width-count-001.xht": [ [ "/css/css-multicol/multicol-width-count-001.xht", @@ -116385,18 +118835,6 @@ {} ] ], - "css/css-multicol/multicol-width-ems-001.xht": [ - [ - "/css/css-multicol/multicol-width-ems-001.xht", - [ - [ - "/css/css-multicol/multicol-width-ems-ref.xht", - "==" - ] - ], - {} - ] - ], "css/css-multicol/multicol-width-invalid-001.xht": [ [ "/css/css-multicol/multicol-width-invalid-001.xht", @@ -116745,6 +119183,18 @@ {} ] ], + "css/css-overflow/input-scrollable-region-001.html": [ + [ + "/css/css-overflow/input-scrollable-region-001.html", + [ + [ + "/css/css-overflow/reference/input-scrollable-region-001-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-paint-api/background-image-alpha.https.html": [ [ "/css/css-paint-api/background-image-alpha.https.html", @@ -116889,6 +119339,18 @@ {} ] ], + "css/css-paint-api/geometry-with-float-size.https.html": [ + [ + "/css/css-paint-api/geometry-with-float-size.https.html", + [ + [ + "/css/css-paint-api/geometry-with-float-size-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-paint-api/hidpi/device-pixel-ratio.https.html": [ [ "/css/css-paint-api/hidpi/device-pixel-ratio.https.html", @@ -117825,6 +120287,18 @@ {} ] ], + "css/css-position/position-sticky-table-parts.html": [ + [ + "/css/css-position/position-sticky-table-parts.html", + [ + [ + "/css/css-position/position-sticky-table-parts-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-position/position-sticky-table-tfoot-bottom.html": [ [ "/css/css-position/position-sticky-table-tfoot-bottom.html", @@ -121986,7 +124460,7 @@ "/css/css-style-attr/style-attr-urls-003.xht", [ [ - "/css/css-style-attr/reference/ref-green-on-green2.xht", + "/css/css-style-attr/reference/ref-green-on-green.xht", "==" ] ], @@ -122041,6 +124515,66 @@ {} ] ], + "css/css-tables/zero-rowspan-001.html": [ + [ + "/css/css-tables/zero-rowspan-001.html", + [ + [ + "/css/css-tables/zero-rowspan-001-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-tables/zero-rowspan-002.html": [ + [ + "/css/css-tables/zero-rowspan-002.html", + [ + [ + "/css/css-tables/zero-rowspan-002-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text-decor/line-through-vertical.html": [ + [ + "/css/css-text-decor/line-through-vertical.html", + [ + [ + "/css/css-text-decor/reference/line-through-vertical-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text-decor/text-decoration-color-recalc.html": [ + [ + "/css/css-text-decor/text-decoration-color-recalc.html", + [ + [ + "/css/css-text-decor/reference/text-decoration-color-recalc-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text-decor/text-decoration-color.html": [ + [ + "/css/css-text-decor/text-decoration-color.html", + [ + [ + "/css/css-text-decor/reference/text-decoration-color-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-text-decor/text-decoration-line-010.xht": [ [ "/css/css-text-decor/text-decoration-line-010.xht", @@ -122089,6 +124623,54 @@ {} ] ], + "css/css-text-decor/text-decoration-line-recalc.html": [ + [ + "/css/css-text-decor/text-decoration-line-recalc.html", + [ + [ + "/css/css-text-decor/reference/text-decoration-line-recalc-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text-decor/text-decoration-line.html": [ + [ + "/css/css-text-decor/text-decoration-line.html", + [ + [ + "/css/css-text-decor/reference/text-decoration-line-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text-decor/text-decoration-style-multiple.html": [ + [ + "/css/css-text-decor/text-decoration-style-multiple.html", + [ + [ + "/css/css-text-decor/reference/text-decoration-style-multiple-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text-decor/text-decoration-style-recalc.html": [ + [ + "/css/css-text-decor/text-decoration-style-recalc.html", + [ + [ + "/css/css-text-decor/reference/text-decoration-style-recalc-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-text-decor/text-emphasis-color-001.xht": [ [ "/css/css-text-decor/text-emphasis-color-001.xht", @@ -130645,6 +133227,18 @@ {} ] ], + "css/css-transforms/css-transform-inherit-scale.html": [ + [ + "/css/css-transforms/css-transform-inherit-scale.html", + [ + [ + "/css/reference/ref-filled-green-200px-square.html", + "==" + ] + ], + {} + ] + ], "css/css-transforms/css-transform-scale-001.html": [ [ "/css/css-transforms/css-transform-scale-001.html", @@ -136373,6 +138967,90 @@ {} ] ], + "css/css-transforms/transform-box/fill-box-mutation.html": [ + [ + "/css/css-transforms/transform-box/fill-box-mutation.html", + [ + [ + "/css/css-transforms/transform-box/support/greensquare200x200.html", + "==" + ] + ], + {} + ] + ], + "css/css-transforms/transform-box/fill-box.html": [ + [ + "/css/css-transforms/transform-box/fill-box.html", + [ + [ + "/css/css-transforms/transform-box/support/greensquare200x200.html", + "==" + ] + ], + {} + ] + ], + "css/css-transforms/transform-box/value-changed.html": [ + [ + "/css/css-transforms/transform-box/value-changed.html", + [ + [ + "/css/css-transforms/transform-box/support/greensquare200x200.html", + "==" + ] + ], + {} + ] + ], + "css/css-transforms/transform-box/view-box-nested.html": [ + [ + "/css/css-transforms/transform-box/view-box-nested.html", + [ + [ + "/css/css-transforms/transform-box/support/greensquare200x200.html", + "==" + ] + ], + {} + ] + ], + "css/css-transforms/transform-box/view-box-viewbox-nested.html": [ + [ + "/css/css-transforms/transform-box/view-box-viewbox-nested.html", + [ + [ + "/css/css-transforms/transform-box/support/greensquare200x200.html", + "==" + ] + ], + {} + ] + ], + "css/css-transforms/transform-box/view-box-viewbox.html": [ + [ + "/css/css-transforms/transform-box/view-box-viewbox.html", + [ + [ + "/css/css-transforms/transform-box/support/greensquare200x200.html", + "==" + ] + ], + {} + ] + ], + "css/css-transforms/transform-box/view-box.html": [ + [ + "/css/css-transforms/transform-box/view-box.html", + [ + [ + "/css/css-transforms/transform-box/support/greensquare200x200.html", + "==" + ] + ], + {} + ] + ], "css/css-transforms/transform-compound-001.html": [ [ "/css/css-transforms/transform-compound-001.html", @@ -148169,6 +150847,18 @@ {} ] ], + "css/css-writing-modes/bidi-table-001.html": [ + [ + "/css/css-writing-modes/bidi-table-001.html", + [ + [ + "/css/css-writing-modes/reference/bidi-table-001.html", + "==" + ] + ], + {} + ] + ], "css/css-writing-modes/bidi-unset-001.html": [ [ "/css/css-writing-modes/bidi-unset-001.html", @@ -149069,6 +151759,18 @@ {} ] ], + "css/css-writing-modes/block-plaintext-006.html": [ + [ + "/css/css-writing-modes/block-plaintext-006.html", + [ + [ + "/css/css-writing-modes/reference/block-plaintext-006.html", + "==" + ] + ], + {} + ] + ], "css/css-writing-modes/border-conflict-element-vlr-003.xht": [ [ "/css/css-writing-modes/border-conflict-element-vlr-003.xht", @@ -155041,6 +157743,18 @@ {} ] ], + "css/cssom-view/scrollTop-display-change.html": [ + [ + "/css/cssom-view/scrollTop-display-change.html", + [ + [ + "/css/cssom-view/scrollTop-display-change-ref.html", + "==" + ] + ], + {} + ] + ], "css/cssom-view/scrollingElement-quirks-dynamic-001.html": [ [ "/css/cssom-view/scrollingElement-quirks-dynamic-001.html", @@ -155065,6 +157779,18 @@ {} ] ], + "css/cssom/medialist-dynamic-001.html": [ + [ + "/css/cssom/medialist-dynamic-001.html", + [ + [ + "/css/cssom/medialist-dynamic-001-ref.html", + "==" + ] + ], + {} + ] + ], "css/cssom/selectorText-modification-restyle-001.html": [ [ "/css/cssom/selectorText-modification-restyle-001.html", @@ -155881,6 +158607,18 @@ {} ] ], + "css/selectors/any-link-dynamic-001.html": [ + [ + "/css/selectors/any-link-dynamic-001.html", + [ + [ + "/css/selectors/any-link-dynamic-001-ref.html", + "==" + ] + ], + {} + ] + ], "css/selectors/focus-within-001.html": [ [ "/css/selectors/focus-within-001.html", @@ -170557,6 +173295,18 @@ {} ] ], + "html/browsers/sandboxing/sandbox-parse-noscript.html": [ + [ + "/html/browsers/sandboxing/sandbox-parse-noscript.html", + [ + [ + "/html/browsers/sandboxing/sandbox-parse-noscript-ref.html", + "==" + ] + ], + {} + ] + ], "html/dom/elements/global-attributes/dir_auto-EN-L.html": [ [ "/html/dom/elements/global-attributes/dir_auto-EN-L.html", @@ -171745,6 +174495,78 @@ {} ] ], + "html/form-elements/the-textarea-element/multiline-placeholder-cr.html": [ + [ + "/html/form-elements/the-textarea-element/multiline-placeholder-cr.html", + [ + [ + "/html/form-elements/the-textarea-element/multiline-placeholder-ref.html", + "==" + ] + ], + {} + ] + ], + "html/form-elements/the-textarea-element/multiline-placeholder-crlf.html": [ + [ + "/html/form-elements/the-textarea-element/multiline-placeholder-crlf.html", + [ + [ + "/html/form-elements/the-textarea-element/multiline-placeholder-ref.html", + "==" + ] + ], + {} + ] + ], + "html/form-elements/the-textarea-element/multiline-placeholder.html": [ + [ + "/html/form-elements/the-textarea-element/multiline-placeholder.html", + [ + [ + "/html/form-elements/the-textarea-element/multiline-placeholder-ref.html", + "==" + ] + ], + {} + ] + ], + "html/input/the-placeholder-attribute/multiline-cr.html": [ + [ + "/html/input/the-placeholder-attribute/multiline-cr.html", + [ + [ + "/html/input/the-placeholder-attribute/multiline-ref.html", + "==" + ] + ], + {} + ] + ], + "html/input/the-placeholder-attribute/multiline-crlf.html": [ + [ + "/html/input/the-placeholder-attribute/multiline-crlf.html", + [ + [ + "/html/input/the-placeholder-attribute/multiline-ref.html", + "==" + ] + ], + {} + ] + ], + "html/input/the-placeholder-attribute/multiline.html": [ + [ + "/html/input/the-placeholder-attribute/multiline.html", + [ + [ + "/html/input/the-placeholder-attribute/multiline-ref.html", + "==" + ] + ], + {} + ] + ], "html/rendering/bindings/the-button-element/button-type-menu-historical.html": [ [ "/html/rendering/bindings/the-button-element/button-type-menu-historical.html", @@ -173461,6 +176283,18 @@ {} ] ], + "html/semantics/text-level-semantics/the-b-element/b-usage.html": [ + [ + "/html/semantics/text-level-semantics/the-b-element/b-usage.html", + [ + [ + "/html/semantics/text-level-semantics/the-b-element/b-usage-notref.html", + "!=" + ] + ], + {} + ] + ], "html/semantics/text-level-semantics/the-bdi-element/bdi-auto-dir-default.html": [ [ "/html/semantics/text-level-semantics/the-bdi-element/bdi-auto-dir-default.html", @@ -173725,6 +176559,18 @@ {} ] ], + "html/semantics/text-level-semantics/the-ruby-element/ruby-usage.html": [ + [ + "/html/semantics/text-level-semantics/the-ruby-element/ruby-usage.html", + [ + [ + "/html/semantics/text-level-semantics/the-ruby-element/ruby-usage-notref.html", + "!=" + ] + ], + {} + ] + ], "html/semantics/text-level-semantics/the-wbr-element/wbr-element.html": [ [ "/html/semantics/text-level-semantics/the-wbr-element/wbr-element.html", @@ -174241,12 +177087,12 @@ {} ] ], - "quirks-mode/historical/list-item-bullet-size.html": [ + "quirks/historical/list-item-bullet-size.html": [ [ - "/quirks-mode/historical/list-item-bullet-size.html", + "/quirks/historical/list-item-bullet-size.html", [ [ - "/quirks-mode/historical/list-item-bullet-size-ref.html", + "/quirks/historical/list-item-bullet-size-ref.html", "==" ] ], @@ -174325,6 +177171,18 @@ {} ] ], + "svg/foreignobject/position-svg-root-in-foreign-object.html": [ + [ + "/svg/foreignobject/position-svg-root-in-foreign-object.html", + [ + [ + "/svg/foreignobject/position-svg-root-in-foreign-object-ref.html", + "==" + ] + ], + {} + ] + ], "svg/linking/reftests/href-a-element-attr-change.html": [ [ "/svg/linking/reftests/href-a-element-attr-change.html", @@ -174445,6 +177303,54 @@ {} ] ], + "svg/path/bearing/absolute.svg": [ + [ + "/svg/path/bearing/absolute.svg", + [ + [ + "/svg/path/bearing/absolute-ref.svg", + "==" + ] + ], + {} + ] + ], + "svg/path/bearing/relative.svg": [ + [ + "/svg/path/bearing/relative.svg", + [ + [ + "/svg/path/bearing/absolute-ref.svg", + "==" + ] + ], + {} + ] + ], + "svg/path/bearing/zero.svg": [ + [ + "/svg/path/bearing/zero.svg", + [ + [ + "/svg/path/bearing/zero-ref.svg", + "==" + ] + ], + {} + ] + ], + "svg/path/property/priority.svg": [ + [ + "/svg/path/property/priority.svg", + [ + [ + "/svg/path/property/priority-ref.svg", + "==" + ] + ], + {} + ] + ], "svg/shapes/rect-01.svg": [ [ "/svg/shapes/rect-01.svg", @@ -177168,6 +180074,42 @@ ], {} ] + ], + "webvtt/rendering/cues-with-video/processing-model/track-cue-rendering-position-align-rtl-center.html": [ + [ + "/webvtt/rendering/cues-with-video/processing-model/track-cue-rendering-position-align-rtl-center.html", + [ + [ + "/webvtt/rendering/cues-with-video/processing-model/track-cue-rendering-position-align-rtl-center-ref.html", + "==" + ] + ], + {} + ] + ], + "webvtt/rendering/cues-with-video/processing-model/track-cue-rendering-position-align-rtl-line-left.html": [ + [ + "/webvtt/rendering/cues-with-video/processing-model/track-cue-rendering-position-align-rtl-line-left.html", + [ + [ + "/webvtt/rendering/cues-with-video/processing-model/track-cue-rendering-position-align-rtl-line-left-ref.html", + "==" + ] + ], + {} + ] + ], + "webvtt/rendering/cues-with-video/processing-model/track-cue-rendering-position-align-rtl-line-right.html": [ + [ + "/webvtt/rendering/cues-with-video/processing-model/track-cue-rendering-position-align-rtl-line-right.html", + [ + [ + "/webvtt/rendering/cues-with-video/processing-model/track-cue-rendering-position-align-rtl-line-right-ref.html", + "==" + ] + ], + {} + ] ] }, "reftest_node": { @@ -178202,6 +181144,18 @@ ], {} ] + ], + "infrastructure/assumptions/ahem-ref.html": [ + [ + "/infrastructure/assumptions/ahem-ref.html", + [ + [ + "/infrastructure/assumptions/ahem-notref.html", + "!=" + ] + ], + {} + ] ] }, "stub": { @@ -179747,6 +182701,11 @@ {} ] ], + "FileAPI/support/send-file-form-helper.js": [ + [ + {} + ] + ], "FileAPI/support/upload.txt": [ [ {} @@ -181017,6 +183976,21 @@ {} ] ], + "accelerometer/Accelerometer-disabled-by-feature-policy.https.html.headers": [ + [ + {} + ] + ], + "accelerometer/Accelerometer-enabled-by-feature-policy.https.html.headers": [ + [ + {} + ] + ], + "accelerometer/Accelerometer-enabled-on-self-origin-by-feature-policy.https.html.headers": [ + [ + {} + ] + ], "accelerometer/OWNERS": [ [ {} @@ -181157,6 +184131,21 @@ {} ] ], + "ambient-light/AmbientLightSensor-disabled-by-feature-policy.https.html.headers": [ + [ + {} + ] + ], + "ambient-light/AmbientLightSensor-enabled-by-feature-policy.https.html.headers": [ + [ + {} + ] + ], + "ambient-light/AmbientLightSensor-enabled-on-self-origin-by-feature-policy.https.html.headers": [ + [ + {} + ] + ], "ambient-light/OWNERS": [ [ {} @@ -183632,6 +186621,11 @@ {} ] ], + "beacon/OWNERS": [ + [ + {} + ] + ], "beacon/beacon-common.sub.js": [ [ {} @@ -183667,6 +186661,16 @@ {} ] ], + "bluetooth/README.md": [ + [ + {} + ] + ], + "bluetooth/resources/bluetooth-helpers.js": [ + [ + {} + ] + ], "clear-site-data/support/echo-clear-site-data.py": [ [ {} @@ -183917,11 +186921,6 @@ {} ] ], - "common/vendor-prefix.js.headers": [ - [ - {} - ] - ], "compat/OWNERS": [ [ {} @@ -203057,6 +206056,11 @@ {} ] ], + "conformance-checkers/html/elements/style/html-spec-comms-isvalid.html": [ + [ + {} + ] + ], "conformance-checkers/html/elements/style/model-isvalid.html": [ [ {} @@ -203092,6 +206096,11 @@ {} ] ], + "conformance-checkers/html/elements/style/type-novalid.html": [ + [ + {} + ] + ], "conformance-checkers/html/elements/sub/model-isvalid.html": [ [ {} @@ -206012,6 +209021,11 @@ {} ] ], + "content-security-policy/base-uri/report-uri-does-not-respect-base-uri.sub.html.sub.headers": [ + [ + {} + ] + ], "content-security-policy/connect-src/resources/simple-event-stream": [ [ {} @@ -206147,6 +209161,11 @@ {} ] ], + "content-security-policy/generic/policy-inherited-correctly-by-plznavigate.html.sub.headers": [ + [ + {} + ] + ], "content-security-policy/generic/positiveTest.js": [ [ {} @@ -206612,6 +209631,11 @@ {} ] ], + "content-security-policy/support/fail.html": [ + [ + {} + ] + ], "content-security-policy/support/fail.js": [ [ {} @@ -206657,6 +209681,11 @@ {} ] ], + "content-security-policy/support/nonce-should-be-blocked.js": [ + [ + {} + ] + ], "content-security-policy/support/pass.png": [ [ {} @@ -206727,6 +209756,16 @@ {} ] ], + "cookie-store/OWNERS": [ + [ + {} + ] + ], + "cookie-store/README.md": [ + [ + {} + ] + ], "cookie-store/resources/cookie-store-tests.js": [ [ {} @@ -206742,7 +209781,27 @@ {} ] ], - "cookies/path/echo-cookie.html": [ + "cookie-store/serviceworker_cookieStore_arguments.js": [ + [ + {} + ] + ], + "cookie-store/serviceworker_cookieStore_basic.js": [ + [ + {} + ] + ], + "cookies/OWNERS": [ + [ + {} + ] + ], + "cookies/README.md": [ + [ + {} + ] + ], + "cookies/resources/echo-cookie.html": [ [ {} ] @@ -206852,6 +209911,21 @@ {} ] ], + "credential-management/support/echoing-nester.html": [ + [ + {} + ] + ], + "credential-management/support/federatedcredential-get.html": [ + [ + {} + ] + ], + "credential-management/support/passwordcredential-get.html": [ + [ + {} + ] + ], "css/.gitignore": [ [ {} @@ -214017,6 +217091,11 @@ {} ] ], + "css/CSS2/fonts/font-148-ref.xht": [ + [ + {} + ] + ], "css/CSS2/fonts/font-applies-to-001-ref.xht": [ [ {} @@ -214552,6 +217631,21 @@ {} ] ], + "css/CSS2/generated-content/after-inheritable-001-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/after-inheritable-002-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/after-location-001-ref.html": [ + [ + {} + ] + ], "css/CSS2/generated-content/before-after-011-ref.xht": [ [ {} @@ -214612,6 +217706,351 @@ {} ] ], + "css/CSS2/generated-content/before-location-001-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/bidi-generated-content-001-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/bidi-generated-content-002-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-001-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-003-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-005-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-006-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-007-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-010-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-011-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-012-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-013-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-014-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-015-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-016-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-017-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-021-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-022-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-023-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-026-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-027-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-028-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-029-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-030-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-031-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-032-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-033-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-037-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-040-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-041-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-042-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-043-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-047-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-048-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-050-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-052-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-053-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-063-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-068-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-070-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-072-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-073-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-075-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-080-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-081-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-082-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-083-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-089-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-090-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-091-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-096-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-097-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-100-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-103-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-113-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-126-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-132-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-135-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-136-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-141-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-143-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-144-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-147-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-149-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-150-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-155-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-156-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-158-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-159-ref.html": [ + [ + {} + ] + ], "css/CSS2/generated-content/content-171-ref.xht": [ [ {} @@ -214642,6 +218081,11 @@ {} ] ], + "css/CSS2/generated-content/content-auto-reset-001-ref.html": [ + [ + {} + ] + ], "css/CSS2/generated-content/content-counter-000-ref.xht": [ [ {} @@ -214712,6 +218156,56 @@ {} ] ], + "css/CSS2/generated-content/content-newline-001-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-white-space-001-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-white-space-002-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-white-space-003-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/content-white-space-004-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/counters-hidden-000-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/counters-hidden-002-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/counters-multi-000-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/counters-order-000-ref.html": [ + [ + {} + ] + ], + "css/CSS2/generated-content/counters-root-000-ref.html": [ + [ + {} + ] + ], "css/CSS2/generated-content/quotes-035-ref.xht": [ [ {} @@ -215767,6 +219261,11 @@ {} ] ], + "css/CSS2/linebox/line-height-oof-descendants-001-ref.html": [ + [ + {} + ] + ], "css/CSS2/linebox/support/1x1-green.png": [ [ {} @@ -224407,6 +227906,66 @@ {} ] ], + "css/CSS2/visudet/reference/content-height-001-ref.html": [ + [ + {} + ] + ], + "css/CSS2/visudet/reference/content-height-002-ref.html": [ + [ + {} + ] + ], + "css/CSS2/visudet/reference/content-height-003-ref.html": [ + [ + {} + ] + ], + "css/CSS2/visudet/reference/content-height-004-ref.html": [ + [ + {} + ] + ], + "css/CSS2/visudet/reference/content-height-005-ref.html": [ + [ + {} + ] + ], + "css/CSS2/visudet/reference/line-height-201-ref.html": [ + [ + {} + ] + ], + "css/CSS2/visudet/reference/line-height-202-ref.html": [ + [ + {} + ] + ], + "css/CSS2/visudet/reference/line-height-203-ref.html": [ + [ + {} + ] + ], + "css/CSS2/visudet/reference/line-height-206-ref.html": [ + [ + {} + ] + ], + "css/CSS2/visudet/support/1x1-green.png": [ + [ + {} + ] + ], + "css/CSS2/visudet/support/AD.woff": [ + [ + {} + ] + ], + "css/CSS2/visudet/support/Revalia.woff": [ + [ + {} + ] + ], "css/CSS2/visudet/support/swatch-blue.png": [ [ {} @@ -224712,11 +228271,6 @@ {} ] ], - "css/OWNERS": [ - [ - {} - ] - ], "css/README.md": [ [ {} @@ -227977,11 +231531,6 @@ {} ] ], - "css/compositing/mix-blend-mode/reference/mix-blend-mode-transition-ref.html": [ - [ - {} - ] - ], "css/compositing/mix-blend-mode/reference/mix-blend-mode-video-notref.html": [ [ {} @@ -228212,6 +231761,11 @@ {} ] ], + "css/css-backgrounds/background-color-body-propagation-ref.html": [ + [ + {} + ] + ], "css/css-backgrounds/background-image-centered-ref.html": [ [ {} @@ -229362,77 +232916,7 @@ {} ] ], - "css/css-block/OWNERS": [ - [ - {} - ] - ], - "css/css-block/run-in-basic-007-ref.xht": [ - [ - {} - ] - ], - "css/css-block/run-in-basic-ref.xht": [ - [ - {} - ] - ], - "css/css-block/run-in-block-ref.xht": [ - [ - {} - ] - ], - "css/css-block/run-in-breaking-001-ref.xht": [ - [ - {} - ] - ], - "css/css-block/run-in-breaking-002-ref.xht": [ - [ - {} - ] - ], - "css/css-block/run-in-inherit-001-ref.xht": [ - [ - {} - ] - ], - "css/css-block/run-in-pre-ref.xht": [ - [ - {} - ] - ], - "css/css-block/run-in-replaced-001-ref.xht": [ - [ - {} - ] - ], - "css/css-block/run-in-text-ref.xht": [ - [ - {} - ] - ], - "css/css-block/support/black15x15.png": [ - [ - {} - ] - ], - "css/css-block/support/blue15x15.png": [ - [ - {} - ] - ], - "css/css-block/support/blue96x96.png": [ - [ - {} - ] - ], - "css/css-block/support/green15x15.png": [ - [ - {} - ] - ], - "css/css-block/support/swatch-blue.png": [ + "css/css-break/OWNERS": [ [ {} ] @@ -229477,11 +232961,21 @@ {} ] ], + "css/css-color/greensquare-ref.html": [ + [ + {} + ] + ], "css/css-color/greentext-ref.html": [ [ {} ] ], + "css/css-color/hex-003-ref.html": [ + [ + {} + ] + ], "css/css-color/htaccess": [ [ {} @@ -229502,6 +232996,26 @@ {} ] ], + "css/css-color/t32-opacity-basic-0.0-a-ref.html": [ + [ + {} + ] + ], + "css/css-color/t32-opacity-basic-1.0-a-ref.html": [ + [ + {} + ] + ], + "css/css-color/t32-opacity-clamping-1.0-b-ref.html": [ + [ + {} + ] + ], + "css/css-color/t32-opacity-offscreen-b-ref.html": [ + [ + {} + ] + ], "css/css-color/t32-opacity-offscreen-multiple-boxes-1-c-ref.html": [ [ {} @@ -229512,6 +233026,31 @@ {} ] ], + "css/css-color/t32-opacity-offscreen-with-alpha-c-ref.html": [ + [ + {} + ] + ], + "css/css-color/t41-html4-keywords-a-ref.html": [ + [ + {} + ] + ], + "css/css-color/t421-rgb-clip-outside-gamut-b-ref.html": [ + [ + {} + ] + ], + "css/css-color/t421-rgb-hex3-expand-b-ref.html": [ + [ + {} + ] + ], + "css/css-color/t421-rgb-values-meaning-b-ref.html": [ + [ + {} + ] + ], "css/css-color/t422-rgba-a1.0-a-ref.html": [ [ {} @@ -229557,6 +233096,11 @@ {} ] ], + "css/css-color/t422-rgba-values-meaning-b-ref.html": [ + [ + {} + ] + ], "css/css-color/t423-transparent-2-a-ref.html": [ [ {} @@ -229572,6 +233116,11 @@ {} ] ], + "css/css-color/t424-hsl-h-rotating-b-ref.html": [ + [ + {} + ] + ], "css/css-color/t424-hsl-parsing-f-ref.html": [ [ {} @@ -229657,11 +233206,21 @@ {} ] ], + "css/css-color/t425-hsla-h-rotating-b-ref.html": [ + [ + {} + ] + ], "css/css-color/t425-hsla-values-b-ref.html": [ [ {} ] ], + "css/css-color/t43-svg-keywords-a-ref.html": [ + [ + {} + ] + ], "css/css-color/t44-currentcolor-background-b-ref.html": [ [ {} @@ -229702,6 +233261,11 @@ {} ] ], + "css/css-contain/contain-style-counters-ref.html": [ + [ + {} + ] + ], "css/css-counter-styles/OWNERS": [ [ {} @@ -229737,6 +233301,11 @@ {} ] ], + "css/css-display/display-contents-dynamic-pseudo-insertion-001-ref.html": [ + [ + {} + ] + ], "css/css-display/display-contents-flex-001-ref.html": [ [ {} @@ -229752,6 +233321,11 @@ {} ] ], + "css/css-display/display-contents-line-height-ref.html": [ + [ + {} + ] + ], "css/css-display/display-contents-list-001-ref.html": [ [ {} @@ -229777,12 +233351,12 @@ {} ] ], - "css/css-display/display-contents-replaced-001-ref.html": [ + "css/css-display/display-contents-state-change-001-ref.html": [ [ {} ] ], - "css/css-display/display-contents-state-change-001-ref.html": [ + "css/css-display/display-contents-svg-elements-ref.html": [ [ {} ] @@ -229797,6 +233371,11 @@ {} ] ], + "css/css-display/display-contents-text-inherit-ref.html": [ + [ + {} + ] + ], "css/css-display/display-contents-text-only-001-ref.html": [ [ {} @@ -229812,6 +233391,81 @@ {} ] ], + "css/css-display/run-in/OWNERS": [ + [ + {} + ] + ], + "css/css-display/run-in/run-in-basic-007-ref.xht": [ + [ + {} + ] + ], + "css/css-display/run-in/run-in-basic-ref.xht": [ + [ + {} + ] + ], + "css/css-display/run-in/run-in-block-ref.xht": [ + [ + {} + ] + ], + "css/css-display/run-in/run-in-breaking-001-ref.xht": [ + [ + {} + ] + ], + "css/css-display/run-in/run-in-breaking-002-ref.xht": [ + [ + {} + ] + ], + "css/css-display/run-in/run-in-inherit-001-ref.xht": [ + [ + {} + ] + ], + "css/css-display/run-in/run-in-pre-ref.xht": [ + [ + {} + ] + ], + "css/css-display/run-in/run-in-replaced-001-ref.xht": [ + [ + {} + ] + ], + "css/css-display/run-in/run-in-text-ref.xht": [ + [ + {} + ] + ], + "css/css-display/run-in/support/black15x15.png": [ + [ + {} + ] + ], + "css/css-display/run-in/support/blue15x15.png": [ + [ + {} + ] + ], + "css/css-display/run-in/support/blue96x96.png": [ + [ + {} + ] + ], + "css/css-display/run-in/support/green15x15.png": [ + [ + {} + ] + ], + "css/css-display/run-in/support/swatch-blue.png": [ + [ + {} + ] + ], "css/css-display/support/acid.css": [ [ {} @@ -229862,6 +233516,11 @@ {} ] ], + "css/css-flexbox/anonymous-flex-item-ref.html": [ + [ + {} + ] + ], "css/css-flexbox/auto-margins-001-ref.html": [ [ {} @@ -230732,6 +234391,11 @@ {} ] ], + "css/css-flexbox/percentage-heights-004-ref.html": [ + [ + {} + ] + ], "css/css-flexbox/percentage-widths-001-ref.html": [ [ {} @@ -231182,6 +234846,61 @@ {} ] ], + "css/css-fonts/first-available-font-001-ref.html": [ + [ + {} + ] + ], + "css/css-fonts/first-available-font-002-ref.html": [ + [ + {} + ] + ], + "css/css-fonts/first-available-font-003-ref.html": [ + [ + {} + ] + ], + "css/css-fonts/first-available-font-005-ref.html": [ + [ + {} + ] + ], + "css/css-fonts/font-default-01-ref.html": [ + [ + {} + ] + ], + "css/css-fonts/font-default-02-ref.html": [ + [ + {} + ] + ], + "css/css-fonts/font-default-03-ref.html": [ + [ + {} + ] + ], + "css/css-fonts/font-default-04-a-ref.html": [ + [ + {} + ] + ], + "css/css-fonts/font-default-04-b-ref.html": [ + [ + {} + ] + ], + "css/css-fonts/font-default-04-c-ref.html": [ + [ + {} + ] + ], + "css/css-fonts/font-display/font-display-change-ref.html": [ + [ + {} + ] + ], "css/css-fonts/font-display/font-display-ref.html": [ [ {} @@ -231722,11 +235441,21 @@ {} ] ], + "css/css-fonts/support/AD.woff": [ + [ + {} + ] + ], "css/css-fonts/support/README": [ [ {} ] ], + "css/css-fonts/support/Revalia.woff": [ + [ + {} + ] + ], "css/css-fonts/support/bar_with_corner_dot.png": [ [ {} @@ -239917,6 +243646,11 @@ {} ] ], + "css/css-lists/counter-7-ref.html": [ + [ + {} + ] + ], "css/css-logical/OWNERS": [ [ {} @@ -240197,11 +243931,6 @@ {} ] ], - "css/css-multicol/multicol-br-inside-avoidcolumn-ref.xht": [ - [ - {} - ] - ], "css/css-multicol/multicol-break-000-ref.xht": [ [ {} @@ -240262,26 +243991,6 @@ {} ] ], - "css/css-multicol/multicol-count-computed-2-ref.xht": [ - [ - {} - ] - ], - "css/css-multicol/multicol-count-computed-ref.xht": [ - [ - {} - ] - ], - "css/css-multicol/multicol-count-large-2-ref.xht": [ - [ - {} - ] - ], - "css/css-multicol/multicol-count-large-ref.xht": [ - [ - {} - ] - ], "css/css-multicol/multicol-fill-000-ref.xht": [ [ {} @@ -240317,21 +244026,11 @@ {} ] ], - "css/css-multicol/multicol-fill-auto-ref.xht": [ - [ - {} - ] - ], "css/css-multicol/multicol-fill-balance-001-ref.xht": [ [ {} ] ], - "css/css-multicol/multicol-fill-ref.xht": [ - [ - {} - ] - ], "css/css-multicol/multicol-gap-000-ref.xht": [ [ {} @@ -240387,11 +244086,6 @@ {} ] ], - "css/css-multicol/multicol-inherit-4-ref.xht": [ - [ - {} - ] - ], "css/css-multicol/multicol-list-item-001-ref.xht": [ [ {} @@ -240562,16 +244256,6 @@ {} ] ], - "css/css-multicol/multicol-rule-style-groove-001-ref.xht": [ - [ - {} - ] - ], - "css/css-multicol/multicol-rule-style-ridge-001-ref.xht": [ - [ - {} - ] - ], "css/css-multicol/multicol-span-000-ref.xht": [ [ {} @@ -240592,16 +244276,6 @@ {} ] ], - "css/css-multicol/multicol-span-all-child-001-ref.xht": [ - [ - {} - ] - ], - "css/css-multicol/multicol-span-all-child-002-ref.xht": [ - [ - {} - ] - ], "css/css-multicol/multicol-span-all-margin-001-ref.xht": [ [ {} @@ -240622,11 +244296,6 @@ {} ] ], - "css/css-multicol/multicol-span-all-margin-nested-3-ref.xht": [ - [ - {} - ] - ], "css/css-multicol/multicol-span-all-margin-nested-firstchild-ref.xht": [ [ {} @@ -240667,7 +244336,7 @@ {} ] ], - "css/css-multicol/multicol-width-ems-ref.xht": [ + "css/css-multicol/multicol-width-ch-ref.xht": [ [ {} ] @@ -240972,6 +244641,11 @@ {} ] ], + "css/css-overflow/reference/input-scrollable-region-001-ref.html": [ + [ + {} + ] + ], "css/css-page/OWNERS": [ [ {} @@ -241222,6 +244896,11 @@ {} ] ], + "css/css-paint-api/geometry-with-float-size-ref.html": [ + [ + {} + ] + ], "css/css-paint-api/hidpi/device-pixel-ratio-ref.html": [ [ {} @@ -241432,6 +245111,11 @@ {} ] ], + "css/css-position/position-sticky-table-parts-ref.html": [ + [ + {} + ] + ], "css/css-position/position-sticky-table-tfoot-bottom-ref.html": [ [ {} @@ -243177,11 +246861,6 @@ {} ] ], - "css/css-style-attr/reference/ref-green-on-green2.xht": [ - [ - {} - ] - ], "css/css-style-attr/reference/ref-green.html": [ [ {} @@ -243542,11 +247221,36 @@ {} ] ], + "css/css-tables/zero-rowspan-001-ref.html": [ + [ + {} + ] + ], + "css/css-tables/zero-rowspan-002-ref.html": [ + [ + {} + ] + ], "css/css-text-decor/OWNERS": [ [ {} ] ], + "css/css-text-decor/reference/line-through-vertical-ref.html": [ + [ + {} + ] + ], + "css/css-text-decor/reference/text-decoration-color-recalc-ref.html": [ + [ + {} + ] + ], + "css/css-text-decor/reference/text-decoration-color-ref.html": [ + [ + {} + ] + ], "css/css-text-decor/reference/text-decoration-line-010-ref.xht": [ [ {} @@ -243567,6 +247271,26 @@ {} ] ], + "css/css-text-decor/reference/text-decoration-line-recalc-ref.html": [ + [ + {} + ] + ], + "css/css-text-decor/reference/text-decoration-line-ref.html": [ + [ + {} + ] + ], + "css/css-text-decor/reference/text-decoration-style-multiple-ref.html": [ + [ + {} + ] + ], + "css/css-text-decor/reference/text-decoration-style-recalc-ref.html": [ + [ + {} + ] + ], "css/css-text-decor/reference/text-emphasis-color-001-ref.xht": [ [ {} @@ -247732,6 +251456,11 @@ {} ] ], + "css/css-transforms/transform-box/support/greensquare200x200.html": [ + [ + {} + ] + ], "css/css-transforms/transform-compound-notref-1.html": [ [ {} @@ -250267,6 +253996,16 @@ {} ] ], + "css/css-values/support/vh-support-transform-origin-iframe.html": [ + [ + {} + ] + ], + "css/css-values/support/vh-support-transform-translate-iframe.html": [ + [ + {} + ] + ], "css/css-values/support/vh_not_refreshing_on_chrome_iframe.html": [ [ {} @@ -252987,6 +256726,11 @@ {} ] ], + "css/cssom-view/scrollTop-display-change-ref.html": [ + [ + {} + ] + ], "css/cssom-view/scrollingElement-quirks-dynamic-001-ref.html": [ [ {} @@ -253222,6 +256966,11 @@ {} ] ], + "css/cssom/medialist-dynamic-001-ref.html": [ + [ + {} + ] + ], "css/cssom/selectorText-modification-restyle-001-ref.html": [ [ {} @@ -254297,6 +258046,11 @@ {} ] ], + "css/reference/nothing.html": [ + [ + {} + ] + ], "css/reference/only_pass_parens_semicolon.html": [ [ {} @@ -254342,6 +258096,11 @@ {} ] ], + "css/reference/ref-filled-green-100px-square-only.html": [ + [ + {} + ] + ], "css/reference/ref-filled-green-100px-square.xht": [ [ {} @@ -254392,6 +258151,11 @@ {} ] ], + "css/selectors/any-link-dynamic-001-ref.html": [ + [ + {} + ] + ], "css/selectors/attribute-selectors/attribute-case/resources/semantics-quirks.html": [ [ {} @@ -260472,6 +264236,11 @@ {} ] ], + "custom-elements/resources/my-custom-element-html-document.html": [ + [ + {} + ] + ], "docs/.gitignore": [ [ {} @@ -262882,6 +266651,16 @@ {} ] ], + "feature-policy/autoplay-allowed-by-feature-policy.https.sub.html.headers": [ + [ + {} + ] + ], + "feature-policy/autoplay-disabled-by-feature-policy.https.sub.html.headers": [ + [ + {} + ] + ], "feature-policy/payment-allowed-by-feature-policy.https.sub.html.headers": [ [ {} @@ -262892,6 +266671,21 @@ {} ] ], + "feature-policy/resources/autoplay.js": [ + [ + {} + ] + ], + "feature-policy/resources/feature-policy-autoplay.html": [ + [ + {} + ] + ], + "feature-policy/resources/feature-policy-generic-sensor.html": [ + [ + {} + ] + ], "feature-policy/resources/feature-policy-payment.html": [ [ {} @@ -263092,6 +266886,46 @@ {} ] ], + "fetch/api/request/destination/resources/dummy": [ + [ + {} + ] + ], + "fetch/api/request/destination/resources/dummy.png": [ + [ + {} + ] + ], + "fetch/api/request/destination/resources/dummy_audio.mp3": [ + [ + {} + ] + ], + "fetch/api/request/destination/resources/dummy_audio.oga": [ + [ + {} + ] + ], + "fetch/api/request/destination/resources/dummy_video.mp4": [ + [ + {} + ] + ], + "fetch/api/request/destination/resources/dummy_video.ogv": [ + [ + {} + ] + ], + "fetch/api/request/destination/resources/empty.https.html": [ + [ + {} + ] + ], + "fetch/api/request/destination/resources/fetch-destination-worker.js": [ + [ + {} + ] + ], "fetch/api/request/multi-globals/current/current.html": [ [ {} @@ -263707,6 +267541,11 @@ {} ] ], + "generic-sensor/generic-sensor-feature-policy-test.sub.js": [ + [ + {} + ] + ], "generic-sensor/generic-sensor-tests.js": [ [ {} @@ -263722,11 +267561,41 @@ {} ] ], + "geolocation-sensor/GeolocationSensor-disabled-by-feature-policy.https.html.headers": [ + [ + {} + ] + ], + "geolocation-sensor/GeolocationSensor-enabled-by-feature-policy.https.html.headers": [ + [ + {} + ] + ], + "geolocation-sensor/GeolocationSensor-enabled-on-self-origin-by-feature-policy.https.html.headers": [ + [ + {} + ] + ], "geolocation-sensor/OWNERS": [ [ {} ] ], + "gyroscope/Gyroscope-disabled-by-feature-policy.https.html.headers": [ + [ + {} + ] + ], + "gyroscope/Gyroscope-enabled-by-feature-policy.https.html.headers": [ + [ + {} + ] + ], + "gyroscope/Gyroscope-enabled-on-self-origin-by-feature-policy.https.html.headers": [ + [ + {} + ] + ], "gyroscope/OWNERS": [ [ {} @@ -265002,6 +268871,16 @@ {} ] ], + "html/browsers/sandboxing/noscript-iframe.html": [ + [ + {} + ] + ], + "html/browsers/sandboxing/sandbox-parse-noscript-ref.html": [ + [ + {} + ] + ], "html/browsers/the-window-object/.gitkeep": [ [ {} @@ -270652,6 +274531,16 @@ {} ] ], + "html/form-elements/the-textarea-element/multiline-placeholder-ref.html": [ + [ + {} + ] + ], + "html/form-elements/the-textarea-element/support/placeholder.css": [ + [ + {} + ] + ], "html/iana/.gitkeep": [ [ {} @@ -271137,6 +275026,11 @@ {} ] ], + "html/input/the-placeholder-attribute/multiline-ref.html": [ + [ + {} + ] + ], "html/introduction/.gitkeep": [ [ {} @@ -272142,6 +276036,306 @@ {} ] ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/align-positioning-bad.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/align-positioning.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/align-text-line-position-bad.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/align-text-line-position.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/alignment-bad.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/alignment-ltr.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/alignment.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/bom.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/captions-fast.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/captions-gaps.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/captions-html.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/captions.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/class-bad.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/class.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cue-id-error.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cue-id.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cue-no-id-error.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cue-no-id.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cue-recovery-cuetext.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cue-recovery-header.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cue-recovery-note.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cue-size-align-bad.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cue-size-align.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cue-size-bad.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cue-size.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cues-no-separation.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cues-overlapping.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cues.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/default-styles.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/degenerate-cues.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/empty-cue.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/entities-wrong.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/entities.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/interspersed-non-cue.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/iso2022jp3.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/large-timestamp.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/line-position-bad.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/line-position.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/markup-bad.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/markup.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/metadata-area.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/metadata.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/missed-cues.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/no-newline-at-eof.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/no-timings.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/no-webvtt.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/positioning-bad.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/positioning-ltr.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/positioning.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/settings-bad-separation.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/settings.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/simple-captions.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/sorted-dispatch.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/timestamp-bad.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/timestamp.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/timings-hour-error.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/timings-hour.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/timings-no-hour-errors.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/timings-no-hour.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/timings-whitespace.vtt": [ + [ + {} + ] + ], "html/semantics/embedded-content/media-elements/track/track-element/resources/track.de.vtt": [ [ {} @@ -272162,6 +276356,61 @@ {} ] ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/unsupported-markup.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/utf8.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/valign-bad.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/valign-ltr.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/valign.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/voice-bad.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/voice.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/vp8-vorbis-webvtt.webm": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/webvtt-file.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/webvtt-rubbish.vtt": [ + [ + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-helpers.js": [ + [ + {} + ] + ], "html/semantics/embedded-content/resources/should-load.html": [ [ {} @@ -272182,6 +276431,11 @@ {} ] ], + "html/semantics/embedded-content/the-area-element/resources/area-download-click.html": [ + [ + {} + ] + ], "html/semantics/embedded-content/the-area-element/support/hit-test.js": [ [ {} @@ -273357,6 +277611,11 @@ {} ] ], + "html/semantics/scripting-1/the-script-element/defer.js": [ + [ + {} + ] + ], "html/semantics/scripting-1/the-script-element/execution-timing/102.html": [ [ {} @@ -273492,6 +277751,36 @@ {} ] ], + "html/semantics/scripting-1/the-script-element/module/choice-of-error-1a.js": [ + [ + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/choice-of-error-1b.js": [ + [ + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/choice-of-error-2a.js": [ + [ + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/choice-of-error-2b.js": [ + [ + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/choice-of-error-3a.js": [ + [ + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/choice-of-error-3b.js": [ + [ + {} + ] + ], "html/semantics/scripting-1/the-script-element/module/crossorigin-common.js": [ [ {} @@ -273572,6 +277861,46 @@ {} ] ], + "html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/Function.js": [ + [ + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/eval.js": [ + [ + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/inline-event-handlers-UA-code.js": [ + [ + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/reflected-inline-event-handlers.js": [ + [ + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/setTimeout.js": [ + [ + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/error-type-1.js": [ + [ + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/error-type-2.js": [ + [ + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/error-type-3.js": [ + [ + {} + ] + ], "html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-common.js": [ [ {} @@ -273907,6 +278236,21 @@ {} ] ], + "html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js": [ + [ + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js.headers": [ + [ + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/resources/import-remote-origin-referrer-checker.sub.js": [ + [ + {} + ] + ], "html/semantics/scripting-1/the-script-element/module/resources/import-utf8-with-charset-header.js": [ [ {} @@ -273932,6 +278276,11 @@ {} ] ], + "html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py": [ + [ + {} + ] + ], "html/semantics/scripting-1/the-script-element/module/set-currentScript-on-window.js": [ [ {} @@ -273982,6 +278331,11 @@ {} ] ], + "html/semantics/scripting-1/the-script-element/module/throw2.js": [ + [ + {} + ] + ], "html/semantics/scripting-1/the-script-element/resources/bom-utf-16be.js": [ [ {} @@ -274397,6 +278751,11 @@ {} ] ], + "html/semantics/text-level-semantics/the-a-element/resources/a-download-click.html": [ + [ + {} + ] + ], "html/semantics/text-level-semantics/the-abbr-element/.gitkeep": [ [ {} @@ -274407,6 +278766,11 @@ {} ] ], + "html/semantics/text-level-semantics/the-b-element/b-usage-notref.html": [ + [ + {} + ] + ], "html/semantics/text-level-semantics/the-bdi-element/.gitkeep": [ [ {} @@ -274572,6 +278936,11 @@ {} ] ], + "html/semantics/text-level-semantics/the-ruby-element/ruby-usage-notref.html": [ + [ + {} + ] + ], "html/semantics/text-level-semantics/the-s-element/.gitkeep": [ [ {} @@ -275372,7 +279741,7 @@ {} ] ], - "infrastructure/assumptions/ahem-ref.html": [ + "infrastructure/assumptions/ahem-notref.html": [ [ {} ] @@ -275497,6 +279866,11 @@ {} ] ], + "interfaces/hr-time.idl": [ + [ + {} + ] + ], "interfaces/html.idl": [ [ {} @@ -275642,6 +280016,21 @@ {} ] ], + "magnetometer/Magnetometer-disabled-by-feature-policy.https.html.headers": [ + [ + {} + ] + ], + "magnetometer/Magnetometer-enabled-by-feature-policy.https.html.headers": [ + [ + {} + ] + ], + "magnetometer/Magnetometer-enabled-on-self-origin-by-feature-policy.https.html.headers": [ + [ + {} + ] + ], "magnetometer/OWNERS": [ [ {} @@ -275817,12 +280206,12 @@ {} ] ], - "mathml/relations/html5-tree/unique-identifier-1-iframe.html": [ + "mathml/relations/html5-tree/unique-identifier-1-iframe-1.html": [ [ {} ] ], - "mathml/relations/html5-tree/unique-identifier-1-ref-iframe.html": [ + "mathml/relations/html5-tree/unique-identifier-1-iframe-2.html": [ [ {} ] @@ -276182,6 +280571,16 @@ {} ] ], + "media/counting.mp4": [ + [ + {} + ] + ], + "media/counting.ogv": [ + [ + {} + ] + ], "media/foo.vtt": [ [ {} @@ -276252,6 +280651,16 @@ {} ] ], + "media/test.mp4": [ + [ + {} + ] + ], + "media/test.ogv": [ + [ + {} + ] + ], "media/white.mp4": [ [ {} @@ -276277,6 +280686,41 @@ {} ] ], + "mimesniff/OWNERS": [ + [ + {} + ] + ], + "mimesniff/README.md": [ + [ + {} + ] + ], + "mimesniff/mime-types/README.md": [ + [ + {} + ] + ], + "mimesniff/mime-types/resources/generated-mime-types.json": [ + [ + {} + ] + ], + "mimesniff/mime-types/resources/generated-mime-types.py": [ + [ + {} + ] + ], + "mimesniff/mime-types/resources/mime-charset.py": [ + [ + {} + ] + ], + "mimesniff/mime-types/resources/mime-types.json": [ + [ + {} + ] + ], "mixed-content/OWNERS": [ [ {} @@ -276527,32 +280971,32 @@ {} ] ], - "mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/keep-scheme-redirect/optionally-blockable/opt-in-blocks.https.html.headers": [ + "mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/keep-scheme-redirect/blockable/opt-in-blocks.https.html.headers": [ [ {} ] ], - "mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/no-redirect/optionally-blockable/opt-in-blocks.https.html.headers": [ + "mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/no-redirect/blockable/opt-in-blocks.https.html.headers": [ [ {} ] ], - "mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/swap-scheme-redirect/optionally-blockable/opt-in-blocks.https.html.headers": [ + "mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/swap-scheme-redirect/blockable/opt-in-blocks.https.html.headers": [ [ {} ] ], - "mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/keep-scheme-redirect/optionally-blockable/opt-in-blocks.https.html.headers": [ + "mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/keep-scheme-redirect/blockable/opt-in-blocks.https.html.headers": [ [ {} ] ], - "mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/no-redirect/optionally-blockable/opt-in-blocks.https.html.headers": [ + "mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/no-redirect/blockable/opt-in-blocks.https.html.headers": [ [ {} ] ], - "mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/swap-scheme-redirect/optionally-blockable/opt-in-blocks.https.html.headers": [ + "mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/swap-scheme-redirect/blockable/opt-in-blocks.https.html.headers": [ [ {} ] @@ -277037,11 +281481,41 @@ {} ] ], + "orientation-sensor/AbsoluteOrientationSensor-disabled-by-feature-policy.https.html.headers": [ + [ + {} + ] + ], + "orientation-sensor/AbsoluteOrientationSensor-enabled-by-feature-policy.https.html.headers": [ + [ + {} + ] + ], + "orientation-sensor/AbsoluteOrientationSensor-enabled-on-self-origin-by-feature-policy.https.html.headers": [ + [ + {} + ] + ], "orientation-sensor/OWNERS": [ [ {} ] ], + "orientation-sensor/RelativeOrientationSensor-disabled-by-feature-policy.https.html.headers": [ + [ + {} + ] + ], + "orientation-sensor/RelativeOrientationSensor-enabled-by-feature-policy.https.html.headers": [ + [ + {} + ] + ], + "orientation-sensor/RelativeOrientationSensor-enabled-on-self-origin-by-feature-policy.https.html.headers": [ + [ + {} + ] + ], "page-visibility/OWNERS": [ [ {} @@ -277212,6 +281686,11 @@ {} ] ], + "preload/OWNERS": [ + [ + {} + ] + ], "preload/dynamic-adding-preload-nonce.html.headers": [ [ {} @@ -277302,11 +281781,6 @@ {} ] ], - "preload/resources/fetch-destination-worker.js": [ - [ - {} - ] - ], "preload/resources/foo.vtt": [ [ {} @@ -277497,12 +281971,7 @@ {} ] ], - "quirks-mode/OWNERS": [ - [ - {} - ] - ], - "quirks-mode/historical/list-item-bullet-size-ref.html": [ + "quirks/historical/list-item-bullet-size-ref.html": [ [ {} ] @@ -280717,6 +285186,31 @@ {} ] ], + "service-workers/service-worker/resources/about-blank-replacement-frame.py": [ + [ + {} + ] + ], + "service-workers/service-worker/resources/about-blank-replacement-ping-frame.py": [ + [ + {} + ] + ], + "service-workers/service-worker/resources/about-blank-replacement-popup-frame.py": [ + [ + {} + ] + ], + "service-workers/service-worker/resources/about-blank-replacement-uncontrolled-nested-frame.html": [ + [ + {} + ] + ], + "service-workers/service-worker/resources/about-blank-replacement-worker.js": [ + [ + {} + ] + ], "service-workers/service-worker/resources/appcache-ordering.install.html": [ [ {} @@ -280957,6 +285451,11 @@ {} ] ], + "service-workers/service-worker/resources/fetch-cors-exposed-header-names-worker.js": [ + [ + {} + ] + ], "service-workers/service-worker/resources/fetch-cors-xhr-iframe.html": [ [ {} @@ -281002,12 +285501,12 @@ {} ] ], - "service-workers/service-worker/resources/fetch-event-respond-with-partial-stream-worker.js": [ + "service-workers/service-worker/resources/fetch-event-respond-with-custom-response-worker.js": [ [ {} ] ], - "service-workers/service-worker/resources/fetch-event-respond-with-readable-stream-iframe.html": [ + "service-workers/service-worker/resources/fetch-event-respond-with-partial-stream-worker.js": [ [ {} ] @@ -281207,41 +285706,6 @@ {} ] ], - "service-workers/service-worker/resources/foreign-fetch-cors-worker.js": [ - [ - {} - ] - ], - "service-workers/service-worker/resources/foreign-fetch-event-worker.js": [ - [ - {} - ] - ], - "service-workers/service-worker/resources/foreign-fetch-helper-iframe.html": [ - [ - {} - ] - ], - "service-workers/service-worker/resources/foreign-fetch-helper-script.js": [ - [ - {} - ] - ], - "service-workers/service-worker/resources/foreign-fetch-helper-worker.js": [ - [ - {} - ] - ], - "service-workers/service-worker/resources/foreign-fetch-helpers.js": [ - [ - {} - ] - ], - "service-workers/service-worker/resources/foreign-fetch-worker.js": [ - [ - {} - ] - ], "service-workers/service-worker/resources/frame-for-getregistrations.html": [ [ {} @@ -281252,11 +285716,6 @@ {} ] ], - "service-workers/service-worker/resources/iframe-register-link-element.html": [ - [ - {} - ] - ], "service-workers/service-worker/resources/immutable-prototype-serviceworker.js": [ [ {} @@ -281307,11 +285766,6 @@ {} ] ], - "service-workers/service-worker/resources/install-worker-helper.html": [ - [ - {} - ] - ], "service-workers/service-worker/resources/interfaces-idls.js": [ [ {} @@ -281362,11 +285816,6 @@ {} ] ], - "service-workers/service-worker/resources/link-header.py": [ - [ - {} - ] - ], "service-workers/service-worker/resources/load_worker.js": [ [ {} @@ -281527,6 +285976,11 @@ {} ] ], + "service-workers/service-worker/resources/pass.txt": [ + [ + {} + ] + ], "service-workers/service-worker/resources/performance-timeline-worker.js": [ [ {} @@ -281582,11 +286036,6 @@ {} ] ], - "service-workers/service-worker/resources/register-foreign-fetch-errors-worker.js": [ - [ - {} - ] - ], "service-workers/service-worker/resources/register-iframe.html": [ [ {} @@ -281647,7 +286096,7 @@ {} ] ], - "service-workers/service-worker/resources/resource-timing-iframe.html": [ + "service-workers/service-worker/resources/resource-timing-iframe.sub.html": [ [ {} ] @@ -281677,6 +286126,16 @@ {} ] ], + "service-workers/service-worker/resources/sandboxed-iframe-fetch-event-iframe.html": [ + [ + {} + ] + ], + "service-workers/service-worker/resources/sandboxed-iframe-fetch-event-worker.js": [ + [ + {} + ] + ], "service-workers/service-worker/resources/sandboxed-iframe-navigator-serviceworker-iframe.html": [ [ {} @@ -282157,6 +286616,11 @@ {} ] ], + "streams/transform-streams/properties.js": [ + [ + {} + ] + ], "streams/transform-streams/reentrant-strategies.js": [ [ {} @@ -282477,6 +286941,11 @@ {} ] ], + "svg/foreignobject/position-svg-root-in-foreign-object-ref.html": [ + [ + {} + ] + ], "svg/import/woffs/Blocky.woff": [ [ {} @@ -282687,6 +287156,31 @@ {} ] ], + "svg/path/bearing/absolute-ref.svg": [ + [ + {} + ] + ], + "svg/path/bearing/relative-ref.svg": [ + [ + {} + ] + ], + "svg/path/bearing/zero-ref.svg": [ + [ + {} + ] + ], + "svg/path/property/priority-ref.svg": [ + [ + {} + ] + ], + "svg/path/property/resources/interpolation-test-common.js": [ + [ + {} + ] + ], "svg/shapes/rect-01-ref.html": [ [ {} @@ -283587,6 +288081,11 @@ {} ] ], + "webdriver/tests/actions/support/mouse.py": [ + [ + {} + ] + ], "webdriver/tests/actions/support/refine.py": [ [ {} @@ -283607,7 +288106,12 @@ {} ] ], - "webdriver/tests/retrieval/__init__.py": [ + "webdriver/tests/element_retrieval/__init__.py": [ + [ + {} + ] + ], + "webdriver/tests/element_send_keys/__init__.py": [ [ {} ] @@ -283802,6 +288306,26 @@ {} ] ], + "webrtc/tools/.eslintrc.js": [ + [ + {} + ] + ], + "webrtc/tools/README.md": [ + [ + {} + ] + ], + "webrtc/tools/package-lock.json": [ + [ + {} + ] + ], + "webrtc/tools/package.json": [ + [ + {} + ] + ], "websockets/OWNERS": [ [ {} @@ -283897,6 +288421,11 @@ {} ] ], + "websockets/handlers/referrer_wsh.py": [ + [ + {} + ] + ], "websockets/handlers/set-cookie-secure_wsh.py": [ [ {} @@ -284502,6 +289031,11 @@ {} ] ], + "webvtt/parsing/file-parsing/tests/support/regions-edge-case.vtt": [ + [ + {} + ] + ], "webvtt/parsing/file-parsing/tests/support/regions-id.vtt": [ [ {} @@ -286182,11 +290716,41 @@ {} ] ], + "webvtt/rendering/cues-with-video/processing-model/track-cue-rendering-position-align-rtl-center-ref.html": [ + [ + {} + ] + ], + "webvtt/rendering/cues-with-video/processing-model/track-cue-rendering-position-align-rtl-line-left-ref.html": [ + [ + {} + ] + ], + "webvtt/rendering/cues-with-video/processing-model/track-cue-rendering-position-align-rtl-line-right-ref.html": [ + [ + {} + ] + ], "webvtt/tools/categorize_results.py": [ [ {} ] ], + "webxr/OWNERS": [ + [ + {} + ] + ], + "webxr/resources/webxr_check.html": [ + [ + {} + ] + ], + "webxr/resources/webxr_util.js": [ + [ + {} + ] + ], "workers/OWNERS": [ [ {} @@ -286317,6 +290881,11 @@ {} ] ], + "workers/data-url-shared-window.html": [ + [ + {} + ] + ], "workers/interfaces/DedicatedWorkerGlobalScope/postMessage/message-event.js": [ [ {} @@ -286562,6 +291131,11 @@ {} ] ], + "workers/support/iframe_sw_dataUrl.html": [ + [ + {} + ] + ], "workers/support/name-as-accidental-global.js": [ [ {} @@ -286612,6 +291186,16 @@ {} ] ], + "worklets/resources/empty-worklet-script-with-cors-header.js": [ + [ + {} + ] + ], + "worklets/resources/empty-worklet-script-with-cors-header.js.headers": [ + [ + {} + ] + ], "worklets/resources/empty-worklet-script.js": [ [ {} @@ -286622,7 +291206,17 @@ {} ] ], - "worklets/resources/import-empty-worklet-script.js": [ + "worklets/resources/import-empty-worklet-script-with-cors-header.js": [ + [ + {} + ] + ], + "worklets/resources/import-empty-worklet-script-with-cors-header.js.headers": [ + [ + {} + ] + ], + "worklets/resources/import-insecure-origin-empty-worklet-script.sub.js": [ [ {} ] @@ -286642,11 +291236,31 @@ {} ] ], + "worklets/resources/import-referrer-checker-worklet-script.sub.js": [ + [ + {} + ] + ], + "worklets/resources/import-referrer-checker-worklet-script.sub.js.headers": [ + [ + {} + ] + ], "worklets/resources/import-remote-origin-empty-worklet-script.sub.js": [ [ {} ] ], + "worklets/resources/import-remote-origin-referrer-checker-worklet-script.sub.js": [ + [ + {} + ] + ], + "worklets/resources/import-remote-origin-referrer-checker-worklet-script.sub.js.headers": [ + [ + {} + ] + ], "worklets/resources/import-syntax-error-worklet-script.js": [ [ {} @@ -286657,6 +291271,11 @@ {} ] ], + "worklets/resources/referrer-checker.py": [ + [ + {} + ] + ], "worklets/resources/referrer-tests.js": [ [ {} @@ -286667,11 +291286,6 @@ {} ] ], - "worklets/resources/referrer.py": [ - [ - {} - ] - ], "worklets/resources/service-worker-interception-tests.js": [ [ {} @@ -291435,12 +296049,24 @@ {} ] ], + "FileAPI/blob/Blob-Request-revoke-fetch.html": [ + [ + "/FileAPI/blob/Blob-Request-revoke-fetch.html", + {} + ] + ], "FileAPI/blob/Blob-XHR-revoke.html": [ [ "/FileAPI/blob/Blob-XHR-revoke.html", {} ] ], + "FileAPI/blob/Blob-constructor-endings.html": [ + [ + "/FileAPI/blob/Blob-constructor-endings.html", + {} + ] + ], "FileAPI/blob/Blob-constructor.html": [ [ "/FileAPI/blob/Blob-constructor.html", @@ -291465,6 +296091,12 @@ {} ] ], + "FileAPI/file/File-constructor-endings.html": [ + [ + "/FileAPI/file/File-constructor-endings.html", + {} + ] + ], "FileAPI/file/File-constructor.html": [ [ "/FileAPI/file/File-constructor.html", @@ -291477,6 +296109,36 @@ {} ] ], + "FileAPI/file/send-file-form-iso-2022-jp.tentative.html": [ + [ + "/FileAPI/file/send-file-form-iso-2022-jp.tentative.html", + {} + ] + ], + "FileAPI/file/send-file-form-utf-8.html": [ + [ + "/FileAPI/file/send-file-form-utf-8.html", + {} + ] + ], + "FileAPI/file/send-file-form-windows-1252.tentative.html": [ + [ + "/FileAPI/file/send-file-form-windows-1252.tentative.html", + {} + ] + ], + "FileAPI/file/send-file-form-x-user-defined.tentative.html": [ + [ + "/FileAPI/file/send-file-form-x-user-defined.tentative.html", + {} + ] + ], + "FileAPI/file/send-file-form.html": [ + [ + "/FileAPI/file/send-file-form.html", + {} + ] + ], "FileAPI/fileReader.html": [ [ "/FileAPI/fileReader.html", @@ -291567,6 +296229,12 @@ {} ] ], + "FileAPI/unicode.html": [ + [ + "/FileAPI/unicode.html", + {} + ] + ], "FileAPI/url/blob-url-in-sandboxed-iframe.html": [ [ "/FileAPI/url/blob-url-in-sandboxed-iframe.html", @@ -293927,173 +298595,161 @@ } ] ], - "WebCryptoAPI/generateKey/failures.worker.js": [ + "WebCryptoAPI/generateKey/failures_AES-CBC.https.worker.js": [ [ - "/WebCryptoAPI/generateKey/failures.worker.html", - {} - ] - ], - "WebCryptoAPI/generateKey/failures_AES-CBC.worker.js": [ - [ - "/WebCryptoAPI/generateKey/failures_AES-CBC.worker.html", + "/WebCryptoAPI/generateKey/failures_AES-CBC.https.worker.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/failures_AES-CTR.worker.js": [ + "WebCryptoAPI/generateKey/failures_AES-CTR.https.worker.js": [ [ - "/WebCryptoAPI/generateKey/failures_AES-CTR.worker.html", + "/WebCryptoAPI/generateKey/failures_AES-CTR.https.worker.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/failures_AES-GCM.worker.js": [ + "WebCryptoAPI/generateKey/failures_AES-GCM.https.worker.js": [ [ - "/WebCryptoAPI/generateKey/failures_AES-GCM.worker.html", + "/WebCryptoAPI/generateKey/failures_AES-GCM.https.worker.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/failures_AES-KW.worker.js": [ + "WebCryptoAPI/generateKey/failures_AES-KW.https.worker.js": [ [ - "/WebCryptoAPI/generateKey/failures_AES-KW.worker.html", + "/WebCryptoAPI/generateKey/failures_AES-KW.https.worker.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/failures_ECDH.worker.js": [ + "WebCryptoAPI/generateKey/failures_ECDH.https.worker.js": [ [ - "/WebCryptoAPI/generateKey/failures_ECDH.worker.html", + "/WebCryptoAPI/generateKey/failures_ECDH.https.worker.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/failures_ECDSA.worker.js": [ + "WebCryptoAPI/generateKey/failures_ECDSA.https.worker.js": [ [ - "/WebCryptoAPI/generateKey/failures_ECDSA.worker.html", + "/WebCryptoAPI/generateKey/failures_ECDSA.https.worker.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/failures_HMAC.worker.js": [ + "WebCryptoAPI/generateKey/failures_HMAC.https.worker.js": [ [ - "/WebCryptoAPI/generateKey/failures_HMAC.worker.html", + "/WebCryptoAPI/generateKey/failures_HMAC.https.worker.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/failures_RSA-OAEP.worker.js": [ + "WebCryptoAPI/generateKey/failures_RSA-OAEP.https.worker.js": [ [ - "/WebCryptoAPI/generateKey/failures_RSA-OAEP.worker.html", + "/WebCryptoAPI/generateKey/failures_RSA-OAEP.https.worker.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/failures_RSA-PSS.worker.js": [ + "WebCryptoAPI/generateKey/failures_RSA-PSS.https.worker.js": [ [ - "/WebCryptoAPI/generateKey/failures_RSA-PSS.worker.html", + "/WebCryptoAPI/generateKey/failures_RSA-PSS.https.worker.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.worker.js": [ + "WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.https.worker.js": [ [ - "/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.worker.html", + "/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.https.worker.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/successes.worker.js": [ + "WebCryptoAPI/generateKey/successes_AES-CBC.https.worker.js": [ [ - "/WebCryptoAPI/generateKey/successes.worker.html", - {} - ] - ], - "WebCryptoAPI/generateKey/successes_AES-CBC.worker.js": [ - [ - "/WebCryptoAPI/generateKey/successes_AES-CBC.worker.html", + "/WebCryptoAPI/generateKey/successes_AES-CBC.https.worker.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/successes_AES-CTR.worker.js": [ + "WebCryptoAPI/generateKey/successes_AES-CTR.https.worker.js": [ [ - "/WebCryptoAPI/generateKey/successes_AES-CTR.worker.html", + "/WebCryptoAPI/generateKey/successes_AES-CTR.https.worker.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/successes_AES-GCM.worker.js": [ + "WebCryptoAPI/generateKey/successes_AES-GCM.https.worker.js": [ [ - "/WebCryptoAPI/generateKey/successes_AES-GCM.worker.html", + "/WebCryptoAPI/generateKey/successes_AES-GCM.https.worker.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/successes_AES-KW.worker.js": [ + "WebCryptoAPI/generateKey/successes_AES-KW.https.worker.js": [ [ - "/WebCryptoAPI/generateKey/successes_AES-KW.worker.html", + "/WebCryptoAPI/generateKey/successes_AES-KW.https.worker.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/successes_ECDH.worker.js": [ + "WebCryptoAPI/generateKey/successes_ECDH.https.worker.js": [ [ - "/WebCryptoAPI/generateKey/successes_ECDH.worker.html", + "/WebCryptoAPI/generateKey/successes_ECDH.https.worker.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/successes_ECDSA.worker.js": [ + "WebCryptoAPI/generateKey/successes_ECDSA.https.worker.js": [ [ - "/WebCryptoAPI/generateKey/successes_ECDSA.worker.html", + "/WebCryptoAPI/generateKey/successes_ECDSA.https.worker.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/successes_HMAC.worker.js": [ + "WebCryptoAPI/generateKey/successes_HMAC.https.worker.js": [ [ - "/WebCryptoAPI/generateKey/successes_HMAC.worker.html", + "/WebCryptoAPI/generateKey/successes_HMAC.https.worker.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/successes_RSA-OAEP.worker.js": [ + "WebCryptoAPI/generateKey/successes_RSA-OAEP.https.worker.js": [ [ - "/WebCryptoAPI/generateKey/successes_RSA-OAEP.worker.html", + "/WebCryptoAPI/generateKey/successes_RSA-OAEP.https.worker.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/successes_RSA-PSS.worker.js": [ + "WebCryptoAPI/generateKey/successes_RSA-PSS.https.worker.js": [ [ - "/WebCryptoAPI/generateKey/successes_RSA-PSS.worker.html", + "/WebCryptoAPI/generateKey/successes_RSA-PSS.https.worker.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.worker.js": [ + "WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.https.worker.js": [ [ - "/WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.worker.html", + "/WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.https.worker.html", { "timeout": "long" } @@ -294115,14 +298771,6 @@ } ] ], - "WebCryptoAPI/generateKey/test_failures.https.html": [ - [ - "/WebCryptoAPI/generateKey/test_failures.https.html", - { - "timeout": "long" - } - ] - ], "WebCryptoAPI/generateKey/test_failures_AES-CBC.https.html": [ [ "/WebCryptoAPI/generateKey/test_failures_AES-CBC.https.html", @@ -294513,6 +299161,16 @@ {} ] ], + "WebIDL/ecmascript-binding/no-regexp-special-casing.any.js": [ + [ + "/WebIDL/ecmascript-binding/no-regexp-special-casing.any.html", + {} + ], + [ + "/WebIDL/ecmascript-binding/no-regexp-special-casing.any.worker.html", + {} + ] + ], "WebIDL/ecmascript-binding/put-forwards.html": [ [ "/WebIDL/ecmascript-binding/put-forwards.html", @@ -296233,6 +300891,36 @@ {} ] ], + "accelerometer/Accelerometer-disabled-by-feature-policy.https.html": [ + [ + "/accelerometer/Accelerometer-disabled-by-feature-policy.https.html", + {} + ] + ], + "accelerometer/Accelerometer-enabled-by-feature-policy-attribute-redirect-on-load.https.html": [ + [ + "/accelerometer/Accelerometer-enabled-by-feature-policy-attribute-redirect-on-load.https.html", + {} + ] + ], + "accelerometer/Accelerometer-enabled-by-feature-policy-attribute.https.html": [ + [ + "/accelerometer/Accelerometer-enabled-by-feature-policy-attribute.https.html", + {} + ] + ], + "accelerometer/Accelerometer-enabled-by-feature-policy.https.html": [ + [ + "/accelerometer/Accelerometer-enabled-by-feature-policy.https.html", + {} + ] + ], + "accelerometer/Accelerometer-enabled-on-self-origin-by-feature-policy.https.html": [ + [ + "/accelerometer/Accelerometer-enabled-on-self-origin-by-feature-policy.https.html", + {} + ] + ], "accelerometer/Accelerometer.https.html": [ [ "/accelerometer/Accelerometer.https.html", @@ -296251,6 +300939,36 @@ {} ] ], + "ambient-light/AmbientLightSensor-disabled-by-feature-policy.https.html": [ + [ + "/ambient-light/AmbientLightSensor-disabled-by-feature-policy.https.html", + {} + ] + ], + "ambient-light/AmbientLightSensor-enabled-by-feature-policy-attribute-redirect-on-load.https.html": [ + [ + "/ambient-light/AmbientLightSensor-enabled-by-feature-policy-attribute-redirect-on-load.https.html", + {} + ] + ], + "ambient-light/AmbientLightSensor-enabled-by-feature-policy-attribute.https.html": [ + [ + "/ambient-light/AmbientLightSensor-enabled-by-feature-policy-attribute.https.html", + {} + ] + ], + "ambient-light/AmbientLightSensor-enabled-by-feature-policy.https.html": [ + [ + "/ambient-light/AmbientLightSensor-enabled-by-feature-policy.https.html", + {} + ] + ], + "ambient-light/AmbientLightSensor-enabled-on-self-origin-by-feature-policy.https.html": [ + [ + "/ambient-light/AmbientLightSensor-enabled-on-self-origin-by-feature-policy.https.html", + {} + ] + ], "ambient-light/AmbientLightSensor.https.html": [ [ "/ambient-light/AmbientLightSensor.https.html", @@ -296503,9 +301221,21 @@ {} ] ], - "bluetooth/idl-Bluetooth.html": [ + "bluetooth/idl/idl-Bluetooth.html": [ [ - "/bluetooth/idl-Bluetooth.html", + "/bluetooth/idl/idl-Bluetooth.html", + {} + ] + ], + "bluetooth/idl/idl-BluetoothUUID.html": [ + [ + "/bluetooth/idl/idl-BluetoothUUID.html", + {} + ] + ], + "bluetooth/idl/idl-NavigatorBluetooth.html": [ + [ + "/bluetooth/idl/idl-NavigatorBluetooth.html", {} ] ], @@ -296615,6 +301345,12 @@ {} ] ], + "content-security-policy/base-uri/report-uri-does-not-respect-base-uri.sub.html": [ + [ + "/content-security-policy/base-uri/report-uri-does-not-respect-base-uri.sub.html", + {} + ] + ], "content-security-policy/blob/blob-urls-do-not-match-self.sub.html": [ [ "/content-security-policy/blob/blob-urls-do-not-match-self.sub.html", @@ -297275,6 +302011,12 @@ {} ] ], + "content-security-policy/generic/policy-inherited-correctly-by-plznavigate.html": [ + [ + "/content-security-policy/generic/policy-inherited-correctly-by-plznavigate.html", + {} + ] + ], "content-security-policy/img-src/icon-allowed.sub.html": [ [ "/content-security-policy/img-src/icon-allowed.sub.html", @@ -297341,6 +302083,12 @@ {} ] ], + "content-security-policy/inheritance/inherited-csp-list-modifications-are-local.html": [ + [ + "/content-security-policy/inheritance/inherited-csp-list-modifications-are-local.html", + {} + ] + ], "content-security-policy/inheritance/window.html": [ [ "/content-security-policy/inheritance/window.html", @@ -297647,6 +302395,12 @@ {} ] ], + "content-security-policy/script-src/nonce-enforce-blocked.html": [ + [ + "/content-security-policy/script-src/nonce-enforce-blocked.html", + {} + ] + ], "content-security-policy/script-src/script-src-1_1.html": [ [ "/content-security-policy/script-src/script-src-1_1.html", @@ -298469,6 +303223,72 @@ {} ] ], + "cookie-store/cookieStore_delete_arguments.tentative.window.js": [ + [ + "/cookie-store/cookieStore_delete_arguments.tentative.window.html", + {} + ] + ], + "cookie-store/cookieStore_getAll_arguments.tentative.window.js": [ + [ + "/cookie-store/cookieStore_getAll_arguments.tentative.window.html", + {} + ] + ], + "cookie-store/cookieStore_getAll_set_basic.tentative.window.js": [ + [ + "/cookie-store/cookieStore_getAll_set_basic.tentative.window.html", + {} + ] + ], + "cookie-store/cookieStore_get_arguments.tentative.window.js": [ + [ + "/cookie-store/cookieStore_get_arguments.tentative.window.html", + {} + ] + ], + "cookie-store/cookieStore_get_delete_basic.tentative.window.js": [ + [ + "/cookie-store/cookieStore_get_delete_basic.tentative.window.html", + {} + ] + ], + "cookie-store/cookieStore_get_set_basic.tentative.window.js": [ + [ + "/cookie-store/cookieStore_get_set_basic.tentative.window.html", + {} + ] + ], + "cookie-store/cookieStore_has_arguments.tentative.window.js": [ + [ + "/cookie-store/cookieStore_has_arguments.tentative.window.html", + {} + ] + ], + "cookie-store/cookieStore_has_basic.tentative.window.js": [ + [ + "/cookie-store/cookieStore_has_basic.tentative.window.html", + {} + ] + ], + "cookie-store/cookieStore_in_detached_frame.tentative.html": [ + [ + "/cookie-store/cookieStore_in_detached_frame.tentative.html", + {} + ] + ], + "cookie-store/cookieStore_set_arguments.tentative.window.js": [ + [ + "/cookie-store/cookieStore_set_arguments.tentative.window.html", + {} + ] + ], + "cookie-store/cookieStore_special_names.tentative.html": [ + [ + "/cookie-store/cookieStore_special_names.tentative.html", + {} + ] + ], "cookie-store/cookie_store_tests.tentative.html": [ [ "/cookie-store/cookie_store_tests.tentative.html", @@ -298565,6 +303385,12 @@ } ] ], + "cookie-store/document_getAll_multiple.tentative.html": [ + [ + "/cookie-store/document_getAll_multiple.tentative.html", + {} + ] + ], "cookie-store/expiration.tentative.html": [ [ "/cookie-store/expiration.tentative.html", @@ -298837,6 +303663,24 @@ } ] ], + "cookie-store/serviceworker_cookieStore_arguments.tentative.https.html": [ + [ + "/cookie-store/serviceworker_cookieStore_arguments.tentative.https.html", + {} + ] + ], + "cookie-store/serviceworker_cookieStore_basic.tentative.https.html": [ + [ + "/cookie-store/serviceworker_cookieStore_basic.tentative.https.html", + {} + ] + ], + "cookies/meta-blocked.html": [ + [ + "/cookies/meta-blocked.html", + {} + ] + ], "cookies/path/match.html": [ [ "/cookies/path/match.html", @@ -298867,9 +303711,9 @@ {} ] ], - "cookies/secure/set-from-ws.https.sub.html": [ + "cookies/secure/set-from-ws.sub.html": [ [ - "/cookies/secure/set-from-ws.https.sub.html", + "/cookies/secure/set-from-ws.sub.html", {} ] ], @@ -299007,12 +303851,24 @@ {} ] ], + "credential-management/federatedcredential-framed-get.sub.https.html": [ + [ + "/credential-management/federatedcredential-framed-get.sub.https.html", + {} + ] + ], "credential-management/idl.https.html": [ [ "/credential-management/idl.https.html", {} ] ], + "credential-management/passwordcredential-framed-get.sub.https.html": [ + [ + "/credential-management/passwordcredential-framed-get.sub.https.html", + {} + ] + ], "css/compositing/mix-blend-mode/mix-blend-mode-creates-stacking-context.html": [ [ "/css/compositing/mix-blend-mode/mix-blend-mode-creates-stacking-context.html", @@ -299219,6 +304075,26 @@ {} ] ], + "css/css-color/color-resolving-hsl.html": [ + [ + "/css/css-color/color-resolving-hsl.html", + { + "timeout": "long" + } + ] + ], + "css/css-color/color-resolving-keywords.html": [ + [ + "/css/css-color/color-resolving-keywords.html", + {} + ] + ], + "css/css-color/color-resolving.html": [ + [ + "/css/css-color/color-resolving.html", + {} + ] + ], "css/css-conditional/js/001.html": [ [ "/css/css-conditional/js/001.html", @@ -299795,6 +304671,12 @@ {} ] ], + "css/css-fonts/font-variant-alternates-parsing.html": [ + [ + "/css/css-fonts/font-variant-alternates-parsing.html", + {} + ] + ], "css/css-fonts/test_datafont_same_origin.html": [ [ "/css/css-fonts/test_datafont_same_origin.html", @@ -299837,6 +304719,48 @@ {} ] ], + "css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-001.html": [ + [ + "/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-001.html", + {} + ] + ], + "css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-002.html": [ + [ + "/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-002.html", + {} + ] + ], + "css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-003.html": [ + [ + "/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-003.html", + {} + ] + ], + "css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-004.html": [ + [ + "/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-004.html", + {} + ] + ], + "css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-005.html": [ + [ + "/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-005.html", + {} + ] + ], + "css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-006.html": [ + [ + "/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-006.html", + {} + ] + ], + "css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-007.html": [ + [ + "/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-007.html", + {} + ] + ], "css/css-grid/abspos/grid-positioned-items-content-alignment-001.html": [ [ "/css/css-grid/abspos/grid-positioned-items-content-alignment-001.html", @@ -300221,6 +305145,12 @@ {} ] ], + "css/css-grid/alignment/grid-column-axis-alignment-positioned-items-017.html": [ + [ + "/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-017.html", + {} + ] + ], "css/css-grid/alignment/grid-fit-content-tracks-dont-stretch-001.html": [ [ "/css/css-grid/alignment/grid-fit-content-tracks-dont-stretch-001.html", @@ -300323,6 +305253,12 @@ {} ] ], + "css/css-grid/alignment/grid-row-axis-alignment-positioned-items-017.html": [ + [ + "/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-017.html", + {} + ] + ], "css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-001.html": [ [ "/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-001.html", @@ -300869,6 +305805,18 @@ {} ] ], + "css/css-grid/grid-items/grid-minimum-size-grid-items-022.html": [ + [ + "/css/css-grid/grid-items/grid-minimum-size-grid-items-022.html", + {} + ] + ], + "css/css-grid/grid-items/grid-minimum-size-grid-items-023.html": [ + [ + "/css/css-grid/grid-items/grid-minimum-size-grid-items-023.html", + {} + ] + ], "css/css-grid/grid-layout-properties.html": [ [ "/css/css-grid/grid-layout-properties.html", @@ -300887,6 +305835,30 @@ {} ] ], + "css/css-grid/grid-model/grid-container-ignores-first-letter-001.html": [ + [ + "/css/css-grid/grid-model/grid-container-ignores-first-letter-001.html", + {} + ] + ], + "css/css-grid/grid-model/grid-container-ignores-first-line-001.html": [ + [ + "/css/css-grid/grid-model/grid-container-ignores-first-line-001.html", + {} + ] + ], + "css/css-grid/grid-model/grid-item-accepts-first-letter-001.html": [ + [ + "/css/css-grid/grid-model/grid-item-accepts-first-letter-001.html", + {} + ] + ], + "css/css-grid/grid-model/grid-item-accepts-first-line-001.html": [ + [ + "/css/css-grid/grid-model/grid-item-accepts-first-line-001.html", + {} + ] + ], "css/css-grid/grid-model/grid-support-display-001.html": [ [ "/css/css-grid/grid-model/grid-support-display-001.html", @@ -300923,6 +305895,24 @@ {} ] ], + "css/css-multicol/multicol-gap-animation-001.html": [ + [ + "/css/css-multicol/multicol-gap-animation-001.html", + {} + ] + ], + "css/css-multicol/multicol-gap-animation-002.html": [ + [ + "/css/css-multicol/multicol-gap-animation-002.html", + {} + ] + ], + "css/css-multicol/multicol-gap-animation-003.html": [ + [ + "/css/css-multicol/multicol-gap-animation-003.html", + {} + ] + ], "css/css-position/position-sticky-get-bounding-client-rect.html": [ [ "/css/css-position/position-sticky-get-bounding-client-rect.html", @@ -300935,6 +305925,12 @@ {} ] ], + "css/css-position/position-sticky-offset-overflow.html": [ + [ + "/css/css-position/position-sticky-offset-overflow.html", + {} + ] + ], "css/css-position/position-sticky-offset-top-left.html": [ [ "/css/css-position/position-sticky-offset-top-left.html", @@ -302117,6 +307113,12 @@ {} ] ], + "css/css-text-decor/text-decoration-serialization.tentative.html": [ + [ + "/css/css-text-decor/text-decoration-serialization.tentative.html", + {} + ] + ], "css/css-text-decor/text-decoration-skip-ink.html": [ [ "/css/css-text-decor/text-decoration-skip-ink.html", @@ -303293,6 +308295,18 @@ {} ] ], + "css/css-typed-om/stylevalue-objects/interface.html": [ + [ + "/css/css-typed-om/stylevalue-objects/interface.html", + {} + ] + ], + "css/css-typed-om/stylevalue-subclasses/cssKeywordValue-interface.html": [ + [ + "/css/css-typed-om/stylevalue-subclasses/cssKeywordValue-interface.html", + {} + ] + ], "css/css-ui/box-sizing-027.html": [ [ "/css/css-ui/box-sizing-027.html", @@ -304223,6 +309237,12 @@ {} ] ], + "css/cssom-view/scroll-behavior-smooth.html": [ + [ + "/css/cssom-view/scroll-behavior-smooth.html", + {} + ] + ], "css/cssom-view/scrollIntoView-shadow.html": [ [ "/css/cssom-view/scrollIntoView-shadow.html", @@ -304571,6 +309591,12 @@ {} ] ], + "css/cssom/setproperty-null-undefined.html": [ + [ + "/css/cssom/setproperty-null-undefined.html", + {} + ] + ], "css/cssom/shorthand-serialization.html": [ [ "/css/cssom/shorthand-serialization.html", @@ -304817,6 +309843,36 @@ {} ] ], + "css/motion/animation/offset-path-interpolation-001.html": [ + [ + "/css/motion/animation/offset-path-interpolation-001.html", + {} + ] + ], + "css/motion/animation/offset-path-interpolation-002.html": [ + [ + "/css/motion/animation/offset-path-interpolation-002.html", + {} + ] + ], + "css/motion/animation/offset-path-interpolation-003.html": [ + [ + "/css/motion/animation/offset-path-interpolation-003.html", + {} + ] + ], + "css/motion/animation/offset-path-interpolation-004.html": [ + [ + "/css/motion/animation/offset-path-interpolation-004.html", + {} + ] + ], + "css/motion/animation/offset-path-interpolation-005.html": [ + [ + "/css/motion/animation/offset-path-interpolation-005.html", + {} + ] + ], "css/motion/animation/offset-position-interpolation.html": [ [ "/css/motion/animation/offset-position-interpolation.html", @@ -305201,6 +310257,12 @@ {} ] ], + "css/selectors/invalidation/any-link-pseudo.html": [ + [ + "/css/selectors/invalidation/any-link-pseudo.html", + {} + ] + ], "css/selectors/missing-right-token.html": [ [ "/css/selectors/missing-right-token.html", @@ -305483,6 +310545,12 @@ {} ] ], + "custom-elements/reactions/with-exceptions.html": [ + [ + "/custom-elements/reactions/with-exceptions.html", + {} + ] + ], "custom-elements/upgrading.html": [ [ "/custom-elements/upgrading.html", @@ -308685,659 +313753,659 @@ {} ] ], - "encrypted-media/clearkey-check-initdata-type.html": [ + "encrypted-media/clearkey-check-initdata-type.https.html": [ [ - "/encrypted-media/clearkey-check-initdata-type.html", + "/encrypted-media/clearkey-check-initdata-type.https.html", {} ] ], - "encrypted-media/clearkey-events-session-closed-event.html": [ + "encrypted-media/clearkey-events-session-closed-event.https.html": [ [ - "/encrypted-media/clearkey-events-session-closed-event.html", + "/encrypted-media/clearkey-events-session-closed-event.https.html", {} ] ], - "encrypted-media/clearkey-events.html": [ + "encrypted-media/clearkey-events.https.html": [ [ - "/encrypted-media/clearkey-events.html", + "/encrypted-media/clearkey-events.https.html", {} ] ], - "encrypted-media/clearkey-generate-request-disallowed-input.html": [ + "encrypted-media/clearkey-generate-request-disallowed-input.https.html": [ [ - "/encrypted-media/clearkey-generate-request-disallowed-input.html", + "/encrypted-media/clearkey-generate-request-disallowed-input.https.html", {} ] ], - "encrypted-media/clearkey-invalid-license.html": [ + "encrypted-media/clearkey-invalid-license.https.html": [ [ - "/encrypted-media/clearkey-invalid-license.html", + "/encrypted-media/clearkey-invalid-license.https.html", {} ] ], - "encrypted-media/clearkey-keystatuses-multiple-sessions.html": [ + "encrypted-media/clearkey-keystatuses-multiple-sessions.https.html": [ [ - "/encrypted-media/clearkey-keystatuses-multiple-sessions.html", + "/encrypted-media/clearkey-keystatuses-multiple-sessions.https.html", {} ] ], - "encrypted-media/clearkey-keystatuses.html": [ + "encrypted-media/clearkey-keystatuses.https.html": [ [ - "/encrypted-media/clearkey-keystatuses.html", + "/encrypted-media/clearkey-keystatuses.https.html", {} ] ], - "encrypted-media/clearkey-mp4-playback-destroy-persistent-license.html": [ + "encrypted-media/clearkey-mp4-playback-destroy-persistent-license.https.html": [ [ - "/encrypted-media/clearkey-mp4-playback-destroy-persistent-license.html", + "/encrypted-media/clearkey-mp4-playback-destroy-persistent-license.https.html", {} ] ], - "encrypted-media/clearkey-mp4-playback-persistent-license-events.html": [ + "encrypted-media/clearkey-mp4-playback-persistent-license-events.https.html": [ [ - "/encrypted-media/clearkey-mp4-playback-persistent-license-events.html", + "/encrypted-media/clearkey-mp4-playback-persistent-license-events.https.html", {} ] ], - "encrypted-media/clearkey-mp4-playback-persistent-license.html": [ + "encrypted-media/clearkey-mp4-playback-persistent-license.https.html": [ [ - "/encrypted-media/clearkey-mp4-playback-persistent-license.html", + "/encrypted-media/clearkey-mp4-playback-persistent-license.https.html", {} ] ], - "encrypted-media/clearkey-mp4-playback-persistent-usage-record-events.html": [ + "encrypted-media/clearkey-mp4-playback-persistent-usage-record-events.https.html": [ [ - "/encrypted-media/clearkey-mp4-playback-persistent-usage-record-events.html", + "/encrypted-media/clearkey-mp4-playback-persistent-usage-record-events.https.html", {} ] ], - "encrypted-media/clearkey-mp4-playback-persistent-usage-record.html": [ + "encrypted-media/clearkey-mp4-playback-persistent-usage-record.https.html": [ [ - "/encrypted-media/clearkey-mp4-playback-persistent-usage-record.html", + "/encrypted-media/clearkey-mp4-playback-persistent-usage-record.https.html", {} ] ], - "encrypted-media/clearkey-mp4-playback-retrieve-destroy-persistent-license.html": [ + "encrypted-media/clearkey-mp4-playback-retrieve-destroy-persistent-license.https.html": [ [ - "/encrypted-media/clearkey-mp4-playback-retrieve-destroy-persistent-license.html", + "/encrypted-media/clearkey-mp4-playback-retrieve-destroy-persistent-license.https.html", {} ] ], - "encrypted-media/clearkey-mp4-playback-retrieve-persistent-license.html": [ + "encrypted-media/clearkey-mp4-playback-retrieve-persistent-license.https.html": [ [ - "/encrypted-media/clearkey-mp4-playback-retrieve-persistent-license.html", + "/encrypted-media/clearkey-mp4-playback-retrieve-persistent-license.https.html", {} ] ], - "encrypted-media/clearkey-mp4-playback-retrieve-persistent-usage-record.html": [ + "encrypted-media/clearkey-mp4-playback-retrieve-persistent-usage-record.https.html": [ [ - "/encrypted-media/clearkey-mp4-playback-retrieve-persistent-usage-record.html", + "/encrypted-media/clearkey-mp4-playback-retrieve-persistent-usage-record.https.html", {} ] ], - "encrypted-media/clearkey-mp4-playback-temporary-clear-encrypted.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-clear-encrypted.https.html": [ [ - "/encrypted-media/clearkey-mp4-playback-temporary-clear-encrypted.html", + "/encrypted-media/clearkey-mp4-playback-temporary-clear-encrypted.https.html", {} ] ], - "encrypted-media/clearkey-mp4-playback-temporary-encrypted-clear-sources.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-encrypted-clear-sources.https.html": [ [ - "/encrypted-media/clearkey-mp4-playback-temporary-encrypted-clear-sources.html", + "/encrypted-media/clearkey-mp4-playback-temporary-encrypted-clear-sources.https.html", { "timeout": "long" } ] ], - "encrypted-media/clearkey-mp4-playback-temporary-encrypted-clear.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-encrypted-clear.https.html": [ [ - "/encrypted-media/clearkey-mp4-playback-temporary-encrypted-clear.html", + "/encrypted-media/clearkey-mp4-playback-temporary-encrypted-clear.https.html", {} ] ], - "encrypted-media/clearkey-mp4-playback-temporary-events.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-events.https.html": [ [ - "/encrypted-media/clearkey-mp4-playback-temporary-events.html", + "/encrypted-media/clearkey-mp4-playback-temporary-events.https.html", {} ] ], - "encrypted-media/clearkey-mp4-playback-temporary-multikey-sequential-readyState.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-multikey-sequential-readyState.https.html": [ [ - "/encrypted-media/clearkey-mp4-playback-temporary-multikey-sequential-readyState.html", + "/encrypted-media/clearkey-mp4-playback-temporary-multikey-sequential-readyState.https.html", { "timeout": "long" } ] ], - "encrypted-media/clearkey-mp4-playback-temporary-multikey-sequential.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-multikey-sequential.https.html": [ [ - "/encrypted-media/clearkey-mp4-playback-temporary-multikey-sequential.html", + "/encrypted-media/clearkey-mp4-playback-temporary-multikey-sequential.https.html", { "timeout": "long" } ] ], - "encrypted-media/clearkey-mp4-playback-temporary-multikey.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-multikey.https.html": [ [ - "/encrypted-media/clearkey-mp4-playback-temporary-multikey.html", + "/encrypted-media/clearkey-mp4-playback-temporary-multikey.https.html", {} ] ], - "encrypted-media/clearkey-mp4-playback-temporary-multisession.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-multisession.https.html": [ [ - "/encrypted-media/clearkey-mp4-playback-temporary-multisession.html", + "/encrypted-media/clearkey-mp4-playback-temporary-multisession.https.html", {} ] ], - "encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-after-src.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-after-src.https.html": [ [ - "/encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-after-src.html", + "/encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-after-src.https.html", {} ] ], - "encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-after-update.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-after-update.https.html": [ [ - "/encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-after-update.html", + "/encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-after-update.https.html", {} ] ], - "encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-immediately.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-immediately.https.html": [ [ - "/encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-immediately.html", + "/encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-immediately.https.html", {} ] ], - "encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-onencrypted.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-onencrypted.https.html": [ [ - "/encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-onencrypted.html", + "/encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-onencrypted.https.html", {} ] ], - "encrypted-media/clearkey-mp4-playback-temporary-two-videos.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-two-videos.https.html": [ [ - "/encrypted-media/clearkey-mp4-playback-temporary-two-videos.html", + "/encrypted-media/clearkey-mp4-playback-temporary-two-videos.https.html", { "timeout": "long" } ] ], - "encrypted-media/clearkey-mp4-playback-temporary-waitingforkey.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-waitingforkey.https.html": [ [ - "/encrypted-media/clearkey-mp4-playback-temporary-waitingforkey.html", + "/encrypted-media/clearkey-mp4-playback-temporary-waitingforkey.https.html", {} ] ], - "encrypted-media/clearkey-mp4-playback-temporary.html": [ + "encrypted-media/clearkey-mp4-playback-temporary.https.html": [ [ - "/encrypted-media/clearkey-mp4-playback-temporary.html", + "/encrypted-media/clearkey-mp4-playback-temporary.https.html", {} ] ], - "encrypted-media/clearkey-mp4-requestmediakeysystemaccess.html": [ + "encrypted-media/clearkey-mp4-requestmediakeysystemaccess.https.html": [ [ - "/encrypted-media/clearkey-mp4-requestmediakeysystemaccess.html", + "/encrypted-media/clearkey-mp4-requestmediakeysystemaccess.https.html", { "timeout": "long" } ] ], - "encrypted-media/clearkey-mp4-reset-src-after-setmediakeys.html": [ + "encrypted-media/clearkey-mp4-reset-src-after-setmediakeys.https.html": [ [ - "/encrypted-media/clearkey-mp4-reset-src-after-setmediakeys.html", + "/encrypted-media/clearkey-mp4-reset-src-after-setmediakeys.https.html", {} ] ], - "encrypted-media/clearkey-mp4-setmediakeys-again-after-playback.html": [ + "encrypted-media/clearkey-mp4-setmediakeys-again-after-playback.https.html": [ [ - "/encrypted-media/clearkey-mp4-setmediakeys-again-after-playback.html", + "/encrypted-media/clearkey-mp4-setmediakeys-again-after-playback.https.html", {} ] ], - "encrypted-media/clearkey-mp4-setmediakeys-again-after-resetting-src.html": [ + "encrypted-media/clearkey-mp4-setmediakeys-again-after-resetting-src.https.html": [ [ - "/encrypted-media/clearkey-mp4-setmediakeys-again-after-resetting-src.html", + "/encrypted-media/clearkey-mp4-setmediakeys-again-after-resetting-src.https.html", {} ] ], - "encrypted-media/clearkey-mp4-setmediakeys-at-same-time.html": [ + "encrypted-media/clearkey-mp4-setmediakeys-at-same-time.https.html": [ [ - "/encrypted-media/clearkey-mp4-setmediakeys-at-same-time.html", + "/encrypted-media/clearkey-mp4-setmediakeys-at-same-time.https.html", {} ] ], - "encrypted-media/clearkey-mp4-setmediakeys-multiple-times-with-different-mediakeys.html": [ + "encrypted-media/clearkey-mp4-setmediakeys-multiple-times-with-different-mediakeys.https.html": [ [ - "/encrypted-media/clearkey-mp4-setmediakeys-multiple-times-with-different-mediakeys.html", + "/encrypted-media/clearkey-mp4-setmediakeys-multiple-times-with-different-mediakeys.https.html", {} ] ], - "encrypted-media/clearkey-mp4-setmediakeys-multiple-times-with-the-same-mediakeys.html": [ + "encrypted-media/clearkey-mp4-setmediakeys-multiple-times-with-the-same-mediakeys.https.html": [ [ - "/encrypted-media/clearkey-mp4-setmediakeys-multiple-times-with-the-same-mediakeys.html", + "/encrypted-media/clearkey-mp4-setmediakeys-multiple-times-with-the-same-mediakeys.https.html", {} ] ], - "encrypted-media/clearkey-mp4-setmediakeys-to-multiple-video-elements.html": [ + "encrypted-media/clearkey-mp4-setmediakeys-to-multiple-video-elements.https.html": [ [ - "/encrypted-media/clearkey-mp4-setmediakeys-to-multiple-video-elements.html", + "/encrypted-media/clearkey-mp4-setmediakeys-to-multiple-video-elements.https.html", {} ] ], - "encrypted-media/clearkey-mp4-setmediakeys.html": [ + "encrypted-media/clearkey-mp4-setmediakeys.https.html": [ [ - "/encrypted-media/clearkey-mp4-setmediakeys.html", + "/encrypted-media/clearkey-mp4-setmediakeys.https.html", {} ] ], - "encrypted-media/clearkey-mp4-syntax-mediakeys.html": [ + "encrypted-media/clearkey-mp4-syntax-mediakeys.https.html": [ [ - "/encrypted-media/clearkey-mp4-syntax-mediakeys.html", + "/encrypted-media/clearkey-mp4-syntax-mediakeys.https.html", {} ] ], - "encrypted-media/clearkey-mp4-syntax-mediakeysession.html": [ + "encrypted-media/clearkey-mp4-syntax-mediakeysession.https.html": [ [ - "/encrypted-media/clearkey-mp4-syntax-mediakeysession.html", + "/encrypted-media/clearkey-mp4-syntax-mediakeysession.https.html", {} ] ], - "encrypted-media/clearkey-mp4-syntax-mediakeysystemaccess.html": [ + "encrypted-media/clearkey-mp4-syntax-mediakeysystemaccess.https.html": [ [ - "/encrypted-media/clearkey-mp4-syntax-mediakeysystemaccess.html", + "/encrypted-media/clearkey-mp4-syntax-mediakeysystemaccess.https.html", {} ] ], - "encrypted-media/clearkey-mp4-unique-origin.html": [ + "encrypted-media/clearkey-mp4-unique-origin.https.html": [ [ - "/encrypted-media/clearkey-mp4-unique-origin.html", + "/encrypted-media/clearkey-mp4-unique-origin.https.html", {} ] ], - "encrypted-media/clearkey-mp4-update-disallowed-input.html": [ + "encrypted-media/clearkey-mp4-update-disallowed-input.https.html": [ [ - "/encrypted-media/clearkey-mp4-update-disallowed-input.html", + "/encrypted-media/clearkey-mp4-update-disallowed-input.https.html", {} ] ], - "encrypted-media/clearkey-mp4-waiting-for-a-key.html": [ + "encrypted-media/clearkey-mp4-waiting-for-a-key.https.html": [ [ - "/encrypted-media/clearkey-mp4-waiting-for-a-key.html", + "/encrypted-media/clearkey-mp4-waiting-for-a-key.https.html", {} ] ], - "encrypted-media/clearkey-not-callable-after-createsession.html": [ + "encrypted-media/clearkey-not-callable-after-createsession.https.html": [ [ - "/encrypted-media/clearkey-not-callable-after-createsession.html", + "/encrypted-media/clearkey-not-callable-after-createsession.https.html", {} ] ], - "encrypted-media/clearkey-update-non-ascii-input.html": [ + "encrypted-media/clearkey-update-non-ascii-input.https.html": [ [ - "/encrypted-media/clearkey-update-non-ascii-input.html", + "/encrypted-media/clearkey-update-non-ascii-input.https.html", {} ] ], - "encrypted-media/drm-check-initdata-type.html": [ + "encrypted-media/drm-check-initdata-type.https.html": [ [ - "/encrypted-media/drm-check-initdata-type.html", + "/encrypted-media/drm-check-initdata-type.https.html", {} ] ], - "encrypted-media/drm-events-session-closed-event.html": [ + "encrypted-media/drm-events-session-closed-event.https.html": [ [ - "/encrypted-media/drm-events-session-closed-event.html", + "/encrypted-media/drm-events-session-closed-event.https.html", {} ] ], - "encrypted-media/drm-events.html": [ + "encrypted-media/drm-events.https.html": [ [ - "/encrypted-media/drm-events.html", + "/encrypted-media/drm-events.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-expiration.html": [ + "encrypted-media/drm-expiration.https.html": [ [ - "/encrypted-media/drm-expiration.html", + "/encrypted-media/drm-expiration.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-generate-request-disallowed-input.html": [ + "encrypted-media/drm-generate-request-disallowed-input.https.html": [ [ - "/encrypted-media/drm-generate-request-disallowed-input.html", + "/encrypted-media/drm-generate-request-disallowed-input.https.html", {} ] ], - "encrypted-media/drm-invalid-license.html": [ + "encrypted-media/drm-invalid-license.https.html": [ [ - "/encrypted-media/drm-invalid-license.html", + "/encrypted-media/drm-invalid-license.https.html", {} ] ], - "encrypted-media/drm-keystatuses-multiple-sessions.html": [ + "encrypted-media/drm-keystatuses-multiple-sessions.https.html": [ [ - "/encrypted-media/drm-keystatuses-multiple-sessions.html", + "/encrypted-media/drm-keystatuses-multiple-sessions.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-keystatuses.html": [ + "encrypted-media/drm-keystatuses.https.html": [ [ - "/encrypted-media/drm-keystatuses.html", + "/encrypted-media/drm-keystatuses.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-onencrypted.html": [ + "encrypted-media/drm-mp4-onencrypted.https.html": [ [ - "/encrypted-media/drm-mp4-onencrypted.html", + "/encrypted-media/drm-mp4-onencrypted.https.html", {} ] ], - "encrypted-media/drm-mp4-playback-destroy-persistent-license.html": [ + "encrypted-media/drm-mp4-playback-destroy-persistent-license.https.html": [ [ - "/encrypted-media/drm-mp4-playback-destroy-persistent-license.html", + "/encrypted-media/drm-mp4-playback-destroy-persistent-license.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-playback-persistent-license-events.html": [ + "encrypted-media/drm-mp4-playback-persistent-license-events.https.html": [ [ - "/encrypted-media/drm-mp4-playback-persistent-license-events.html", + "/encrypted-media/drm-mp4-playback-persistent-license-events.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-playback-persistent-license.html": [ + "encrypted-media/drm-mp4-playback-persistent-license.https.html": [ [ - "/encrypted-media/drm-mp4-playback-persistent-license.html", + "/encrypted-media/drm-mp4-playback-persistent-license.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-playback-persistent-usage-record-events.html": [ + "encrypted-media/drm-mp4-playback-persistent-usage-record-events.https.html": [ [ - "/encrypted-media/drm-mp4-playback-persistent-usage-record-events.html", + "/encrypted-media/drm-mp4-playback-persistent-usage-record-events.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-playback-persistent-usage-record.html": [ + "encrypted-media/drm-mp4-playback-persistent-usage-record.https.html": [ [ - "/encrypted-media/drm-mp4-playback-persistent-usage-record.html", + "/encrypted-media/drm-mp4-playback-persistent-usage-record.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-playback-retrieve-destroy-persistent-license.html": [ + "encrypted-media/drm-mp4-playback-retrieve-destroy-persistent-license.https.html": [ [ - "/encrypted-media/drm-mp4-playback-retrieve-destroy-persistent-license.html", + "/encrypted-media/drm-mp4-playback-retrieve-destroy-persistent-license.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-playback-retrieve-persistent-license.html": [ + "encrypted-media/drm-mp4-playback-retrieve-persistent-license.https.html": [ [ - "/encrypted-media/drm-mp4-playback-retrieve-persistent-license.html", + "/encrypted-media/drm-mp4-playback-retrieve-persistent-license.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-playback-retrieve-persistent-usage-record.html": [ + "encrypted-media/drm-mp4-playback-retrieve-persistent-usage-record.https.html": [ [ - "/encrypted-media/drm-mp4-playback-retrieve-persistent-usage-record.html", + "/encrypted-media/drm-mp4-playback-retrieve-persistent-usage-record.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-playback-temporary-clear-encrypted.html": [ + "encrypted-media/drm-mp4-playback-temporary-clear-encrypted.https.html": [ [ - "/encrypted-media/drm-mp4-playback-temporary-clear-encrypted.html", + "/encrypted-media/drm-mp4-playback-temporary-clear-encrypted.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-playback-temporary-encrypted-clear-sources.html": [ + "encrypted-media/drm-mp4-playback-temporary-encrypted-clear-sources.https.html": [ [ - "/encrypted-media/drm-mp4-playback-temporary-encrypted-clear-sources.html", + "/encrypted-media/drm-mp4-playback-temporary-encrypted-clear-sources.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-playback-temporary-encrypted-clear.html": [ + "encrypted-media/drm-mp4-playback-temporary-encrypted-clear.https.html": [ [ - "/encrypted-media/drm-mp4-playback-temporary-encrypted-clear.html", + "/encrypted-media/drm-mp4-playback-temporary-encrypted-clear.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-playback-temporary-events.html": [ + "encrypted-media/drm-mp4-playback-temporary-events.https.html": [ [ - "/encrypted-media/drm-mp4-playback-temporary-events.html", + "/encrypted-media/drm-mp4-playback-temporary-events.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-playback-temporary-expired.html": [ + "encrypted-media/drm-mp4-playback-temporary-expired.https.html": [ [ - "/encrypted-media/drm-mp4-playback-temporary-expired.html", + "/encrypted-media/drm-mp4-playback-temporary-expired.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-playback-temporary-multikey-sequential-readyState.html": [ + "encrypted-media/drm-mp4-playback-temporary-multikey-sequential-readyState.https.html": [ [ - "/encrypted-media/drm-mp4-playback-temporary-multikey-sequential-readyState.html", + "/encrypted-media/drm-mp4-playback-temporary-multikey-sequential-readyState.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-playback-temporary-multikey-sequential.html": [ + "encrypted-media/drm-mp4-playback-temporary-multikey-sequential.https.html": [ [ - "/encrypted-media/drm-mp4-playback-temporary-multikey-sequential.html", + "/encrypted-media/drm-mp4-playback-temporary-multikey-sequential.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-playback-temporary-multikey.html": [ + "encrypted-media/drm-mp4-playback-temporary-multikey.https.html": [ [ - "/encrypted-media/drm-mp4-playback-temporary-multikey.html", + "/encrypted-media/drm-mp4-playback-temporary-multikey.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-playback-temporary-multisession.html": [ + "encrypted-media/drm-mp4-playback-temporary-multisession.https.html": [ [ - "/encrypted-media/drm-mp4-playback-temporary-multisession.html", + "/encrypted-media/drm-mp4-playback-temporary-multisession.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-playback-temporary-setMediaKeys-after-src.html": [ + "encrypted-media/drm-mp4-playback-temporary-setMediaKeys-after-src.https.html": [ [ - "/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-after-src.html", + "/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-after-src.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-playback-temporary-setMediaKeys-after-update.html": [ + "encrypted-media/drm-mp4-playback-temporary-setMediaKeys-after-update.https.html": [ [ - "/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-after-update.html", + "/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-after-update.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-playback-temporary-setMediaKeys-immediately.html": [ + "encrypted-media/drm-mp4-playback-temporary-setMediaKeys-immediately.https.html": [ [ - "/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-immediately.html", + "/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-immediately.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-playback-temporary-setMediaKeys-onencrypted.html": [ + "encrypted-media/drm-mp4-playback-temporary-setMediaKeys-onencrypted.https.html": [ [ - "/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-onencrypted.html", + "/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-onencrypted.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-playback-temporary-two-videos.html": [ + "encrypted-media/drm-mp4-playback-temporary-two-videos.https.html": [ [ - "/encrypted-media/drm-mp4-playback-temporary-two-videos.html", + "/encrypted-media/drm-mp4-playback-temporary-two-videos.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-playback-temporary-waitingforkey.html": [ + "encrypted-media/drm-mp4-playback-temporary-waitingforkey.https.html": [ [ - "/encrypted-media/drm-mp4-playback-temporary-waitingforkey.html", + "/encrypted-media/drm-mp4-playback-temporary-waitingforkey.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-playback-temporary.html": [ + "encrypted-media/drm-mp4-playback-temporary.https.html": [ [ - "/encrypted-media/drm-mp4-playback-temporary.html", + "/encrypted-media/drm-mp4-playback-temporary.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-requestmediakeysystemaccess.html": [ + "encrypted-media/drm-mp4-requestmediakeysystemaccess.https.html": [ [ - "/encrypted-media/drm-mp4-requestmediakeysystemaccess.html", + "/encrypted-media/drm-mp4-requestmediakeysystemaccess.https.html", {} ] ], - "encrypted-media/drm-mp4-reset-src-after-setmediakeys.html": [ + "encrypted-media/drm-mp4-reset-src-after-setmediakeys.https.html": [ [ - "/encrypted-media/drm-mp4-reset-src-after-setmediakeys.html", + "/encrypted-media/drm-mp4-reset-src-after-setmediakeys.https.html", {} ] ], - "encrypted-media/drm-mp4-setmediakeys-again-after-playback.html": [ + "encrypted-media/drm-mp4-setmediakeys-again-after-playback.https.html": [ [ - "/encrypted-media/drm-mp4-setmediakeys-again-after-playback.html", + "/encrypted-media/drm-mp4-setmediakeys-again-after-playback.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-setmediakeys-again-after-resetting-src.html": [ + "encrypted-media/drm-mp4-setmediakeys-again-after-resetting-src.https.html": [ [ - "/encrypted-media/drm-mp4-setmediakeys-again-after-resetting-src.html", + "/encrypted-media/drm-mp4-setmediakeys-again-after-resetting-src.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-setmediakeys-at-same-time.html": [ + "encrypted-media/drm-mp4-setmediakeys-at-same-time.https.html": [ [ - "/encrypted-media/drm-mp4-setmediakeys-at-same-time.html", + "/encrypted-media/drm-mp4-setmediakeys-at-same-time.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-setmediakeys-multiple-times-with-different-mediakeys.html": [ + "encrypted-media/drm-mp4-setmediakeys-multiple-times-with-different-mediakeys.https.html": [ [ - "/encrypted-media/drm-mp4-setmediakeys-multiple-times-with-different-mediakeys.html", + "/encrypted-media/drm-mp4-setmediakeys-multiple-times-with-different-mediakeys.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-setmediakeys-multiple-times-with-the-same-mediakeys.html": [ + "encrypted-media/drm-mp4-setmediakeys-multiple-times-with-the-same-mediakeys.https.html": [ [ - "/encrypted-media/drm-mp4-setmediakeys-multiple-times-with-the-same-mediakeys.html", + "/encrypted-media/drm-mp4-setmediakeys-multiple-times-with-the-same-mediakeys.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-setmediakeys-to-multiple-video-elements.html": [ + "encrypted-media/drm-mp4-setmediakeys-to-multiple-video-elements.https.html": [ [ - "/encrypted-media/drm-mp4-setmediakeys-to-multiple-video-elements.html", + "/encrypted-media/drm-mp4-setmediakeys-to-multiple-video-elements.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-mp4-setmediakeys.html": [ + "encrypted-media/drm-mp4-setmediakeys.https.html": [ [ - "/encrypted-media/drm-mp4-setmediakeys.html", + "/encrypted-media/drm-mp4-setmediakeys.https.html", {} ] ], - "encrypted-media/drm-mp4-syntax-mediakeys.html": [ + "encrypted-media/drm-mp4-syntax-mediakeys.https.html": [ [ - "/encrypted-media/drm-mp4-syntax-mediakeys.html", + "/encrypted-media/drm-mp4-syntax-mediakeys.https.html", {} ] ], - "encrypted-media/drm-mp4-syntax-mediakeysession.html": [ + "encrypted-media/drm-mp4-syntax-mediakeysession.https.html": [ [ - "/encrypted-media/drm-mp4-syntax-mediakeysession.html", + "/encrypted-media/drm-mp4-syntax-mediakeysession.https.html", {} ] ], - "encrypted-media/drm-mp4-syntax-mediakeysystemaccess.html": [ + "encrypted-media/drm-mp4-syntax-mediakeysystemaccess.https.html": [ [ - "/encrypted-media/drm-mp4-syntax-mediakeysystemaccess.html", + "/encrypted-media/drm-mp4-syntax-mediakeysystemaccess.https.html", {} ] ], - "encrypted-media/drm-mp4-unique-origin.html": [ + "encrypted-media/drm-mp4-unique-origin.https.html": [ [ - "/encrypted-media/drm-mp4-unique-origin.html", + "/encrypted-media/drm-mp4-unique-origin.https.html", {} ] ], - "encrypted-media/drm-mp4-waiting-for-a-key.html": [ + "encrypted-media/drm-mp4-waiting-for-a-key.https.html": [ [ - "/encrypted-media/drm-mp4-waiting-for-a-key.html", + "/encrypted-media/drm-mp4-waiting-for-a-key.https.html", { "timeout": "long" } ] ], - "encrypted-media/drm-not-callable-after-createsession.html": [ + "encrypted-media/drm-not-callable-after-createsession.https.html": [ [ - "/encrypted-media/drm-not-callable-after-createsession.html", + "/encrypted-media/drm-not-callable-after-createsession.https.html", {} ] ], - "encrypted-media/drm-temporary-license-type.html": [ + "encrypted-media/drm-temporary-license-type.https.html": [ [ - "/encrypted-media/drm-temporary-license-type.html", + "/encrypted-media/drm-temporary-license-type.https.html", { "timeout": "long" } @@ -309349,9 +314417,9 @@ {} ] ], - "encrypted-media/idlharness.html": [ + "encrypted-media/idlharness.https.html": [ [ - "/encrypted-media/idlharness.html", + "/encrypted-media/idlharness.https.html", {} ] ], @@ -309733,6 +314801,46 @@ {} ] ], + "feature-policy/autoplay-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html": [ + [ + "/feature-policy/autoplay-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html", + { + "testdriver": true + } + ] + ], + "feature-policy/autoplay-allowed-by-feature-policy-attribute.https.sub.html": [ + [ + "/feature-policy/autoplay-allowed-by-feature-policy-attribute.https.sub.html", + { + "testdriver": true + } + ] + ], + "feature-policy/autoplay-allowed-by-feature-policy.https.sub.html": [ + [ + "/feature-policy/autoplay-allowed-by-feature-policy.https.sub.html", + { + "testdriver": true + } + ] + ], + "feature-policy/autoplay-default-feature-policy.https.sub.html": [ + [ + "/feature-policy/autoplay-default-feature-policy.https.sub.html", + { + "testdriver": true + } + ] + ], + "feature-policy/autoplay-disabled-by-feature-policy.https.sub.html": [ + [ + "/feature-policy/autoplay-disabled-by-feature-policy.https.sub.html", + { + "testdriver": true + } + ] + ], "feature-policy/payment-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html": [ [ "/feature-policy/payment-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html", @@ -310457,6 +315565,12 @@ {} ] ], + "fetch/api/request/destination/fetch-destination.https.html": [ + [ + "/fetch/api/request/destination/fetch-destination.https.html", + {} + ] + ], "fetch/api/request/multi-globals/url-parsing.html": [ [ "/fetch/api/request/multi-globals/url-parsing.html", @@ -310953,12 +316067,84 @@ {} ] ], + "geolocation-sensor/GeolocationSensor-disabled-by-feature-policy.https.html": [ + [ + "/geolocation-sensor/GeolocationSensor-disabled-by-feature-policy.https.html", + {} + ] + ], + "geolocation-sensor/GeolocationSensor-enabled-by-feature-policy-attribute-redirect-on-load.https.html": [ + [ + "/geolocation-sensor/GeolocationSensor-enabled-by-feature-policy-attribute-redirect-on-load.https.html", + {} + ] + ], + "geolocation-sensor/GeolocationSensor-enabled-by-feature-policy-attribute.https.html": [ + [ + "/geolocation-sensor/GeolocationSensor-enabled-by-feature-policy-attribute.https.html", + {} + ] + ], + "geolocation-sensor/GeolocationSensor-enabled-by-feature-policy.https.html": [ + [ + "/geolocation-sensor/GeolocationSensor-enabled-by-feature-policy.https.html", + {} + ] + ], + "geolocation-sensor/GeolocationSensor-enabled-on-self-origin-by-feature-policy.https.html": [ + [ + "/geolocation-sensor/GeolocationSensor-enabled-on-self-origin-by-feature-policy.https.html", + {} + ] + ], + "geolocation-sensor/GeolocationSensor.https.html": [ + [ + "/geolocation-sensor/GeolocationSensor.https.html", + {} + ] + ], + "geolocation-sensor/GeolocationSensor_insecure_context.html": [ + [ + "/geolocation-sensor/GeolocationSensor_insecure_context.html", + {} + ] + ], "geolocation-sensor/idlharness.https.html": [ [ "/geolocation-sensor/idlharness.https.html", {} ] ], + "gyroscope/Gyroscope-disabled-by-feature-policy.https.html": [ + [ + "/gyroscope/Gyroscope-disabled-by-feature-policy.https.html", + {} + ] + ], + "gyroscope/Gyroscope-enabled-by-feature-policy-attribute-redirect-on-load.https.html": [ + [ + "/gyroscope/Gyroscope-enabled-by-feature-policy-attribute-redirect-on-load.https.html", + {} + ] + ], + "gyroscope/Gyroscope-enabled-by-feature-policy-attribute.https.html": [ + [ + "/gyroscope/Gyroscope-enabled-by-feature-policy-attribute.https.html", + {} + ] + ], + "gyroscope/Gyroscope-enabled-by-feature-policy.https.html": [ + [ + "/gyroscope/Gyroscope-enabled-by-feature-policy.https.html", + {} + ] + ], + "gyroscope/Gyroscope-enabled-on-self-origin-by-feature-policy.https.html": [ + [ + "/gyroscope/Gyroscope-enabled-on-self-origin-by-feature-policy.https.html", + {} + ] + ], "gyroscope/Gyroscope.https.html": [ [ "/gyroscope/Gyroscope.https.html", @@ -311003,6 +316189,12 @@ {} ] ], + "hr-time/performance-tojson.html": [ + [ + "/hr-time/performance-tojson.html", + {} + ] + ], "hr-time/test_cross_frame_start.html": [ [ "/hr-time/test_cross_frame_start.html", @@ -314005,6 +319197,12 @@ {} ] ], + "html/dom/usvstring-reflection.html": [ + [ + "/html/dom/usvstring-reflection.html", + {} + ] + ], "html/editing/activation/click.html": [ [ "/html/editing/activation/click.html", @@ -314987,6 +320185,12 @@ {} ] ], + "html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLMediaElement/crossOrigin.html": [ + [ + "/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLMediaElement/crossOrigin.html", + {} + ] + ], "html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLMediaElement/textTracks.html": [ [ "/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLMediaElement/textTracks.html", @@ -315095,6 +320299,12 @@ {} ] ], + "html/semantics/embedded-content/media-elements/interfaces/TextTrackCue/constructor.html": [ + [ + "/html/semantics/embedded-content/media-elements/interfaces/TextTrackCue/constructor.html", + {} + ] + ], "html/semantics/embedded-content/media-elements/interfaces/TextTrackCue/endTime.html": [ [ "/html/semantics/embedded-content/media-elements/interfaces/TextTrackCue/endTime.html", @@ -315887,24 +321097,390 @@ {} ] ], + "html/semantics/embedded-content/media-elements/track/track-element/track-active-cues.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-active-cues.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-add-remove-cue.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-add-remove-cue.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-add-track.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-add-track.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-addtrack-kind.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-addtrack-kind.html", + {} + ] + ], "html/semantics/embedded-content/media-elements/track/track-element/track-api-texttracks.html": [ [ "/html/semantics/embedded-content/media-elements/track/track-element/track-api-texttracks.html", {} ] ], + "html/semantics/embedded-content/media-elements/track/track-element/track-cue-empty.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-cue-empty.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-cue-inline.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-cue-inline.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-cue-mutable-fragment.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-cue-mutable-fragment.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-cue-mutable.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-cue-mutable.html", + {} + ] + ], "html/semantics/embedded-content/media-elements/track/track-element/track-cue-order.html": [ [ "/html/semantics/embedded-content/media-elements/track/track-element/track-cue-order.html", {} ] ], + "html/semantics/embedded-content/media-elements/track/track-element/track-cues-missed.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-cues-missed.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-cues-pause-on-exit.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-cues-pause-on-exit.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-cues-seeking.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-cues-seeking.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-cues-sorted-before-dispatch.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-cues-sorted-before-dispatch.html", + {} + ] + ], "html/semantics/embedded-content/media-elements/track/track-element/track-data-url.html": [ [ "/html/semantics/embedded-content/media-elements/track/track-element/track-data-url.html", {} ] ], + "html/semantics/embedded-content/media-elements/track/track-element/track-disabled-addcue.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-disabled-addcue.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-disabled.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-disabled.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-element-dom-change.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-element-dom-change.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-element-src-change-error.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-element-src-change-error.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-element-src-change.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-element-src-change.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-large-timestamp.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-large-timestamp.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-load-error-readyState.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-load-error-readyState.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-load-from-element-readyState.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-load-from-element-readyState.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-load-from-src-readyState.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-load-from-src-readyState.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-mode-disabled.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-mode-disabled.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-mode-not-changed-by-new-track.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-mode-not-changed-by-new-track.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-mode-triggers-loading.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-mode-triggers-loading.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-mode.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-mode.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-remove-active-cue.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-remove-active-cue.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-remove-by-setting-innerHTML.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-remove-by-setting-innerHTML.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-remove-insert-ready-state.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-remove-insert-ready-state.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-remove-quickly.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-remove-quickly.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-remove-track.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-remove-track.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-align-positioning.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-align-positioning.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-align-text-line-position.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-align-text-line-position.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-alignment.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-alignment.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-blank-lines.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-blank-lines.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-bom.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-bom.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-class-markup.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-class-markup.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-identifiers.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-identifiers.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-no-id.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-no-id.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-recovery.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-recovery.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-size-align.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-size-align.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-size.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-size.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-degenerate-cues.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-degenerate-cues.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-empty-cue.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-empty-cue.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-entities.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-entities.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-header-comment.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-header-comment.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-interspersed-non-cue.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-interspersed-non-cue.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-line-position.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-line-position.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-magic-header.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-magic-header.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-markup.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-markup.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-newlines.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-newlines.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-no-timings.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-no-timings.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-positioning.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-positioning.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-settings.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-settings.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-timestamp.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-timestamp.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-timings-hour.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-timings-hour.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-timings-no-hours.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-timings-no-hours.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-timings-whitespace.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-timings-whitespace.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-unsupported-markup.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-unsupported-markup.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-utf8.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-utf8.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-valign.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-valign.html", + {} + ] + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-voice.html": [ + [ + "/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-voice.html", + {} + ] + ], "html/semantics/embedded-content/media-elements/user-interface/muted.html": [ [ "/html/semantics/embedded-content/media-elements/user-interface/muted.html", @@ -318221,6 +323797,12 @@ {} ] ], + "html/semantics/forms/the-select-element/select-add.html": [ + [ + "/html/semantics/forms/the-select-element/select-add.html", + {} + ] + ], "html/semantics/forms/the-select-element/select-ask-for-reset.html": [ [ "/html/semantics/forms/the-select-element/select-ask-for-reset.html", @@ -318395,6 +323977,12 @@ {} ] ], + "html/semantics/interactive-elements/the-dialog-element/abspos-dialog-layout.html": [ + [ + "/html/semantics/interactive-elements/the-dialog-element/abspos-dialog-layout.html", + {} + ] + ], "html/semantics/interactive-elements/the-dialog-element/centering.html": [ [ "/html/semantics/interactive-elements/the-dialog-element/centering.html", @@ -318437,12 +324025,30 @@ {} ] ], + "html/semantics/interactive-elements/the-dialog-element/dialog-scrolled-viewport.html": [ + [ + "/html/semantics/interactive-elements/the-dialog-element/dialog-scrolled-viewport.html", + {} + ] + ], "html/semantics/interactive-elements/the-dialog-element/dialog-showModal.html": [ [ "/html/semantics/interactive-elements/the-dialog-element/dialog-showModal.html", {} ] ], + "html/semantics/interactive-elements/the-dialog-element/inert-does-not-match-disabled-selector.html": [ + [ + "/html/semantics/interactive-elements/the-dialog-element/inert-does-not-match-disabled-selector.html", + {} + ] + ], + "html/semantics/interactive-elements/the-dialog-element/inert-node-is-unfocusable.html": [ + [ + "/html/semantics/interactive-elements/the-dialog-element/inert-node-is-unfocusable.html", + {} + ] + ], "html/semantics/interactive-elements/the-dialog-element/show-modal-focusing-steps.html": [ [ "/html/semantics/interactive-elements/the-dialog-element/show-modal-focusing-steps.html", @@ -319517,6 +325123,24 @@ {} ] ], + "html/semantics/scripting-1/the-script-element/module/choice-of-error-1.html": [ + [ + "/html/semantics/scripting-1/the-script-element/module/choice-of-error-1.html", + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/choice-of-error-2.html": [ + [ + "/html/semantics/scripting-1/the-script-element/module/choice-of-error-2.html", + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/choice-of-error-3.html": [ + [ + "/html/semantics/scripting-1/the-script-element/module/choice-of-error-3.html", + {} + ] + ], "html/semantics/scripting-1/the-script-element/module/compilation-error-1.html": [ [ "/html/semantics/scripting-1/the-script-element/module/compilation-error-1.html", @@ -319601,15 +325225,27 @@ {} ] ], - "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-classic.html": [ + "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-classic.html": [ [ - "/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-classic.html", + "/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-classic.html", {} ] ], - "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-module.html": [ + "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-module.html": [ [ - "/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-module.html", + "/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-module.html", + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-classic.html": [ + [ + "/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-classic.html", + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-module.html": [ + [ + "/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-module.html", {} ] ], @@ -319619,18 +325255,60 @@ {} ] ], + "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-classic.html": [ + [ + "/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-classic.html", + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-module.html": [ + [ + "/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-module.html", + {} + ] + ], "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-module.html": [ [ "/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-module.html", {} ] ], + "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-classic.html": [ + [ + "/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-classic.html", + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-module.html": [ + [ + "/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-module.html", + {} + ] + ], "html/semantics/scripting-1/the-script-element/module/error-and-slow-dependency.html": [ [ "/html/semantics/scripting-1/the-script-element/module/error-and-slow-dependency.html", {} ] ], + "html/semantics/scripting-1/the-script-element/module/error-type-1.html": [ + [ + "/html/semantics/scripting-1/the-script-element/module/error-type-1.html", + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/error-type-2.html": [ + [ + "/html/semantics/scripting-1/the-script-element/module/error-type-2.html", + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/error-type-3.html": [ + [ + "/html/semantics/scripting-1/the-script-element/module/error-type-3.html", + {} + ] + ], "html/semantics/scripting-1/the-script-element/module/errorhandling.html": [ [ "/html/semantics/scripting-1/the-script-element/module/errorhandling.html", @@ -319801,6 +325479,36 @@ {} ] ], + "html/semantics/scripting-1/the-script-element/module/referrer-no-referrer.sub.html": [ + [ + "/html/semantics/scripting-1/the-script-element/module/referrer-no-referrer.sub.html", + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub.html": [ + [ + "/html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub.html", + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/referrer-origin.sub.html": [ + [ + "/html/semantics/scripting-1/the-script-element/module/referrer-origin.sub.html", + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/referrer-same-origin.sub.html": [ + [ + "/html/semantics/scripting-1/the-script-element/module/referrer-same-origin.sub.html", + {} + ] + ], + "html/semantics/scripting-1/the-script-element/module/referrer-unsafe-url.sub.html": [ + [ + "/html/semantics/scripting-1/the-script-element/module/referrer-unsafe-url.sub.html", + {} + ] + ], "html/semantics/scripting-1/the-script-element/module/script-for-event.html": [ [ "/html/semantics/scripting-1/the-script-element/module/script-for-event.html", @@ -319897,6 +325605,12 @@ {} ] ], + "html/semantics/scripting-1/the-script-element/script-defer.html": [ + [ + "/html/semantics/scripting-1/the-script-element/script-defer.html", + {} + ] + ], "html/semantics/scripting-1/the-script-element/script-for-event-xhtml.xhtml": [ [ "/html/semantics/scripting-1/the-script-element/script-for-event-xhtml.xhtml", @@ -322863,12 +328577,48 @@ {} ] ], + "longtask-timing/longtask-tojson.html": [ + [ + "/longtask-timing/longtask-tojson.html", + {} + ] + ], "longtask-timing/shared-renderer/longtask-in-new-window.html": [ [ "/longtask-timing/shared-renderer/longtask-in-new-window.html", {} ] ], + "magnetometer/Magnetometer-disabled-by-feature-policy.https.html": [ + [ + "/magnetometer/Magnetometer-disabled-by-feature-policy.https.html", + {} + ] + ], + "magnetometer/Magnetometer-enabled-by-feature-policy-attribute-redirect-on-load.https.html": [ + [ + "/magnetometer/Magnetometer-enabled-by-feature-policy-attribute-redirect-on-load.https.html", + {} + ] + ], + "magnetometer/Magnetometer-enabled-by-feature-policy-attribute.https.html": [ + [ + "/magnetometer/Magnetometer-enabled-by-feature-policy-attribute.https.html", + {} + ] + ], + "magnetometer/Magnetometer-enabled-by-feature-policy.https.html": [ + [ + "/magnetometer/Magnetometer-enabled-by-feature-policy.https.html", + {} + ] + ], + "magnetometer/Magnetometer-enabled-on-self-origin-by-feature-policy.https.html": [ + [ + "/magnetometer/Magnetometer-enabled-on-self-origin-by-feature-policy.https.html", + {} + ] + ], "magnetometer/Magnetometer.https.html": [ [ "/magnetometer/Magnetometer.https.html", @@ -323643,6 +329393,26 @@ {} ] ], + "mimesniff/mime-types/charset-parameter.window.js": [ + [ + "/mimesniff/mime-types/charset-parameter.window.html", + {} + ] + ], + "mimesniff/mime-types/parsing.any.js": [ + [ + "/mimesniff/mime-types/parsing.any.html", + { + "timeout": "long" + } + ], + [ + "/mimesniff/mime-types/parsing.any.worker.html", + { + "timeout": "long" + } + ] + ], "mixed-content/audio-tag/http-csp/cross-origin-http/top-level/keep-scheme-redirect/optionally-blockable/opt-in-blocks.https.html": [ [ "/mixed-content/audio-tag/http-csp/cross-origin-http/top-level/keep-scheme-redirect/optionally-blockable/opt-in-blocks.https.html", @@ -324105,39 +329875,39 @@ {} ] ], - "mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/keep-scheme-redirect/optionally-blockable/opt-in-blocks.https.html": [ + "mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/keep-scheme-redirect/blockable/opt-in-blocks.https.html": [ [ - "/mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/keep-scheme-redirect/optionally-blockable/opt-in-blocks.https.html", + "/mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/keep-scheme-redirect/blockable/opt-in-blocks.https.html", {} ] ], - "mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/no-redirect/optionally-blockable/opt-in-blocks.https.html": [ + "mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/no-redirect/blockable/opt-in-blocks.https.html": [ [ - "/mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/no-redirect/optionally-blockable/opt-in-blocks.https.html", + "/mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/no-redirect/blockable/opt-in-blocks.https.html", {} ] ], - "mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/swap-scheme-redirect/optionally-blockable/opt-in-blocks.https.html": [ + "mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/swap-scheme-redirect/blockable/opt-in-blocks.https.html": [ [ - "/mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/swap-scheme-redirect/optionally-blockable/opt-in-blocks.https.html", + "/mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/swap-scheme-redirect/blockable/opt-in-blocks.https.html", {} ] ], - "mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/keep-scheme-redirect/optionally-blockable/opt-in-blocks.https.html": [ + "mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/keep-scheme-redirect/blockable/opt-in-blocks.https.html": [ [ - "/mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/keep-scheme-redirect/optionally-blockable/opt-in-blocks.https.html", + "/mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/keep-scheme-redirect/blockable/opt-in-blocks.https.html", {} ] ], - "mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/no-redirect/optionally-blockable/opt-in-blocks.https.html": [ + "mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/no-redirect/blockable/opt-in-blocks.https.html": [ [ - "/mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/no-redirect/optionally-blockable/opt-in-blocks.https.html", + "/mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/no-redirect/blockable/opt-in-blocks.https.html", {} ] ], - "mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/swap-scheme-redirect/optionally-blockable/opt-in-blocks.https.html": [ + "mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/swap-scheme-redirect/blockable/opt-in-blocks.https.html": [ [ - "/mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/swap-scheme-redirect/optionally-blockable/opt-in-blocks.https.html", + "/mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/swap-scheme-redirect/blockable/opt-in-blocks.https.html", {} ] ], @@ -324153,15 +329923,15 @@ {} ] ], - "mixed-content/link-prefetch-tag/meta-csp/cross-origin-http/top-level/no-redirect/optionally-blockable/opt-in-blocks.https.html": [ + "mixed-content/link-prefetch-tag/meta-csp/cross-origin-http/top-level/no-redirect/blockable/opt-in-blocks.https.html": [ [ - "/mixed-content/link-prefetch-tag/meta-csp/cross-origin-http/top-level/no-redirect/optionally-blockable/opt-in-blocks.https.html", + "/mixed-content/link-prefetch-tag/meta-csp/cross-origin-http/top-level/no-redirect/blockable/opt-in-blocks.https.html", {} ] ], - "mixed-content/link-prefetch-tag/meta-csp/same-host-http/top-level/no-redirect/optionally-blockable/opt-in-blocks.https.html": [ + "mixed-content/link-prefetch-tag/meta-csp/same-host-http/top-level/no-redirect/blockable/opt-in-blocks.https.html": [ [ - "/mixed-content/link-prefetch-tag/meta-csp/same-host-http/top-level/no-redirect/optionally-blockable/opt-in-blocks.https.html", + "/mixed-content/link-prefetch-tag/meta-csp/same-host-http/top-level/no-redirect/blockable/opt-in-blocks.https.html", {} ] ], @@ -324171,39 +329941,39 @@ {} ] ], - "mixed-content/link-prefetch-tag/no-opt-in/cross-origin-http/top-level/keep-scheme-redirect/optionally-blockable/no-opt-in-allows.https.html": [ + "mixed-content/link-prefetch-tag/no-opt-in/cross-origin-http/top-level/keep-scheme-redirect/blockable/no-opt-in-blocks.https.html": [ [ - "/mixed-content/link-prefetch-tag/no-opt-in/cross-origin-http/top-level/keep-scheme-redirect/optionally-blockable/no-opt-in-allows.https.html", + "/mixed-content/link-prefetch-tag/no-opt-in/cross-origin-http/top-level/keep-scheme-redirect/blockable/no-opt-in-blocks.https.html", {} ] ], - "mixed-content/link-prefetch-tag/no-opt-in/cross-origin-http/top-level/no-redirect/optionally-blockable/no-opt-in-allows.https.html": [ + "mixed-content/link-prefetch-tag/no-opt-in/cross-origin-http/top-level/no-redirect/blockable/no-opt-in-blocks.https.html": [ [ - "/mixed-content/link-prefetch-tag/no-opt-in/cross-origin-http/top-level/no-redirect/optionally-blockable/no-opt-in-allows.https.html", + "/mixed-content/link-prefetch-tag/no-opt-in/cross-origin-http/top-level/no-redirect/blockable/no-opt-in-blocks.https.html", {} ] ], - "mixed-content/link-prefetch-tag/no-opt-in/cross-origin-http/top-level/swap-scheme-redirect/optionally-blockable/no-opt-in-allows.https.html": [ + "mixed-content/link-prefetch-tag/no-opt-in/cross-origin-http/top-level/swap-scheme-redirect/blockable/no-opt-in-blocks.https.html": [ [ - "/mixed-content/link-prefetch-tag/no-opt-in/cross-origin-http/top-level/swap-scheme-redirect/optionally-blockable/no-opt-in-allows.https.html", + "/mixed-content/link-prefetch-tag/no-opt-in/cross-origin-http/top-level/swap-scheme-redirect/blockable/no-opt-in-blocks.https.html", {} ] ], - "mixed-content/link-prefetch-tag/no-opt-in/same-host-http/top-level/keep-scheme-redirect/optionally-blockable/no-opt-in-allows.https.html": [ + "mixed-content/link-prefetch-tag/no-opt-in/same-host-http/top-level/keep-scheme-redirect/blockable/no-opt-in-blocks.https.html": [ [ - "/mixed-content/link-prefetch-tag/no-opt-in/same-host-http/top-level/keep-scheme-redirect/optionally-blockable/no-opt-in-allows.https.html", + "/mixed-content/link-prefetch-tag/no-opt-in/same-host-http/top-level/keep-scheme-redirect/blockable/no-opt-in-blocks.https.html", {} ] ], - "mixed-content/link-prefetch-tag/no-opt-in/same-host-http/top-level/no-redirect/optionally-blockable/no-opt-in-allows.https.html": [ + "mixed-content/link-prefetch-tag/no-opt-in/same-host-http/top-level/no-redirect/blockable/no-opt-in-blocks.https.html": [ [ - "/mixed-content/link-prefetch-tag/no-opt-in/same-host-http/top-level/no-redirect/optionally-blockable/no-opt-in-allows.https.html", + "/mixed-content/link-prefetch-tag/no-opt-in/same-host-http/top-level/no-redirect/blockable/no-opt-in-blocks.https.html", {} ] ], - "mixed-content/link-prefetch-tag/no-opt-in/same-host-http/top-level/swap-scheme-redirect/optionally-blockable/no-opt-in-allows.https.html": [ + "mixed-content/link-prefetch-tag/no-opt-in/same-host-http/top-level/swap-scheme-redirect/blockable/no-opt-in-blocks.https.html": [ [ - "/mixed-content/link-prefetch-tag/no-opt-in/same-host-http/top-level/swap-scheme-redirect/optionally-blockable/no-opt-in-allows.https.html", + "/mixed-content/link-prefetch-tag/no-opt-in/same-host-http/top-level/swap-scheme-redirect/blockable/no-opt-in-blocks.https.html", {} ] ], @@ -334137,6 +339907,36 @@ {} ] ], + "orientation-sensor/AbsoluteOrientationSensor-disabled-by-feature-policy.https.html": [ + [ + "/orientation-sensor/AbsoluteOrientationSensor-disabled-by-feature-policy.https.html", + {} + ] + ], + "orientation-sensor/AbsoluteOrientationSensor-enabled-by-feature-policy-attribute-redirect-on-load.https.html": [ + [ + "/orientation-sensor/AbsoluteOrientationSensor-enabled-by-feature-policy-attribute-redirect-on-load.https.html", + {} + ] + ], + "orientation-sensor/AbsoluteOrientationSensor-enabled-by-feature-policy-attribute.https.html": [ + [ + "/orientation-sensor/AbsoluteOrientationSensor-enabled-by-feature-policy-attribute.https.html", + {} + ] + ], + "orientation-sensor/AbsoluteOrientationSensor-enabled-by-feature-policy.https.html": [ + [ + "/orientation-sensor/AbsoluteOrientationSensor-enabled-by-feature-policy.https.html", + {} + ] + ], + "orientation-sensor/AbsoluteOrientationSensor-enabled-on-self-origin-by-feature-policy.https.html": [ + [ + "/orientation-sensor/AbsoluteOrientationSensor-enabled-on-self-origin-by-feature-policy.https.html", + {} + ] + ], "orientation-sensor/OrientationSensor.https.html": [ [ "/orientation-sensor/OrientationSensor.https.html", @@ -334149,6 +339949,36 @@ {} ] ], + "orientation-sensor/RelativeOrientationSensor-disabled-by-feature-policy.https.html": [ + [ + "/orientation-sensor/RelativeOrientationSensor-disabled-by-feature-policy.https.html", + {} + ] + ], + "orientation-sensor/RelativeOrientationSensor-enabled-by-feature-policy-attribute-redirect-on-load.https.html": [ + [ + "/orientation-sensor/RelativeOrientationSensor-enabled-by-feature-policy-attribute-redirect-on-load.https.html", + {} + ] + ], + "orientation-sensor/RelativeOrientationSensor-enabled-by-feature-policy-attribute.https.html": [ + [ + "/orientation-sensor/RelativeOrientationSensor-enabled-by-feature-policy-attribute.https.html", + {} + ] + ], + "orientation-sensor/RelativeOrientationSensor-enabled-by-feature-policy.https.html": [ + [ + "/orientation-sensor/RelativeOrientationSensor-enabled-by-feature-policy.https.html", + {} + ] + ], + "orientation-sensor/RelativeOrientationSensor-enabled-on-self-origin-by-feature-policy.https.html": [ + [ + "/orientation-sensor/RelativeOrientationSensor-enabled-on-self-origin-by-feature-policy.https.html", + {} + ] + ], "orientation-sensor/idlharness.https.html": [ [ "/orientation-sensor/idlharness.https.html", @@ -334275,6 +340105,12 @@ {} ] ], + "paint-timing/sibling-painting-first-image.html": [ + [ + "/paint-timing/sibling-painting-first-image.html", + {} + ] + ], "payment-handler/interfaces.https.any.js": [ [ "/payment-handler/interfaces.https.any.html", @@ -334425,6 +340261,12 @@ {} ] ], + "payment-request/payment-request-not-exposed.https.worker.js": [ + [ + "/payment-request/payment-request-not-exposed.https.worker.html", + {} + ] + ], "payment-request/payment-request-onshippingaddresschange-attribute.https.html": [ [ "/payment-request/payment-request-onshippingaddresschange-attribute.https.html", @@ -334483,6 +340325,12 @@ {} ] ], + "performance-timeline/performanceentry-tojson.html": [ + [ + "/performance-timeline/performanceentry-tojson.html", + {} + ] + ], "performance-timeline/po-callback-mutate.any.js": [ [ "/performance-timeline/po-callback-mutate.any.html", @@ -334651,12 +340499,6 @@ {} ] ], - "preload/fetch-destination.https.html": [ - [ - "/preload/fetch-destination.https.html", - {} - ] - ], "preload/link-header-on-subresource.html": [ [ "/preload/link-header-on-subresource.html", @@ -334831,59 +340673,59 @@ {} ] ], - "quirks-mode/blocks-ignore-line-height.html": [ + "quirks/blocks-ignore-line-height.html": [ [ - "/quirks-mode/blocks-ignore-line-height.html", + "/quirks/blocks-ignore-line-height.html", {} ] ], - "quirks-mode/classname-query-after-sibling-adoption.html": [ + "quirks/classname-query-after-sibling-adoption.html": [ [ - "/quirks-mode/classname-query-after-sibling-adoption.html", + "/quirks/classname-query-after-sibling-adoption.html", {} ] ], - "quirks-mode/hashless-hex-color.html": [ + "quirks/hashless-hex-color.html": [ [ - "/quirks-mode/hashless-hex-color.html", + "/quirks/hashless-hex-color.html", { "timeout": "long" } ] ], - "quirks-mode/line-height-calculation.html": [ + "quirks/line-height-calculation.html": [ [ - "/quirks-mode/line-height-calculation.html", + "/quirks/line-height-calculation.html", {} ] ], - "quirks-mode/percentage-height-calculation.html": [ + "quirks/percentage-height-calculation.html": [ [ - "/quirks-mode/percentage-height-calculation.html", + "/quirks/percentage-height-calculation.html", {} ] ], - "quirks-mode/supports.html": [ + "quirks/supports.html": [ [ - "/quirks-mode/supports.html", + "/quirks/supports.html", {} ] ], - "quirks-mode/table-cell-nowrap-minimum-width-calculation.html": [ + "quirks/table-cell-nowrap-minimum-width-calculation.html": [ [ - "/quirks-mode/table-cell-nowrap-minimum-width-calculation.html", + "/quirks/table-cell-nowrap-minimum-width-calculation.html", {} ] ], - "quirks-mode/table-cell-width-calculation.html": [ + "quirks/table-cell-width-calculation.html": [ [ - "/quirks-mode/table-cell-width-calculation.html", + "/quirks/table-cell-width-calculation.html", {} ] ], - "quirks-mode/unitless-length.html": [ + "quirks/unitless-length.html": [ [ - "/quirks-mode/unitless-length.html", + "/quirks/unitless-length.html", {} ] ], @@ -343071,6 +348913,12 @@ {} ] ], + "resource-timing/resource-timing-tojson.html": [ + [ + "/resource-timing/resource-timing-tojson.html", + {} + ] + ], "resource-timing/resource-timing.html": [ [ "/resource-timing/resource-timing.html", @@ -343813,6 +349661,14 @@ {} ] ], + "service-workers/service-worker/about-blank-replacement.https.html": [ + [ + "/service-workers/service-worker/about-blank-replacement.https.html", + { + "timeout": "long" + } + ] + ], "service-workers/service-worker/activate-event-after-install-state-change.https.html": [ [ "/service-workers/service-worker/activate-event-after-install-state-change.https.html", @@ -343999,6 +349855,12 @@ {} ] ], + "service-workers/service-worker/fetch-cors-exposed-header-names.https.html": [ + [ + "/service-workers/service-worker/fetch-cors-exposed-header-names.https.html", + {} + ] + ], "service-workers/service-worker/fetch-cors-xhr.https.html": [ [ "/service-workers/service-worker/fetch-cors-xhr.https.html", @@ -344049,6 +349911,12 @@ {} ] ], + "service-workers/service-worker/fetch-event-respond-with-custom-response.https.html": [ + [ + "/service-workers/service-worker/fetch-event-respond-with-custom-response.https.html", + {} + ] + ], "service-workers/service-worker/fetch-event-respond-with-partial-stream.https.html": [ [ "/service-workers/service-worker/fetch-event-respond-with-partial-stream.https.html", @@ -344205,30 +350073,6 @@ } ] ], - "service-workers/service-worker/foreign-fetch-basics.https.html": [ - [ - "/service-workers/service-worker/foreign-fetch-basics.https.html", - {} - ] - ], - "service-workers/service-worker/foreign-fetch-cors.https.html": [ - [ - "/service-workers/service-worker/foreign-fetch-cors.https.html", - {} - ] - ], - "service-workers/service-worker/foreign-fetch-event.https.html": [ - [ - "/service-workers/service-worker/foreign-fetch-event.https.html", - {} - ] - ], - "service-workers/service-worker/foreign-fetch-workers.https.html": [ - [ - "/service-workers/service-worker/foreign-fetch-workers.https.html", - {} - ] - ], "service-workers/service-worker/getregistration.https.html": [ [ "/service-workers/service-worker/getregistration.https.html", @@ -344247,12 +350091,6 @@ {} ] ], - "service-workers/service-worker/iframe-sandbox-register-link-element.https.html": [ - [ - "/service-workers/service-worker/iframe-sandbox-register-link-element.https.html", - {} - ] - ], "service-workers/service-worker/immutable-prototype-serviceworker.https.html": [ [ "/service-workers/service-worker/immutable-prototype-serviceworker.https.html", @@ -344325,42 +350163,6 @@ {} ] ], - "service-workers/service-worker/link-element-register-basic.https.html": [ - [ - "/service-workers/service-worker/link-element-register-basic.https.html", - {} - ] - ], - "service-workers/service-worker/link-element-register-mime-types.https.html": [ - [ - "/service-workers/service-worker/link-element-register-mime-types.https.html", - {} - ] - ], - "service-workers/service-worker/link-element-register-scope.https.html": [ - [ - "/service-workers/service-worker/link-element-register-scope.https.html", - {} - ] - ], - "service-workers/service-worker/link-element-register-script-url.https.html": [ - [ - "/service-workers/service-worker/link-element-register-script-url.https.html", - {} - ] - ], - "service-workers/service-worker/link-element-register-script.https.html": [ - [ - "/service-workers/service-worker/link-element-register-script.https.html", - {} - ] - ], - "service-workers/service-worker/link-element-register-security-error.https.html": [ - [ - "/service-workers/service-worker/link-element-register-security-error.https.html", - {} - ] - ], "service-workers/service-worker/mime-sniffing.https.html": [ [ "/service-workers/service-worker/mime-sniffing.https.html", @@ -344543,18 +350345,6 @@ {} ] ], - "service-workers/service-worker/register-foreign-fetch-errors.https.html": [ - [ - "/service-workers/service-worker/register-foreign-fetch-errors.https.html", - {} - ] - ], - "service-workers/service-worker/register-link-header.https.html": [ - [ - "/service-workers/service-worker/register-link-header.https.html", - {} - ] - ], "service-workers/service-worker/register-same-scope-different-script-url.https.html": [ [ "/service-workers/service-worker/register-same-scope-different-script-url.https.html", @@ -344657,6 +350447,12 @@ {} ] ], + "service-workers/service-worker/sandboxed-iframe-fetch-event.https.html": [ + [ + "/service-workers/service-worker/sandboxed-iframe-fetch-event.https.html", + {} + ] + ], "service-workers/service-worker/sandboxed-iframe-navigator-serviceworker.https.html": [ [ "/service-workers/service-worker/sandboxed-iframe-navigator-serviceworker.https.html", @@ -344903,6 +350699,12 @@ {} ] ], + "shadow-dom/event-composed-path-after-dom-mutation.html": [ + [ + "/shadow-dom/event-composed-path-after-dom-mutation.html", + {} + ] + ], "shadow-dom/event-composed-path-with-related-target.html": [ [ "/shadow-dom/event-composed-path-with-related-target.html", @@ -345377,6 +351179,12 @@ {} ] ], + "storage/estimate-parallel.https.html": [ + [ + "/storage/estimate-parallel.https.html", + {} + ] + ], "storage/interfaces.https.html": [ [ "/storage/interfaces.https.html", @@ -346253,6 +352061,30 @@ {} ] ], + "streams/transform-streams/properties.dedicatedworker.html": [ + [ + "/streams/transform-streams/properties.dedicatedworker.html", + {} + ] + ], + "streams/transform-streams/properties.html": [ + [ + "/streams/transform-streams/properties.html", + {} + ] + ], + "streams/transform-streams/properties.serviceworker.https.html": [ + [ + "/streams/transform-streams/properties.serviceworker.https.html", + {} + ] + ], + "streams/transform-streams/properties.sharedworker.html": [ + [ + "/streams/transform-streams/properties.sharedworker.html", + {} + ] + ], "streams/transform-streams/reentrant-strategies.dedicatedworker.html": [ [ "/streams/transform-streams/reentrant-strategies.dedicatedworker.html", @@ -346709,6 +352541,12 @@ {} ] ], + "svg/extensibility/foreignObject/properties.svg": [ + [ + "/svg/extensibility/foreignObject/properties.svg", + {} + ] + ], "svg/extensibility/interfaces/foreignObject-graphics.svg": [ [ "/svg/extensibility/interfaces/foreignObject-graphics.svg", @@ -346753,12 +352591,138 @@ {} ] ], + "svg/path/property/d-interpolation-discrete.svg": [ + [ + "/svg/path/property/d-interpolation-discrete.svg", + {} + ] + ], + "svg/path/property/d-interpolation-relative-absolute.svg": [ + [ + "/svg/path/property/d-interpolation-relative-absolute.svg", + {} + ] + ], + "svg/path/property/d-interpolation-single.svg": [ + [ + "/svg/path/property/d-interpolation-single.svg", + {} + ] + ], + "svg/path/property/getComputedStyle.svg": [ + [ + "/svg/path/property/getComputedStyle.svg", + {} + ] + ], "svg/struct/UnknownElement/interface.svg": [ [ "/svg/struct/UnknownElement/interface.svg", {} ] ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGClipPathElement.html": [ + [ + "/svg/types/scripted/SVGAnimatedEnumeration-SVGClipPathElement.html", + {} + ] + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGComponentTransferFunctionElement.html": [ + [ + "/svg/types/scripted/SVGAnimatedEnumeration-SVGComponentTransferFunctionElement.html", + {} + ] + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGFEBlendElement.html": [ + [ + "/svg/types/scripted/SVGAnimatedEnumeration-SVGFEBlendElement.html", + {} + ] + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGFEColorMatrixElement.html": [ + [ + "/svg/types/scripted/SVGAnimatedEnumeration-SVGFEColorMatrixElement.html", + {} + ] + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGFECompositeElement.html": [ + [ + "/svg/types/scripted/SVGAnimatedEnumeration-SVGFECompositeElement.html", + {} + ] + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGFEConvolveMatrixElement.html": [ + [ + "/svg/types/scripted/SVGAnimatedEnumeration-SVGFEConvolveMatrixElement.html", + {} + ] + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGFEDisplacementMapElement.html": [ + [ + "/svg/types/scripted/SVGAnimatedEnumeration-SVGFEDisplacementMapElement.html", + {} + ] + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGFEMorphologyElement.html": [ + [ + "/svg/types/scripted/SVGAnimatedEnumeration-SVGFEMorphologyElement.html", + {} + ] + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGFETurbulenceElement.html": [ + [ + "/svg/types/scripted/SVGAnimatedEnumeration-SVGFETurbulenceElement.html", + {} + ] + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGFilterElement.html": [ + [ + "/svg/types/scripted/SVGAnimatedEnumeration-SVGFilterElement.html", + {} + ] + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGGradientElement.html": [ + [ + "/svg/types/scripted/SVGAnimatedEnumeration-SVGGradientElement.html", + {} + ] + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGMarkerElement.html": [ + [ + "/svg/types/scripted/SVGAnimatedEnumeration-SVGMarkerElement.html", + {} + ] + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGMaskElement.html": [ + [ + "/svg/types/scripted/SVGAnimatedEnumeration-SVGMaskElement.html", + {} + ] + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGPatternElement.html": [ + [ + "/svg/types/scripted/SVGAnimatedEnumeration-SVGPatternElement.html", + {} + ] + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGTextContentElement.html": [ + [ + "/svg/types/scripted/SVGAnimatedEnumeration-SVGTextContentElement.html", + {} + ] + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGTextPathElement.html": [ + [ + "/svg/types/scripted/SVGAnimatedEnumeration-SVGTextPathElement.html", + {} + ] + ], + "svg/types/scripted/SVGAnimatedEnumeration.html": [ + [ + "/svg/types/scripted/SVGAnimatedEnumeration.html", + {} + ] + ], "svg/types/scripted/SVGLength-px-with-context.html": [ [ "/svg/types/scripted/SVGLength-px-with-context.html", @@ -347429,12 +353393,24 @@ {} ] ], + "wake-lock/wakelock-cancel-twice.https.html": [ + [ + "/wake-lock/wakelock-cancel-twice.https.html", + {} + ] + ], "wake-lock/wakelock-disabled-by-feature-policy.https.sub.html": [ [ "/wake-lock/wakelock-disabled-by-feature-policy.https.sub.html", {} ] ], + "wake-lock/wakelock-document-hidden.https.html": [ + [ + "/wake-lock/wakelock-document-hidden.https.html", + {} + ] + ], "wake-lock/wakelock-enabled-by-feature-policy-attribute-redirect-on-load.https.sub.html": [ [ "/wake-lock/wakelock-enabled-by-feature-policy-attribute-redirect-on-load.https.sub.html", @@ -347459,9 +353435,9 @@ {} ] ], - "wake-lock/wakelock-object-is-independent.https.html": [ + "wake-lock/wakelock-insecure-context.html": [ [ - "/wake-lock/wakelock-object-is-independent.https.html", + "/wake-lock/wakelock-insecure-context.html", {} ] ], @@ -347471,12 +353447,30 @@ {} ] ], + "wake-lock/wakelock-promise.https.html": [ + [ + "/wake-lock/wakelock-promise.https.html", + {} + ] + ], + "wake-lock/wakelock-state-is-global.https.html": [ + [ + "/wake-lock/wakelock-state-is-global.https.html", + {} + ] + ], "wake-lock/wakelock-type.https.html": [ [ "/wake-lock/wakelock-type.https.html", {} ] ], + "wake-lock/wakelockrequest-is-independent.https.html": [ + [ + "/wake-lock/wakelockrequest-is-independent.https.html", + {} + ] + ], "wasm/create_multiple_memory.worker.js": [ [ "/wasm/create_multiple_memory.worker.html", @@ -347525,9 +353519,9 @@ {} ] ], - "web-animations/animation-model/animation-types/discrete-animation.html": [ + "web-animations/animation-model/animation-types/discrete.html": [ [ - "/web-animations/animation-model/animation-types/discrete-animation.html", + "/web-animations/animation-model/animation-types/discrete.html", {} ] ], @@ -347537,6 +353531,12 @@ {} ] ], + "web-animations/animation-model/animation-types/visibility.html": [ + [ + "/web-animations/animation-model/animation-types/visibility.html", + {} + ] + ], "web-animations/animation-model/combining-effects/effect-composition.html": [ [ "/web-animations/animation-model/combining-effects/effect-composition.html", @@ -347549,6 +353549,12 @@ {} ] ], + "web-animations/animation-model/keyframe-effects/effect-value-iteration-composite-operation.html": [ + [ + "/web-animations/animation-model/keyframe-effects/effect-value-iteration-composite-operation.html", + {} + ] + ], "web-animations/animation-model/keyframe-effects/effect-value-overlapping-keyframes.html": [ [ "/web-animations/animation-model/keyframe-effects/effect-value-overlapping-keyframes.html", @@ -347561,12 +353567,6 @@ {} ] ], - "web-animations/animation-model/keyframe-effects/effect-value-visibility.html": [ - [ - "/web-animations/animation-model/keyframe-effects/effect-value-visibility.html", - {} - ] - ], "web-animations/interfaces/Animatable/animate-no-browsing-context.html": [ [ "/web-animations/interfaces/Animatable/animate-no-browsing-context.html", @@ -347645,15 +353645,15 @@ {} ] ], - "web-animations/interfaces/Animation/play.html": [ + "web-animations/interfaces/Animation/pending.html": [ [ - "/web-animations/interfaces/Animation/play.html", + "/web-animations/interfaces/Animation/pending.html", {} ] ], - "web-animations/interfaces/Animation/playState.html": [ + "web-animations/interfaces/Animation/play.html": [ [ - "/web-animations/interfaces/Animation/playState.html", + "/web-animations/interfaces/Animation/play.html", {} ] ], @@ -347711,15 +353711,9 @@ {} ] ], - "web-animations/interfaces/AnimationEffectTiming/getAnimations.html": [ + "web-animations/interfaces/AnimationEffectTiming/getComputedTiming.html": [ [ - "/web-animations/interfaces/AnimationEffectTiming/getAnimations.html", - {} - ] - ], - "web-animations/interfaces/AnimationEffectTiming/getComputedStyle.html": [ - [ - "/web-animations/interfaces/AnimationEffectTiming/getComputedStyle.html", + "/web-animations/interfaces/AnimationEffectTiming/getComputedTiming.html", {} ] ], @@ -347795,12 +353789,6 @@ {} ] ], - "web-animations/interfaces/KeyframeEffect/getComputedTiming.html": [ - [ - "/web-animations/interfaces/KeyframeEffect/getComputedTiming.html", - {} - ] - ], "web-animations/interfaces/KeyframeEffect/idlharness.html": [ [ "/web-animations/interfaces/KeyframeEffect/idlharness.html", @@ -347831,9 +353819,9 @@ {} ] ], - "web-animations/interfaces/KeyframeEffect/setTarget.html": [ + "web-animations/interfaces/KeyframeEffect/target.html": [ [ - "/web-animations/interfaces/KeyframeEffect/setTarget.html", + "/web-animations/interfaces/KeyframeEffect/target.html", {} ] ], @@ -347891,6 +353879,12 @@ {} ] ], + "web-animations/timing-model/animations/play-states.html": [ + [ + "/web-animations/timing-model/animations/play-states.html", + {} + ] + ], "web-animations/timing-model/animations/playing-an-animation.html": [ [ "/web-animations/timing-model/animations/playing-an-animation.html", @@ -348197,12 +354191,6 @@ {} ] ], - "webdriver/interface/interface.html": [ - [ - "/webdriver/interface/interface.html", - {} - ] - ], "webdriver/tests/interface.html": [ [ "/webdriver/tests/interface.html", @@ -348979,6 +354967,12 @@ {} ] ], + "webrtc/RTCPeerConnection-createOffer-offerToReceive.html": [ + [ + "/webrtc/RTCPeerConnection-createOffer-offerToReceive.html", + {} + ] + ], "webrtc/RTCPeerConnection-createOffer.html": [ [ "/webrtc/RTCPeerConnection-createOffer.html", @@ -349027,12 +355021,6 @@ {} ] ], - "webrtc/RTCPeerConnection-idl.html": [ - [ - "/webrtc/RTCPeerConnection-idl.html", - {} - ] - ], "webrtc/RTCPeerConnection-ondatachannel.html": [ [ "/webrtc/RTCPeerConnection-ondatachannel.html", @@ -349213,9 +355201,9 @@ {} ] ], - "webrtc/RTCRtpSender-getStats.html": [ + "webrtc/RTCRtpSender-getStats.https.html": [ [ - "/webrtc/RTCRtpSender-getStats.html", + "/webrtc/RTCRtpSender-getStats.https.html", {} ] ], @@ -349249,6 +355237,12 @@ {} ] ], + "webrtc/RTCSctpTransport-maxMessageSize.html": [ + [ + "/webrtc/RTCSctpTransport-maxMessageSize.html", + {} + ] + ], "webrtc/RTCTrackEvent-constructor.html": [ [ "/webrtc/RTCTrackEvent-constructor.html", @@ -349261,12 +355255,6 @@ {} ] ], - "webrtc/datachannel-idlharness.html": [ - [ - "/webrtc/datachannel-idlharness.html", - {} - ] - ], "webrtc/getstats.html": [ [ "/webrtc/getstats.html", @@ -350947,6 +356935,16 @@ {} ] ], + "websockets/referrer.any.js": [ + [ + "/websockets/referrer.any.html", + {} + ], + [ + "/websockets/referrer.any.worker.html", + {} + ] + ], "websockets/security/001.html": [ [ "/websockets/security/001.html", @@ -351435,6 +357433,12 @@ {} ] ], + "webvtt/api/VTTCue/constructor-exceptions.html": [ + [ + "/webvtt/api/VTTCue/constructor-exceptions.html", + {} + ] + ], "webvtt/api/VTTCue/constructor.html": [ [ "/webvtt/api/VTTCue/constructor.html", @@ -351651,6 +357655,12 @@ {} ] ], + "webvtt/parsing/file-parsing/tests/regions-edge-case.html": [ + [ + "/webvtt/parsing/file-parsing/tests/regions-edge-case.html", + {} + ] + ], "webvtt/parsing/file-parsing/tests/regions-id.html": [ [ "/webvtt/parsing/file-parsing/tests/regions-id.html", @@ -351825,12 +357835,24 @@ {} ] ], + "webxr/webxr_availability.http.sub.html": [ + [ + "/webxr/webxr_availability.http.sub.html", + {} + ] + ], "workers/SharedWorker_blobUrl.html": [ [ "/workers/SharedWorker_blobUrl.html", {} ] ], + "workers/SharedWorker_dataUrl.html": [ + [ + "/workers/SharedWorker_dataUrl.html", + {} + ] + ], "workers/WorkerGlobalScope_ErrorEvent_colno.htm": [ [ "/workers/WorkerGlobalScope_ErrorEvent_colno.htm", @@ -356939,720 +362961,66 @@ {} ] ], - "css/CSS2/generated-content/after-inheritable-001.xht": [ - [ - "/css/CSS2/generated-content/after-inheritable-001.xht", - {} - ] - ], - "css/CSS2/generated-content/after-inheritable-002.xht": [ - [ - "/css/CSS2/generated-content/after-inheritable-002.xht", - {} - ] - ], - "css/CSS2/generated-content/after-location-001.xht": [ - [ - "/css/CSS2/generated-content/after-location-001.xht", - {} - ] - ], - "css/CSS2/generated-content/before-after-002.xht": [ - [ - "/css/CSS2/generated-content/before-after-002.xht", - {} - ] - ], - "css/CSS2/generated-content/before-inheritable-001.xht": [ - [ - "/css/CSS2/generated-content/before-inheritable-001.xht", - {} - ] - ], - "css/CSS2/generated-content/before-inheritable-002.xht": [ - [ - "/css/CSS2/generated-content/before-inheritable-002.xht", - {} - ] - ], - "css/CSS2/generated-content/before-location-001.xht": [ - [ - "/css/CSS2/generated-content/before-location-001.xht", - {} - ] - ], - "css/CSS2/generated-content/bidi-generated-content-001.xht": [ - [ - "/css/CSS2/generated-content/bidi-generated-content-001.xht", - {} - ] - ], - "css/CSS2/generated-content/bidi-generated-content-002.xht": [ - [ - "/css/CSS2/generated-content/bidi-generated-content-002.xht", - {} - ] - ], - "css/CSS2/generated-content/content-002.xht": [ - [ - "/css/CSS2/generated-content/content-002.xht", - {} - ] - ], - "css/CSS2/generated-content/content-003.xht": [ - [ - "/css/CSS2/generated-content/content-003.xht", - {} - ] - ], - "css/CSS2/generated-content/content-004.xht": [ - [ - "/css/CSS2/generated-content/content-004.xht", - {} - ] - ], - "css/CSS2/generated-content/content-005.xht": [ - [ - "/css/CSS2/generated-content/content-005.xht", - {} - ] - ], - "css/CSS2/generated-content/content-006.xht": [ - [ - "/css/CSS2/generated-content/content-006.xht", - {} - ] - ], - "css/CSS2/generated-content/content-007.xht": [ - [ - "/css/CSS2/generated-content/content-007.xht", - {} - ] - ], "css/CSS2/generated-content/content-008.xht": [ [ "/css/CSS2/generated-content/content-008.xht", {} ] ], - "css/CSS2/generated-content/content-009.xht": [ - [ - "/css/CSS2/generated-content/content-009.xht", - {} - ] - ], - "css/CSS2/generated-content/content-010.xht": [ - [ - "/css/CSS2/generated-content/content-010.xht", - {} - ] - ], - "css/CSS2/generated-content/content-011.xht": [ - [ - "/css/CSS2/generated-content/content-011.xht", - {} - ] - ], - "css/CSS2/generated-content/content-012.xht": [ - [ - "/css/CSS2/generated-content/content-012.xht", - {} - ] - ], - "css/CSS2/generated-content/content-013.xht": [ - [ - "/css/CSS2/generated-content/content-013.xht", - {} - ] - ], - "css/CSS2/generated-content/content-014.xht": [ - [ - "/css/CSS2/generated-content/content-014.xht", - {} - ] - ], - "css/CSS2/generated-content/content-015.xht": [ - [ - "/css/CSS2/generated-content/content-015.xht", - {} - ] - ], - "css/CSS2/generated-content/content-016.xht": [ - [ - "/css/CSS2/generated-content/content-016.xht", - {} - ] - ], - "css/CSS2/generated-content/content-017.xht": [ - [ - "/css/CSS2/generated-content/content-017.xht", - {} - ] - ], - "css/CSS2/generated-content/content-018.xht": [ - [ - "/css/CSS2/generated-content/content-018.xht", - {} - ] - ], - "css/CSS2/generated-content/content-019.xht": [ - [ - "/css/CSS2/generated-content/content-019.xht", - {} - ] - ], - "css/CSS2/generated-content/content-020.xht": [ - [ - "/css/CSS2/generated-content/content-020.xht", - {} - ] - ], - "css/CSS2/generated-content/content-021.xht": [ - [ - "/css/CSS2/generated-content/content-021.xht", - {} - ] - ], - "css/CSS2/generated-content/content-022.xht": [ - [ - "/css/CSS2/generated-content/content-022.xht", - {} - ] - ], - "css/CSS2/generated-content/content-023.xht": [ - [ - "/css/CSS2/generated-content/content-023.xht", - {} - ] - ], "css/CSS2/generated-content/content-024.xht": [ [ "/css/CSS2/generated-content/content-024.xht", {} ] ], - "css/CSS2/generated-content/content-025.xht": [ - [ - "/css/CSS2/generated-content/content-025.xht", - {} - ] - ], - "css/CSS2/generated-content/content-026.xht": [ - [ - "/css/CSS2/generated-content/content-026.xht", - {} - ] - ], - "css/CSS2/generated-content/content-027.xht": [ - [ - "/css/CSS2/generated-content/content-027.xht", - {} - ] - ], - "css/CSS2/generated-content/content-028.xht": [ - [ - "/css/CSS2/generated-content/content-028.xht", - {} - ] - ], - "css/CSS2/generated-content/content-029.xht": [ - [ - "/css/CSS2/generated-content/content-029.xht", - {} - ] - ], - "css/CSS2/generated-content/content-030.xht": [ - [ - "/css/CSS2/generated-content/content-030.xht", - {} - ] - ], - "css/CSS2/generated-content/content-031.xht": [ - [ - "/css/CSS2/generated-content/content-031.xht", - {} - ] - ], - "css/CSS2/generated-content/content-032.xht": [ - [ - "/css/CSS2/generated-content/content-032.xht", - {} - ] - ], - "css/CSS2/generated-content/content-033.xht": [ - [ - "/css/CSS2/generated-content/content-033.xht", - {} - ] - ], - "css/CSS2/generated-content/content-034.xht": [ - [ - "/css/CSS2/generated-content/content-034.xht", - {} - ] - ], - "css/CSS2/generated-content/content-035.xht": [ - [ - "/css/CSS2/generated-content/content-035.xht", - {} - ] - ], - "css/CSS2/generated-content/content-037.xht": [ - [ - "/css/CSS2/generated-content/content-037.xht", - {} - ] - ], - "css/CSS2/generated-content/content-038.xht": [ - [ - "/css/CSS2/generated-content/content-038.xht", - {} - ] - ], - "css/CSS2/generated-content/content-039.xht": [ - [ - "/css/CSS2/generated-content/content-039.xht", - {} - ] - ], - "css/CSS2/generated-content/content-040.xht": [ - [ - "/css/CSS2/generated-content/content-040.xht", - {} - ] - ], - "css/CSS2/generated-content/content-041.xht": [ - [ - "/css/CSS2/generated-content/content-041.xht", - {} - ] - ], - "css/CSS2/generated-content/content-042.xht": [ - [ - "/css/CSS2/generated-content/content-042.xht", - {} - ] - ], - "css/CSS2/generated-content/content-043.xht": [ - [ - "/css/CSS2/generated-content/content-043.xht", - {} - ] - ], - "css/CSS2/generated-content/content-046.xht": [ - [ - "/css/CSS2/generated-content/content-046.xht", - {} - ] - ], - "css/CSS2/generated-content/content-047.xht": [ - [ - "/css/CSS2/generated-content/content-047.xht", - {} - ] - ], - "css/CSS2/generated-content/content-048.xht": [ - [ - "/css/CSS2/generated-content/content-048.xht", - {} - ] - ], "css/CSS2/generated-content/content-049.xht": [ [ "/css/CSS2/generated-content/content-049.xht", {} ] ], - "css/CSS2/generated-content/content-050.xht": [ - [ - "/css/CSS2/generated-content/content-050.xht", - {} - ] - ], "css/CSS2/generated-content/content-051.xht": [ [ "/css/CSS2/generated-content/content-051.xht", {} ] ], - "css/CSS2/generated-content/content-052.xht": [ - [ - "/css/CSS2/generated-content/content-052.xht", - {} - ] - ], - "css/CSS2/generated-content/content-053.xht": [ - [ - "/css/CSS2/generated-content/content-053.xht", - {} - ] - ], - "css/CSS2/generated-content/content-054.xht": [ - [ - "/css/CSS2/generated-content/content-054.xht", - {} - ] - ], - "css/CSS2/generated-content/content-056.xht": [ - [ - "/css/CSS2/generated-content/content-056.xht", - {} - ] - ], - "css/CSS2/generated-content/content-057.xht": [ - [ - "/css/CSS2/generated-content/content-057.xht", - {} - ] - ], - "css/CSS2/generated-content/content-063.xht": [ - [ - "/css/CSS2/generated-content/content-063.xht", - {} - ] - ], - "css/CSS2/generated-content/content-065.xht": [ - [ - "/css/CSS2/generated-content/content-065.xht", - {} - ] - ], "css/CSS2/generated-content/content-066.xht": [ [ "/css/CSS2/generated-content/content-066.xht", {} ] ], - "css/CSS2/generated-content/content-067.xht": [ - [ - "/css/CSS2/generated-content/content-067.xht", - {} - ] - ], - "css/CSS2/generated-content/content-068.xht": [ - [ - "/css/CSS2/generated-content/content-068.xht", - {} - ] - ], - "css/CSS2/generated-content/content-070.xht": [ - [ - "/css/CSS2/generated-content/content-070.xht", - {} - ] - ], - "css/CSS2/generated-content/content-072.xht": [ - [ - "/css/CSS2/generated-content/content-072.xht", - {} - ] - ], - "css/CSS2/generated-content/content-073.xht": [ - [ - "/css/CSS2/generated-content/content-073.xht", - {} - ] - ], - "css/CSS2/generated-content/content-075.xht": [ - [ - "/css/CSS2/generated-content/content-075.xht", - {} - ] - ], - "css/CSS2/generated-content/content-076.xht": [ - [ - "/css/CSS2/generated-content/content-076.xht", - {} - ] - ], - "css/CSS2/generated-content/content-077.xht": [ - [ - "/css/CSS2/generated-content/content-077.xht", - {} - ] - ], "css/CSS2/generated-content/content-078.xht": [ [ "/css/CSS2/generated-content/content-078.xht", {} ] ], - "css/CSS2/generated-content/content-080.xht": [ - [ - "/css/CSS2/generated-content/content-080.xht", - {} - ] - ], - "css/CSS2/generated-content/content-081.xht": [ - [ - "/css/CSS2/generated-content/content-081.xht", - {} - ] - ], - "css/CSS2/generated-content/content-082.xht": [ - [ - "/css/CSS2/generated-content/content-082.xht", - {} - ] - ], - "css/CSS2/generated-content/content-083.xht": [ - [ - "/css/CSS2/generated-content/content-083.xht", - {} - ] - ], - "css/CSS2/generated-content/content-085.xht": [ - [ - "/css/CSS2/generated-content/content-085.xht", - {} - ] - ], - "css/CSS2/generated-content/content-086.xht": [ - [ - "/css/CSS2/generated-content/content-086.xht", - {} - ] - ], - "css/CSS2/generated-content/content-089.xht": [ - [ - "/css/CSS2/generated-content/content-089.xht", - {} - ] - ], - "css/CSS2/generated-content/content-090.xht": [ - [ - "/css/CSS2/generated-content/content-090.xht", - {} - ] - ], - "css/CSS2/generated-content/content-091.xht": [ - [ - "/css/CSS2/generated-content/content-091.xht", - {} - ] - ], - "css/CSS2/generated-content/content-096.xht": [ - [ - "/css/CSS2/generated-content/content-096.xht", - {} - ] - ], - "css/CSS2/generated-content/content-097.xht": [ - [ - "/css/CSS2/generated-content/content-097.xht", - {} - ] - ], - "css/CSS2/generated-content/content-099.xht": [ - [ - "/css/CSS2/generated-content/content-099.xht", - {} - ] - ], - "css/CSS2/generated-content/content-100.xht": [ - [ - "/css/CSS2/generated-content/content-100.xht", - {} - ] - ], - "css/CSS2/generated-content/content-103.xht": [ - [ - "/css/CSS2/generated-content/content-103.xht", - {} - ] - ], - "css/CSS2/generated-content/content-105.xht": [ - [ - "/css/CSS2/generated-content/content-105.xht", - {} - ] - ], - "css/CSS2/generated-content/content-109.xht": [ - [ - "/css/CSS2/generated-content/content-109.xht", - {} - ] - ], - "css/CSS2/generated-content/content-113.xht": [ - [ - "/css/CSS2/generated-content/content-113.xht", - {} - ] - ], - "css/CSS2/generated-content/content-122.xht": [ - [ - "/css/CSS2/generated-content/content-122.xht", - {} - ] - ], - "css/CSS2/generated-content/content-123.xht": [ - [ - "/css/CSS2/generated-content/content-123.xht", - {} - ] - ], - "css/CSS2/generated-content/content-126.xht": [ - [ - "/css/CSS2/generated-content/content-126.xht", - {} - ] - ], - "css/CSS2/generated-content/content-127.xht": [ - [ - "/css/CSS2/generated-content/content-127.xht", - {} - ] - ], - "css/CSS2/generated-content/content-129.xht": [ - [ - "/css/CSS2/generated-content/content-129.xht", - {} - ] - ], "css/CSS2/generated-content/content-130.xht": [ [ "/css/CSS2/generated-content/content-130.xht", {} ] ], - "css/CSS2/generated-content/content-131.xht": [ - [ - "/css/CSS2/generated-content/content-131.xht", - {} - ] - ], - "css/CSS2/generated-content/content-132.xht": [ - [ - "/css/CSS2/generated-content/content-132.xht", - {} - ] - ], - "css/CSS2/generated-content/content-135.xht": [ - [ - "/css/CSS2/generated-content/content-135.xht", - {} - ] - ], - "css/CSS2/generated-content/content-136.xht": [ - [ - "/css/CSS2/generated-content/content-136.xht", - {} - ] - ], - "css/CSS2/generated-content/content-138.xht": [ - [ - "/css/CSS2/generated-content/content-138.xht", - {} - ] - ], "css/CSS2/generated-content/content-140.xht": [ [ "/css/CSS2/generated-content/content-140.xht", {} ] ], - "css/CSS2/generated-content/content-141.xht": [ - [ - "/css/CSS2/generated-content/content-141.xht", - {} - ] - ], "css/CSS2/generated-content/content-142.xht": [ [ "/css/CSS2/generated-content/content-142.xht", {} ] ], - "css/CSS2/generated-content/content-143.xht": [ - [ - "/css/CSS2/generated-content/content-143.xht", - {} - ] - ], - "css/CSS2/generated-content/content-144.xht": [ - [ - "/css/CSS2/generated-content/content-144.xht", - {} - ] - ], - "css/CSS2/generated-content/content-145.xht": [ - [ - "/css/CSS2/generated-content/content-145.xht", - {} - ] - ], - "css/CSS2/generated-content/content-146.xht": [ - [ - "/css/CSS2/generated-content/content-146.xht", - {} - ] - ], - "css/CSS2/generated-content/content-147.xht": [ - [ - "/css/CSS2/generated-content/content-147.xht", - {} - ] - ], - "css/CSS2/generated-content/content-149.xht": [ - [ - "/css/CSS2/generated-content/content-149.xht", - {} - ] - ], - "css/CSS2/generated-content/content-150.xht": [ - [ - "/css/CSS2/generated-content/content-150.xht", - {} - ] - ], "css/CSS2/generated-content/content-151.xht": [ [ "/css/CSS2/generated-content/content-151.xht", {} ] ], - "css/CSS2/generated-content/content-152.xht": [ - [ - "/css/CSS2/generated-content/content-152.xht", - {} - ] - ], - "css/CSS2/generated-content/content-153.xht": [ - [ - "/css/CSS2/generated-content/content-153.xht", - {} - ] - ], - "css/CSS2/generated-content/content-155.xht": [ - [ - "/css/CSS2/generated-content/content-155.xht", - {} - ] - ], - "css/CSS2/generated-content/content-156.xht": [ - [ - "/css/CSS2/generated-content/content-156.xht", - {} - ] - ], - "css/CSS2/generated-content/content-157.xht": [ - [ - "/css/CSS2/generated-content/content-157.xht", - {} - ] - ], - "css/CSS2/generated-content/content-158.xht": [ - [ - "/css/CSS2/generated-content/content-158.xht", - {} - ] - ], - "css/CSS2/generated-content/content-159.xht": [ - [ - "/css/CSS2/generated-content/content-159.xht", - {} - ] - ], "css/CSS2/generated-content/content-160.xht": [ [ "/css/CSS2/generated-content/content-160.xht", @@ -357665,36 +363033,12 @@ {} ] ], - "css/CSS2/generated-content/content-attr-001.xht": [ - [ - "/css/CSS2/generated-content/content-attr-001.xht", - {} - ] - ], "css/CSS2/generated-content/content-attr-002.xht": [ [ "/css/CSS2/generated-content/content-attr-002.xht", {} ] ], - "css/CSS2/generated-content/content-attr-case-001.html": [ - [ - "/css/CSS2/generated-content/content-attr-case-001.html", - {} - ] - ], - "css/CSS2/generated-content/content-attr-case-002.xht": [ - [ - "/css/CSS2/generated-content/content-attr-case-002.xht", - {} - ] - ], - "css/CSS2/generated-content/content-auto-reset-001.xht": [ - [ - "/css/CSS2/generated-content/content-auto-reset-001.xht", - {} - ] - ], "css/CSS2/generated-content/content-counters-000.xht": [ [ "/css/CSS2/generated-content/content-counters-000.xht", @@ -357815,42 +363159,12 @@ {} ] ], - "css/CSS2/generated-content/content-newline-001.xht": [ - [ - "/css/CSS2/generated-content/content-newline-001.xht", - {} - ] - ], "css/CSS2/generated-content/content-uri-001.xht": [ [ "/css/CSS2/generated-content/content-uri-001.xht", {} ] ], - "css/CSS2/generated-content/content-white-space-001.xht": [ - [ - "/css/CSS2/generated-content/content-white-space-001.xht", - {} - ] - ], - "css/CSS2/generated-content/content-white-space-002.xht": [ - [ - "/css/CSS2/generated-content/content-white-space-002.xht", - {} - ] - ], - "css/CSS2/generated-content/content-white-space-003.xht": [ - [ - "/css/CSS2/generated-content/content-white-space-003.xht", - {} - ] - ], - "css/CSS2/generated-content/content-white-space-004.xht": [ - [ - "/css/CSS2/generated-content/content-white-space-004.xht", - {} - ] - ], "css/CSS2/generated-content/counter-increment-000.xht": [ [ "/css/CSS2/generated-content/counter-increment-000.xht", @@ -357887,54 +363201,12 @@ {} ] ], - "css/CSS2/generated-content/counters-hidden-000.xht": [ - [ - "/css/CSS2/generated-content/counters-hidden-000.xht", - {} - ] - ], - "css/CSS2/generated-content/counters-hidden-001.xht": [ - [ - "/css/CSS2/generated-content/counters-hidden-001.xht", - {} - ] - ], - "css/CSS2/generated-content/counters-hidden-002.xht": [ - [ - "/css/CSS2/generated-content/counters-hidden-002.xht", - {} - ] - ], - "css/CSS2/generated-content/counters-multi-000.xht": [ - [ - "/css/CSS2/generated-content/counters-multi-000.xht", - {} - ] - ], - "css/CSS2/generated-content/counters-multi-001.xht": [ - [ - "/css/CSS2/generated-content/counters-multi-001.xht", - {} - ] - ], - "css/CSS2/generated-content/counters-order-000.xht": [ - [ - "/css/CSS2/generated-content/counters-order-000.xht", - {} - ] - ], "css/CSS2/generated-content/counters-order-001.xht": [ [ "/css/CSS2/generated-content/counters-order-001.xht", {} ] ], - "css/CSS2/generated-content/counters-root-000.xht": [ - [ - "/css/CSS2/generated-content/counters-root-000.xht", - {} - ] - ], "css/CSS2/generated-content/counters-scope-000.xht": [ [ "/css/CSS2/generated-content/counters-scope-000.xht", @@ -371465,702 +376737,600 @@ {} ] ], - "css/css-block/after-content-display-004.xht": [ - [ - "/css/css-block/after-content-display-004.xht", - {} - ] - ], - "css/css-block/anonymous-box-generation-002.xht": [ - [ - "/css/css-block/anonymous-box-generation-002.xht", - {} - ] - ], - "css/css-block/background-applies-to-011.xht": [ - [ - "/css/css-block/background-applies-to-011.xht", - {} - ] - ], - "css/css-block/background-attachment-applies-to-011.xht": [ - [ - "/css/css-block/background-attachment-applies-to-011.xht", - {} - ] - ], - "css/css-block/background-color-applies-to-011.xht": [ - [ - "/css/css-block/background-color-applies-to-011.xht", - {} - ] - ], - "css/css-block/background-image-applies-to-011.xht": [ - [ - "/css/css-block/background-image-applies-to-011.xht", - {} - ] - ], - "css/css-block/background-position-applies-to-011.xht": [ - [ - "/css/css-block/background-position-applies-to-011.xht", - {} - ] - ], - "css/css-block/background-repeat-applies-to-011.xht": [ - [ - "/css/css-block/background-repeat-applies-to-011.xht", - {} - ] - ], - "css/css-block/before-content-display-004.xht": [ - [ - "/css/css-block/before-content-display-004.xht", - {} - ] - ], - "css/css-block/border-applies-to-011.xht": [ - [ - "/css/css-block/border-applies-to-011.xht", - {} - ] - ], - "css/css-block/border-bottom-applies-to-011.xht": [ - [ - "/css/css-block/border-bottom-applies-to-011.xht", - {} - ] - ], - "css/css-block/border-bottom-color-applies-to-011.xht": [ - [ - "/css/css-block/border-bottom-color-applies-to-011.xht", - {} - ] - ], - "css/css-block/border-bottom-style-applies-to-011.xht": [ - [ - "/css/css-block/border-bottom-style-applies-to-011.xht", - {} - ] - ], - "css/css-block/border-bottom-width-applies-to-011.xht": [ - [ - "/css/css-block/border-bottom-width-applies-to-011.xht", - {} - ] - ], - "css/css-block/border-collapse-applies-to-004.xht": [ - [ - "/css/css-block/border-collapse-applies-to-004.xht", - {} - ] - ], - "css/css-block/border-color-applies-to-011.xht": [ - [ - "/css/css-block/border-color-applies-to-011.xht", - {} - ] - ], - "css/css-block/border-left-applies-to-011.xht": [ - [ - "/css/css-block/border-left-applies-to-011.xht", - {} - ] - ], - "css/css-block/border-left-color-applies-to-011.xht": [ - [ - "/css/css-block/border-left-color-applies-to-011.xht", - {} - ] - ], - "css/css-block/border-left-style-applies-to-011.xht": [ - [ - "/css/css-block/border-left-style-applies-to-011.xht", - {} - ] - ], - "css/css-block/border-left-width-applies-to-011.xht": [ - [ - "/css/css-block/border-left-width-applies-to-011.xht", - {} - ] - ], - "css/css-block/border-right-applies-to-011.xht": [ - [ - "/css/css-block/border-right-applies-to-011.xht", - {} - ] - ], - "css/css-block/border-right-color-applies-to-011.xht": [ - [ - "/css/css-block/border-right-color-applies-to-011.xht", - {} - ] - ], - "css/css-block/border-right-style-applies-to-011.xht": [ - [ - "/css/css-block/border-right-style-applies-to-011.xht", - {} - ] - ], - "css/css-block/border-right-width-applies-to-011.xht": [ - [ - "/css/css-block/border-right-width-applies-to-011.xht", - {} - ] - ], - "css/css-block/border-spacing-applies-to-004.xht": [ - [ - "/css/css-block/border-spacing-applies-to-004.xht", - {} - ] - ], - "css/css-block/border-style-applies-to-011.xht": [ - [ - "/css/css-block/border-style-applies-to-011.xht", - {} - ] - ], - "css/css-block/border-top-applies-to-011.xht": [ - [ - "/css/css-block/border-top-applies-to-011.xht", - {} - ] - ], - "css/css-block/border-top-color-applies-to-011.xht": [ - [ - "/css/css-block/border-top-color-applies-to-011.xht", - {} - ] - ], - "css/css-block/border-top-style-applies-to-011.xht": [ - [ - "/css/css-block/border-top-style-applies-to-011.xht", - {} - ] - ], - "css/css-block/border-top-width-applies-to-011.xht": [ - [ - "/css/css-block/border-top-width-applies-to-011.xht", - {} - ] - ], - "css/css-block/border-width-applies-to-011.xht": [ - [ - "/css/css-block/border-width-applies-to-011.xht", - {} - ] - ], - "css/css-block/bottom-applies-to-011.xht": [ - [ - "/css/css-block/bottom-applies-to-011.xht", - {} - ] - ], - "css/css-block/caption-side-applies-to-004.xht": [ - [ - "/css/css-block/caption-side-applies-to-004.xht", - {} - ] - ], - "css/css-block/clear-applies-to-011.xht": [ - [ - "/css/css-block/clear-applies-to-011.xht", - {} - ] - ], - "css/css-block/clear-runin-001.xht": [ - [ - "/css/css-block/clear-runin-001.xht", - {} - ] - ], - "css/css-block/color-applies-to-011.xht": [ - [ - "/css/css-block/color-applies-to-011.xht", - {} - ] - ], - "css/css-block/direction-applies-to-011.xht": [ - [ - "/css/css-block/direction-applies-to-011.xht", - {} - ] - ], - "css/css-block/display-004.xht": [ - [ - "/css/css-block/display-004.xht", - {} - ] - ], - "css/css-block/empty-cells-applies-to-004.xht": [ - [ - "/css/css-block/empty-cells-applies-to-004.xht", - {} - ] - ], - "css/css-block/first-line-pseudo-009.xht": [ - [ - "/css/css-block/first-line-pseudo-009.xht", - {} - ] - ], - "css/css-block/float-applies-to-011.xht": [ - [ - "/css/css-block/float-applies-to-011.xht", - {} - ] - ], - "css/css-block/font-applies-to-004.xht": [ - [ - "/css/css-block/font-applies-to-004.xht", - {} - ] - ], - "css/css-block/font-family-applies-to-004.xht": [ - [ - "/css/css-block/font-family-applies-to-004.xht", - {} - ] - ], - "css/css-block/font-size-applies-to-004.xht": [ - [ - "/css/css-block/font-size-applies-to-004.xht", - {} - ] - ], - "css/css-block/left-applies-to-011.xht": [ - [ - "/css/css-block/left-applies-to-011.xht", - {} - ] - ], - "css/css-block/line-height-applies-to-011.xht": [ - [ - "/css/css-block/line-height-applies-to-011.xht", - {} - ] - ], - "css/css-block/list-style-image-applies-to-011.xht": [ - [ - "/css/css-block/list-style-image-applies-to-011.xht", - {} - ] - ], - "css/css-block/list-style-position-applies-to-011.xht": [ - [ - "/css/css-block/list-style-position-applies-to-011.xht", - {} - ] - ], - "css/css-block/margin-applies-to-011.xht": [ - [ - "/css/css-block/margin-applies-to-011.xht", - {} - ] - ], - "css/css-block/margin-bottom-applies-to-011.xht": [ - [ - "/css/css-block/margin-bottom-applies-to-011.xht", - {} - ] - ], - "css/css-block/margin-left-applies-to-011.xht": [ - [ - "/css/css-block/margin-left-applies-to-011.xht", - {} - ] - ], - "css/css-block/margin-right-applies-to-011.xht": [ - [ - "/css/css-block/margin-right-applies-to-011.xht", - {} - ] - ], - "css/css-block/margin-top-applies-to-011.xht": [ - [ - "/css/css-block/margin-top-applies-to-011.xht", - {} - ] - ], - "css/css-block/outline-applies-to-011.xht": [ - [ - "/css/css-block/outline-applies-to-011.xht", - {} - ] - ], - "css/css-block/outline-color-applies-to-011.xht": [ - [ - "/css/css-block/outline-color-applies-to-011.xht", - {} - ] - ], - "css/css-block/outline-style-applies-to-011.xht": [ - [ - "/css/css-block/outline-style-applies-to-011.xht", - {} - ] - ], - "css/css-block/outline-width-applies-to-011.xht": [ - [ - "/css/css-block/outline-width-applies-to-011.xht", - {} - ] - ], - "css/css-block/overflow-applies-to-011.xht": [ - [ - "/css/css-block/overflow-applies-to-011.xht", - {} - ] - ], - "css/css-block/padding-applies-to-011.xht": [ - [ - "/css/css-block/padding-applies-to-011.xht", - {} - ] - ], - "css/css-block/padding-bottom-applies-to-011.xht": [ - [ - "/css/css-block/padding-bottom-applies-to-011.xht", - {} - ] - ], - "css/css-block/padding-left-applies-to-011.xht": [ - [ - "/css/css-block/padding-left-applies-to-011.xht", - {} - ] - ], - "css/css-block/padding-right-applies-to-011.xht": [ - [ - "/css/css-block/padding-right-applies-to-011.xht", - {} - ] - ], - "css/css-block/padding-top-applies-to-011.xht": [ - [ - "/css/css-block/padding-top-applies-to-011.xht", - {} - ] - ], - "css/css-block/position-applies-to-011.xht": [ - [ - "/css/css-block/position-applies-to-011.xht", - {} - ] - ], - "css/css-block/right-applies-to-011.xht": [ - [ - "/css/css-block/right-applies-to-011.xht", - {} - ] - ], - "css/css-block/run-in-001.xht": [ - [ - "/css/css-block/run-in-001.xht", - {} - ] - ], - "css/css-block/run-in-002.xht": [ - [ - "/css/css-block/run-in-002.xht", - {} - ] - ], - "css/css-block/run-in-003.xht": [ - [ - "/css/css-block/run-in-003.xht", - {} - ] - ], - "css/css-block/run-in-004.xht": [ - [ - "/css/css-block/run-in-004.xht", - {} - ] - ], - "css/css-block/run-in-005.xht": [ - [ - "/css/css-block/run-in-005.xht", - {} - ] - ], - "css/css-block/run-in-006.xht": [ - [ - "/css/css-block/run-in-006.xht", - {} - ] - ], - "css/css-block/run-in-007.xht": [ - [ - "/css/css-block/run-in-007.xht", - {} - ] - ], - "css/css-block/run-in-008.xht": [ - [ - "/css/css-block/run-in-008.xht", - {} - ] - ], - "css/css-block/run-in-009.xht": [ - [ - "/css/css-block/run-in-009.xht", - {} - ] - ], - "css/css-block/run-in-010.xht": [ - [ - "/css/css-block/run-in-010.xht", - {} - ] - ], - "css/css-block/run-in-011.xht": [ - [ - "/css/css-block/run-in-011.xht", - {} - ] - ], - "css/css-block/run-in-012.xht": [ - [ - "/css/css-block/run-in-012.xht", - {} - ] - ], - "css/css-block/run-in-013.xht": [ - [ - "/css/css-block/run-in-013.xht", - {} - ] - ], - "css/css-block/run-in-inheritance-001.xht": [ - [ - "/css/css-block/run-in-inheritance-001.xht", - {} - ] - ], - "css/css-block/run-in-linebox-001.xht": [ - [ - "/css/css-block/run-in-linebox-001.xht", - {} - ] - ], - "css/css-block/run-in-linebox-002.xht": [ - [ - "/css/css-block/run-in-linebox-002.xht", - {} - ] - ], - "css/css-block/table-anonymous-block-001.xht": [ - [ - "/css/css-block/table-anonymous-block-001.xht", - {} - ] - ], - "css/css-block/table-layout-applies-to-004.xht": [ - [ - "/css/css-block/table-layout-applies-to-004.xht", - {} - ] - ], - "css/css-block/text-align-applies-to-004.xht": [ - [ - "/css/css-block/text-align-applies-to-004.xht", - {} - ] - ], - "css/css-block/text-indent-applies-to-004.xht": [ - [ - "/css/css-block/text-indent-applies-to-004.xht", - {} - ] - ], - "css/css-block/top-applies-to-011.xht": [ - [ - "/css/css-block/top-applies-to-011.xht", - {} - ] - ], - "css/css-block/unicode-bidi-applies-to-011.xht": [ - [ - "/css/css-block/unicode-bidi-applies-to-011.xht", - {} - ] - ], - "css/css-block/vertical-align-applies-to-011.xht": [ - [ - "/css/css-block/vertical-align-applies-to-011.xht", - {} - ] - ], - "css/css-block/visibility-applies-to-011.xht": [ - [ - "/css/css-block/visibility-applies-to-011.xht", - {} - ] - ], - "css/css-block/white-space-applies-to-004.xht": [ - [ - "/css/css-block/white-space-applies-to-004.xht", - {} - ] - ], - "css/css-block/word-spacing-applies-to-004.xht": [ - [ - "/css/css-block/word-spacing-applies-to-004.xht", - {} - ] - ], - "css/css-block/z-index-applies-to-011.xht": [ - [ - "/css/css-block/z-index-applies-to-011.xht", - {} - ] - ], "css/css-break/break-before-always-001.xht": [ [ "/css/css-break/break-before-always-001.xht", {} ] ], - "css/css-color/hex-003.html": [ - [ - "/css/css-color/hex-003.html", - {} - ] - ], - "css/css-color/hex-004.html": [ - [ - "/css/css-color/hex-004.html", - {} - ] - ], - "css/css-color/t32-opacity-basic-0.0-a.xht": [ - [ - "/css/css-color/t32-opacity-basic-0.0-a.xht", - {} - ] - ], "css/css-color/t32-opacity-basic-0.6-a.xht": [ [ "/css/css-color/t32-opacity-basic-0.6-a.xht", {} ] ], - "css/css-color/t32-opacity-basic-1.0-a.xht": [ - [ - "/css/css-color/t32-opacity-basic-1.0-a.xht", - {} - ] - ], - "css/css-color/t32-opacity-clamping-0.0-b.xht": [ - [ - "/css/css-color/t32-opacity-clamping-0.0-b.xht", - {} - ] - ], - "css/css-color/t32-opacity-clamping-1.0-b.xht": [ - [ - "/css/css-color/t32-opacity-clamping-1.0-b.xht", - {} - ] - ], - "css/css-color/t32-opacity-offscreen-b.xht": [ - [ - "/css/css-color/t32-opacity-offscreen-b.xht", - {} - ] - ], - "css/css-color/t32-opacity-offscreen-with-alpha-c.xht": [ - [ - "/css/css-color/t32-opacity-offscreen-with-alpha-c.xht", - {} - ] - ], "css/css-color/t32-opacity-zorder-c.xht": [ [ "/css/css-color/t32-opacity-zorder-c.xht", {} ] ], - "css/css-color/t41-html4-keywords-a.xht": [ - [ - "/css/css-color/t41-html4-keywords-a.xht", - {} - ] - ], - "css/css-color/t421-rgb-clip-outside-gamut-b.xht": [ - [ - "/css/css-color/t421-rgb-clip-outside-gamut-b.xht", - {} - ] - ], "css/css-color/t421-rgb-hex3-expand-b.xht": [ [ "/css/css-color/t421-rgb-hex3-expand-b.xht", {} ] ], - "css/css-color/t421-rgb-values-meaning-b.xht": [ - [ - "/css/css-color/t421-rgb-values-meaning-b.xht", - {} - ] - ], - "css/css-color/t422-rgba-a0.0-a.xht": [ - [ - "/css/css-color/t422-rgba-a0.0-a.xht", - {} - ] - ], "css/css-color/t422-rgba-a0.6-a.xht": [ [ "/css/css-color/t422-rgba-a0.6-a.xht", {} ] ], - "css/css-color/t422-rgba-values-meaning-b.xht": [ - [ - "/css/css-color/t422-rgba-values-meaning-b.xht", - {} - ] - ], - "css/css-color/t424-hsl-h-rotating-b.xht": [ - [ - "/css/css-color/t424-hsl-h-rotating-b.xht", - {} - ] - ], "css/css-color/t425-hsla-basic-a.xht": [ [ "/css/css-color/t425-hsla-basic-a.xht", {} ] ], - "css/css-color/t425-hsla-h-rotating-b.xht": [ - [ - "/css/css-color/t425-hsla-h-rotating-b.xht", - {} - ] - ], - "css/css-color/t425-hsla-onscreen-b.xht": [ - [ - "/css/css-color/t425-hsla-onscreen-b.xht", - {} - ] - ], - "css/css-color/t43-svg-keywords-a.xht": [ - [ - "/css/css-color/t43-svg-keywords-a.xht", - {} - ] - ], "css/css-color/t451-system-colors-a.xht": [ [ "/css/css-color/t451-system-colors-a.xht", {} ] ], + "css/css-display/run-in/after-content-display-004.xht": [ + [ + "/css/css-display/run-in/after-content-display-004.xht", + {} + ] + ], + "css/css-display/run-in/anonymous-box-generation-002.xht": [ + [ + "/css/css-display/run-in/anonymous-box-generation-002.xht", + {} + ] + ], + "css/css-display/run-in/background-applies-to-011.xht": [ + [ + "/css/css-display/run-in/background-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/background-attachment-applies-to-011.xht": [ + [ + "/css/css-display/run-in/background-attachment-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/background-color-applies-to-011.xht": [ + [ + "/css/css-display/run-in/background-color-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/background-image-applies-to-011.xht": [ + [ + "/css/css-display/run-in/background-image-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/background-position-applies-to-011.xht": [ + [ + "/css/css-display/run-in/background-position-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/background-repeat-applies-to-011.xht": [ + [ + "/css/css-display/run-in/background-repeat-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/before-content-display-004.xht": [ + [ + "/css/css-display/run-in/before-content-display-004.xht", + {} + ] + ], + "css/css-display/run-in/border-applies-to-011.xht": [ + [ + "/css/css-display/run-in/border-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/border-bottom-applies-to-011.xht": [ + [ + "/css/css-display/run-in/border-bottom-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/border-bottom-color-applies-to-011.xht": [ + [ + "/css/css-display/run-in/border-bottom-color-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/border-bottom-style-applies-to-011.xht": [ + [ + "/css/css-display/run-in/border-bottom-style-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/border-bottom-width-applies-to-011.xht": [ + [ + "/css/css-display/run-in/border-bottom-width-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/border-collapse-applies-to-004.xht": [ + [ + "/css/css-display/run-in/border-collapse-applies-to-004.xht", + {} + ] + ], + "css/css-display/run-in/border-color-applies-to-011.xht": [ + [ + "/css/css-display/run-in/border-color-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/border-left-applies-to-011.xht": [ + [ + "/css/css-display/run-in/border-left-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/border-left-color-applies-to-011.xht": [ + [ + "/css/css-display/run-in/border-left-color-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/border-left-style-applies-to-011.xht": [ + [ + "/css/css-display/run-in/border-left-style-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/border-left-width-applies-to-011.xht": [ + [ + "/css/css-display/run-in/border-left-width-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/border-right-applies-to-011.xht": [ + [ + "/css/css-display/run-in/border-right-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/border-right-color-applies-to-011.xht": [ + [ + "/css/css-display/run-in/border-right-color-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/border-right-style-applies-to-011.xht": [ + [ + "/css/css-display/run-in/border-right-style-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/border-right-width-applies-to-011.xht": [ + [ + "/css/css-display/run-in/border-right-width-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/border-spacing-applies-to-004.xht": [ + [ + "/css/css-display/run-in/border-spacing-applies-to-004.xht", + {} + ] + ], + "css/css-display/run-in/border-style-applies-to-011.xht": [ + [ + "/css/css-display/run-in/border-style-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/border-top-applies-to-011.xht": [ + [ + "/css/css-display/run-in/border-top-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/border-top-color-applies-to-011.xht": [ + [ + "/css/css-display/run-in/border-top-color-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/border-top-style-applies-to-011.xht": [ + [ + "/css/css-display/run-in/border-top-style-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/border-top-width-applies-to-011.xht": [ + [ + "/css/css-display/run-in/border-top-width-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/border-width-applies-to-011.xht": [ + [ + "/css/css-display/run-in/border-width-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/bottom-applies-to-011.xht": [ + [ + "/css/css-display/run-in/bottom-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/caption-side-applies-to-004.xht": [ + [ + "/css/css-display/run-in/caption-side-applies-to-004.xht", + {} + ] + ], + "css/css-display/run-in/clear-applies-to-011.xht": [ + [ + "/css/css-display/run-in/clear-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/clear-runin-001.xht": [ + [ + "/css/css-display/run-in/clear-runin-001.xht", + {} + ] + ], + "css/css-display/run-in/color-applies-to-011.xht": [ + [ + "/css/css-display/run-in/color-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/direction-applies-to-011.xht": [ + [ + "/css/css-display/run-in/direction-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/display-004.xht": [ + [ + "/css/css-display/run-in/display-004.xht", + {} + ] + ], + "css/css-display/run-in/empty-cells-applies-to-004.xht": [ + [ + "/css/css-display/run-in/empty-cells-applies-to-004.xht", + {} + ] + ], + "css/css-display/run-in/first-line-pseudo-009.xht": [ + [ + "/css/css-display/run-in/first-line-pseudo-009.xht", + {} + ] + ], + "css/css-display/run-in/float-applies-to-011.xht": [ + [ + "/css/css-display/run-in/float-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/font-applies-to-004.xht": [ + [ + "/css/css-display/run-in/font-applies-to-004.xht", + {} + ] + ], + "css/css-display/run-in/font-family-applies-to-004.xht": [ + [ + "/css/css-display/run-in/font-family-applies-to-004.xht", + {} + ] + ], + "css/css-display/run-in/font-size-applies-to-004.xht": [ + [ + "/css/css-display/run-in/font-size-applies-to-004.xht", + {} + ] + ], + "css/css-display/run-in/left-applies-to-011.xht": [ + [ + "/css/css-display/run-in/left-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/line-height-applies-to-011.xht": [ + [ + "/css/css-display/run-in/line-height-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/list-style-image-applies-to-011.xht": [ + [ + "/css/css-display/run-in/list-style-image-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/list-style-position-applies-to-011.xht": [ + [ + "/css/css-display/run-in/list-style-position-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/margin-applies-to-011.xht": [ + [ + "/css/css-display/run-in/margin-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/margin-bottom-applies-to-011.xht": [ + [ + "/css/css-display/run-in/margin-bottom-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/margin-left-applies-to-011.xht": [ + [ + "/css/css-display/run-in/margin-left-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/margin-right-applies-to-011.xht": [ + [ + "/css/css-display/run-in/margin-right-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/margin-top-applies-to-011.xht": [ + [ + "/css/css-display/run-in/margin-top-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/outline-applies-to-011.xht": [ + [ + "/css/css-display/run-in/outline-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/outline-color-applies-to-011.xht": [ + [ + "/css/css-display/run-in/outline-color-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/outline-style-applies-to-011.xht": [ + [ + "/css/css-display/run-in/outline-style-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/outline-width-applies-to-011.xht": [ + [ + "/css/css-display/run-in/outline-width-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/overflow-applies-to-011.xht": [ + [ + "/css/css-display/run-in/overflow-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/padding-applies-to-011.xht": [ + [ + "/css/css-display/run-in/padding-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/padding-bottom-applies-to-011.xht": [ + [ + "/css/css-display/run-in/padding-bottom-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/padding-left-applies-to-011.xht": [ + [ + "/css/css-display/run-in/padding-left-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/padding-right-applies-to-011.xht": [ + [ + "/css/css-display/run-in/padding-right-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/padding-top-applies-to-011.xht": [ + [ + "/css/css-display/run-in/padding-top-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/position-applies-to-011.xht": [ + [ + "/css/css-display/run-in/position-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/right-applies-to-011.xht": [ + [ + "/css/css-display/run-in/right-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/run-in-001.xht": [ + [ + "/css/css-display/run-in/run-in-001.xht", + {} + ] + ], + "css/css-display/run-in/run-in-002.xht": [ + [ + "/css/css-display/run-in/run-in-002.xht", + {} + ] + ], + "css/css-display/run-in/run-in-003.xht": [ + [ + "/css/css-display/run-in/run-in-003.xht", + {} + ] + ], + "css/css-display/run-in/run-in-004.xht": [ + [ + "/css/css-display/run-in/run-in-004.xht", + {} + ] + ], + "css/css-display/run-in/run-in-005.xht": [ + [ + "/css/css-display/run-in/run-in-005.xht", + {} + ] + ], + "css/css-display/run-in/run-in-006.xht": [ + [ + "/css/css-display/run-in/run-in-006.xht", + {} + ] + ], + "css/css-display/run-in/run-in-007.xht": [ + [ + "/css/css-display/run-in/run-in-007.xht", + {} + ] + ], + "css/css-display/run-in/run-in-008.xht": [ + [ + "/css/css-display/run-in/run-in-008.xht", + {} + ] + ], + "css/css-display/run-in/run-in-009.xht": [ + [ + "/css/css-display/run-in/run-in-009.xht", + {} + ] + ], + "css/css-display/run-in/run-in-010.xht": [ + [ + "/css/css-display/run-in/run-in-010.xht", + {} + ] + ], + "css/css-display/run-in/run-in-011.xht": [ + [ + "/css/css-display/run-in/run-in-011.xht", + {} + ] + ], + "css/css-display/run-in/run-in-012.xht": [ + [ + "/css/css-display/run-in/run-in-012.xht", + {} + ] + ], + "css/css-display/run-in/run-in-013.xht": [ + [ + "/css/css-display/run-in/run-in-013.xht", + {} + ] + ], + "css/css-display/run-in/run-in-inheritance-001.xht": [ + [ + "/css/css-display/run-in/run-in-inheritance-001.xht", + {} + ] + ], + "css/css-display/run-in/run-in-linebox-001.xht": [ + [ + "/css/css-display/run-in/run-in-linebox-001.xht", + {} + ] + ], + "css/css-display/run-in/run-in-linebox-002.xht": [ + [ + "/css/css-display/run-in/run-in-linebox-002.xht", + {} + ] + ], + "css/css-display/run-in/table-anonymous-block-001.xht": [ + [ + "/css/css-display/run-in/table-anonymous-block-001.xht", + {} + ] + ], + "css/css-display/run-in/table-layout-applies-to-004.xht": [ + [ + "/css/css-display/run-in/table-layout-applies-to-004.xht", + {} + ] + ], + "css/css-display/run-in/text-align-applies-to-004.xht": [ + [ + "/css/css-display/run-in/text-align-applies-to-004.xht", + {} + ] + ], + "css/css-display/run-in/text-indent-applies-to-004.xht": [ + [ + "/css/css-display/run-in/text-indent-applies-to-004.xht", + {} + ] + ], + "css/css-display/run-in/top-applies-to-011.xht": [ + [ + "/css/css-display/run-in/top-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/unicode-bidi-applies-to-011.xht": [ + [ + "/css/css-display/run-in/unicode-bidi-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/vertical-align-applies-to-011.xht": [ + [ + "/css/css-display/run-in/vertical-align-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/visibility-applies-to-011.xht": [ + [ + "/css/css-display/run-in/visibility-applies-to-011.xht", + {} + ] + ], + "css/css-display/run-in/white-space-applies-to-004.xht": [ + [ + "/css/css-display/run-in/white-space-applies-to-004.xht", + {} + ] + ], + "css/css-display/run-in/word-spacing-applies-to-004.xht": [ + [ + "/css/css-display/run-in/word-spacing-applies-to-004.xht", + {} + ] + ], + "css/css-display/run-in/z-index-applies-to-011.xht": [ + [ + "/css/css-display/run-in/z-index-applies-to-011.xht", + {} + ] + ], "css/css-flexbox/align-content_center.html": [ [ "/css/css-flexbox/align-content_center.html", @@ -372791,12 +377961,6 @@ {} ] ], - "css/css-transforms/css-transform-inherit-scale.html": [ - [ - "/css/css-transforms/css-transform-inherit-scale.html", - {} - ] - ], "css/css-transforms/rotate-180-degrees-001.html": [ [ "/css/css-transforms/rotate-180-degrees-001.html", @@ -372821,36 +377985,12 @@ {} ] ], - "css/css-values/iframe/vh-support-transform-origin-iframe.html": [ - [ - "/css/css-values/iframe/vh-support-transform-origin-iframe.html", - {} - ] - ], - "css/css-values/iframe/vh-support-transform-translate-iframe.html": [ - [ - "/css/css-values/iframe/vh-support-transform-translate-iframe.html", - {} - ] - ], - "css/css-writing-modes/bidi-table-001.html": [ - [ - "/css/css-writing-modes/bidi-table-001.html", - {} - ] - ], "css/css-writing-modes/block-plaintext-005.html": [ [ "/css/css-writing-modes/block-plaintext-005.html", {} ] ], - "css/css-writing-modes/block-plaintext-006.html": [ - [ - "/css/css-writing-modes/block-plaintext-006.html", - {} - ] - ], "css/css-writing-modes/form-controls-slr-004.xht": [ [ "/css/css-writing-modes/form-controls-slr-004.xht", @@ -373291,6 +378431,12 @@ {} ] ], + "webdriver/tests/actions/key_shortcuts.py": [ + [ + "/webdriver/tests/actions/key_shortcuts.py", + {} + ] + ], "webdriver/tests/actions/modifier_click.py": [ [ "/webdriver/tests/actions/modifier_click.py", @@ -373305,6 +378451,12 @@ {} ] ], + "webdriver/tests/actions/mouse_dblclick.py": [ + [ + "/webdriver/tests/actions/mouse_dblclick.py", + {} + ] + ], "webdriver/tests/actions/sequence.py": [ [ "/webdriver/tests/actions/sequence.py", @@ -373361,18 +378513,90 @@ {} ] ], + "webdriver/tests/document_handling/page_source.py": [ + [ + "/webdriver/tests/document_handling/page_source.py", + {} + ] + ], + "webdriver/tests/element_click/bubbling.py": [ + [ + "/webdriver/tests/element_click/bubbling.py", + {} + ] + ], "webdriver/tests/element_click/select.py": [ [ "/webdriver/tests/element_click/select.py", {} ] ], + "webdriver/tests/element_click/stale.py": [ + [ + "/webdriver/tests/element_click/stale.py", + {} + ] + ], + "webdriver/tests/element_retrieval/find_element.py": [ + [ + "/webdriver/tests/element_retrieval/find_element.py", + {} + ] + ], + "webdriver/tests/element_retrieval/find_element_from_element.py": [ + [ + "/webdriver/tests/element_retrieval/find_element_from_element.py", + {} + ] + ], + "webdriver/tests/element_retrieval/find_elements.py": [ + [ + "/webdriver/tests/element_retrieval/find_elements.py", + {} + ] + ], + "webdriver/tests/element_retrieval/find_elements_from_element.py": [ + [ + "/webdriver/tests/element_retrieval/find_elements_from_element.py", + {} + ] + ], "webdriver/tests/element_retrieval/get_active_element.py": [ [ "/webdriver/tests/element_retrieval/get_active_element.py", {} ] ], + "webdriver/tests/element_send_keys/interactability.py": [ + [ + "/webdriver/tests/element_send_keys/interactability.py", + {} + ] + ], + "webdriver/tests/element_send_keys/scroll_into_view.py": [ + [ + "/webdriver/tests/element_send_keys/scroll_into_view.py", + {} + ] + ], + "webdriver/tests/execute_async_script/user_prompts.py": [ + [ + "/webdriver/tests/execute_async_script/user_prompts.py", + {} + ] + ], + "webdriver/tests/execute_script/cyclic.py": [ + [ + "/webdriver/tests/execute_script/cyclic.py", + {} + ] + ], + "webdriver/tests/execute_script/user_prompts.py": [ + [ + "/webdriver/tests/execute_script/user_prompts.py", + {} + ] + ], "webdriver/tests/fullscreen_window.py": [ [ "/webdriver/tests/fullscreen_window.py", @@ -373417,30 +378641,6 @@ {} ] ], - "webdriver/tests/retrieval/find_element.py": [ - [ - "/webdriver/tests/retrieval/find_element.py", - {} - ] - ], - "webdriver/tests/retrieval/find_element_from_element.py": [ - [ - "/webdriver/tests/retrieval/find_element_from_element.py", - {} - ] - ], - "webdriver/tests/retrieval/find_element_from_elements.py": [ - [ - "/webdriver/tests/retrieval/find_element_from_elements.py", - {} - ] - ], - "webdriver/tests/retrieval/find_elements.py": [ - [ - "/webdriver/tests/retrieval/find_elements.py", - {} - ] - ], "webdriver/tests/sessions/get_timeouts.py": [ [ "/webdriver/tests/sessions/get_timeouts.py", @@ -373495,6 +378695,12 @@ } ] ], + "webdriver/tests/sessions/status.py": [ + [ + "/webdriver/tests/sessions/status.py", + {} + ] + ], "webdriver/tests/set_window_rect.py": [ [ "/webdriver/tests/set_window_rect.py", @@ -373533,12 +378739,6 @@ {} ] ], - "webdriver/tests/status.py": [ - [ - "/webdriver/tests/status.py", - {} - ] - ], "webdriver/tests/switch_to_parent_frame.py": [ [ "/webdriver/tests/switch_to_parent_frame.py", @@ -373585,7 +378785,7 @@ "support" ], "./.travis.yml": [ - "ee7a0f7a54701f7cc9a5cb192a9400b864805371", + "5713c525560fa7419944eb6fae32bb62f0c9e3fe", "support" ], "./CONTRIBUTING.md": [ @@ -373601,7 +378801,7 @@ "support" ], "./README.md": [ - "2a2ab5b7d22a1e65e52bdb2cc2b787b8fa03472b", + "c58b661f8a9377baf6d71b9e2b704441b127ef5d", "support" ], "./check_stability.ini": [ @@ -373613,7 +378813,7 @@ "support" ], "./lint.whitelist": [ - "b5d3ae0d3de0f8332904829ef0070f547dd3bc83", + "466e640065159fe12574aec8682dc74cf67fe49a", "support" ], "./serve.py": [ @@ -373625,7 +378825,7 @@ "support" ], "./update-built-tests.sh": [ - "d0184e7d0761064d0acaae095a50c0b1dfd9c3b6", + "e632acfa68de35b71b650db172ffff6d048399a7", "support" ], "./wpt": [ @@ -375785,7 +380985,7 @@ "support" ], "2dcontext/fill-and-stroke-styles/2d.gradient.object.invalidcolour.html": [ - "9208f03b80abcf89354a56f913acf5aeb1b0edfe", + "80cf63aa87d02a9618094c822b18c83b235222ae", "testharness" ], "2dcontext/fill-and-stroke-styles/2d.gradient.object.invalidoffset.html": [ @@ -376113,7 +381313,7 @@ "testharness" ], "2dcontext/imagebitmap/createImageBitmap-invalid-args.html": [ - "e839d537057d03f55108b871d2d32272cac7bc7f", + "badef04a0354c9e41f99370b86e5f757b1926ea7", "testharness" ], "2dcontext/imagebitmap/createImageBitmap-sizeOverflow.html": [ @@ -377605,7 +382805,7 @@ "support" ], "2dcontext/tools/tests2d.yaml": [ - "99a4d558b9ad07ae18fa71a6276d0b08db0f49e1", + "057e6bc1199bb897e84a0d2ed7efefb616ba978c", "support" ], "2dcontext/tools/tests2dtext.yaml": [ @@ -377772,12 +382972,20 @@ "f1d0cf569f445712d986e9a85f3cbc717137d7fe", "support" ], + "FileAPI/blob/Blob-Request-revoke-fetch.html": [ + "54df50603ac5ff79f60d50a85c26339483da297b", + "testharness" + ], "FileAPI/blob/Blob-XHR-revoke.html": [ "5858a79442dcad6325b3ab4bb6a20fc302fcf64c", "testharness" ], + "FileAPI/blob/Blob-constructor-endings.html": [ + "5ba751f75b52359a021da7b3f6c2f2a304f36d7f", + "testharness" + ], "FileAPI/blob/Blob-constructor.html": [ - "fc5f5ef1deff60ceb2e2db86b511cdc03f19072f", + "96eb93bd23ec6b1f1faf5b7ba617fdf5f0eb75f7", "testharness" ], "FileAPI/blob/Blob-in-worker.worker.js": [ @@ -377792,14 +383000,38 @@ "7fc333cf82539fab242e421b8d486c6d406dfaa0", "testharness" ], + "FileAPI/file/File-constructor-endings.html": [ + "70e8d8b794e92f9b5c1c05d11af391468a82498a", + "testharness" + ], "FileAPI/file/File-constructor.html": [ - "052ea42d7c68ca7d1d2f84de88e747c37e5deb10", + "95198c8156dadc851d279a863b883c8befdc3930", "testharness" ], "FileAPI/file/Worker-read-file-constructor.worker.js": [ "187acfc89c6123286cd759aac390c7de3b25c5a1", "testharness" ], + "FileAPI/file/send-file-form-iso-2022-jp.tentative.html": [ + "89f7e08e63145e07f06a5c45f6ba5e4835a75ece", + "testharness" + ], + "FileAPI/file/send-file-form-utf-8.html": [ + "f2cfbcc800aacd8a98ee496db7d123a35d2a1b2c", + "testharness" + ], + "FileAPI/file/send-file-form-windows-1252.tentative.html": [ + "43b967a2543c07ed8349db572eb10fc589b202fc", + "testharness" + ], + "FileAPI/file/send-file-form-x-user-defined.tentative.html": [ + "f07b9491bf42650379f187c36c8c306f88928120", + "testharness" + ], + "FileAPI/file/send-file-form.html": [ + "3bc42189304cd2ae051cfb015d8209176c699f0b", + "testharness" + ], "FileAPI/fileReader.html": [ "fdfa73b1182058d10c1eb1b447885ecdce77fa6a", "testharness" @@ -377833,7 +383065,7 @@ "manual" ], "FileAPI/idlharness.html": [ - "0eb0d3b2f6c394a6b30f71102bd002ae6e339283", + "66720cf090912985b9ea4e9cfe01126778f61e36", "testharness" ], "FileAPI/idlharness.idl": [ @@ -377916,6 +383148,10 @@ "36ccc5cb2de09589d02430b1c0582280d3240f32", "support" ], + "FileAPI/support/send-file-form-helper.js": [ + "f9bf42d1296f4fc6410b3bf77f3e29530bc58ad8", + "support" + ], "FileAPI/support/upload.txt": [ "f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0", "support" @@ -377924,6 +383160,10 @@ "18972f4ed024eb5e1494ac466426ae32b3f5525f", "support" ], + "FileAPI/unicode.html": [ + "99a52f519e0d12bb9ece822f1480e0b08dca77e3", + "testharness" + ], "FileAPI/url/blob-url-in-sandboxed-iframe.html": [ "59188b2e679f56d5eb7ea01428ce06ff0068111a", "testharness" @@ -377957,7 +383197,7 @@ "support" ], "FileAPI/url/url_xmlhttprequest_img.html": [ - "ce325c9fcefab1864c9943d7d1dcc77c1d22390f", + "33c65ffbbe2ab33fa1d5ce946d0be536dd7d0a69", "reftest" ], "IndexedDB/OWNERS": [ @@ -379169,7 +384409,7 @@ "testharness" ], "IndexedDB/interfaces.html": [ - "d2ff3cf10fbaf798d3bf5868699979829703d859", + "ad40586fec970a4907546e3a33aef14f23e378ff", "testharness" ], "IndexedDB/interfaces.idl": [ @@ -379556,47 +384796,43 @@ "61db89f7b21982628428d274dd238ad0f56a3c6d", "support" ], - "WebCryptoAPI/generateKey/failures.worker.js": [ - "248df758c6a92939799690abfd991fe888f90257", - "testharness" - ], - "WebCryptoAPI/generateKey/failures_AES-CBC.worker.js": [ + "WebCryptoAPI/generateKey/failures_AES-CBC.https.worker.js": [ "d462df4da1958c1a7a923f4f6f8d74fc7e20f2bb", "testharness" ], - "WebCryptoAPI/generateKey/failures_AES-CTR.worker.js": [ + "WebCryptoAPI/generateKey/failures_AES-CTR.https.worker.js": [ "b745bb807622e053d8e5b2ad8f77ebdd1a5caa05", "testharness" ], - "WebCryptoAPI/generateKey/failures_AES-GCM.worker.js": [ + "WebCryptoAPI/generateKey/failures_AES-GCM.https.worker.js": [ "c65c0c81ea710e071df9bbb36796c65c09023b2f", "testharness" ], - "WebCryptoAPI/generateKey/failures_AES-KW.worker.js": [ + "WebCryptoAPI/generateKey/failures_AES-KW.https.worker.js": [ "aba136c70512155f57879d90e8387f468cd08eb0", "testharness" ], - "WebCryptoAPI/generateKey/failures_ECDH.worker.js": [ + "WebCryptoAPI/generateKey/failures_ECDH.https.worker.js": [ "24ad2f00216f7dfbf0488e7fe0096877b7126093", "testharness" ], - "WebCryptoAPI/generateKey/failures_ECDSA.worker.js": [ + "WebCryptoAPI/generateKey/failures_ECDSA.https.worker.js": [ "1fcde344bd6f05a1aec5ba568f5d6d7ede8c1b8c", "testharness" ], - "WebCryptoAPI/generateKey/failures_HMAC.worker.js": [ + "WebCryptoAPI/generateKey/failures_HMAC.https.worker.js": [ "0c8d20aff7988acd571156f83be3825c6078686a", "testharness" ], - "WebCryptoAPI/generateKey/failures_RSA-OAEP.worker.js": [ + "WebCryptoAPI/generateKey/failures_RSA-OAEP.https.worker.js": [ "06527a268ef2e009517230aae7e0c027ab94377b", "testharness" ], - "WebCryptoAPI/generateKey/failures_RSA-PSS.worker.js": [ + "WebCryptoAPI/generateKey/failures_RSA-PSS.https.worker.js": [ "76553f02e30a990b521d51b3a13447459b5360ab", "testharness" ], - "WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.worker.js": [ + "WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.https.worker.js": [ "f1b875ecbe690db60e4e0706ed35f25cbd996d85", "testharness" ], @@ -379604,47 +384840,43 @@ "9623250b44a270bd23f6d892e8a8296351fac708", "support" ], - "WebCryptoAPI/generateKey/successes.worker.js": [ - "03f20782f7615881757c5febe211383e7ef19ebf", - "testharness" - ], - "WebCryptoAPI/generateKey/successes_AES-CBC.worker.js": [ + "WebCryptoAPI/generateKey/successes_AES-CBC.https.worker.js": [ "c7f1d0c5e7ecf28cfc052c56739aaa3bc949ffca", "testharness" ], - "WebCryptoAPI/generateKey/successes_AES-CTR.worker.js": [ + "WebCryptoAPI/generateKey/successes_AES-CTR.https.worker.js": [ "4b388cfe97d99300e7f9c4514140e3b030ba4553", "testharness" ], - "WebCryptoAPI/generateKey/successes_AES-GCM.worker.js": [ + "WebCryptoAPI/generateKey/successes_AES-GCM.https.worker.js": [ "5502fcb3da8257d28e3c49d1d391e3f6dfd3c022", "testharness" ], - "WebCryptoAPI/generateKey/successes_AES-KW.worker.js": [ + "WebCryptoAPI/generateKey/successes_AES-KW.https.worker.js": [ "19c0af9024a49ce6e1b2c884c0806960686509e0", "testharness" ], - "WebCryptoAPI/generateKey/successes_ECDH.worker.js": [ + "WebCryptoAPI/generateKey/successes_ECDH.https.worker.js": [ "751da81c9530a7dc5c31b02ed7c6e3dab8d997b4", "testharness" ], - "WebCryptoAPI/generateKey/successes_ECDSA.worker.js": [ + "WebCryptoAPI/generateKey/successes_ECDSA.https.worker.js": [ "900abdfba6c8a142d0cea1af9c1f6417bf05eb25", "testharness" ], - "WebCryptoAPI/generateKey/successes_HMAC.worker.js": [ + "WebCryptoAPI/generateKey/successes_HMAC.https.worker.js": [ "90bdffb8858c79694521cb9a831bc658b2c72834", "testharness" ], - "WebCryptoAPI/generateKey/successes_RSA-OAEP.worker.js": [ + "WebCryptoAPI/generateKey/successes_RSA-OAEP.https.worker.js": [ "e74fcd1eaa98078c3f1bb6c16fbf82a754397d4b", "testharness" ], - "WebCryptoAPI/generateKey/successes_RSA-PSS.worker.js": [ + "WebCryptoAPI/generateKey/successes_RSA-PSS.https.worker.js": [ "bccff0d804b1d06ae9b183ebc38c72b3031c7f8a", "testharness" ], - "WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.worker.js": [ + "WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.https.worker.js": [ "b9e9790245742b8eeb4af7679cc0144710380c07", "testharness" ], @@ -379656,10 +384888,6 @@ "3804433a5bd2c382c8bd9afbd1b41792d9f927c1", "testharness" ], - "WebCryptoAPI/generateKey/test_failures.https.html": [ - "a1458bc27b594b9051bfbb7e537aebe2c95b6859", - "testharness" - ], "WebCryptoAPI/generateKey/test_failures_AES-CBC.https.html": [ "bf4b12efa09c2602bed73b4ae2b94ebdf5bf9749", "testharness" @@ -379729,7 +384957,7 @@ "testharness" ], "WebCryptoAPI/generateKey/test_successes_RSA-OAEP.https.html": [ - "04b89d631e81fd7822049c8513984c3af3711efd", + "7ebe1df33a5df5f5a2cead014af5502246b6b833", "testharness" ], "WebCryptoAPI/generateKey/test_successes_RSA-PSS.https.html": [ @@ -379745,11 +384973,11 @@ "testharness" ], "WebCryptoAPI/idlharness.html": [ - "52b5381311cc0e2595d251273e054fa826de9765", + "f97da6e12fbd08b0fe93a6bc0fb9724053d147a8", "testharness" ], "WebCryptoAPI/idlharness.https.html": [ - "52b5381311cc0e2595d251273e054fa826de9765", + "f97da6e12fbd08b0fe93a6bc0fb9724053d147a8", "testharness" ], "WebCryptoAPI/idlharness.worker.js": [ @@ -379861,7 +385089,7 @@ "testharness" ], "WebCryptoAPI/tools/generate.py": [ - "e7b1269e1b432d017256eb200540c7fabeadff25", + "058fc13d71d3d030477593591d4119b59fa3cd54", "support" ], "WebCryptoAPI/util/helpers.js": [ @@ -379932,6 +385160,10 @@ "24807487f4acea28e3b1315e0876d99a79fb592d", "testharness" ], + "WebIDL/ecmascript-binding/no-regexp-special-casing.any.js": [ + "21d817e7095ae8b6ce3b661aeb339ed6e96ceb1a", + "testharness" + ], "WebIDL/ecmascript-binding/put-forwards.html": [ "95fcfc28dae32ab9aadf21d2512a519d6a9fd5ab", "testharness" @@ -381617,7 +386849,7 @@ "testharness" ], "XMLHttpRequest/send-network-error-sync-events.sub.htm": [ - "c455c57e952ca5d44843b42840becd2c56f11213", + "8dd189e5d654c1fc46808dbd860ed0b055851227", "testharness" ], "XMLHttpRequest/send-no-response-event-loadend.htm": [ @@ -381661,7 +386893,7 @@ "testharness" ], "XMLHttpRequest/send-redirect-post-upload.htm": [ - "381627d16e8ad618b3dd9d31c51466a154ad7200", + "504168881ffa74378fc151f01fe53a177fc89633", "testharness" ], "XMLHttpRequest/send-redirect-to-cors.htm": [ @@ -381908,16 +387140,48 @@ "8051e72ea6d92c55fa457eb88f00da3b7a873225", "testharness" ], + "accelerometer/Accelerometer-disabled-by-feature-policy.https.html": [ + "37ec335921c5e3cb6011986e76da04254106f4f6", + "testharness" + ], + "accelerometer/Accelerometer-disabled-by-feature-policy.https.html.headers": [ + "bde03e5f36844e0818f4d1092c4fe6788cb4e194", + "support" + ], + "accelerometer/Accelerometer-enabled-by-feature-policy-attribute-redirect-on-load.https.html": [ + "b03ee7c22f1dd78e2681632f2f67598da67a09cb", + "testharness" + ], + "accelerometer/Accelerometer-enabled-by-feature-policy-attribute.https.html": [ + "6f5a595f9ee8d8e0dcd29eae9816210846c43557", + "testharness" + ], + "accelerometer/Accelerometer-enabled-by-feature-policy.https.html": [ + "9997d07beb3ef1c711dcfd6308c58d11c938244d", + "testharness" + ], + "accelerometer/Accelerometer-enabled-by-feature-policy.https.html.headers": [ + "18a6f86070b21bff87cc9dc37194cdb6113af198", + "support" + ], + "accelerometer/Accelerometer-enabled-on-self-origin-by-feature-policy.https.html": [ + "3b4500e2ff0f8a3efae8ace952a8993ed3005bd6", + "testharness" + ], + "accelerometer/Accelerometer-enabled-on-self-origin-by-feature-policy.https.html.headers": [ + "c1723ad9944cf2393a5519a91e4e47a0255bcaf4", + "support" + ], "accelerometer/Accelerometer.https.html": [ - "cdf386711da6ef6a795bcf179e7c7ce373751f56", + "c0ca55250886c6a8c6194b658ed362e8b10ccae3", "testharness" ], "accelerometer/Accelerometer_insecure_context.html": [ - "da374eab5cbc963d8e5e2f2025d9fb1a94043643", + "ad29f70c8f506002154e6ffa430b87f5e5ae0923", "testharness" ], "accelerometer/Accelerometer_onerror-manual.https.html": [ - "e03faad7d297ce2c5d6fefa66a2397c3d9a32e2d", + "f20acb4b4e2f774fc13c870f972aaa2ca82afd27", "manual" ], "accelerometer/OWNERS": [ @@ -382017,7 +387281,7 @@ "support" ], "acid/acid3/test.html": [ - "1822fb86b9af47dd384398e56afb6d8ed2f0565b", + "67435e96f4240675943bad5ca296a1020cf04fe5", "reftest" ], "acid/acid3/xhtml.1": [ @@ -382044,6 +387308,38 @@ "889fd09853f091aba8fea3b45cfeb36437be1c2b", "support" ], + "ambient-light/AmbientLightSensor-disabled-by-feature-policy.https.html": [ + "0e09d27c24fa43fa4b854597f2eebc7589d565b3", + "testharness" + ], + "ambient-light/AmbientLightSensor-disabled-by-feature-policy.https.html.headers": [ + "60c9a6457eebafad8ac6c139f80ababb6efd1ceb", + "support" + ], + "ambient-light/AmbientLightSensor-enabled-by-feature-policy-attribute-redirect-on-load.https.html": [ + "c062b275f18a69d092fe4f8d20d01f93a631556f", + "testharness" + ], + "ambient-light/AmbientLightSensor-enabled-by-feature-policy-attribute.https.html": [ + "e719162b3001f7a6ef307a1f3af9ac048a0f7ce3", + "testharness" + ], + "ambient-light/AmbientLightSensor-enabled-by-feature-policy.https.html": [ + "605f76f34e24f91ca9e2a6538624ec89633c6d1a", + "testharness" + ], + "ambient-light/AmbientLightSensor-enabled-by-feature-policy.https.html.headers": [ + "00f610fe390dc2bd24b76170cf268a08483fe4aa", + "support" + ], + "ambient-light/AmbientLightSensor-enabled-on-self-origin-by-feature-policy.https.html": [ + "6ed23575a7dc16c7044970d81d7768796e9968d4", + "testharness" + ], + "ambient-light/AmbientLightSensor-enabled-on-self-origin-by-feature-policy.https.html.headers": [ + "9c9b554e33d34e1513dd315ecd6299f756d68b43", + "support" + ], "ambient-light/AmbientLightSensor.https.html": [ "86a1f84e2e034d58b2a7f6fc01880028b444c7cd", "testharness" @@ -384184,6 +389480,10 @@ "61b61d09a21daee964e0ebd26f7bdfdd1964c8ae", "support" ], + "beacon/OWNERS": [ + "500e8f078ef1f3e56bf3e2590a2799046832f573", + "support" + ], "beacon/beacon-basic-blob.html": [ "60262cdcf9a58117db70f2afdeed195c820b04c7", "testharness" @@ -384296,10 +389596,26 @@ "ef497e5da8691971c612980bb94eae44fc17c509", "support" ], - "bluetooth/idl-Bluetooth.html": [ + "bluetooth/README.md": [ + "570b51035ed737c73da8b266cbe0eb658745286e", + "support" + ], + "bluetooth/idl/idl-Bluetooth.html": [ "5d4d8278b1f24798765974c35777f70fcbfc9cfa", "testharness" ], + "bluetooth/idl/idl-BluetoothUUID.html": [ + "4feb7657e77a18489bbe2d7a98405470c6ce0b82", + "testharness" + ], + "bluetooth/idl/idl-NavigatorBluetooth.html": [ + "9367593c5bfe07afb4629791cf6aab70460dcd4c", + "testharness" + ], + "bluetooth/resources/bluetooth-helpers.js": [ + "bca57dea31c477c56e8323919f45df6a755101f5", + "support" + ], "clear-site-data/navigation-insecure.html": [ "97c069cf7c938e1ebdba3f243ad48369a7fb5542", "testharness" @@ -384473,7 +389789,7 @@ "support" ], "common/media.js": [ - "a575b8135e6ddb1501fc2a082d7544ee86011b7d", + "33c78c9c056dc4879c2503075e6cedbf2211b6d2", "support" ], "common/media.js.headers": [ @@ -384489,7 +389805,7 @@ "support" ], "common/performance-timeline-utils.js": [ - "cf06f5a0e00f29d862753144634b4e1d0f074fb8", + "8a914a75398a2865da676183a62b00753607fbca", "support" ], "common/performance-timeline-utils.js.headers": [ @@ -384540,10 +389856,6 @@ "e3593850f8098d3f3ff82c042deab15f51c66a52", "support" ], - "common/vendor-prefix.js.headers": [ - "e3593850f8098d3f3ff82c042deab15f51c66a52", - "support" - ], "compat/OWNERS": [ "e714708a95e56bc556b64d991cb72f0ccace4f92", "support" @@ -384653,11 +389965,11 @@ "support" ], "conformance-checkers/html-aria/_functional/tree/ariatree.html": [ - "f9e85f04e0e2342a2dc3441a25c238f6db577139", + "3db4a5ff2c0d9be937ea32bf061951b2a09c996e", "support" ], "conformance-checkers/html-aria/_functional/tree/ariatree2.html": [ - "3c4cb0fe40016f75f90a1e58b7952ea4b34f6e63", + "6860d66ea736a7b3044242f24692669bec6c22a5", "support" ], "conformance-checkers/html-aria/_functional/tree/css/img/expander.gif": [ @@ -384705,195 +390017,195 @@ "support" ], "conformance-checkers/html-aria/accessible-name-updates/673.html": [ - "1a576c12517202a5d943f602d29d84678a73b59c", + "cfcfde79147f7d295571623600c90f639e6efb4f", "support" ], "conformance-checkers/html-aria/accessible-name-updates/674.html": [ - "d0a1e8fb30dfc582472b412dcf17ee760234dcda", + "dd12a4c0d1fa1b51606c7aee9fa7abb02bf76767", "support" ], "conformance-checkers/html-aria/accessible-name-updates/675.html": [ - "7c75478bf0536dbc0f3c605d98521a954cd299d7", + "e63b719817288c9d064942f310ac3bae6f25d473", "support" ], "conformance-checkers/html-aria/accessible-name-updates/676.html": [ - "42a1256f62fbb4940a4c5e180bbbdd9debb622ff", + "955c4e95fe420685d172408590f03f6d69cca725", "support" ], "conformance-checkers/html-aria/accessible-name-updates/677.html": [ - "07baaad9d0c60f94aa5ac9ca9cc17333b0aa654e", + "1eeca423944499c0f2896c06aa4d2fce849db199", "support" ], "conformance-checkers/html-aria/accessible-name-updates/678.html": [ - "3ef183bb165bbeebb9c0907514a3fb4dfd85c8a0", + "da67c23ee1f6a090d6abd7f91fc06b2d94fbc25d", "support" ], "conformance-checkers/html-aria/accessible-name-updates/679.html": [ - "9d23235020d67bb17357b19aea6aa9bc90b8113a", + "9a791faa521cc1b240f6801a0406fcf5219527a1", "support" ], "conformance-checkers/html-aria/accessible-name-updates/680.html": [ - "81d90ec378ca4cdf16238235c9602c86f3ad23a2", + "f8a7dd3acc810386f9a6b1a76243e986c9976a7e", "support" ], "conformance-checkers/html-aria/accessible-name-updates/681.html": [ - "6bb2c295a11d12e83ed792d2de3dafa7d805fc20", + "72b29b7292f02cea663478c838567d6ac7fe3170", "support" ], "conformance-checkers/html-aria/accessible-name-updates/682.html": [ - "f4052c03fda369769050267868e57e75ffb8870a", + "68b34220f7ddf88ea55c3b0850e2f3773941d4b8", "support" ], "conformance-checkers/html-aria/accessible-name-updates/683.html": [ - "49d439774c8911452a2bc149f4e7fb5b18b241ce", + "60aa9176d5e117fc46019758ce514b1a64d39ef6", "support" ], "conformance-checkers/html-aria/accessible-name-updates/684.html": [ - "850500dedc5d3f6f26ad00c7e957afbbd66f495d", + "abf8162860876fd5244fe460d9080c5da2fc7f45", "support" ], "conformance-checkers/html-aria/accessible-name-updates/685.html": [ - "93a467c8a0f92d4181220a32adaf7fef5c45539f", + "994daef845049f08d75545f8bba27e7cf117fe91", "support" ], "conformance-checkers/html-aria/accessible-name-updates/686.html": [ - "3f273b86aa88e8b9ed82a5765ba7f051b4c4c114", + "2feab848a496557a0ad9b786927f198d0dfacc41", "support" ], "conformance-checkers/html-aria/accessible-name-updates/687.html": [ - "3b72b339456f16c61dc6a31a05cff0b8d3b0fd7c", + "59a2193fda29ef228e82fb47b69e6fa8cb1a124a", "support" ], "conformance-checkers/html-aria/accessible-name-updates/688.html": [ - "5b9277b49901add92345009fdece487793596de2", + "ec660350987878ba0c54a5ae235d16d9ed4183e0", "support" ], "conformance-checkers/html-aria/accessible-name-updates/689.html": [ - "ec2f320c14352a85fddc6e4aeed3ce55e14ae6ef", + "043954301260b11673803f817ac4aaa5b22398a3", "support" ], "conformance-checkers/html-aria/accessible-name-updates/690.html": [ - "5bd040685231ced758210f56234baa26acdf00c1", + "f1b0d87a1b11241cc1d7d7613f7b3700001a55a4", "support" ], "conformance-checkers/html-aria/accessible-name-updates/691.html": [ - "9af038de68bc193a12958418971714e85d6f0d52", + "80917ea366906c9ebb4b1bc24a1f4dde5e9e765f", "support" ], "conformance-checkers/html-aria/accessible-name-updates/692.html": [ - "a97b4a4853756e245dadfb2521ef58d36565328f", + "fdca97a7ef4448d2743be36718df5a1d3972035d", "support" ], "conformance-checkers/html-aria/accessible-name-updates/693.html": [ - "a21c65bb0e28d0a8c65dc729ad958deafb8fe8aa", + "450b2ed97e4225bb7dd7ab06d9e4398b910a16b8", "support" ], "conformance-checkers/html-aria/accessible-name-updates/694.html": [ - "877a162fa7495c40a675d8df9cac5bfd1913c50a", + "7cbd07132cd55a39e3e8a0615864fe0d6249b4a3", "support" ], "conformance-checkers/html-aria/accessible-name-updates/695.html": [ - "3399fe6f5e20b47d8999225ff45860f0c780af64", + "b0608580f623674105f735d764af5179623664c1", "support" ], "conformance-checkers/html-aria/accessible-name-updates/696.html": [ - "1a115b5def088c8992a172ff6dd70b1bfbff8f5c", + "d62c9ea4ca6ef04cdb3c1a633a297f01171f39d9", "support" ], "conformance-checkers/html-aria/accessible-name-updates/697.html": [ - "5c9f91b552f4d2eeb6baca10c22fb9db0802896a", + "fbf369f993893bf97e924e08853dee6cbf5c7a20", "support" ], "conformance-checkers/html-aria/accessible-name-updates/698.html": [ - "8731402b6f2ff8180a70673f73d4a3c72c176ade", + "da4c27037d56bb296956bbd754b3fed93e14f9ad", "support" ], "conformance-checkers/html-aria/accessible-name-updates/699.html": [ - "3f2768c03515ed34c5c98cbc91092de51c949170", + "2efbc0d35b5f81927a8aa47c71cea034b534e213", "support" ], "conformance-checkers/html-aria/accessible-name-updates/700.html": [ - "67289abb6e8fd4dadc00e2bd49ce4d95fb33f8b0", + "b891f3bdf8e175147bd340f730752a3ccc1231d7", "support" ], "conformance-checkers/html-aria/accessible-name-updates/701.html": [ - "81e336700dd18b844e275081e0c41e02c57dcf05", + "586b9acb8f174ac53e21c480da9a9949940c0cd0", "support" ], "conformance-checkers/html-aria/accessible-name-updates/702.html": [ - "f9d9473c4bbf68fb3fede8f537df88e9bea1baa9", + "1b9d66be9d95b632e34abf69f0be0dbc68f8fa3c", "support" ], "conformance-checkers/html-aria/accessible-name-updates/703.html": [ - "572612434ee452c9d1c1377cd2feeae00f7a3f49", + "d9472daeb7024354f20e38016857995651cf131b", "support" ], "conformance-checkers/html-aria/accessible-name-updates/704.html": [ - "57ee82c925e403a1d5b79591ba2b71b15f23f032", + "f82e4d39ae101a43b6ade90c0ada017b5f80bebe", "support" ], "conformance-checkers/html-aria/accessible-name-updates/705.html": [ - "89a99ab74e99b35d0f91f4927a4bcb233bdaf24e", + "04cdd01ff1555dff235c5c7ae91cd147c81de299", "support" ], "conformance-checkers/html-aria/accessible-name-updates/706.html": [ - "37cac6282727d0ba82b245254af56de86097d1bd", + "a1ba506851d2c0427451f45b8d5cabfde18f9e4a", "support" ], "conformance-checkers/html-aria/accessible-name-updates/707.html": [ - "b71460bdc499131298ca82224c304e5605d303ea", + "b378aab84338105f9aeed36cd3606ff4736942df", "support" ], "conformance-checkers/html-aria/accessible-name-updates/708.html": [ - "dfae811bf6784caf26035e77f3a9df0b1e01b8ba", + "94f336593fb6d4a1f417c73ec673bb0de5b70176", "support" ], "conformance-checkers/html-aria/accessible-name-updates/709.html": [ - "18c678ef080f49549a8c9abe5a2264c73c008ccc", + "33461017ccda24eb09fb236edacebd01507ac956", "support" ], "conformance-checkers/html-aria/accessible-name-updates/710.html": [ - "3c764065fde0deea537183c07dbf1eee79d3a216", + "f020f0224c86139407adf34155398bb9c1718b92", "support" ], "conformance-checkers/html-aria/accessible-name-updates/711.html": [ - "9824adccf8c14a07cffdab79174312ab1ea6316e", + "0787df1ced7c0e9e67612aade934483e135774a7", "support" ], "conformance-checkers/html-aria/accessible-name-updates/712.html": [ - "789eec3d5e875de0b47683f44707ac81a95e64ca", + "33076074760742b435a4fa8ceb751eaa59179a69", "support" ], "conformance-checkers/html-aria/accessible-name-updates/713.html": [ - "057e9d9dc6a29c26392f427a5532d98af90c8b3e", + "4941ac15aa8a4239e8a2ec7d7202ea94f5cde8d0", "support" ], "conformance-checkers/html-aria/accessible-name-updates/714.html": [ - "ba5893d78efa51dfa67598836a177e8c7d0b18f5", + "addd44a63339378290ef8ce844073a6b9417ba43", "support" ], "conformance-checkers/html-aria/accessible-name-updates/715.html": [ - "f7b2a149a027de9f7088cd064e1d5c3771c8b531", + "77d138ee6917d10f3edb3cb79846a5986c09fe56", "support" ], "conformance-checkers/html-aria/accessible-name-updates/716.html": [ - "f1436c18795e2dadf36fe93f6e4d2be74a0cd338", + "114823344ddb18c21e81cf6c3745f97fc8198e5f", "support" ], "conformance-checkers/html-aria/accessible-name-updates/717.html": [ - "f8df430d2df817bbe9804b8e2d1bc231c5792abd", + "c6c9aff3de53b00a02b7832e44b2563f41650ac1", "support" ], "conformance-checkers/html-aria/accessible-name-updates/718.html": [ - "a7cb893fc65215c91b8489efa6ab6a3d418653a8", + "091e2e2f3250ac792c52509a842253f6a6c05212", "support" ], "conformance-checkers/html-aria/accessible-name-updates/719.html": [ - "b9daf582eb8ed45cdabc90df8a49c5feaeb2a817", + "ac48074d746edf167e5bd0342ad3d888435b99ba", "support" ], "conformance-checkers/html-aria/accessible-name-updates/720.html": [ - "7f17c0c016e8c6410b25097f943980396903524c", + "ba2bfa7c4508ccf9672a41a591ef1d050220acfe", "support" ], "conformance-checkers/html-aria/aria-describedby/772.html": [ @@ -384913,11 +390225,11 @@ "support" ], "conformance-checkers/html-aria/author-requirements/567.html": [ - "2089b053bce7f3d2b11f0bad964e5cb31460052e", + "d4a6d547d0b6abc3cad927cd2e5ffbe465b58ab6", "support" ], "conformance-checkers/html-aria/author-requirements/568.html": [ - "1da280ec0c5039680965616577e772e93bedb4f1", + "926e47114e9ff9230336dffcb1236e5fed7e0e3d", "support" ], "conformance-checkers/html-aria/author-requirements/569.html": [ @@ -384925,15 +390237,15 @@ "support" ], "conformance-checkers/html-aria/author-requirements/571-haswarn.html": [ - "706508247ce630c6c5b3295bfbb6a58110ba8439", + "3f069b431d4a68609e6d7884c57d6de4d031d333", "support" ], "conformance-checkers/html-aria/author-requirements/572-haswarn.html": [ - "d036b8971cc46b496550fd98bf45dfb613e18d76", + "6a5bf9157bd1c711c8fcf74c3eab2a243f34959b", "support" ], "conformance-checkers/html-aria/author-requirements/573-haswarn.html": [ - "39bcd0438b81208daf037e3880cbb5f8e24fd892", + "e8e253c5515fc9e2e2f7759e6420f8bb9f1ef0d8", "support" ], "conformance-checkers/html-aria/author-requirements/574.html": [ @@ -384961,7 +390273,7 @@ "support" ], "conformance-checkers/html-aria/author-requirements/580.html": [ - "779bed9dc84d13dbe7222fd60e8e8648629d71aa", + "d605c2af2645bab6c0c480a02854d5e6f0216ac9", "support" ], "conformance-checkers/html-aria/author-requirements/581.html": [ @@ -385029,27 +390341,27 @@ "support" ], "conformance-checkers/html-aria/live-events/test-case-live-event-1.html": [ - "1d141e5e8c03df30877e2f00d08bd18763241118", + "d66547dc32b127d7d8662ebb7f87a0b7991cb006", "support" ], "conformance-checkers/html-aria/live-events/test-case-live-event-2.html": [ - "5ddf6c2bfd7b9adfc45720ef4f28f47724027adc", + "80182786fa25c32827b336aa263b689e29852a49", "support" ], "conformance-checkers/html-aria/live-events/test-case-live-event-3.html": [ - "e5e9ddbeaa5fb6722f87e53e0cfe257682bdf0ec", + "54ed58aa6f57947eab81b097fe25c2f18d3c8e05", "support" ], "conformance-checkers/html-aria/live-events/test-case-live-event-4.html": [ - "0f45ecb2dbf86b1c32ef33709cb2a9cf338dcaca", + "81b6d75109141ea494aa835a7a7b5266ee1076da", "support" ], "conformance-checkers/html-aria/live-events/test-case-live-event-5.html": [ - "407fccfc2a953c5fef01799e25be3a900bf8b145", + "f3d25d49ceaace70d0434c94a8b709db916278dd", "support" ], "conformance-checkers/html-aria/live-events/test-case-live-event-6.html": [ - "e17f8497bf864ec1cee44f0acb251adaaee33fe3", + "ffdc39a54d106141486677160983f4f5efbf98af", "support" ], "conformance-checkers/html-aria/mixed-value/585.html": [ @@ -385201,23 +390513,23 @@ "support" ], "conformance-checkers/html-aria/name-computation-input/659.html": [ - "c5e402b9f6d80d697f7afd6fc94fb872954f9945", + "b1ce4a674402c8f833f815deb6906ac6ab76f13b", "support" ], "conformance-checkers/html-aria/name-computation-input/660.html": [ - "901b68c26bbb9a723837ebea2b91fa880536f0e4", + "07f0d9c33c16b0da5e4b64051d305eeca59aa3de", "support" ], "conformance-checkers/html-aria/name-computation-input/661.html": [ - "6b6990e01092bdeba015637ad3a3cdc1d36a8ead", + "4eeb3fe92494a3636914a37ae561fa025723597b", "support" ], "conformance-checkers/html-aria/name-computation-input/662.html": [ - "18e091c8ad97eaa09cfc834419e40528eaeb695b", + "33f668ed9d283c0806c8ac3844ce2d98e4c145d7", "support" ], "conformance-checkers/html-aria/name-computation-input/663.html": [ - "21a67cd21457ca61435c44b099ea071bd8d5af35", + "1da9833691a26f99579a817dc0849bdd19576117", "support" ], "conformance-checkers/html-aria/name-computation-input/721.html": [ @@ -385785,7 +391097,7 @@ "support" ], "conformance-checkers/html-aria/roles-plain-concrete/roles-plain-concrete-listbox-parent-combobox.html": [ - "c2b471304af885d0d3715b03c5e8fca750d016af", + "e2cb06bfa3ec9533a4d9fc87e56856a29609f627", "support" ], "conformance-checkers/html-aria/roles-plain-concrete/roles-plain-concrete-listbox.html": [ @@ -387145,19 +392457,19 @@ "support" ], "conformance-checkers/html-aria/selected-state/670.html": [ - "6e65f4d28d029ff94679718f7f21efadaed177f1", + "467c82ca654e35c80ca3dc0bb62239b9c011840c", "support" ], "conformance-checkers/html-aria/selected-state/671.html": [ - "e28f109690756a7ae95680948f00a2720d2415e7", + "358c29bbd3d615d6f875f740702e3aad19e0d8cd", "support" ], "conformance-checkers/html-aria/selected-state/672.html": [ - "9cf2912de31390727c02a52502f44e78db4b4112", + "526c1f37f668f15abdfbb9d95c04c8fb9cd67ba8", "support" ], "conformance-checkers/html-aria/setsize-posinset-level/setsize-posinset-level-1.html": [ - "2d62f1e7e2659cd05a4ab0f46c0193283bdd2701", + "daff5d78defe7e27254c8857755aae200a79e9f0", "support" ], "conformance-checkers/html-aria/setsize-posinset-level/setsize-posinset-level-5.html": [ @@ -387173,27 +392485,27 @@ "support" ], "conformance-checkers/html-aria/stability-of-dom/669.html": [ - "c0e6c5137b8d4ae90235be5b23c0ac360fdff5eb", + "45b9ba0e7447419112c86890b3526c172eccdc43", "support" ], "conformance-checkers/html-aria/testcases-multiselectable/testcase-listbox-multiselectable-A.html": [ - "f135227d46a5449ee75552301926c325b520d33c", + "104b0f3ff63f518dd2dadff1c6a07520608b2e4b", "support" ], "conformance-checkers/html-aria/testcases-multiselectable/testcase-listbox-multiselectable-B.html": [ - "aa44fffaa89c2769c3ebf9497c4933993eb3db1f", + "fa808d143b2dc7a596b1de9e993ede72ec96fbc5", "support" ], "conformance-checkers/html-aria/testcases-multiselectable/testcase-listbox-multiselectable-C.html": [ - "b8c96a991f0db6f3890c534aa572560547c30e0b", + "cb549a4c278d9de823a983137665e561f09cfd55", "support" ], "conformance-checkers/html-aria/testcases-multiselectable/testcase-multiselectable-D.html": [ - "bd50bab315f21422d9a70a5a17c835c12046a303", + "2bce50e8b66893dc2d155e1dd251aa4099e6f248", "support" ], "conformance-checkers/html-aria/testcases-multiselectable/testcase-tree-multiselectable-C.html": [ - "55cfc48c6f3dc254a36d939553d135ff2885cc0f", + "19d77de4bcfe5c42a7a5eb77a16ab1289613ca2a", "support" ], "conformance-checkers/html-its/allowedcharacters/html/allowedcharacters1html.html": [ @@ -387797,19 +393109,19 @@ "support" ], "conformance-checkers/html-its/locqualityissue/html/locqualityissue4html.html": [ - "f416ac2b181cc1a1e03c2b9713c0ec0e99248254", + "76ee9f93525f88e97b3259d0f7a5dc610039d575", "support" ], "conformance-checkers/html-its/locqualityissue/html/locqualityissue5html.html": [ - "f4cb3fac343ac3141ca9490c19715cd4cbd9b802", + "c18b1507e44586881c422f380054cdba334544c0", "support" ], "conformance-checkers/html-its/locqualityissue/html/locqualityissue6html.html": [ - "e18daf5bb1e9eda592f9bb0c48e18775daba1766", + "5c507b9dbf2e5637b6a461a60fc39d9e852fa309", "support" ], "conformance-checkers/html-its/locqualityissue/html/locqualityissue7html.html": [ - "e595c25de0a0ae226cd40d889f296adedeb96552", + "875b6a8f81ad179eda3344e9baa2b14d09a3bc8e", "support" ], "conformance-checkers/html-its/locqualityissue/html/locqualityissue8html.html": [ @@ -389677,7 +394989,7 @@ "support" ], "conformance-checkers/html-svg/animate-elem-33-t-isvalid.html": [ - "a30177e9b3a709eaa1d28fcdada39ced5a417601", + "39c155e80765b020b7916e3c32359f2aed72fd4b", "support" ], "conformance-checkers/html-svg/animate-elem-34-t-isvalid.html": [ @@ -389821,11 +395133,11 @@ "support" ], "conformance-checkers/html-svg/animate-elem-90-b-isvalid.html": [ - "5c18ff07cb929e65eb9222831d1e109255f9f078", + "1211f66d533725e2ae8d9bddb1964a26c9ab5820", "support" ], "conformance-checkers/html-svg/animate-elem-91-t-isvalid.html": [ - "b9acbaeeb5866c191915143dafbb88db16899035", + "0f6f9a118e0727d846c07e3c6aafebca695b8a1d", "support" ], "conformance-checkers/html-svg/animate-elem-92-t-isvalid.html": [ @@ -390185,7 +395497,7 @@ "support" ], "conformance-checkers/html-svg/filters-turb-02-f-isvalid.html": [ - "78d5a333b247e1c8c02530cf495f6a7feed634a5", + "ae4310846727cebacc09c028529a716f8cf09ddb", "support" ], "conformance-checkers/html-svg/fonts-desc-01-t-isvalid.html": [ @@ -390217,11 +395529,11 @@ "support" ], "conformance-checkers/html-svg/fonts-elem-03-b-isvalid.html": [ - "45fd874162b71ccee5ae5fc3054b33f573d56c08", + "1406ce68111c8628588e8af93a816b80ced7792e", "support" ], "conformance-checkers/html-svg/fonts-elem-04-b-isvalid.html": [ - "3382c4004e5fc216eaf033732c44fac3ebb6961c", + "8fdaa02b1fb57a278997dfcfd8de59358c1a8c20", "support" ], "conformance-checkers/html-svg/fonts-elem-05-t-isvalid.html": [ @@ -390233,7 +395545,7 @@ "support" ], "conformance-checkers/html-svg/fonts-elem-07-b-isvalid.html": [ - "99e555d3c6e39a62bfbeecd5a96acdf6d1a4f875", + "13246af933d7c55942b73947ab3504995b1bb744", "support" ], "conformance-checkers/html-svg/fonts-glyph-02-t-isvalid.html": [ @@ -390325,7 +395637,7 @@ "support" ], "conformance-checkers/html-svg/interact-pevents-10-f-isvalid.html": [ - "5d137aff8110099676359bdb43bef36f0ee8f6b6", + "fda3638dafcca97f305c6056cbad755f8e4b43c7", "support" ], "conformance-checkers/html-svg/interact-pointer-01-t-isvalid.html": [ @@ -390341,7 +395653,7 @@ "support" ], "conformance-checkers/html-svg/interact-pointer-04-f-isvalid.html": [ - "fc5923a5d8e74c0900e64425aa9c3116d71e5415", + "76a6c30090943843d2607992e2d7a6dea36134f9", "support" ], "conformance-checkers/html-svg/interact-zoom-01-t-isvalid.html": [ @@ -390413,7 +395725,7 @@ "support" ], "conformance-checkers/html-svg/masking-mask-01-b-isvalid.html": [ - "86f649ce812d1754013761b1578333f28aefc6cc", + "6d916c4fb24db24f4e244a3906e2750b73d4e36f", "support" ], "conformance-checkers/html-svg/masking-mask-02-f-isvalid.html": [ @@ -390469,7 +395781,7 @@ "support" ], "conformance-checkers/html-svg/masking-path-12-f-isvalid.html": [ - "b0387378e21fb9ef1450b18426924c5e3ddc2063", + "f13dace7dce3470b076d9bf77af872e9ee874004", "support" ], "conformance-checkers/html-svg/masking-path-13-f-isvalid.html": [ @@ -390537,7 +395849,7 @@ "support" ], "conformance-checkers/html-svg/painting-marker-03-f-isvalid.html": [ - "19c5504836dfb92d40510cde6f467cca6ed12cde", + "bb3871c8cc0cfdba81ef4ec08e827b77f54240cc", "support" ], "conformance-checkers/html-svg/painting-marker-04-f-novalid.html": [ @@ -390545,7 +395857,7 @@ "support" ], "conformance-checkers/html-svg/painting-marker-05-f-isvalid.html": [ - "9aba948fb721bc5b074772e9326b11324bae2479", + "4001dd917f17d7085197b0472549a5411a9fd6b9", "support" ], "conformance-checkers/html-svg/painting-marker-06-f-isvalid.html": [ @@ -390557,7 +395869,7 @@ "support" ], "conformance-checkers/html-svg/painting-marker-properties-01-f-isvalid.html": [ - "894b51da314acdbbf80c278e6c053f91c5520ae8", + "ef266c0e0c0ce7b73c03dc5ca927f98b86cde4e8", "support" ], "conformance-checkers/html-svg/painting-render-01-b-isvalid.html": [ @@ -390721,7 +396033,7 @@ "support" ], "conformance-checkers/html-svg/pservers-grad-08-b-isvalid.html": [ - "45817568696bffd2c59c1b29c349e9bc35a14f27", + "5f425fd090508b9bb2f893134fef4b24dc62efe9", "support" ], "conformance-checkers/html-svg/pservers-grad-09-b-isvalid.html": [ @@ -390833,23 +396145,23 @@ "support" ], "conformance-checkers/html-svg/render-elems-06-t-isvalid.html": [ - "374e29a6204f48b53608d58a06b42897d4eec2e7", + "ce7ae0d43978a2177871ef36c0b79578b265188e", "support" ], "conformance-checkers/html-svg/render-elems-07-t-isvalid.html": [ - "c7173373d787b8c0936603ef031fcff2cacde09e", + "dd067362aa8447e5d0cacab7c49bc757ed57b862", "support" ], "conformance-checkers/html-svg/render-elems-08-t-isvalid.html": [ - "cbd577e886e322e5ee292aeb12951c5c6e209db2", + "454ca0e9274c07dabe2616560210d3e8f30c9592", "support" ], "conformance-checkers/html-svg/render-groups-01-b-isvalid.html": [ - "fb6a45936a926dd4358ffaf3e1fecc481cfe966c", + "670cca23fb6eaed1f0b830bfc66612cb3247172a", "support" ], "conformance-checkers/html-svg/render-groups-03-t-isvalid.html": [ - "f82e73ed07769f73e7c058672e36a0ad28bba701", + "aae614973c8471f0f840ebd9b0c84a5f889549ec", "support" ], "conformance-checkers/html-svg/script-handle-01-b-isvalid.html": [ @@ -391037,7 +396349,7 @@ "support" ], "conformance-checkers/html-svg/struct-dom-13-f-isvalid.html": [ - "6a2a71827d9d0e6b5f8f7101d088ba7598cc6164", + "1eb76a92a5f8821af0e4feb66197f0b5b30f7834", "support" ], "conformance-checkers/html-svg/struct-dom-14-f-isvalid.html": [ @@ -391049,19 +396361,19 @@ "support" ], "conformance-checkers/html-svg/struct-dom-16-f-isvalid.html": [ - "3d0e1a2fb739c745dff8e986dfd90abeab3b94c5", + "6d144891e2a947b723f7d4125943bd29b5a5979b", "support" ], "conformance-checkers/html-svg/struct-dom-17-f-novalid.html": [ - "9c80ab5c4313f6db48f9f749624d8b5bf74a9d79", + "050c76ad66ded814a0bad0843588526ec463261a", "support" ], "conformance-checkers/html-svg/struct-dom-18-f-isvalid.html": [ - "b10b2269cb2b28fbb0acfefbba99d09e9726d884", + "0c6df2c514de06387e6e15ac61f26d70406632db", "support" ], "conformance-checkers/html-svg/struct-dom-19-f-novalid.html": [ - "562c226f83e41995bdf5d636aee52742baa535b4", + "a0201a7da16de8bb775e218f2037cedb38c42d63", "support" ], "conformance-checkers/html-svg/struct-dom-20-f-isvalid.html": [ @@ -391181,11 +396493,11 @@ "support" ], "conformance-checkers/html-svg/struct-svg-01-f-isvalid.html": [ - "11a7bc3c616311e2fd8a9cd38c786ff0719e5702", + "5bc007fad67cc5b1081730c69ad1ed7bf3ef82c6", "support" ], "conformance-checkers/html-svg/struct-svg-02-f-isvalid.html": [ - "4126b74298f58742d9185cc14f023159926c7f26", + "2cfbeb2364a6de41f9641c41441843bcff9f644b", "support" ], "conformance-checkers/html-svg/struct-svg-03-f-isvalid.html": [ @@ -391229,11 +396541,11 @@ "support" ], "conformance-checkers/html-svg/struct-use-10-f-isvalid.html": [ - "0903f45dbc87b29b14e4237e41e36fc8ee65f884", + "eeb7439fb70da73249e803b8e8480da0ccc194fd", "support" ], "conformance-checkers/html-svg/struct-use-11-f-novalid.html": [ - "54766246e44dfd53548ceb733fbdf9074581f8e6", + "4b185477eab79704b455aed8d5bab2afdae9991e", "support" ], "conformance-checkers/html-svg/struct-use-12-f-novalid.html": [ @@ -391245,39 +396557,39 @@ "support" ], "conformance-checkers/html-svg/struct-use-14-f-isvalid.html": [ - "1a73e4b3afec59a3b1bb078df4b9173a1493c617", + "b9b52218645613654a1246777aa52077f3c86047", "support" ], "conformance-checkers/html-svg/struct-use-15-f-isvalid.html": [ - "60bc0106463fdeaf97bf1ffce0284baed7c1aad3", + "d40145cab642bf8bf5dd588e8bee0f56a21cd85d", "support" ], "conformance-checkers/html-svg/styling-class-01-f-isvalid.html": [ - "b25098191314cb5a528665fbbab8ec529d723469", + "0f592aac2c8ff79e7b8a96b6f61346c56fc3b050", "support" ], "conformance-checkers/html-svg/styling-css-01-b-isvalid.html": [ - "65456b1c4ea7f5d0cce1610eb35387db89b62d97", + "502137765bb11ee3d5290a62ab25e8162b0d01d0", "support" ], "conformance-checkers/html-svg/styling-css-02-b-isvalid.html": [ - "4e2fc40cc418fd59598b5fe656fbb5ba44e9db30", + "0686e1ea236b67c301fa258a244cbcb8e19dffb9", "support" ], "conformance-checkers/html-svg/styling-css-03-b-isvalid.html": [ - "1ceb14dc956bbd243308a7ce2b9f0dbaf677ebe9", + "0e001287f80c7ae63836b25760577562c9794741", "support" ], "conformance-checkers/html-svg/styling-css-04-f-isvalid.html": [ - "377ffc2b8f1c3c07113d549ecc9a36898e93a1d9", + "079aed55ff1e69da19f2f2a11daa03d28ef05c00", "support" ], "conformance-checkers/html-svg/styling-css-05-b-isvalid.html": [ - "ed1ce9cabf6bd7d04620a8d7ff23dbf814ff0ae0", + "b4523f395a30231b663380713f9136d86db9199f", "support" ], "conformance-checkers/html-svg/styling-css-06-b-isvalid.html": [ - "ac602ee8848bdeb0329b44f38441c8c54f858256", + "4c2ef4d223d71a89cdab39dfee3af30a7e20947e", "support" ], "conformance-checkers/html-svg/styling-css-07-f-isvalid.html": [ @@ -391285,15 +396597,15 @@ "support" ], "conformance-checkers/html-svg/styling-css-08-f-isvalid.html": [ - "46df1bccf4665493887a587d187edb631c666a09", + "a89e2936dc2dc57c7b0cef59d87295db4fc7b1f6", "support" ], "conformance-checkers/html-svg/styling-css-09-f-isvalid.html": [ - "6dbbcdfdfc6ce72bd29f8aefc75853026c1cc901", + "987a5a85c90666ba7c88f0a34f41b00970606e64", "support" ], "conformance-checkers/html-svg/styling-css-10-f-isvalid.html": [ - "63e67a1071cb83fa384578c4c5080039e11a0fb4", + "38c267e1ed3632cb6af81000b30f7b429856a2ff", "support" ], "conformance-checkers/html-svg/styling-elem-01-b-isvalid.html": [ @@ -391317,11 +396629,11 @@ "support" ], "conformance-checkers/html-svg/styling-pres-04-f-isvalid.html": [ - "3ca9ada2290ec7db5d8c2480b18df505799c596c", + "76478896e0022cc5b647825a8ac7c167cbf52b98", "support" ], "conformance-checkers/html-svg/styling-pres-05-f-isvalid.html": [ - "3cb1fd7f158bef03fc4893f6c99a3db0cba3dfa1", + "700a9d92bf2f649e325ef3ddaf1292adab443a89", "support" ], "conformance-checkers/html-svg/svgdom-over-01-f-novalid.html": [ @@ -391357,7 +396669,7 @@ "support" ], "conformance-checkers/html-svg/text-align-08-b-isvalid.html": [ - "92aeb0eaa3468c34910b62ccf833d066463c239b", + "821fa951273afd7899d3ab3179b274d85f47adee", "support" ], "conformance-checkers/html-svg/text-altglyph-01-b-isvalid.html": [ @@ -391385,7 +396697,7 @@ "support" ], "conformance-checkers/html-svg/text-dom-02-f-isvalid.html": [ - "c555e032b8d6e50e121ccb22a0bb367b19c30f3a", + "f4d8ef1f3b7978bed5ac416683be55780e9c2919", "support" ], "conformance-checkers/html-svg/text-dom-03-f-novalid.html": [ @@ -391397,7 +396709,7 @@ "support" ], "conformance-checkers/html-svg/text-dom-05-f-isvalid.html": [ - "a467dbf921d7886c7f2ed1ed24bcd2aaca3b4f26", + "56fb513d999d2bb5b04838bcb433e7b8484cc753", "support" ], "conformance-checkers/html-svg/text-fonts-01-t-isvalid.html": [ @@ -391429,7 +396741,7 @@ "support" ], "conformance-checkers/html-svg/text-fonts-204-t-isvalid.html": [ - "fa3d50e70395fd486a0b0b9662edca2f1bdfc9df", + "344bbda75a9b43f3773481fdb8ebdc02ca88c139", "support" ], "conformance-checkers/html-svg/text-intro-01-t-isvalid.html": [ @@ -391453,7 +396765,7 @@ "support" ], "conformance-checkers/html-svg/text-intro-06-t-isvalid.html": [ - "47a36baa657b2ab4cf19157bcf91a8920c090a50", + "a05ed454500df7ea92095806199ac128e8808c70", "support" ], "conformance-checkers/html-svg/text-intro-07-t-isvalid.html": [ @@ -391461,7 +396773,7 @@ "support" ], "conformance-checkers/html-svg/text-intro-09-b-isvalid.html": [ - "313f648a45a65000ffbe6a829686190b169cb0de", + "48df2f1d46ab3d9f4185f03a1a3d0e3b4c3e5176", "support" ], "conformance-checkers/html-svg/text-intro-10-f-isvalid.html": [ @@ -391473,7 +396785,7 @@ "support" ], "conformance-checkers/html-svg/text-intro-12-t-isvalid.html": [ - "21ba8ee506fb4a9f9cdc80cb85a185840d6bcf03", + "ee4e586b2eb44204ede5354466df0ec1335a5a2d", "support" ], "conformance-checkers/html-svg/text-path-01-b-isvalid.html": [ @@ -391481,7 +396793,7 @@ "support" ], "conformance-checkers/html-svg/text-path-02-b-isvalid.html": [ - "d1d7e408a6a464bcff5e8555610099549b6804cc", + "f77392b5da7a2163f64495963e4e87d6e0fc4d63", "support" ], "conformance-checkers/html-svg/text-spacing-01-b-isvalid.html": [ @@ -391497,15 +396809,15 @@ "support" ], "conformance-checkers/html-svg/text-text-04-t-isvalid.html": [ - "49ca6d0539d8610cd50522b646129442cb1b1d4e", + "88ccdd31ecbf13986c3cd336f0d66f85ab3182b3", "support" ], "conformance-checkers/html-svg/text-text-05-t-isvalid.html": [ - "3fddf7f8c6fe485fc80ea6467f66037e3c63a4eb", + "5173e61b13f9f62b20b99743dca202da11345771", "support" ], "conformance-checkers/html-svg/text-text-06-t-isvalid.html": [ - "384a8f470255e3cf8f0e725ed2495281e7ef960f", + "842a8dbc81ef460e4d9f0b19244e5ca611584984", "support" ], "conformance-checkers/html-svg/text-text-07-t-isvalid.html": [ @@ -391529,7 +396841,7 @@ "support" ], "conformance-checkers/html-svg/text-text-12-t-isvalid.html": [ - "3e5cd8bd712619121082c9f265cf17e5f48845db", + "e922e41c86c881d63e7360ffaa5ae91915d3aa5e", "support" ], "conformance-checkers/html-svg/text-tref-01-b-isvalid.html": [ @@ -391545,7 +396857,7 @@ "support" ], "conformance-checkers/html-svg/text-tselect-03-f-isvalid.html": [ - "5c123a50b6afdd52852170f6ffd8b2e1ee88e27d", + "6980a2c8b5f4e006893d6df5a91922ae775516ea", "support" ], "conformance-checkers/html-svg/text-tspan-01-b-isvalid.html": [ @@ -391597,23 +396909,23 @@ "support" ], "conformance-checkers/html-svg/types-dom-svgfittoviewbox-01-f-isvalid.html": [ - "51915fa4c49e811bdf6fafb3609f91ae487581eb", + "42a856696a25493f49818e4cc68e5dd6af473ba7", "support" ], "conformance-checkers/html-svg/types-dom-svglengthlist-01-f-isvalid.html": [ - "5b166a8070280178591e90b7326a046e1b447b3a", + "9536d27904a04d03920476f7c5300fc2ca22ccd5", "support" ], "conformance-checkers/html-svg/types-dom-svgnumberlist-01-f-isvalid.html": [ - "fc3c1a8a8e39529941f21a215c9360b9c43060a0", + "9c40558341d0c92f34b7d9c0462e8463185703d0", "support" ], "conformance-checkers/html-svg/types-dom-svgstringlist-01-f-isvalid.html": [ - "b528dadf838e7862d851262e6f04ec46f3e5ea83", + "40cd5ddffd205fb2bdc14a64e4ff92cbd5c8660b", "support" ], "conformance-checkers/html-svg/types-dom-svgtransformable-01-f-isvalid.html": [ - "6d496e2790f0d7623bd6e3c0988539a459cc3d5b", + "14c50bec4c35e0b8b3dfd03e5b7362f4dc95073f", "support" ], "conformance-checkers/html/Makefile": [ @@ -399912,8 +405224,12 @@ "7a669924345c81629052168ee70e7b82035bf25d", "support" ], + "conformance-checkers/html/elements/style/html-spec-comms-isvalid.html": [ + "5a5c97af316b5eedb093cea453ba58a1a32e975a", + "support" + ], "conformance-checkers/html/elements/style/model-isvalid.html": [ - "95edf20c9686883cbc6e715fc8654f0bf1071de5", + "00b0870d863f5512002fe8af7d8e9874676e5d4c", "support" ], "conformance-checkers/html/elements/style/scoped-as-div-child-novalid.html": [ @@ -399940,6 +405256,10 @@ "198284a6acc5e69361554fa8d9a6720ee77996c2", "support" ], + "conformance-checkers/html/elements/style/type-novalid.html": [ + "1dd8d1cf5c9165209cb211d0d9c154d02b413636", + "support" + ], "conformance-checkers/html/elements/sub/model-isvalid.html": [ "9993643406c23f0f5f607cc7895cd35ff00ae919", "support" @@ -401793,11 +407113,11 @@ "support" ], "conformance-checkers/index.html": [ - "7a82e657e375abbdd2794ae24db859c4bda7cd08", + "7eaf95edd9b09087f815850be12dc8efa5592f76", "support" ], "conformance-checkers/messages.json": [ - "77e43d470fe6884315c194bb64b0acec88e29827", + "17e9506c7b34532366ba3f473a01e0a7e88eefdd", "support" ], "conformance-checkers/tools/build-svg-tests.py": [ @@ -402308,6 +407628,14 @@ "19d2027dc8784a479722b7f405fee31973808e2f", "testharness" ], + "content-security-policy/base-uri/report-uri-does-not-respect-base-uri.sub.html": [ + "7dd8bccbd166c7ac938699c406bc2209a7f5677f", + "testharness" + ], + "content-security-policy/base-uri/report-uri-does-not-respect-base-uri.sub.html.sub.headers": [ + "6adacb07a9ade6e135b5c24ef658384d26ed2dff", + "support" + ], "content-security-policy/blob/blob-urls-do-not-match-self.sub.html": [ "8fb0231ccaff9062464119096a4ae89c04216b42", "testharness" @@ -402856,6 +408184,14 @@ "7e092f21440fffed98068f59bd2ddfd09a683515", "testharness" ], + "content-security-policy/generic/policy-inherited-correctly-by-plznavigate.html": [ + "11de7fcc2fd1ca6e2277b22a53a2c2c7ba11aa2c", + "testharness" + ], + "content-security-policy/generic/policy-inherited-correctly-by-plznavigate.html.sub.headers": [ + "0ca17bc3c1370af097fdb2ee803cc802c7e58718", + "support" + ], "content-security-policy/generic/positiveTest.js": [ "92b715fcc3269e189318734739a5e4fb620d9dff", "support" @@ -402940,6 +408276,10 @@ "3121f2277196e721af7d8cd522be148c875c79bd", "testharness" ], + "content-security-policy/inheritance/inherited-csp-list-modifications-are-local.html": [ + "b11ead62cbc23529449cdfd5dceba1058c1127b8", + "testharness" + ], "content-security-policy/inheritance/window.html": [ "5a59b9b239186ad49aa1928f0beb9cf4234b4a6e", "testharness" @@ -403061,7 +408401,7 @@ "testharness" ], "content-security-policy/nonce-hiding/script-nonces-hidden.tentative.html": [ - "c3265d6ead066201f712aa06beac162f365dd058", + "44982a605aaef57edfd9bbd9af98b1eee8d9ba1d", "testharness" ], "content-security-policy/nonce-hiding/script-nonces-hidden.tentative.html.headers": [ @@ -403177,7 +408517,7 @@ "support" ], "content-security-policy/reporting/securitypolicyviolation-idl.html": [ - "3f0b501b2ef45c7c59b3654b4f2aa2fed7710a7a", + "831948d2397790fa68e6d8bc96454dcb2f3e3280", "testharness" ], "content-security-policy/sandbox/iframe-inside-csp.sub.html": [ @@ -403276,6 +408616,10 @@ "e8583f7292cd90aa13e0e997aedf41763eb18928", "support" ], + "content-security-policy/script-src/nonce-enforce-blocked.html": [ + "79bb6635e0964eef935cc2c9e93ff68034353f55", + "testharness" + ], "content-security-policy/script-src/script-src-1_1.html": [ "b4285b63b3f9a8fab266ac93b3b7c1a70a7bdfcc", "testharness" @@ -403613,7 +408957,7 @@ "testharness" ], "content-security-policy/securitypolicyviolation/idl.html": [ - "5f2ff4a87aa476168cf3d13b10a8d81a387b8e42", + "fb8f2938d76a29cc68c46fb49a12feebc0031e54", "testharness" ], "content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html": [ @@ -403769,7 +409113,7 @@ "testharness" ], "content-security-policy/style-src/style-src-imported-style-blocked.html": [ - "e59517d75d3fbc29b701ffa296b7dd007a05c79d", + "a7d3453f54478b773e4d5702a7d83f0a38664f19", "testharness" ], "content-security-policy/style-src/style-src-injected-inline-style-allowed.html": [ @@ -403888,6 +409232,10 @@ "76e9a5bdd43e13f9665135c7178dbca3114eb11e", "support" ], + "content-security-policy/support/fail.html": [ + "7825725abb38ec93b6d9122f05ea58f3b1bc4601", + "support" + ], "content-security-policy/support/fail.js": [ "90d888b42df7812ab893788918fac7cdaf27d1d6", "support" @@ -403924,6 +409272,10 @@ "53203da2c93399cdc4c3355a60d098c203cc7c85", "support" ], + "content-security-policy/support/nonce-should-be-blocked.js": [ + "ec8990a2902e37798bb3dc6b0ba66495066c6e6b", + "support" + ], "content-security-policy/support/pass.png": [ "c06160c04726a02f1583caa0f380d632b6019179", "support" @@ -403965,7 +409317,7 @@ "support" ], "content-security-policy/svg/including.sub.svg": [ - "4a7db45f8feeee77456ef0f837210b6f2f734a47", + "6e6534212bf7ac65d317b06ad7d9b719e6123b09", "support" ], "content-security-policy/svg/including.sub.svg.sub.headers": [ @@ -404112,192 +409464,248 @@ "ff4d7ca289ea20fa00bca535fdcf929876a2278b", "testharness" ], + "cookie-store/OWNERS": [ + "9e68d9eb0784e10786bd8b0c6009afb42516acdc", + "support" + ], + "cookie-store/README.md": [ + "f2c101203c2a2d82a4191164943e79734530d124", + "support" + ], + "cookie-store/cookieStore_delete_arguments.tentative.window.js": [ + "f33ce9a975c759ce6da8a5caa371ca026dd537c4", + "testharness" + ], + "cookie-store/cookieStore_getAll_arguments.tentative.window.js": [ + "cf818fe92c16dfe42f0ac778f665094533d8ab10", + "testharness" + ], + "cookie-store/cookieStore_getAll_set_basic.tentative.window.js": [ + "e6349dab874b99050cbbf5012db93de50612ce56", + "testharness" + ], + "cookie-store/cookieStore_get_arguments.tentative.window.js": [ + "944e71f01e0d9b9b00f36fff2b84d6a9b93538e1", + "testharness" + ], + "cookie-store/cookieStore_get_delete_basic.tentative.window.js": [ + "0b8c7725e0824d82c049a45e428a332212419bfd", + "testharness" + ], + "cookie-store/cookieStore_get_set_basic.tentative.window.js": [ + "7439e63ae3e5b06a43ab168ece73123f90712f25", + "testharness" + ], + "cookie-store/cookieStore_has_arguments.tentative.window.js": [ + "7512c46b8c7ec0b3ce33e3182671cc8c726a5e4e", + "testharness" + ], + "cookie-store/cookieStore_has_basic.tentative.window.js": [ + "c53d313cebc3970e28d87c69a5d13a1b5e81529b", + "testharness" + ], + "cookie-store/cookieStore_in_detached_frame.tentative.html": [ + "600452c1a496b8335b27bd24943b8834e37bf4d5", + "testharness" + ], + "cookie-store/cookieStore_set_arguments.tentative.window.js": [ + "27019d0e79b6754715a292f40e064de53daaf5e8", + "testharness" + ], + "cookie-store/cookieStore_special_names.tentative.html": [ + "d1cfe7619cc915b17dbf4d358363b16ec8ba9666", + "testharness" + ], "cookie-store/cookie_store_tests.tentative.html": [ - "a370f31b8f2c0953e0230f377f3a06b5f6c74d9e", + "245e7096ba810ae0c2311a801845ce0355f1ff75", "testharness" ], "cookie-store/cookie_store_tests.tentative.https.html": [ - "706f99692c2712fefc6555693bd8193ef824af2b", + "80e5f99d4e0b66f2d610c1f2826cb4553d532676", "testharness" ], "cookie-store/cookie_store_tests_static.tentative.html": [ - "b8c90332eb487b2084a0ca011d2acda868fc1a36", + "4c02698eec209e52ba2203f9e0a82d84a029ee0f", "testharness" ], "cookie-store/cookie_store_tests_static.tentative.https.html": [ - "92b427911ef551a8fe45ba9815806ece173dcf2a", + "3ab3e4103cc30105fbab3db789891309d0e76428", "testharness" ], "cookie-store/delete_cookies.tentative.html": [ - "f78bef2c934bac010d000331d69aa923a6c2d6fb", + "0ca53252ef4ee4609613775229d3365ad1ffeafc", "testharness" ], "cookie-store/delete_cookies.tentative.https.html": [ - "553e933c0aec3eacb23f02994f4ccf598391fc49", + "5c5323abea15eb3649fa9b8ccc5075964bcf157b", "testharness" ], "cookie-store/delete_cookies_static.tentative.html": [ - "8657475cda36f15a81a3aa83aff32d5eb680d05d", + "c2869a65f9ca8834e8b3e463ace14e651bafd4aa", "testharness" ], "cookie-store/delete_cookies_static.tentative.https.html": [ - "f5ad565786a1d54dc445ac7249cbb4159957df7c", + "77f4da0946bbe53224a33014dd17216fdd20a07d", "testharness" ], "cookie-store/document_cookie.tentative.html": [ - "336ba25988a44701027c7cfd70efa9f11d8a389b", + "6664e739c03c46c164cfc5dbfdb786123417e5a8", "testharness" ], "cookie-store/document_cookie.tentative.https.html": [ - "db08e7cbb72b5e1af56a58458fc0cff6415fbd91", + "a51cc13bdb5b92a535fee3fec1b130e3b27cbcba", "testharness" ], "cookie-store/document_cookie_static.tentative.html": [ - "d7844a369785a2150a81f95bba4bfe7fc4bfc687", + "1ea750d2ba36d4f90e2c586f3ead9d80d8b353ac", "testharness" ], "cookie-store/document_cookie_static.tentative.https.html": [ - "4af584983ef1c52accab44a23ad543bbd7291404", + "fbd6d1a628df1b8afa6941f2279697ff0a2677a8", + "testharness" + ], + "cookie-store/document_getAll_multiple.tentative.html": [ + "179f3ffe69715f9767ec2d2ef661c429fef52bc6", "testharness" ], "cookie-store/expiration.tentative.html": [ - "18435a38d1239d8b12b892018ea00e2fe0fd92f4", + "9bfb18862c9b9f6ace5f97ceb4f9d1da15eed64d", "testharness" ], "cookie-store/expiration.tentative.https.html": [ - "1c123dd08eb978ceb09263df4b512b5a321c132b", + "8f1aaa4a1b0ebf0c99f6d92f1e70e02d9a23c249", "testharness" ], "cookie-store/expiration_static.tentative.html": [ - "f71f95dec014e89bfaf8a26baf2d60c4d72a9611", + "7a308f48f5c51ddf4df04069259f7d3feff4cc8e", "testharness" ], "cookie-store/expiration_static.tentative.https.html": [ - "e7fe4735b9ccbadde6829e10109234bb7fa59328", + "d708add276da0fc58b6b628f05bacaa2965795ca", "testharness" ], "cookie-store/get_set_get_all.tentative.html": [ - "70e71c3cba821a1d97d53876b72bbd4ed0f6e976", + "dc66cbf2b2a939179cae29aaeb39cb44eb488e2a", "testharness" ], "cookie-store/get_set_get_all.tentative.https.html": [ - "61ec0e51fc907c4dd6186c8499cf0bdfd6aad8fe", + "8359d66bc5de963f57596033d29eca513f30ef79", "testharness" ], "cookie-store/get_set_get_all_static.tentative.html": [ - "4a339b426b1cc31af1d2b252fb728784de82c0c9", + "17f09f2aa4f41bdfc7e0541309ea36b6af232380", "testharness" ], "cookie-store/get_set_get_all_static.tentative.https.html": [ - "efc155bfff9280aa6b782270a99b32d4943e95d8", + "d8f03ba31699bfad79e4d4870208fa3ad94c261a", "testharness" ], "cookie-store/http_cookie_and_set_cookie_headers.tentative.html": [ - "93a9d4fbbda70461745f7f62f9b6fe23f73b0c7e", + "42c03466979c5e6d94803d5e69b6c07a595e9728", "testharness" ], "cookie-store/http_cookie_and_set_cookie_headers.tentative.https.html": [ - "95e61ca3ce90e4665f7061f7739c01772e6852fe", + "11c763dd1b7b3a1bff14b9f65538fb33ca97b81b", "testharness" ], "cookie-store/meta_http_equiv_set_cookie.tentative.html": [ - "99d220e96f28fbd4b3cef89323e687e18e95ccf4", + "6b7dc5aaa1f3c765c45886017163b70520e5f367", "testharness" ], "cookie-store/meta_http_equiv_set_cookie.tentative.https.html": [ - "b632f52614c1ffcd9e460282c2b6ddc6408b941e", + "c1d942ff3fb24b77fd659f9e60bd385bbbfe2279", "testharness" ], "cookie-store/meta_http_equiv_set_cookie_static.tentative.html": [ - "52973785d2e988fb6543c1aa8f4cd093e9075afb", + "991dae7d02c9c1f03842bd9f43fdc21bfbf9f261", "testharness" ], "cookie-store/meta_http_equiv_set_cookie_static.tentative.https.html": [ - "9d9d04519d9a4916b28f7567a830c3a96bf163ed", + "36d0c3672f44335eb6a0a294b55cf61b9efecd03", "testharness" ], "cookie-store/no_name_and_no_value.tentative.html": [ - "97068e2af8b42537e75990dbd9138de530dc8d5f", + "634ceaac54e40d7227772abb097f029ce901876b", "testharness" ], "cookie-store/no_name_and_no_value.tentative.https.html": [ - "bd1fdaa9c1e5266987d3b85bcecd5fe47fb2e6aa", + "c943068f523d6345abfeec24135438fc88fad8de", "testharness" ], "cookie-store/no_name_and_no_value_static.tentative.html": [ - "040357b08945c44bb8453deec5ed97393ecc8361", + "073a939169dafa7685c02ebdd51653d8f5c49df5", "testharness" ], "cookie-store/no_name_and_no_value_static.tentative.https.html": [ - "4e9a265483bbcc0469ecb22db4bb61a28ba7ae3c", + "a67b186ef0d5393c0bcf8dab8870a76384e14bcf", "testharness" ], "cookie-store/no_name_equals_in_value.tentative.html": [ - "189c847e82ff403f2d1836d88e2af8c5db345f3d", + "22273b9be0e44dc35a59b701733265d8f538aeb1", "testharness" ], "cookie-store/no_name_equals_in_value.tentative.https.html": [ - "cd6a35a4763ba7b0bca2d29a21b4800c5b6424eb", + "351b8ac618717bb7a8205cee65678a72a7df7450", "testharness" ], "cookie-store/no_name_equals_in_value_static.tentative.html": [ - "b12e7a43303372ddde410688e26ae027228dea09", + "84f03808a8c20ed1809c682982719c5fab1d6b34", "testharness" ], "cookie-store/no_name_equals_in_value_static.tentative.https.html": [ - "f1ee338299654bb44f4e867dcbacd3aafe4acef5", + "cb98e1c8c370e1415dd51cec75be7c4f1c933a18", "testharness" ], "cookie-store/no_name_multiple_values.tentative.html": [ - "7e65cf3f0ed8e5e2722279805a34ed95444413d5", + "864d3955cf9a92ec4bddf00b19fdb471c691e3cd", "testharness" ], "cookie-store/no_name_multiple_values.tentative.https.html": [ - "0b5bd1414b928dedaa72db393a0a7bc79bb04f98", + "e4671297e2474c38e73cd76268f7cdd53eb46b28", "testharness" ], "cookie-store/no_name_multiple_values_static.tentative.html": [ - "daebad2df149f4b79998d7e10d51c27d34596487", + "2bb6d547e7ac220a1c36172dfd2c59e36b49c520", "testharness" ], "cookie-store/no_name_multiple_values_static.tentative.https.html": [ - "3e45ea4cde17c549f8761e143472e0862797fd6d", + "e10639064527c376420fb51cc5ef5137069dec7b", "testharness" ], "cookie-store/observation.tentative.html": [ - "f2b16274bdd2c2f2117a0bfa126ae2d783211169", + "e0029a6a2cbe1e696cc3afeae9c30b245218d672", "testharness" ], "cookie-store/observation.tentative.https.html": [ - "06f7ca48269b7bdc9a408c99df687e3af1eae5c4", + "954a81b8bac1fae57b8074ca3f15210806622bfb", "testharness" ], "cookie-store/observation_static.tentative.html": [ - "8137d847b0d091dfb6a0cec6275942fb5234b296", + "8f6c1a6cc4e671162c6aa7d26d829dc9866d69bd", "testharness" ], "cookie-store/observation_static.tentative.https.html": [ - "6779d29a8e11c88f8adf2327c54b397d8d5b3fd9", + "007ec0bb007aa3b2d6855e9364ea0d8e269999a2", "testharness" ], "cookie-store/one_simple_origin_cookie.tentative.html": [ - "56737fe668c83b89b967c8a9edbbcbd314a7c087", + "f96fb6627746fd1e586d959249b28886ea8ba504", "testharness" ], "cookie-store/one_simple_origin_cookie.tentative.https.html": [ - "943f3a50da17574a393af9a18c791b80c9f6209e", + "b31ea6c06f2e5ecaabdaa3e28efef0e012a65cb4", "testharness" ], "cookie-store/one_simple_origin_cookie_static.tentative.html": [ - "f28f4dfd2cac6be784ff106080d59962d6a1d2f8", + "d9064910e2771a2ea5337f5470299c71d831b62a", "testharness" ], "cookie-store/one_simple_origin_cookie_static.tentative.https.html": [ - "4d8ffa9f27e62e5893777b8a6c35a97fa002709b", + "15449e84b8a2854243b0efabca7e893d1ab427dd", "testharness" ], "cookie-store/resources/cookie-store-tests.js": [ - "5d779c03a170a2a3fe210c28c027b90d7e74dbda", + "5f314a536820d78418a558e588af478154e33369", "support" ], "cookie-store/resources/cookie_helper.py": [ @@ -404305,17 +409713,45 @@ "support" ], "cookie-store/resources/testharness-helpers.js": [ - "ace8944b16bb4b7d1b2261b4f8ef549daff7fc7e", + "b7bc4516ad4ac7ae1bb572191c0c3932c29eb863", "support" ], - "cookies/path/echo-cookie.html": [ - "cbb91823a75f6e5c5ae435c5bc4c3b15a09c483e", + "cookie-store/serviceworker_cookieStore_arguments.js": [ + "a90956237d63fd51556f2d9e50967522870816d4", "support" ], + "cookie-store/serviceworker_cookieStore_arguments.tentative.https.html": [ + "3b74e70504793eb570fd15851fac53146af4b86d", + "testharness" + ], + "cookie-store/serviceworker_cookieStore_basic.js": [ + "38fe0bc6fbf08e5387f81e32348252c481af03c0", + "support" + ], + "cookie-store/serviceworker_cookieStore_basic.tentative.https.html": [ + "0700dc72bc1e00832546d4a6826a5474600af06c", + "testharness" + ], + "cookies/OWNERS": [ + "15417c1a9e90762ae826b0258fe3619cc6a78b0e", + "support" + ], + "cookies/README.md": [ + "1949878db1be4093ec8d9595710f9fd8887434ba", + "support" + ], + "cookies/meta-blocked.html": [ + "1ece2f38a340ff4ff4713ada5568281d0e1c5be2", + "testharness" + ], "cookies/path/match.html": [ - "f0a64d36154617213cbe846eb5ef0c93f7a65556", + "a54ac9afd9c176da2c8844389feb3cb0150fcf5c", "testharness" ], + "cookies/resources/echo-cookie.html": [ + "ac15291ad85804f61bf690525bad958bb2672ca0", + "support" + ], "cookies/resources/echo-json.py": [ "c5b3d11bdfc3a4092d0ed53648d58e0e3bbd2d91", "support" @@ -404352,7 +409788,7 @@ "b1b6ee4d317f108574453da7410f91d52eecdf83", "support" ], - "cookies/secure/set-from-ws.https.sub.html": [ + "cookies/secure/set-from-ws.sub.html": [ "2d60b86d8beaa5b3329c804949c7ee0d51d929c3", "testharness" ], @@ -404433,7 +409869,7 @@ "manual" ], "core-aam/aria-checked_value_changes-manual.html": [ - "1b60088a1e7441cd4074fec2f674d9f055e5841e", + "ab6b990cc593eb6f135b78af886b41e4a69fb752", "manual" ], "core-aam/aria-colcount_new-manual.html": [ @@ -404525,11 +409961,11 @@ "manual" ], "core-aam/aria-expanded_value_changes-manual.html": [ - "4695aed01e4473c45e723f1e21bfff74c1231a98", + "b1e42b76a3088ce00494366f53a5d696d4ee914e", "manual" ], "core-aam/aria-flowto-manual.html": [ - "ab781f7aed85fbb840bb3b38e1b16897d0cb9b20", + "aa2b63438ffe1ce2dad9073cd0065f70b4002630", "manual" ], "core-aam/aria-grabbed_false-manual.html": [ @@ -404673,7 +410109,7 @@ "manual" ], "core-aam/aria-owns_may_need_manual_verification-manual.html": [ - "13e3796ff854b458a0319709f04f1aae2a11f39a", + "4c6e3d6fedc2ed371b957e99c286c78983d19898", "manual" ], "core-aam/aria-placeholder_new-manual.html": [ @@ -404737,7 +410173,7 @@ "manual" ], "core-aam/aria-roledescription_is_empty_or_whitespace_characters_new-manual.html": [ - "3962c1149025fb57e6e2ab3968c945f34a8d93f4", + "00496d1c81b91a2431606f4452a6084e312b0a81", "manual" ], "core-aam/aria-roledescription_new-manual.html": [ @@ -404801,7 +410237,7 @@ "manual" ], "core-aam/aria-valuenow_value_changes-manual.html": [ - "25b56657fd81c6d75967b4e70e304d6c6e001e1e", + "313c1fa7c20afbc3047ab251ed32b860b5d5e15f", "manual" ], "core-aam/aria-valuetext-manual.html": [ @@ -405125,7 +410561,7 @@ "manual" ], "core-aam/progressbar-manual.html": [ - "c4fd3f1c2a0762700aa7b05dff80b47123fdc2c5", + "0d0e4c44b9e953a00898a4c57a507bd976fa4aeb", "manual" ], "core-aam/radio-manual.html": [ @@ -405141,7 +410577,7 @@ "manual" ], "core-aam/region_without_an_accessible_name_new-manual.html": [ - "a2a6f7766fe0b57726b6f7fb76de982b5830d510", + "2e89a57d2f7edd723224cc80695d57af2543b5b1", "manual" ], "core-aam/row_inside_treegrid-manual.html": [ @@ -405161,7 +410597,7 @@ "manual" ], "core-aam/scrollbar-manual.html": [ - "1cec55790cb5b7394872df2b9003fde85b0ba176", + "a62bdc1ae12a5683d033925934287e44e4a3b94c", "manual" ], "core-aam/search-manual.html": [ @@ -405181,11 +410617,11 @@ "manual" ], "core-aam/slider-manual.html": [ - "07890401b354c4374c234567296e6e3e8002b5da", + "b30c6f0835349083b3d8e5b4f45433cea928b26b", "manual" ], "core-aam/spinbutton-manual.html": [ - "d1b86e8184d1f4bf0120c14314d38b2b21db6155", + "d206a25f2379cd22b2394f92b4a52ac388e4667e", "manual" ], "core-aam/status-manual.html": [ @@ -405385,13 +410821,33 @@ "support" ], "credential-management/credentialscontainer-create-basics.https.html": [ - "ee1e63bbe0d74a932650c2c32ed26d7ca41e1c7d", + "4889217f5e821965907d4d60a9ffdd19d4bc79af", + "testharness" + ], + "credential-management/federatedcredential-framed-get.sub.https.html": [ + "561636e62d50da2d14e50516c62cbaea1c5bb924", "testharness" ], "credential-management/idl.https.html": [ "e9a108beef51c52bbaaf2e53371aec57e69541c0", "testharness" ], + "credential-management/passwordcredential-framed-get.sub.https.html": [ + "3ce3b0a2eaa10928aec1f32c9e3bcbe2af5fafba", + "testharness" + ], + "credential-management/support/echoing-nester.html": [ + "408bf741f31a9f69a2a9a50d93877f6a999cd9d9", + "support" + ], + "credential-management/support/federatedcredential-get.html": [ + "59b8314b8cb9044bfccf6a2a0e520a879fdf9f66", + "support" + ], + "credential-management/support/passwordcredential-get.html": [ + "cfed192579bfc57c2d266b9d4f30b669c3fccc0c", + "support" + ], "css/.gitignore": [ "3f645ca3bf6a77220d48e3e07b6dc3e1653d883c", "support" @@ -407337,7 +412793,7 @@ "reftest" ], "css/CSS2/backgrounds/background-color-030.xht": [ - "9e0fe96277f3ecbf27b966e7484e600f26bc946a", + "1ee6e42bf37f7ecd91e6bd7b962cc52413dd534f", "reftest" ], "css/CSS2/backgrounds/background-color-031.xht": [ @@ -407989,7 +413445,7 @@ "reftest" ], "css/CSS2/backgrounds/background-color-174.xht": [ - "b81fb760dd55ffac95b733cb2d6ca7034c502cc7", + "c42029d2c4d36d343bb75c7e12134008a8a4f838", "reftest" ], "css/CSS2/backgrounds/background-color-175-ref.xht": [ @@ -408085,7 +413541,7 @@ "reftest" ], "css/CSS2/backgrounds/background-image-002.xht": [ - "12608a885087556cbf0ac4bd5d7e75756cb522c6", + "d828cc277fdfd302c8dc371d29138277a1043a41", "reftest" ], "css/CSS2/backgrounds/background-image-003.xht": [ @@ -419141,7 +424597,7 @@ "reftest" ], "css/CSS2/colors/color-083-ref.xht": [ - "185b1887a6a4a8102f9f6ce5fb395fcb1598967b", + "314b144d6b2d0aecd2f53b419ff24a55181a31fe", "support" ], "css/CSS2/colors/color-083.xht": [ @@ -424032,6 +429488,14 @@ "040b4663df4744881121a6f88756cf562bedc50a", "visual" ], + "css/CSS2/fonts/font-148-ref.xht": [ + "9470c3fd45cff44705702939516ef69348bad4a5", + "support" + ], + "css/CSS2/fonts/font-148.xht": [ + "1520e8283eb0769fba63e9dda3f0b8b0b6a8da00", + "reftest" + ], "css/CSS2/fonts/font-applies-to-001-ref.xht": [ "e4c2fbe9a73859fb46ff14ce2d6f4401aca9d783", "support" @@ -425664,25 +431128,37 @@ "f5aa12ce214ee0b04a4e43248b990f95be97ece8", "reftest" ], + "css/CSS2/generated-content/after-inheritable-001-ref.html": [ + "31930c4d11b3f4afc155fd3a2a6cd7e0d376bb59", + "support" + ], "css/CSS2/generated-content/after-inheritable-001.xht": [ - "39d768f9b5cafe0a283d99395b2b6c7950202387", - "visual" + "5b82f2a029d5fea4fb52e66b83bb26b3ee8a5407", + "reftest" + ], + "css/CSS2/generated-content/after-inheritable-002-ref.html": [ + "6a8902b2e38e799bd4516c04ab1b01e4eb055145", + "support" ], "css/CSS2/generated-content/after-inheritable-002.xht": [ - "7996c7ca5f496c41382ce154d74a8f1014cd80b4", - "visual" + "6faa8965a8fb8e662c77bb14b06424a92aa65a74", + "reftest" + ], + "css/CSS2/generated-content/after-location-001-ref.html": [ + "646907ab4468bf43ee30e1ca353b1cd4efe8c820", + "support" ], "css/CSS2/generated-content/after-location-001.xht": [ - "19df667583b6d3a485ea7e8e0df15e5ac8a8614e", - "visual" + "d969663cc21c4af514775eea9951169aed497850", + "reftest" ], "css/CSS2/generated-content/before-after-001.xht": [ "983f20158f5653741e31e47b1e0bc866a8c26d52", "reftest" ], "css/CSS2/generated-content/before-after-002.xht": [ - "cea0b058b3c03ad494203e0bcc1873f056bb714a", - "visual" + "1f6aed90dd4e09b998b913340a567605c7afe961", + "reftest" ], "css/CSS2/generated-content/before-after-011-ref.xht": [ "72e71292a7df5b9a1a331254ce8c73237ebdf7f7", @@ -425849,348 +431325,564 @@ "reftest" ], "css/CSS2/generated-content/before-inheritable-001.xht": [ - "6f51b953584ad5a49dc11a6708545d8e18d0a9c1", - "visual" + "6d57c8a72b38e751272fad7bcf1ac374e53fe9aa", + "reftest" ], "css/CSS2/generated-content/before-inheritable-002.xht": [ - "63b9021bbf0b17ee036967c1dc49723dc1eb063a", - "visual" + "7b9a71f88f52594315361deec12d9edf25d21df7", + "reftest" + ], + "css/CSS2/generated-content/before-location-001-ref.html": [ + "4a53e1180a69dae0d67cff4df345758378ea0e63", + "support" ], "css/CSS2/generated-content/before-location-001.xht": [ - "7820bcf75995b761c9ef1aeba78c4a0117fd5fe6", - "visual" + "398d7d80114075a0d3eb2b2c03c6f14b6cd013fa", + "reftest" + ], + "css/CSS2/generated-content/bidi-generated-content-001-ref.html": [ + "839ce12dc8d07ec2a33c2ed2ed66cdeac0aa902c", + "support" ], "css/CSS2/generated-content/bidi-generated-content-001.xht": [ - "147176473aa56d200a2d4400fe476c2d78850312", - "visual" + "7cf0ae8a07a01eea46d28095b8f1aa85be1f6f4b", + "reftest" + ], + "css/CSS2/generated-content/bidi-generated-content-002-ref.html": [ + "8824d77b3266e1fd40b7c1ed59dfa0cc56a5fb9d", + "support" ], "css/CSS2/generated-content/bidi-generated-content-002.xht": [ - "e7c38d8e6c9347720ec18e134ec02c994904365c", - "visual" + "e3bbe0f13e25353f8eb9f54038ff64f306032d75", + "reftest" + ], + "css/CSS2/generated-content/content-001-ref.html": [ + "93a9c212d449144e303f708a1d72346bcf83dd07", + "support" ], "css/CSS2/generated-content/content-001.xht": [ - "a1e2c7403bb38d914d75ce20a62cf34ae86a589c", + "4ce4769352e20029ea31afeebe45a9ef7bf194ff", "reftest" ], "css/CSS2/generated-content/content-002.xht": [ - "3b347a4ac345610c51f04540a75fe07221e196a4", - "visual" + "c6d49cf18b8094de65776e1deccb8d177123dd3d", + "reftest" + ], + "css/CSS2/generated-content/content-003-ref.html": [ + "5818d7301c754c2bafe11d3b1a6a5ec79b07b19b", + "support" ], "css/CSS2/generated-content/content-003.xht": [ - "14d906642d5324d77acfa4817d63c3c22ecdee03", - "visual" + "117764df465bd2bbf22d39b6f1a1ad209c4ff34c", + "reftest" ], "css/CSS2/generated-content/content-004.xht": [ - "53fdc7d929fc457d2bf573be9e59165c55808fc3", - "visual" + "21997d31183dc6961f23989f4b12fe90691dad86", + "reftest" + ], + "css/CSS2/generated-content/content-005-ref.html": [ + "22bb38fe67f503dd7aa5fec0e20352af0c85d00b", + "support" ], "css/CSS2/generated-content/content-005.xht": [ - "ec5833380097c44dfa69ee5203cdc48f3acd816a", - "visual" + "8ee433c9daff5151f3c3f52fc27922d6f7a388a5", + "reftest" + ], + "css/CSS2/generated-content/content-006-ref.html": [ + "3c6876aef8774cfa74e9971dfde4c3ec0da158a5", + "support" ], "css/CSS2/generated-content/content-006.xht": [ - "ab7ab5b6a454651b999f73646ff5b20745b3a8c0", - "visual" + "aa16a2cb5927b546d8f09fd562a124fcc3385054", + "reftest" + ], + "css/CSS2/generated-content/content-007-ref.html": [ + "1660a6b021adc24afeb52310aaee0bcac6397989", + "support" ], "css/CSS2/generated-content/content-007.xht": [ - "fee3a5c4c9d6e5d81e4158c16ba2bd25ba7028be", - "visual" + "338f7087bafa52754e0592d26693095b61a03ec8", + "reftest" ], "css/CSS2/generated-content/content-008.xht": [ "3770e069a5b6a715cafb661af0ee44466b91e791", "visual" ], "css/CSS2/generated-content/content-009.xht": [ - "37ccb387b372b9077956072af6bf817820a43bba", - "visual" + "926489232d05e398ad7c7c50a20283d2e5dec918", + "reftest" + ], + "css/CSS2/generated-content/content-010-ref.html": [ + "4adda8b8a32a4a050175ae27a54da774ce553c39", + "support" ], "css/CSS2/generated-content/content-010.xht": [ - "5c4856460e89aa1b5a147082680f5828b413cc37", - "visual" + "52f5f24bcb4ada8bf4d9438621b96f409ff715f2", + "reftest" + ], + "css/CSS2/generated-content/content-011-ref.html": [ + "f717c9ae23b12737878dc5d97fea9b8a5ac0ac47", + "support" ], "css/CSS2/generated-content/content-011.xht": [ - "741b60f98e5e3c5f97eedec19dd56a8b3e7cc787", - "visual" + "4ebde6055cd2c7276ae16618c1df8f0cf31aa0f5", + "reftest" + ], + "css/CSS2/generated-content/content-012-ref.html": [ + "05f93132e832d9344022267ca6e9522553686053", + "support" ], "css/CSS2/generated-content/content-012.xht": [ - "214b59371e4749d459bb9439b5ff8c2d7ba68d9b", - "visual" + "181ef189694fd15289f92b4c2165fb33ce86a447", + "reftest" + ], + "css/CSS2/generated-content/content-013-ref.html": [ + "b9de627614b112803aec90f7a73bdce794bd76dd", + "support" ], "css/CSS2/generated-content/content-013.xht": [ - "212751b945f41da74f72f48d2d0282aba3733b7f", - "visual" + "0864b92a8885099c7959c7853e9516aa42a5b563", + "reftest" + ], + "css/CSS2/generated-content/content-014-ref.html": [ + "543ef35a8221d4379ff0710bf9deb1cc7dc91914", + "support" ], "css/CSS2/generated-content/content-014.xht": [ - "a2fa5bc09d08820da4091b5178c6cdfe04b7b221", - "visual" + "1a95c6e9079c0116fbcc31f7a7698de9d130e74f", + "reftest" + ], + "css/CSS2/generated-content/content-015-ref.html": [ + "826552c48dc4e1d3e044a6f2cec68ebe660787d9", + "support" ], "css/CSS2/generated-content/content-015.xht": [ - "e199bdfae50d1c3d66caaed8eab5e13adf9e2291", - "visual" + "ac3f726c3c99ed2dd043eb552e545f257300cb73", + "reftest" + ], + "css/CSS2/generated-content/content-016-ref.html": [ + "ba303e06fd91d2d07a518f16ea75af0b1c4593c9", + "support" ], "css/CSS2/generated-content/content-016.xht": [ - "a8c1772ab662bb0b76477926fb4b383830c4ac69", - "visual" + "c76a77d3459cb8e3e2e38e772e489bb661cfaa7b", + "reftest" + ], + "css/CSS2/generated-content/content-017-ref.html": [ + "df027694d825f1d0716e48b19dab17a50dd09c63", + "support" ], "css/CSS2/generated-content/content-017.xht": [ - "181338f2fb322ffddaf34452f3999aa60919cb6b", - "visual" + "00cf1b752bf5b543bb9c44f9ba7e254e1d23987a", + "reftest" ], "css/CSS2/generated-content/content-018.xht": [ - "c120672727fe40f5e0cad473acf19814bb9acfa0", - "visual" + "b380a9bd79aa112365c5cd5eae6e15c1062194eb", + "reftest" ], "css/CSS2/generated-content/content-019.xht": [ - "d8c76bebee3c841798b04689890c0786304f89b3", - "visual" + "54a8f681e366a9c7b55626022085a27a09f54517", + "reftest" ], "css/CSS2/generated-content/content-020.xht": [ - "20b5bdaecf1868aac94fee9e75b6677587218dd5", - "visual" + "50e31e8432f235f2934bf0b6e8efc44ce36c370c", + "reftest" + ], + "css/CSS2/generated-content/content-021-ref.html": [ + "5e5b948acdae134afa74c8d37f80bea17d57eae0", + "support" ], "css/CSS2/generated-content/content-021.xht": [ - "bc80777ed501696c6c0fd074f004c2393e73e0e3", - "visual" + "eb42cda01574eff595d74c90b1f6768271cc965f", + "reftest" + ], + "css/CSS2/generated-content/content-022-ref.html": [ + "96bc3b3586262089474cf4cb3aa10bb3f842756c", + "support" ], "css/CSS2/generated-content/content-022.xht": [ - "26d4e35551a3f1176563581df5547686b9a1fbb0", - "visual" + "44e1524f55081bdfdcea42f20ea082568341c663", + "reftest" + ], + "css/CSS2/generated-content/content-023-ref.html": [ + "0359aef7ae2a2189581f19eb8ebeac5b975e5db2", + "support" ], "css/CSS2/generated-content/content-023.xht": [ - "51715072e84329216fd1ccb9cdedcff1d5fc3f18", - "visual" + "35e0bc59499836398520ee4b7b7c877f142630d8", + "reftest" ], "css/CSS2/generated-content/content-024.xht": [ "10efece3a5c890164161a9bc3e72b6ee71be397c", "visual" ], "css/CSS2/generated-content/content-025.xht": [ - "e53e136793f9edd724bc744d85b4382af318d88f", - "visual" - ], - "css/CSS2/generated-content/content-026.xht": [ - "b5a04d2916a376d51bed18ae3f04cd8a323a1c6d", - "visual" - ], - "css/CSS2/generated-content/content-027.xht": [ - "e9002676f06e5e10aca8b71f36e379c2657ae30e", - "visual" - ], - "css/CSS2/generated-content/content-028.xht": [ - "1c906d005941683b6c42ea8b8332b04b4dde87a8", - "visual" - ], - "css/CSS2/generated-content/content-029.xht": [ - "54f4b50b857ca248fe9c65112c3a4095dbed6426", - "visual" - ], - "css/CSS2/generated-content/content-030.xht": [ - "9e8a118f741d55a0530f540cfb802e40ff654d09", - "visual" - ], - "css/CSS2/generated-content/content-031.xht": [ - "ddc2214e9105c0aae96669d312f444693e3a85cc", - "visual" - ], - "css/CSS2/generated-content/content-032.xht": [ - "9c3de37f82b299b68ee11f10e824e42487104da4", - "visual" - ], - "css/CSS2/generated-content/content-033.xht": [ - "b4ded13cd6ec12cf8ace6754efaf05c1e89bab28", - "visual" - ], - "css/CSS2/generated-content/content-034.xht": [ - "21c8472ca8ae11d70068bdb599811a0734ba8f7c", - "visual" - ], - "css/CSS2/generated-content/content-035.xht": [ - "0ce2c23a32794c8e2ecb281d14e52375c0212751", - "visual" - ], - "css/CSS2/generated-content/content-036.xht": [ - "8bcf7ef6ed2ce487e69f29c22a551d2e4eb13122", + "550ca31894f42c2c6f7fbc1b88ad0061675d953d", "reftest" ], + "css/CSS2/generated-content/content-026-ref.html": [ + "3b200a8ae2e285aa16a5047d35137c5f6740610e", + "support" + ], + "css/CSS2/generated-content/content-026.xht": [ + "6d4cece80b6c51204f2c67fd5eca7aeb51955957", + "reftest" + ], + "css/CSS2/generated-content/content-027-ref.html": [ + "879f868bc759b40f3a7fccfc6a16059353943786", + "support" + ], + "css/CSS2/generated-content/content-027.xht": [ + "41158698b7ee2c739e1662a97e575522e915b309", + "reftest" + ], + "css/CSS2/generated-content/content-028-ref.html": [ + "d1177c25bf3b2dd88aed726ae80588b7bbcbfb76", + "support" + ], + "css/CSS2/generated-content/content-028.xht": [ + "5a96e52e350ec3430afcebbd3814ebb6ce016c46", + "reftest" + ], + "css/CSS2/generated-content/content-029-ref.html": [ + "8ed7eb2b13d5706f7b22d6558e5a0e730385737a", + "support" + ], + "css/CSS2/generated-content/content-029.xht": [ + "a017cb5dc161aa360491a6cfb73af24b10d6ff13", + "reftest" + ], + "css/CSS2/generated-content/content-030-ref.html": [ + "9ca0d2b85476c4c09f79fecb97550929f6a77952", + "support" + ], + "css/CSS2/generated-content/content-030.xht": [ + "c0d8d1340786d83caf40fad6761661f8bfc1fc7f", + "reftest" + ], + "css/CSS2/generated-content/content-031-ref.html": [ + "5c300548e9b351318caf1386db375a09eae74f4d", + "support" + ], + "css/CSS2/generated-content/content-031.xht": [ + "0f62044d086fb070be37a9c5de4678ee087f9e59", + "reftest" + ], + "css/CSS2/generated-content/content-032-ref.html": [ + "deed41afc9c76923db16f4e351684474423ca96b", + "support" + ], + "css/CSS2/generated-content/content-032.xht": [ + "5c6e1c2c116425235e140cfa143af3424c49e422", + "reftest" + ], + "css/CSS2/generated-content/content-033-ref.html": [ + "af29f781fa1ca5a27e57e11a38ad8191b982e9b3", + "support" + ], + "css/CSS2/generated-content/content-033.xht": [ + "599e3bd6d66ad6e74595d5a30f98ec3a4c65d82a", + "reftest" + ], + "css/CSS2/generated-content/content-034.xht": [ + "0257b3ae5475f02121d6a6978ee6379fcc618623", + "reftest" + ], + "css/CSS2/generated-content/content-035.xht": [ + "739bfad28f7e62a4cdf6ad7a788d0b927ce9a0b4", + "reftest" + ], + "css/CSS2/generated-content/content-036.xht": [ + "e680f99e5671de0a762a2ca5b3b2e7aa09f330be", + "reftest" + ], + "css/CSS2/generated-content/content-037-ref.html": [ + "c76cc63fc5f36f4e76653ef8f0d7d8be5277fc6c", + "support" + ], "css/CSS2/generated-content/content-037.xht": [ - "a63c9f042e04a27af77b067f277f1bd9b9cd2e59", - "visual" + "c2ce76e7979c49c1549a705399aa56318016679f", + "reftest" ], "css/CSS2/generated-content/content-038.xht": [ - "6a6d611b02e02ae216fdc66444f4d2738a950509", - "visual" + "9a14fbd8c1e1a82953711dc5d2f695b5d67a6691", + "reftest" ], "css/CSS2/generated-content/content-039.xht": [ - "7e5164cfa7c70dceb46a300a82e8334e0e7caec3", - "visual" + "28951d4bdf7b44f7402f16ac972fa554e9906078", + "reftest" + ], + "css/CSS2/generated-content/content-040-ref.html": [ + "ecf41fb1f3395c1eb2b8fb56758c857623c85e60", + "support" ], "css/CSS2/generated-content/content-040.xht": [ - "fbbc6e5198621db722ea0aa3f615795c470fd28a", - "visual" + "b5ab90ad8e509840667b36dc83c23054795081e1", + "reftest" + ], + "css/CSS2/generated-content/content-041-ref.html": [ + "fbf3ce185004461878f9bfbbdaaf767f558893a1", + "support" ], "css/CSS2/generated-content/content-041.xht": [ - "0883dba7ee1badc06107161f1676f01462a878b6", - "visual" + "7759d9a42ca36d78ed16dae70ba3628c1bea1d40", + "reftest" + ], + "css/CSS2/generated-content/content-042-ref.html": [ + "a386fcddc0374a4e1af91120497b710d5978251e", + "support" ], "css/CSS2/generated-content/content-042.xht": [ - "9c2f61cf8021a084f9c49216e60b2e464f6ba2dd", - "visual" + "30541d06303ab8bc5e9e3e3de38710fb4b4f7c75", + "reftest" + ], + "css/CSS2/generated-content/content-043-ref.html": [ + "743d51de79b34d1fa3a968cb74ad276c987ee1be", + "support" ], "css/CSS2/generated-content/content-043.xht": [ - "61132ef01363d09ae0f1231dc921bf42fcc3aad2", - "visual" + "1b15927db3f9ddbf9e3505ee9366248435775dd5", + "reftest" ], "css/CSS2/generated-content/content-046.xht": [ - "4e9449dc08d1b89b810b31ead6edc9444eac4341", - "visual" + "40dd644e4dd5e53dbe64e201d642a12b66b60203", + "reftest" + ], + "css/CSS2/generated-content/content-047-ref.html": [ + "b0ab85d0ce594bfc1cde1e18197bc4b05f5f4cea", + "support" ], "css/CSS2/generated-content/content-047.xht": [ - "ffb5b0dee84d27f63e392f6a96407e41be5168ff", - "visual" + "9b6b48213c74d8fa872d06b601511c9a14b23908", + "reftest" + ], + "css/CSS2/generated-content/content-048-ref.html": [ + "1229f7ea7299fd5da63258fb5499437182f723bb", + "support" ], "css/CSS2/generated-content/content-048.xht": [ - "cfb2eaf73a19c1bb87ff750f0087190d0b47c486", - "visual" + "7f40b8c09bdea5f7d418cd6039293fa2abf14fa7", + "reftest" ], "css/CSS2/generated-content/content-049.xht": [ "e8e22935c15c5e3e7630b127f6cc1beca6045dbf", "visual" ], + "css/CSS2/generated-content/content-050-ref.html": [ + "6eb034f12c30a7e0c84cb3c39fbdd3651f87f80b", + "support" + ], "css/CSS2/generated-content/content-050.xht": [ - "6e203fa1ba4145d12cdee485838a07789ad0c2e0", - "visual" + "e9555b95a424c5336b8801d19bc27b3d077fa31a", + "reftest" ], "css/CSS2/generated-content/content-051.xht": [ "2c93ec9775d6eb6a48afe4ac6b99a04f0b2010da", "visual" ], + "css/CSS2/generated-content/content-052-ref.html": [ + "dfe0e1de0057ba29e659e70fd43a4a087992478a", + "support" + ], "css/CSS2/generated-content/content-052.xht": [ - "169705cf0437c9443461cf43315401ea17b86c8a", - "visual" + "5b1aee2698b432e1f989c8af620796b8bf607eea", + "reftest" + ], + "css/CSS2/generated-content/content-053-ref.html": [ + "f15be1a7dda4372a0aebf05be4b19d9096104865", + "support" ], "css/CSS2/generated-content/content-053.xht": [ - "6872d2b4f196ba7798df752199cef64c77f532de", - "visual" + "bdbd119ec900516a0f740cdbbe2a8c1b185ab645", + "reftest" ], "css/CSS2/generated-content/content-054.xht": [ - "b7515674ecd0d1b73ee6b623a9fdd47f6783cf09", - "visual" + "2aa0d9feeeb9d2dc11046ca2a3103d9444a3616c", + "reftest" ], "css/CSS2/generated-content/content-056.xht": [ - "b21aadc4b6dc60bddf3a0f873fa89c06c874f5d5", - "visual" + "2ef418a9da41cb3fec3c57ad0bff13bece26d9eb", + "reftest" ], "css/CSS2/generated-content/content-057.xht": [ - "b70de2922b0d0f38dca52bfcbacfca050303646f", - "visual" + "5229125f5dba23adae84e7dc6527df1c56cd78aa", + "reftest" + ], + "css/CSS2/generated-content/content-063-ref.html": [ + "58d7f0ba6b947822a01fce09550ac8d58cba35e3", + "support" ], "css/CSS2/generated-content/content-063.xht": [ - "87fa18402bfa277b8dade28c82214ac0272c2c32", - "visual" + "efd852940a661635aedef1cf02db0a1994c7bceb", + "reftest" ], "css/CSS2/generated-content/content-065.xht": [ - "f1f5391d2f0189a797adb7274a486b4f04920bd8", - "visual" + "401ff2e38c88f277ef3c1260c60d94d44849c383", + "reftest" ], "css/CSS2/generated-content/content-066.xht": [ "5d3a82eaa195d0f51c46986816d6fda6f9eb9244", "visual" ], "css/CSS2/generated-content/content-067.xht": [ - "bf9937a869f2246442c212efe8716db9f0f251ff", - "visual" + "856fba5ec96fb16d8cca26801835255a55172066", + "reftest" + ], + "css/CSS2/generated-content/content-068-ref.html": [ + "d339dca8b16a0f36c8a20931a487609aacefc5cf", + "support" ], "css/CSS2/generated-content/content-068.xht": [ - "0ece41a5b5d229016d10cd75b2986b9cf6ef101f", - "visual" + "542fb2c65fd75d6842c35da306d26f6465717bf5", + "reftest" + ], + "css/CSS2/generated-content/content-070-ref.html": [ + "6dfdade2b1e132c2dd25b88443305ade7e62900a", + "support" ], "css/CSS2/generated-content/content-070.xht": [ - "2ceab78104c8e49a115b3818d7ff373168d69bdb", - "visual" + "6086e831ebf324e4a871fdb684d13feedb53675d", + "reftest" + ], + "css/CSS2/generated-content/content-072-ref.html": [ + "463e7ee546a4067f322a88582f3b9d147dd4faf5", + "support" ], "css/CSS2/generated-content/content-072.xht": [ - "31ed9dc7725aeb0dd9279e4c946c143111ace418", - "visual" + "fd1d10397fa8308332f3dcec0ca75bb02a399a41", + "reftest" + ], + "css/CSS2/generated-content/content-073-ref.html": [ + "e3f703e323482f230146824ef83d2db369462f56", + "support" ], "css/CSS2/generated-content/content-073.xht": [ - "dd994d7a6051582295c9f1e4f20daf0110669a0a", - "visual" + "bc4e2d4e21ecccb68ed31283a9970f5d18465fca", + "reftest" + ], + "css/CSS2/generated-content/content-075-ref.html": [ + "661e739a38e1173a6745e2f52d0437b35ef7b19f", + "support" ], "css/CSS2/generated-content/content-075.xht": [ - "13b6235db663ed80aa7e5d2f175133407036a01a", - "visual" + "733eaaf078eed89c182f42278da5c05a59bb8090", + "reftest" ], "css/CSS2/generated-content/content-076.xht": [ - "398946563f71f1fb45a900dbdc16c22e7165377c", - "visual" + "41774972bafc2815ca9ec1fc66286d60998ab10e", + "reftest" ], "css/CSS2/generated-content/content-077.xht": [ - "7df5236558794e41c5986e141da3d88f5dd84c86", - "visual" + "a0f5aed7a09062f7f554db78badfa4a0f3cab9c0", + "reftest" ], "css/CSS2/generated-content/content-078.xht": [ "1e4d5027858c09a1f020a6043092ca75839cb05d", "visual" ], + "css/CSS2/generated-content/content-080-ref.html": [ + "789dac38a057e2d3f874ed847116a08808dbddb5", + "support" + ], "css/CSS2/generated-content/content-080.xht": [ - "331353d73e1d0169c56f3be2813dbe0b617907cf", - "visual" + "78a19448df490617c45920895bb9cd2e501e6011", + "reftest" + ], + "css/CSS2/generated-content/content-081-ref.html": [ + "641518632420ac6281381ce9ee766ac9c3f4443f", + "support" ], "css/CSS2/generated-content/content-081.xht": [ - "92126a03c26e7c9316d496e0ef871cb008641169", - "visual" + "2cda22c21c23f42119bb9281c703d35e55a4e975", + "reftest" + ], + "css/CSS2/generated-content/content-082-ref.html": [ + "817efad77b46cfb731f879c4868d9b871c11bdca", + "support" ], "css/CSS2/generated-content/content-082.xht": [ - "8441670c152b4c53db4610ce83f32fc1f85fe0e8", - "visual" + "d42e394f5c0f283adbcd718f853f785e23a818c1", + "reftest" + ], + "css/CSS2/generated-content/content-083-ref.html": [ + "1615f4404ba11036ac880526aabac89a82daccc3", + "support" ], "css/CSS2/generated-content/content-083.xht": [ - "15f66ed7e28ccf9f1b78574eabd9df2a64b81d89", - "visual" + "e494972b8b586c7ab9e65992974e9b8d38a560b7", + "reftest" ], "css/CSS2/generated-content/content-085.xht": [ - "8538fb8763391d556c96643517ed7148bd9d9212", - "visual" + "666258b96d1f85fe599b01efea029b719d6dd6ab", + "reftest" ], "css/CSS2/generated-content/content-086.xht": [ - "74a94c5349c8b1c9c82d7e943b40996557475eaf", - "visual" + "df8b06374e8155336167b9084ffe107d4d1f9c6b", + "reftest" + ], + "css/CSS2/generated-content/content-089-ref.html": [ + "1615f4404ba11036ac880526aabac89a82daccc3", + "support" ], "css/CSS2/generated-content/content-089.xht": [ - "c33267a9b785e3991572d9bfd4e00b91f7cdade7", - "visual" + "8de7cb8c3bcfdf082190803e8e712f588bd1a9c8", + "reftest" + ], + "css/CSS2/generated-content/content-090-ref.html": [ + "b78d605d096c45b73ba48200e8f035334c7fcd54", + "support" ], "css/CSS2/generated-content/content-090.xht": [ - "92ecdb49178d7d0c2274c031d254e1cfe59df81c", - "visual" + "b81d78f38ee5bd49c86872c65d4948b7c2b54225", + "reftest" + ], + "css/CSS2/generated-content/content-091-ref.html": [ + "78e364761d4adcc4a0031ad77954b7613ecb0b83", + "support" ], "css/CSS2/generated-content/content-091.xht": [ - "672d790b5178a20275f9c6c0ba168ac65c5d2a71", - "visual" + "907808e77b61cf6375079e924b0b1bef51bcc70b", + "reftest" + ], + "css/CSS2/generated-content/content-096-ref.html": [ + "e1a38c6c2fe87293817cde5856a1bfff5f6287f8", + "support" ], "css/CSS2/generated-content/content-096.xht": [ - "64537cca3e2afb89e70abd5759c5ce9ce88b9f3e", - "visual" + "4627b242c53af5ce27d5d79767e704ac1a336bc5", + "reftest" + ], + "css/CSS2/generated-content/content-097-ref.html": [ + "d7c0cc6a11ab55c60cb97d38387defc56a870a58", + "support" ], "css/CSS2/generated-content/content-097.xht": [ - "eda4e9b3ddc0ca0e1a8fce2d1cb5293dc8dee9b9", - "visual" + "6561f554c77b4cedf0ae0cc5721d59f83c777465", + "reftest" ], "css/CSS2/generated-content/content-099.xht": [ - "d9f2345256809e3bb355927e796621e48732723b", - "visual" + "972320f0d6931738959302a637579a7e79accf82", + "reftest" + ], + "css/CSS2/generated-content/content-100-ref.html": [ + "bf886ae366ffaa3969bbd734f22167cb7e5a0c44", + "support" ], "css/CSS2/generated-content/content-100.xht": [ - "ab0784494c860de119bbd4bc9c965c319f467725", - "visual" + "f24bdf6751fec913b10a871c65db70fa54ce600e", + "reftest" + ], + "css/CSS2/generated-content/content-103-ref.html": [ + "422b7a53469fd26d03d6c1c7f0742da4941b8e22", + "support" ], "css/CSS2/generated-content/content-103.xht": [ - "1ecd167094cf1964fc1f76bcab5d82790fd627bc", - "visual" + "0095da1df3314f77ec68daa72c6419358d7e259c", + "reftest" ], "css/CSS2/generated-content/content-105.xht": [ - "953a0ad087d94d09f5f0d3eda22721ad2885f0b7", - "visual" + "4c23e629f3cbec501abd618605fecb5ef8a90293", + "reftest" ], "css/CSS2/generated-content/content-107.xht": [ "d96ac86bbe47ff4b4a3ee7f068ee6de21492c424", @@ -426201,8 +431893,8 @@ "reftest" ], "css/CSS2/generated-content/content-109.xht": [ - "8aa12c850f21d77792975d4d7093b4a7f961a8b5", - "visual" + "14489af88fd985aef47708073c55c0c725d0e6d9", + "reftest" ], "css/CSS2/generated-content/content-110.xht": [ "3456d0c765afca85552f869373a8d218deb4a2c8", @@ -426216,9 +431908,13 @@ "44143b958137423ca4d95b86a7a8c0948339ed56", "reftest" ], + "css/CSS2/generated-content/content-113-ref.html": [ + "18c8f08f2c880c033e0824039d8bf1904ade89b1", + "support" + ], "css/CSS2/generated-content/content-113.xht": [ - "86bf0e3d425a75baaf53f25aa921bf736ea801ed", - "visual" + "9eed15c15502e92ffed9d5e3795bc0e23e74d4d4", + "reftest" ], "css/CSS2/generated-content/content-114.xht": [ "264aa0d3d3b36fbb9008d184f3b14c7077c1a716", @@ -426249,120 +431945,176 @@ "reftest" ], "css/CSS2/generated-content/content-122.xht": [ - "00a7b7c48b3f8d9bcfd4022b5b13d174aed24165", - "visual" + "db510090fbec6df00ee70ba9d5ebc0deb50816c9", + "reftest" ], "css/CSS2/generated-content/content-123.xht": [ - "5a8c7966f5cd6a2ff63733071a034f5e191b7b66", - "visual" + "60d0552ec4647f9b85c7122567a051790e8c9ad3", + "reftest" + ], + "css/CSS2/generated-content/content-126-ref.html": [ + "1aa43fca0f1d4b0e10a706ed380483073d0d9f7b", + "support" ], "css/CSS2/generated-content/content-126.xht": [ - "b1cb68fa02044bb5bafe2aa744a28fe8f378cdc7", - "visual" + "4fa9e583f43ef8f5422ec203241e07b79396ee5f", + "reftest" ], "css/CSS2/generated-content/content-127.xht": [ - "2f36ae9ffe2bf84b5f2563066f3c547b93dc4153", - "visual" + "bf971e547f0fb47630cb4cfa6e91299253e83d34", + "reftest" ], "css/CSS2/generated-content/content-129.xht": [ - "9878e5260ca4c3bd6565eabe2434a1c1786d1748", - "visual" + "8d6a3fe5125fba825e1b7dbaddf56f8fcf92f23f", + "reftest" ], "css/CSS2/generated-content/content-130.xht": [ "326219b3a69cb1718e50525212ebf960c1490847", "visual" ], "css/CSS2/generated-content/content-131.xht": [ - "22b0f29f51e2868bffb0524814647bc196d777a3", - "visual" + "1039bc76db903dc5ceba39426604a6aba5b18569", + "reftest" + ], + "css/CSS2/generated-content/content-132-ref.html": [ + "3384039df388d1a3981a631221a4c4efbcb6c89a", + "support" ], "css/CSS2/generated-content/content-132.xht": [ - "f7fa99cca43357b27cd5cfc37dfa82227984d441", - "visual" + "05f1eb8fae82f4a6ea14643eea3646a484698cb5", + "reftest" + ], + "css/CSS2/generated-content/content-135-ref.html": [ + "dd7757d53f233f8de44c4333e43f17249ca3394f", + "support" ], "css/CSS2/generated-content/content-135.xht": [ - "788aae94056f4cbafa83fb9a2233d757d4147994", - "visual" + "6a1f11d890b45b577c7594688cf9723537506adb", + "reftest" + ], + "css/CSS2/generated-content/content-136-ref.html": [ + "94e6d3ca39b0eeebbb6a11728370998751457142", + "support" ], "css/CSS2/generated-content/content-136.xht": [ - "5d3c3f4d5ac3a0808b677848b6225e9a9d4efe9d", - "visual" + "e33d8ca80475ef988c5d45315fd20c7d9830fa25", + "reftest" ], "css/CSS2/generated-content/content-138.xht": [ - "155ce600c88f114db512c29027fa3471b933efa1", - "visual" + "7650618dff9b734b894710101c2ab917fe86d42c", + "reftest" ], "css/CSS2/generated-content/content-140.xht": [ "9261e82f6b3bffaa2950764848989c1629577494", "visual" ], + "css/CSS2/generated-content/content-141-ref.html": [ + "8e87f38d4d12389f99f64fc027941d9782310447", + "support" + ], "css/CSS2/generated-content/content-141.xht": [ - "fa0892854f36543a210481286c6b7b26dc07093b", - "visual" + "943de06685610b2d5eb7c5859e747b96dd0cbfa1", + "reftest" ], "css/CSS2/generated-content/content-142.xht": [ "d9c9efd22ac0fdae887c535221a6a87638fd8874", "visual" ], + "css/CSS2/generated-content/content-143-ref.html": [ + "0f74a336125f7db1dc9a43d78ae165b4e109a495", + "support" + ], "css/CSS2/generated-content/content-143.xht": [ - "2ca23d4fa513db422107a58435e4900bfc02a811", - "visual" + "fb0c58246015480076432896d147286b66869539", + "reftest" + ], + "css/CSS2/generated-content/content-144-ref.html": [ + "d53cb4a28dd17903a68cb69b1bcb75d02bc63dc8", + "support" ], "css/CSS2/generated-content/content-144.xht": [ - "17a3c64a1ff4d4965c2b6d113c0b72a465cd13be", - "visual" + "911a497bb282a3487a69862d9e865599c3cf9b02", + "reftest" ], "css/CSS2/generated-content/content-145.xht": [ - "906369b33e89a868076e3caa079b5e0db4835dc8", - "visual" + "860389d53cb820ea19857628eb195990e59a3b7a", + "reftest" ], "css/CSS2/generated-content/content-146.xht": [ - "2e534c23b7074b417269aca88354a4470b1fdf84", - "visual" + "a845bd2ea468178550efe67abc3bec7eaa5427ce", + "reftest" + ], + "css/CSS2/generated-content/content-147-ref.html": [ + "bf1ac303d8f397dd054955f310672f743f938aed", + "support" ], "css/CSS2/generated-content/content-147.xht": [ - "78c4d6bdb6d75caf889ac8ec99b0239b3a85fcfb", - "visual" + "4a545de935292410d7200a74c7c169032d396e2f", + "reftest" + ], + "css/CSS2/generated-content/content-149-ref.html": [ + "ec4228da18bd5dc7eafd90b7d0b982e1ea6c186f", + "support" ], "css/CSS2/generated-content/content-149.xht": [ - "f666d03ec21135bf652f81fb141b26f0a32c3e2d", - "visual" + "1ad87ccce1e4ccea7d1e5f3098e6e2ff224491cc", + "reftest" + ], + "css/CSS2/generated-content/content-150-ref.html": [ + "32a30eda299be341a1b66cc0f948142ceae42e82", + "support" ], "css/CSS2/generated-content/content-150.xht": [ - "0bd549aa9b3003954366dd9319d3ea0a9bf96abc", - "visual" + "18d432e51b1a88d89396ba4b6959e337eaca92b0", + "reftest" ], "css/CSS2/generated-content/content-151.xht": [ "9efb22636e2e5bd06f8393b68c41f3420c6a1e0e", "visual" ], "css/CSS2/generated-content/content-152.xht": [ - "0ef4f8b1f7bc845feddfe99a584e21f122667d20", - "visual" + "6b802ad4b702d2eecb1830cb35741e650f5afe61", + "reftest" ], "css/CSS2/generated-content/content-153.xht": [ - "eed73f671c227e458211890cea12adfdd2d96fda", - "visual" + "d93e9404202426e0f97925c68cab21992fa384fd", + "reftest" + ], + "css/CSS2/generated-content/content-155-ref.html": [ + "ca516f6671b877e517b491010f72c09486259a17", + "support" ], "css/CSS2/generated-content/content-155.xht": [ - "08fc985b4ba22412c52d4b498fb78a44f6180148", - "visual" + "af8d68287b18f944d3523c4b913b78134aa241cd", + "reftest" + ], + "css/CSS2/generated-content/content-156-ref.html": [ + "36e4844e8174f3cc69af8add5418dd79eaa54933", + "support" ], "css/CSS2/generated-content/content-156.xht": [ - "6b7ce278cd19a3db9965c0390ec04945bdc45938", - "visual" + "fa1e87875c24ce51397c293e7a701e2127b9b8e3", + "reftest" ], "css/CSS2/generated-content/content-157.xht": [ - "7904b65d5172f464785b28cc5551db4f043e9405", - "visual" + "21d82565bfe80ddf117b21920949d127a83af581", + "reftest" + ], + "css/CSS2/generated-content/content-158-ref.html": [ + "fdcdd9ada31d57e1f7b150780ce3bbe3bbe16041", + "support" ], "css/CSS2/generated-content/content-158.xht": [ - "2f0bb55cd06cf0b5fcaef6eb00321c329a36213f", - "visual" + "bf8d47b7849c698e1f0417890198cefa352b5d9c", + "reftest" + ], + "css/CSS2/generated-content/content-159-ref.html": [ + "847e1ac3da66a0673323ec5dc1e3885b42f0bef4", + "support" ], "css/CSS2/generated-content/content-159.xht": [ - "b470b94294f0f23f8a590c82a2a7372aaded3bfc", - "visual" + "441e31aa08a4fe28e66be7e3a7fc063a70af9662", + "reftest" ], "css/CSS2/generated-content/content-160.xht": [ "723f35be2a0ac3db0c0b11de0b580b95aeeed37f", @@ -426425,24 +432177,28 @@ "visual" ], "css/CSS2/generated-content/content-attr-001.xht": [ - "06a4b3449c026f018e5591ec25e6bbcf947f0842", - "visual" + "e1c68833536e23d0e0da86611ebaa26488f67de5", + "reftest" ], "css/CSS2/generated-content/content-attr-002.xht": [ "67ff295748a46db75ba6b6bcf9b3fc955cdb6054", "visual" ], "css/CSS2/generated-content/content-attr-case-001.html": [ - "0c1a92a7119fafa091ca269edb6ba7a6cef7d3ca", - "visual" + "868e1fb639f2b3cdbfd6f6c361ccb796bef0f2a3", + "reftest" ], "css/CSS2/generated-content/content-attr-case-002.xht": [ - "ccf14b1d669032191372e955f77e7f63d0718739", - "visual" + "fa2ffef772d90ce1f358da9a5dafca0fc8a46b31", + "reftest" + ], + "css/CSS2/generated-content/content-auto-reset-001-ref.html": [ + "bbe6c8ce25e9a27aa2fcb0843b1f5a6b2432de80", + "support" ], "css/CSS2/generated-content/content-auto-reset-001.xht": [ - "8f2962d27daa66dc5d548a6e440684c013639f65", - "visual" + "5d1245c7101997a54b03f34a28ad7aad8aa1618d", + "reftest" ], "css/CSS2/generated-content/content-counter-000-ref.xht": [ "cb947dd17c994e66de34b41b2bd4062948d04930", @@ -426652,29 +432408,49 @@ "f80bd32d1bc8955ff00de66d211b9df6f0a4a9f2", "reftest" ], + "css/CSS2/generated-content/content-newline-001-ref.html": [ + "792d23ddadd740eb4a05c60efbb0b71e2922c716", + "support" + ], "css/CSS2/generated-content/content-newline-001.xht": [ - "4387d521d200a5cba6edff04463dbe8847be5cc3", - "visual" + "bfdd3ccf6338c835532368b80fbeacc6ffc1a5c3", + "reftest" ], "css/CSS2/generated-content/content-uri-001.xht": [ "470ee7c21508137d4ca15dd35a57f9414a567ce0", "visual" ], + "css/CSS2/generated-content/content-white-space-001-ref.html": [ + "e7ea132de591d986bff01f230f8e272f6e195d27", + "support" + ], "css/CSS2/generated-content/content-white-space-001.xht": [ - "8cf7294e169bb708d922735a0cba4172ce8a95dd", - "visual" + "bbca6fac952179359b6740193b6e4430473c0ce2", + "reftest" + ], + "css/CSS2/generated-content/content-white-space-002-ref.html": [ + "66023264d1a4f82e92c68c8618a5005dd8101aaf", + "support" ], "css/CSS2/generated-content/content-white-space-002.xht": [ - "a5d1f5ab5002b969bd3a420d54a4c29385544b9e", - "visual" + "2efbae79cf35d90bd31e0a8a06876ce2630096c1", + "reftest" + ], + "css/CSS2/generated-content/content-white-space-003-ref.html": [ + "e2b4d4fe25d44d431dbac408125629a8b6f4e58d", + "support" ], "css/CSS2/generated-content/content-white-space-003.xht": [ - "bfa9f8e591f609a783099ed6fec777e5da06edf6", - "visual" + "38728ce5af93a5a8c0c1395dc741fb6e716a8dc1", + "reftest" + ], + "css/CSS2/generated-content/content-white-space-004-ref.html": [ + "7546cec8f1d7147ecc363d8c2bfaf977befcd74c", + "support" ], "css/CSS2/generated-content/content-white-space-004.xht": [ - "c25e18c139b53e46a92c55072e3a4b460193139f", - "visual" + "6f9f59377ea5f4917dea5a363647bb0ecb4074b1", + "reftest" ], "css/CSS2/generated-content/counter-increment-000.xht": [ "3499696cf5d953dd6d075d0b7c084b41c28a79d3", @@ -426700,37 +432476,57 @@ "a8dbf7e6a480189cae384fab758a507781c7a01b", "visual" ], + "css/CSS2/generated-content/counters-hidden-000-ref.html": [ + "ed9cd1beda8d45ce136775410594de083d66c80c", + "support" + ], "css/CSS2/generated-content/counters-hidden-000.xht": [ - "fa75afe23cc29aca9b9955417c7fdc843d86b638", - "visual" + "5e793dcfb16d24a00d35229cda6c360d2ce4a048", + "reftest" ], "css/CSS2/generated-content/counters-hidden-001.xht": [ - "251485e38dc64c4f5e620d363b2821402d64e131", - "visual" + "47699481449894ac7c0a6c57de85753f92a9bae9", + "reftest" + ], + "css/CSS2/generated-content/counters-hidden-002-ref.html": [ + "4305621626ec39ad5476511b832d0127c4e43749", + "support" ], "css/CSS2/generated-content/counters-hidden-002.xht": [ - "1326e94220ba6d78fb3a573f0574bab182d8eba9", - "visual" + "79ffca13df20085a7bb534ac2a8d15f7400d3f0d", + "reftest" + ], + "css/CSS2/generated-content/counters-multi-000-ref.html": [ + "53eda0a7e918513fef73aefcad2c02e24113e4c3", + "support" ], "css/CSS2/generated-content/counters-multi-000.xht": [ - "9afc27360f8b3b727718e52ea71bf60c6ba1fb0d", - "visual" + "3ab2fa7b87beeb5dfe2ca4afcd01fb497e1573af", + "reftest" ], "css/CSS2/generated-content/counters-multi-001.xht": [ - "817db5ac6b5d748b035c666495f7f60a239f2e3c", - "visual" + "a98c00491e1af2bc2b76d2da9dd49e55f0f7605b", + "reftest" + ], + "css/CSS2/generated-content/counters-order-000-ref.html": [ + "f062712e8662f81340a0014fc4cc382804d77884", + "support" ], "css/CSS2/generated-content/counters-order-000.xht": [ - "311345cea8c6b2f851d76ab9548576d55b8de8a4", - "visual" + "053eb6c18101f6ce18056e6facb7e9b9b7b5f886", + "reftest" ], "css/CSS2/generated-content/counters-order-001.xht": [ "8a439c13b321576d85708a4ee361bca7a2efcb3a", "visual" ], + "css/CSS2/generated-content/counters-root-000-ref.html": [ + "006f12f97aa57a0a16aa29a62d50c1de4bea479f", + "support" + ], "css/CSS2/generated-content/counters-root-000.xht": [ - "d43c7dc5b402a0d493d8bc5d15ebbbfbb7e268c8", - "visual" + "91291e98d2e03e0db1865844c8795402b491a4af", + "reftest" ], "css/CSS2/generated-content/counters-scope-000.xht": [ "418ed951641c85d3c23330987fd48e0a980c6400", @@ -428628,6 +434424,14 @@ "2927ed2a8c86f6a791db5d6eb670ad1961b17e9e", "visual" ], + "css/CSS2/linebox/line-height-oof-descendants-001-ref.html": [ + "284fd0f610f5428bea7a5f9c0dee1bdde3a4670b", + "support" + ], + "css/CSS2/linebox/line-height-oof-descendants-001.html": [ + "bb8949f890f140305ac76beb3f3ae1f2d15b16a3", + "reftest" + ], "css/CSS2/linebox/support/1x1-green.png": [ "51e7b6974a09eda6cb31337717c5eaeb9c44b443", "support" @@ -457765,7 +463569,7 @@ "support" ], "css/CSS2/values/numbers-units-011.xht": [ - "e7ec181207bbc94c6aad4175d19f11debc7cab67", + "17c979afd18db2ae6c76c85290ecac491c8b8269", "reftest" ], "css/CSS2/values/numbers-units-012-ref.xht": [ @@ -458032,6 +463836,26 @@ "0f9684f5b6f8a289b4ed680f10c2460b701f93fe", "reftest" ], + "css/CSS2/visudet/content-height-001.html": [ + "a5eacd7718cf4c9772eec96bdeebc5117274764f", + "reftest" + ], + "css/CSS2/visudet/content-height-002.html": [ + "1446a35470b7119d688a60d4254f82277704568f", + "reftest" + ], + "css/CSS2/visudet/content-height-003.html": [ + "4f161ed93fe5facaca17bb0d6ea1ec95db8fdeea", + "reftest" + ], + "css/CSS2/visudet/content-height-004.html": [ + "85ce343a8af7e564e76e49e4efd68248639cf3cb", + "reftest" + ], + "css/CSS2/visudet/content-height-005.html": [ + "5f417858f0d8b45b0d728bdc12cecbeb5fd8f4ce", + "reftest" + ], "css/CSS2/visudet/height-applies-to-010a-ref.xht": [ "581de95a4963b6b2333aa52ffaa40d8602d4a69f", "support" @@ -458072,10 +463896,82 @@ "7de15523c5a70277df00ce5c36cf0495796e8834", "reftest" ], + "css/CSS2/visudet/line-height-201.html": [ + "819c633cbf3c9f9f90dfad4b994805a0bf9c39b6", + "reftest" + ], + "css/CSS2/visudet/line-height-202.html": [ + "5cdd43dfb4521c879fd5f71f5c8e729175acb592", + "reftest" + ], + "css/CSS2/visudet/line-height-203.html": [ + "cadcb023d118268729b1dac65da5c58aee767841", + "reftest" + ], + "css/CSS2/visudet/line-height-204.html": [ + "542b71b278592fc511ab946185b8adaf1caea638", + "reftest" + ], + "css/CSS2/visudet/line-height-205.html": [ + "b7abe6f77d1dbd251f332fb6f3b0c719badef9f5", + "reftest" + ], + "css/CSS2/visudet/line-height-206.html": [ + "3fb676d1813f4b8b7e6ee4a0aa30aa19b94b74d6", + "reftest" + ], "css/CSS2/visudet/max-width-109.xht": [ "f16a156aae237e8f41a03692776f4f62ec38e52b", "visual" ], + "css/CSS2/visudet/reference/content-height-001-ref.html": [ + "3f269c5eec17d12e97e26c53a4e576aaa72877d0", + "support" + ], + "css/CSS2/visudet/reference/content-height-002-ref.html": [ + "fb5af8b1620174a1e7346477ea5f0d00a98cc74e", + "support" + ], + "css/CSS2/visudet/reference/content-height-003-ref.html": [ + "1f3e8ae567881df8d0f07c2df56a0528a8367526", + "support" + ], + "css/CSS2/visudet/reference/content-height-004-ref.html": [ + "dc50725289cbdb628635f7b1a2854326bbada4bf", + "support" + ], + "css/CSS2/visudet/reference/content-height-005-ref.html": [ + "46615347aa82e74273e8580a04a0944a3f82e232", + "support" + ], + "css/CSS2/visudet/reference/line-height-201-ref.html": [ + "2f285902b55a9a2bcd7e09f7437e3aae6d0269bc", + "support" + ], + "css/CSS2/visudet/reference/line-height-202-ref.html": [ + "66d52a0c9bfde0b1bef9ac5054f7cf400fef1573", + "support" + ], + "css/CSS2/visudet/reference/line-height-203-ref.html": [ + "ffa2e91fd888edf5598cb0ac19ff2c65078fb4a1", + "support" + ], + "css/CSS2/visudet/reference/line-height-206-ref.html": [ + "221b497ef9262ecc61cbe97cdc533d00cca8b231", + "support" + ], + "css/CSS2/visudet/support/1x1-green.png": [ + "51e7b6974a09eda6cb31337717c5eaeb9c44b443", + "support" + ], + "css/CSS2/visudet/support/AD.woff": [ + "2bff1f1a01ce7c959341300952b2467e87e60dd5", + "support" + ], + "css/CSS2/visudet/support/Revalia.woff": [ + "f2b20022818e53e9c9c5f22bcc52703c6858eb1c", + "support" + ], "css/CSS2/visudet/support/swatch-blue.png": [ "e79958e10feeeed3db88dee9bae9ea80055593c5", "support" @@ -459084,12 +464980,8 @@ "b96e97be7cc4eb1e5e40d037895cb81735f78ec6", "reftest" ], - "css/OWNERS": [ - "77e15937dd2bef6cf8ffb55f2698e8b1f0a3f065", - "support" - ], "css/README.md": [ - "17ea0b79a120fb33e736c10fa967cfd001f9b181", + "ab97108074d4c07c5333ff1148fe9a5e425484ca", "support" ], "css/WOFF2/OWNERS": [ @@ -462960,10 +468852,6 @@ "b0cf703533a323305eb772c6def00afe21cdcdb8", "reftest" ], - "css/compositing/mix-blend-mode/mix-blend-mode-transition.html": [ - "2a9c826f5db1d9eb5a4748351a7d411b4c65a93b", - "reftest" - ], "css/compositing/mix-blend-mode/mix-blend-mode-video-sibling.html": [ "d9682264f4ce1859b0d7f22b8dfca5cc482028a8", "reftest" @@ -463100,10 +468988,6 @@ "543892c3466ace307bd125801a2231dae3a95b92", "support" ], - "css/compositing/mix-blend-mode/reference/mix-blend-mode-transition-ref.html": [ - "2fdce2d337a053453bc339ffb7f9e0560c1f0095", - "support" - ], "css/compositing/mix-blend-mode/reference/mix-blend-mode-video-notref.html": [ "4407e55ee0412f2064caeee74acad93424a849c7", "support" @@ -463340,6 +469224,10 @@ "d41b539ff28c250e1b7fe0c810e026f2fe57a67e", "reftest" ], + "css/css-animations/animation-delay-011.html": [ + "60f8a0ee02c497dc3ea7e24d6a2d722261e86990", + "reftest" + ], "css/css-animations/animation-direction-001.html": [ "0bf1bfdcb407dc77beaedb5e0468e6913230f831", "manual" @@ -463900,6 +469788,22 @@ "da703cf56e71cd9dc8ff4f7ca34b11963eb5afb3", "visual" ], + "css/css-backgrounds/background-color-body-propagation-001.html": [ + "26f2d7efeb2063e8672f3f831d2bd382976a099d", + "reftest" + ], + "css/css-backgrounds/background-color-body-propagation-002.html": [ + "0b9b3ffa3574c8f5e6202c5177dd5d6cfe636b16", + "reftest" + ], + "css/css-backgrounds/background-color-body-propagation-003.html": [ + "f87fe8066c21356425c1eab1129a5a5c0f64b1f4", + "reftest" + ], + "css/css-backgrounds/background-color-body-propagation-ref.html": [ + "843bae3267a34e4160763b16c59ea63036cd9e0b", + "support" + ], "css/css-backgrounds/background-color-border-box.htm": [ "d638cc24e5598d10acfbf6d0c3a25552141a2ad5", "visual" @@ -463944,6 +469848,10 @@ "7e296a53a2abebcd5fcee2431b182efe6f148c64", "reftest" ], + "css/css-backgrounds/background-image-none-gradient-repaint.html": [ + "d2d9cb520ad7bb14b1499f2fbb6a87a20ff96d44", + "reftest" + ], "css/css-backgrounds/background-origin-001.html": [ "11fa7ee04754b43a0837115bb223966351eaaad8", "testharness" @@ -465745,87 +471653,87 @@ "visual" ], "css/css-backgrounds/border-radius-001-ref.xht": [ - "ef1308b55e3c17000ad94cf85a03d05ece24f66c", + "565982e400e9a1b62f6224ed655c977064ef3952", "support" ], "css/css-backgrounds/border-radius-001.xht": [ - "3f669ee04eca21655211dd4ec317e5f1cf4dfe39", + "448d22583ccdf4d4b245a219014eded8666a7bfa", "reftest" ], "css/css-backgrounds/border-radius-002-ref.xht": [ - "f8f2373accc3cfbcaf84a07aa6f850ac047931da", + "4bf3a05d4e3f531f59d1a8bb434d9ae8df3e089c", "support" ], "css/css-backgrounds/border-radius-002.xht": [ - "5f9bb278ae68dbdc0b85c54dfff2a8c5c2d6a576", + "54bdc142548fe5cd71336e3757f6b9ad8d8f75ef", "reftest" ], "css/css-backgrounds/border-radius-003-ref.xht": [ - "780b37d4e473e1e73b3c1221441f5c00cc9b64ba", + "21d3674eef4a60927e3849770a391e6b7a46f81a", "support" ], "css/css-backgrounds/border-radius-003.xht": [ - "77439d7aad5f3e58f2d85b034119c8907038545a", + "e27aa9bc45c17c77aeab571a581933bc97bcb95f", "reftest" ], "css/css-backgrounds/border-radius-004-ref.xht": [ - "c7e269aa1a07c964d1f78c943563856344789098", + "5e26e7f77aa27fcbef6636eb498fb9b0fa1e92e6", "support" ], "css/css-backgrounds/border-radius-004.xht": [ - "953b456c7aa306c9420d0d70d889bdf4207bcd53", + "eaf678007f7d5f8ca6751916638e509aea9909f5", "reftest" ], "css/css-backgrounds/border-radius-005-ref.xht": [ - "c2a6c35eba7c158f86922bab340cf20285ecdc0e", + "7dd0c30f5445c9f16cd575b7a48ebd0b8f407560", "support" ], "css/css-backgrounds/border-radius-005.xht": [ - "62e1da7ba92b46dffb2f0ee9a5fd725ae878af5b", + "59c424eed52f033c8c2f695107f44ae5a20b295e", "reftest" ], "css/css-backgrounds/border-radius-006-ref.xht": [ - "63a490cba1adaa2450e9a03edde3d1d3416703a1", + "28fcb03b46a25236eb58f057f056e7718dcf32e1", "support" ], "css/css-backgrounds/border-radius-006.xht": [ - "5d2a76914f94c10bf8d907d863365ee3d63c9d7c", + "4a9190103806f526f570f95ef824e007804fd645", "reftest" ], "css/css-backgrounds/border-radius-007-ref.xht": [ - "a8c78252ac61b36d0631aca15e8ec6ad3a3c16db", + "f547b82c811905504be2e37e4983d4dab8a5b31b", "support" ], "css/css-backgrounds/border-radius-007.xht": [ - "811f971181c1cf3fece208d6989567ed84d08070", + "1f7e0dc63717b1c6caa414d5ada7129510dd979c", "reftest" ], "css/css-backgrounds/border-radius-008.xht": [ - "193de4a55be9f442995b0adeabed0e14664e3f62", + "593d270ff4e46a92517459aa9992507f4b3e6c6a", "reftest" ], "css/css-backgrounds/border-radius-009-ref.xht": [ - "6c9457e7c251b0eb933edfc4be10e5bcb405ec57", + "013f339641d80aebee0ea3a97e44753806fdbd41", "support" ], "css/css-backgrounds/border-radius-009.xht": [ - "0b25cce5f284dcc2dac3e87c3419575ee84f764f", + "f4371415c6f2b4edf2bcf4920408d73493904519", "reftest" ], "css/css-backgrounds/border-radius-010-ref.xht": [ - "1039ef9b8bbe885c440ac80f017ac28567f3dc00", + "281bea790d41ae2cc3adbb8938130f75181f828c", "support" ], "css/css-backgrounds/border-radius-010.xht": [ - "6cd9f8f4f2fa156948f05be417d6e9e20f160b89", + "aa88a59894c5a73470221edaa02e0eadbc1a426b", "reftest" ], "css/css-backgrounds/border-radius-011-ref.xht": [ - "7a708c587aa874ea1bbd7a4862e1eb11eaa0f88f", + "d94d45fb036ee95933d251cdfd2ed491ab0405d2", "support" ], "css/css-backgrounds/border-radius-011.xht": [ - "1fcb231f6b7b8eb638bdcadace732ef80d274f6b", + "8e9493ba18bde48b0ad9e03adab856b54aae1f3b", "reftest" ], "css/css-backgrounds/border-radius-applies-to-001.htm": [ @@ -466832,972 +472740,12 @@ "ceb5773fc9d6264d1f9210d8675b7bf48764d296", "reftest" ], - "css/css-block/OWNERS": [ - "6634529fb114ab2e29cb2fa4a633289ee9038c22", + "css/css-break/OWNERS": [ + "77055bd48cd1e192db8b2c6c47d736d7b1fcbe65", "support" ], - "css/css-block/after-content-display-004.xht": [ - "61fd73789062cb65193cd3e2ab535151b2565b8b", - "visual" - ], - "css/css-block/anonymous-box-generation-002.xht": [ - "d8b897bec271896fa3362a6aef4a2c628ebbe0b3", - "visual" - ], - "css/css-block/background-applies-to-011.xht": [ - "a4f27fa89ec568aaeeccd6867b5dd1afcb4b86f6", - "visual" - ], - "css/css-block/background-attachment-applies-to-011.xht": [ - "02c5f4feaf50905f325b00d2635a77e631cbfe84", - "visual" - ], - "css/css-block/background-color-applies-to-011.xht": [ - "8b3b119f15080301b1314ea5b45e270b2823df89", - "visual" - ], - "css/css-block/background-image-applies-to-011.xht": [ - "9e9a51ef23a8968edc5d4a4c6f0305f6ddf0d7ed", - "visual" - ], - "css/css-block/background-position-applies-to-011.xht": [ - "ff1707da202a90261724386b16a401aef3b48f6e", - "visual" - ], - "css/css-block/background-repeat-applies-to-011.xht": [ - "88339d4a1b2cfc2fdff0905e592dcfaf75750cbb", - "visual" - ], - "css/css-block/before-content-display-004.xht": [ - "d7f0c8005d0ab64c13b48c0589c1c0083bcb254b", - "visual" - ], - "css/css-block/border-applies-to-011.xht": [ - "36eded364e030b01fe560e74e50f8fa8c118a433", - "visual" - ], - "css/css-block/border-bottom-applies-to-011.xht": [ - "daad8099c06632a6423a90a913fef6643bef2366", - "visual" - ], - "css/css-block/border-bottom-color-applies-to-011.xht": [ - "1f06ae35fa63cdc01c50754e945135cd65c81336", - "visual" - ], - "css/css-block/border-bottom-style-applies-to-011.xht": [ - "f14782efe820b83b706b3ff6ecf1893bff256e42", - "visual" - ], - "css/css-block/border-bottom-width-applies-to-011.xht": [ - "20389e139890e0e699712d9d9fc967ea0cb81d97", - "visual" - ], - "css/css-block/border-collapse-applies-to-004.xht": [ - "44cbf688dbc21665f0cab3f608521293fc562796", - "visual" - ], - "css/css-block/border-color-applies-to-011.xht": [ - "29ae73e9211b753a7d687ba7e73e30daf052d169", - "visual" - ], - "css/css-block/border-left-applies-to-011.xht": [ - "74d022f4145b07d71c0ac5cd008df29138ae4d31", - "visual" - ], - "css/css-block/border-left-color-applies-to-011.xht": [ - "08bd2a4ec6c575b8121e96bbdb8a0b2aa74140e3", - "visual" - ], - "css/css-block/border-left-style-applies-to-011.xht": [ - "6270c843418d4eb40cccb1705ab2b17ac0f92f3d", - "visual" - ], - "css/css-block/border-left-width-applies-to-011.xht": [ - "7496c6f5f5b46eb69de37176935cca76ad56d6bb", - "visual" - ], - "css/css-block/border-right-applies-to-011.xht": [ - "78cd49b2e855a61cecb4e1b523841cab00081643", - "visual" - ], - "css/css-block/border-right-color-applies-to-011.xht": [ - "e2391f060977badec62709241a824f97e597eccd", - "visual" - ], - "css/css-block/border-right-style-applies-to-011.xht": [ - "ae3f43f85ef5266eeda294bf4524d125e871a317", - "visual" - ], - "css/css-block/border-right-width-applies-to-011.xht": [ - "3209cbf4c1aa5d5c023ed13a17eac529052652a8", - "visual" - ], - "css/css-block/border-spacing-applies-to-004.xht": [ - "862913eace05677ad332a5c76532599694bf69f6", - "visual" - ], - "css/css-block/border-style-applies-to-011.xht": [ - "2ddc53bf2d5b8ab1e5c3b16e48ae5a2036fe31ea", - "visual" - ], - "css/css-block/border-top-applies-to-011.xht": [ - "ba40b08236b9c5993613af13f8dd96d3932c8475", - "visual" - ], - "css/css-block/border-top-color-applies-to-011.xht": [ - "b5184bc4fde674a806dccd7a061bd86fdb2f15a0", - "visual" - ], - "css/css-block/border-top-style-applies-to-011.xht": [ - "75e780e649cac1c0e695ac8275a8a588751b939a", - "visual" - ], - "css/css-block/border-top-width-applies-to-011.xht": [ - "9d5bedf58e1f861eab96f9d0b9fe90b58e021413", - "visual" - ], - "css/css-block/border-width-applies-to-011.xht": [ - "a7126e39d2d60e8f4d2f018cea4d001b8cc94066", - "visual" - ], - "css/css-block/bottom-applies-to-011.xht": [ - "f8e7490e71cf3899de316e306cea3947a17e1f77", - "visual" - ], - "css/css-block/caption-side-applies-to-004.xht": [ - "ce42ae349ae0e76af642f7e7ad19c812690562df", - "visual" - ], - "css/css-block/clear-applies-to-011.xht": [ - "3279ebd7562dcbf8c29f872e4d3ce76447c6d9c8", - "visual" - ], - "css/css-block/clear-runin-001.xht": [ - "bcaed5391dc08f90de390194e84df4db9b0d8e38", - "visual" - ], - "css/css-block/color-applies-to-011.xht": [ - "605a38365b79fa452ab47c9d1b7e77e68bc96218", - "visual" - ], - "css/css-block/counter-increment-applies-to-011.xht": [ - "e040221f01a337cc4bd5294dfa665ca34be3c716", - "reftest" - ], - "css/css-block/counter-reset-applies-to-011.xht": [ - "44aefba5a24f432500773763f95f45ca0887d7e8", - "reftest" - ], - "css/css-block/cursor-applies-to-011.xht": [ - "cc19264db7880b0a52412e501cb2852d33fd175d", - "manual" - ], - "css/css-block/direction-applies-to-011.xht": [ - "44512ff84708807b22f18a79bb18623a4b933f27", - "visual" - ], - "css/css-block/display-004.xht": [ - "7471ec0ca8d4f375feb49136e468dc06ab52f265", - "visual" - ], - "css/css-block/empty-cells-applies-to-004.xht": [ - "1a5763fed630b9d731f2af9961514be9af9f907e", - "visual" - ], - "css/css-block/first-line-pseudo-009.xht": [ - "5636f5b08a197f797debed5dea6726315578828f", - "visual" - ], - "css/css-block/float-applies-to-011.xht": [ - "01efe6f3b3298581cb45d2850b1f9732868fd381", - "visual" - ], - "css/css-block/font-applies-to-004.xht": [ - "9b51369f7b55b2be28ae1c472a446e0de5e476e0", - "visual" - ], - "css/css-block/font-family-applies-to-004.xht": [ - "627f012fde5832fa4fc098b2b1423e4db05ce95b", - "visual" - ], - "css/css-block/font-size-applies-to-004.xht": [ - "a3bcca3e7c843c4e0fa6ccb72a2b5ce6a193eecf", - "visual" - ], - "css/css-block/font-style-applies-to-004.xht": [ - "f759dd69c263ca2a976eeeadefc40f2c5c0364d8", - "reftest" - ], - "css/css-block/font-variant-applies-to-004.xht": [ - "b254e27e04e40d32596c2a1171a5979c8f0e28c6", - "reftest" - ], - "css/css-block/font-weight-applies-to-004.xht": [ - "8cbbee85603d1aa5db4e2d4abc6057254aadc30e", - "reftest" - ], - "css/css-block/height-applies-to-011.xht": [ - "cef91dff5dd646f563a484fe329f62ea5d89d50d", - "reftest" - ], - "css/css-block/left-applies-to-011.xht": [ - "ac86f465cdda1d482a5d336e3055d219b7547b9c", - "visual" - ], - "css/css-block/letter-spacing-applies-to-004.xht": [ - "b2eef03d34f7698ece360bf0fe379e8024b30e37", - "reftest" - ], - "css/css-block/line-height-applies-to-011.xht": [ - "5a504d5186b825f7a3ce231e7467319ecde7864c", - "visual" - ], - "css/css-block/list-style-applies-to-011.xht": [ - "d6b3f818f50f92e6bd71742d8abc52c2ce40e13d", - "reftest" - ], - "css/css-block/list-style-image-applies-to-011.xht": [ - "e6d6ef7fcfe75338a9f4c5d74bcf8695602417d8", - "visual" - ], - "css/css-block/list-style-position-applies-to-011.xht": [ - "86092ff94df9f7268dce918a9edcc6ff86b570e0", - "visual" - ], - "css/css-block/list-style-type-applies-to-011.xht": [ - "1b171ea4ced44a6bb7cd089088e2a156ff904ff7", - "reftest" - ], - "css/css-block/margin-applies-to-011.xht": [ - "23b14b25f9629a21eb30d27e9d8dadb15fc05b4e", - "visual" - ], - "css/css-block/margin-bottom-applies-to-011.xht": [ - "c528dcd41815a387a9e3625821135da92d7f032b", - "visual" - ], - "css/css-block/margin-left-applies-to-011.xht": [ - "124c70029386ebd9a72571a2177d968544d46421", - "visual" - ], - "css/css-block/margin-right-applies-to-011.xht": [ - "e819e775b2b1395c5f8210bb37beee1f1f8859b9", - "visual" - ], - "css/css-block/margin-top-applies-to-011.xht": [ - "dd48bef2f6e5fec6a57cef62997affd1a9d882c7", - "visual" - ], - "css/css-block/max-height-applies-to-011.xht": [ - "406878c807bd16c6c66f3fbb9455d7efef771fbc", - "reftest" - ], - "css/css-block/max-width-applies-to-011.xht": [ - "eab9c01bea21c0e0196d6dc118d6a988ab79a8ca", - "reftest" - ], - "css/css-block/min-height-applies-to-011.xht": [ - "6cd2f4f6ab2dde7b8887d2ba93ca4e246584939e", - "reftest" - ], - "css/css-block/min-width-applies-to-011.xht": [ - "b78b3c65ed834da92ac60b55ebbead516d2aa7ee", - "reftest" - ], - "css/css-block/outline-applies-to-011.xht": [ - "191fa8aafcab7760a159b1e4bb4f1e763d79ec22", - "visual" - ], - "css/css-block/outline-color-applies-to-011.xht": [ - "c8ef9366d397901fc7cfc60fcfeb7e779cc2b629", - "visual" - ], - "css/css-block/outline-style-applies-to-011.xht": [ - "395b8328ab7ffe7a8e542b377383c6f2fc23e168", - "visual" - ], - "css/css-block/outline-width-applies-to-011.xht": [ - "d367fcd30a2a5cace628c6414bdaea814c64434f", - "visual" - ], - "css/css-block/overflow-applies-to-011.xht": [ - "94ec0236bb7babe73b3bfa3135ef59077792a14c", - "visual" - ], - "css/css-block/padding-applies-to-011.xht": [ - "06043f0bc1ee56f9c9aa14ee894c7f71ae66d08c", - "visual" - ], - "css/css-block/padding-bottom-applies-to-011.xht": [ - "1f99d22839b620ead278902451b4393d16320cdf", - "visual" - ], - "css/css-block/padding-left-applies-to-011.xht": [ - "c46dcccd743de4c4af7e159cdab344e9e6e8c943", - "visual" - ], - "css/css-block/padding-right-applies-to-011.xht": [ - "b828450be59f1a3f52a60dec63f98255b21901ed", - "visual" - ], - "css/css-block/padding-top-applies-to-011.xht": [ - "9674c7b62e79e1cd886db2b4b84f5cbb5514aece", - "visual" - ], - "css/css-block/position-applies-to-011.xht": [ - "0720bf370b26ef35c9e2ea50c9faead2c98b8139", - "visual" - ], - "css/css-block/quotes-applies-to-011.xht": [ - "6af5a17886b29abdce4fb2aef1b4fcf1f5c4f776", - "reftest" - ], - "css/css-block/right-applies-to-011.xht": [ - "a80a4cee631686ec8df21372dacd609be35b8fa6", - "visual" - ], - "css/css-block/run-in-001.xht": [ - "b0a4627e8ac492cd231537db0bdc18dc27dc7104", - "visual" - ], - "css/css-block/run-in-002.xht": [ - "544419a0449424193f44b911e248fbfd0de23246", - "visual" - ], - "css/css-block/run-in-003.xht": [ - "e9a318519677aab01514814a6ba97c9a936807fb", - "visual" - ], - "css/css-block/run-in-004.xht": [ - "7b0837c9ee4571e49f97b083b855fcd691865bb3", - "visual" - ], - "css/css-block/run-in-005.xht": [ - "5b97ec05a44c1d7cf7895808255ba2fc18c80f86", - "visual" - ], - "css/css-block/run-in-006.xht": [ - "a59419542724e65457923d0389004a3eec2a4f77", - "visual" - ], - "css/css-block/run-in-007.xht": [ - "c175c5311ac085143da2e59f54f5774ed5f2f5e9", - "visual" - ], - "css/css-block/run-in-008.xht": [ - "1d0865927beea6342fff5c4fc69040acc9489512", - "visual" - ], - "css/css-block/run-in-009.xht": [ - "71095c3996aff8d47fe520ff8fee2fa3b1cb2ebf", - "visual" - ], - "css/css-block/run-in-010.xht": [ - "49213be77399f1a831d5b4b1a2f34fddeaa79b22", - "visual" - ], - "css/css-block/run-in-011.xht": [ - "1974e33d93c187081046429312c76ea134df919e", - "visual" - ], - "css/css-block/run-in-012.xht": [ - "ee5dac6b692fd283d7a097682dadfa6b626a05e1", - "visual" - ], - "css/css-block/run-in-013.xht": [ - "11bc7fde7caf907343151062bb9ae809bae8c82d", - "visual" - ], - "css/css-block/run-in-abspos-between-001.xht": [ - "3e1ad3faad361d1d2d593768a443910cf4cd490b", - "reftest" - ], - "css/css-block/run-in-abspos-between-002.xht": [ - "c107b4fb41bd56638a0eb720131f91d4e5538a78", - "reftest" - ], - "css/css-block/run-in-abspos-between-003.xht": [ - "23dea7a79da74d238e1c25a8c28296de817bc59b", - "reftest" - ], - "css/css-block/run-in-basic-001.xht": [ - "0c34f3144766492c0cb309877d6db143697d9e02", - "reftest" - ], - "css/css-block/run-in-basic-002.xht": [ - "09c62f1052efe44790ec822550e8e3cd835beb6a", - "reftest" - ], - "css/css-block/run-in-basic-003.xht": [ - "087430960604e40634bba7dc932f788570b8c598", - "reftest" - ], - "css/css-block/run-in-basic-004.xht": [ - "3831b02ab852d1d9f0c9417921ab4ca927896dc4", - "reftest" - ], - "css/css-block/run-in-basic-005.xht": [ - "b2135f56d2885505eb44dcaaf2160ce29df7e4fa", - "reftest" - ], - "css/css-block/run-in-basic-006.xht": [ - "01817fa44e367c4a7a020513aeb7c3456161cdd5", - "reftest" - ], - "css/css-block/run-in-basic-007-ref.xht": [ - "11014cb21bcdf13e85c4d0086df9a25507613808", - "support" - ], - "css/css-block/run-in-basic-007.xht": [ - "43dd105bde7f2e41c15d36b33e6554e391dc079f", - "reftest" - ], - "css/css-block/run-in-basic-008.xht": [ - "f24259a5fed7bf8cab18b9184e35212e02800c96", - "reftest" - ], - "css/css-block/run-in-basic-009.xht": [ - "e98daeb42c3a54d32b97d843addfa5d2dda44828", - "reftest" - ], - "css/css-block/run-in-basic-010.xht": [ - "0bc99c24b856b18ea3fa55869db75a67de43ab8d", - "reftest" - ], - "css/css-block/run-in-basic-011.xht": [ - "a1b654d27c1dab2ad1e4703b67e38d3e9bd2a188", - "reftest" - ], - "css/css-block/run-in-basic-012.xht": [ - "c81ee8a2132c0ba8a6b21724d096cdafb847378b", - "reftest" - ], - "css/css-block/run-in-basic-013.xht": [ - "2531d2898252313a9fe2f58723b88dd8fc687db3", - "reftest" - ], - "css/css-block/run-in-basic-014.xht": [ - "59d9c7c29da0b266a4ff93650fb5d6a7855ec4e8", - "reftest" - ], - "css/css-block/run-in-basic-015.xht": [ - "8a07cf400198531a7967b5902c2bc2d54619ab43", - "reftest" - ], - "css/css-block/run-in-basic-016.xht": [ - "6e253d56c74265591f9f8f56975698e88c2f14fc", - "reftest" - ], - "css/css-block/run-in-basic-017.xht": [ - "a2146b35df1dc7bd6a6ea30600576d66523c1934", - "reftest" - ], - "css/css-block/run-in-basic-018.xht": [ - "62720b81190790760a9bc1fab01a5643cdf10395", - "reftest" - ], - "css/css-block/run-in-basic-ref.xht": [ - "5c7bf6627792ff8dfa7898148318478fc9397673", - "support" - ], - "css/css-block/run-in-block-between-001.xht": [ - "8bd7a8465542fdddf4a766566058ea858094f3c0", - "reftest" - ], - "css/css-block/run-in-block-between-002.xht": [ - "5dc15f0706212f0231f83f98f6625041f8cbd2f1", - "reftest" - ], - "css/css-block/run-in-block-between-003.xht": [ - "4a6ffa1bc42e3730571f20877d486ee8787168a5", - "reftest" - ], - "css/css-block/run-in-block-ref.xht": [ - "071c80df59c30b1d27eb71bf640dc1851c82caae", - "support" - ], - "css/css-block/run-in-breaking-001-ref.xht": [ - "2340373520e5da7655abe63565a265dc5cb033b9", - "support" - ], - "css/css-block/run-in-breaking-001.xht": [ - "5fc81726a11c8dacd0836d7c58e6d3b2e6520de9", - "reftest" - ], - "css/css-block/run-in-breaking-002-ref.xht": [ - "0a7d186899713e3176f1fec521fdba32aec23c75", - "support" - ], - "css/css-block/run-in-breaking-002.xht": [ - "845947b845f9ac605a6be41e2159c0f5940017da", - "reftest" - ], - "css/css-block/run-in-clear-001.xht": [ - "7a2c163d274376ebc920d4861a6050f2ee150ae7", - "reftest" - ], - "css/css-block/run-in-clear-002.xht": [ - "150555e798c6a601b272f4f399ac59bf01181d49", - "reftest" - ], - "css/css-block/run-in-contains-abspos-001.xht": [ - "505db18a1ef6306f55d3ccb0da91468eb1832e45", - "reftest" - ], - "css/css-block/run-in-contains-block-001.xht": [ - "14a094004359b5d82a346789d943a10986a219ca", - "reftest" - ], - "css/css-block/run-in-contains-block-002.xht": [ - "da1db69ceba2cbeb435c05d2b0db72400e7da3d6", - "reftest" - ], - "css/css-block/run-in-contains-block-003.xht": [ - "3cd68ce6725aea4a8dc0d9c0a2c0f9a6d11fd9d9", - "reftest" - ], - "css/css-block/run-in-contains-block-004.xht": [ - "7db957af8ab1c8baa83fe1c80030038c24a1a7f5", - "reftest" - ], - "css/css-block/run-in-contains-block-005.xht": [ - "f9edbb5b1931152f0fc59a49fa7ceaf562907e10", - "reftest" - ], - "css/css-block/run-in-contains-block-inside-inline-001.xht": [ - "8acc13aafb56c42ea28056d89c75ec7abf5ded8a", - "reftest" - ], - "css/css-block/run-in-contains-block-inside-inline-002.xht": [ - "c2819892d00974d39407022d3999dc0e3a99cc86", - "reftest" - ], - "css/css-block/run-in-contains-block-inside-inline-003.xht": [ - "66cbe19763f9d390ec7c059ea290abc8594cdde8", - "reftest" - ], - "css/css-block/run-in-contains-float-001.xht": [ - "c761acc50f08e90f703a81ae8f22ff6e42709491", - "reftest" - ], - "css/css-block/run-in-contains-inline-001.xht": [ - "4d7b0268d78bfbd575a2b83d0c220bb9773a0b68", - "reftest" - ], - "css/css-block/run-in-contains-inline-002.xht": [ - "51c1489ef21996a11c5fb2b316fb33e0382eedb9", - "reftest" - ], - "css/css-block/run-in-contains-inline-003.xht": [ - "cc4c7b96db888e2c4b5c72500b826d8594b2e131", - "reftest" - ], - "css/css-block/run-in-contains-inline-004.xht": [ - "153dba85a8e212106ba545d91e769bfa7ed01f75", - "reftest" - ], - "css/css-block/run-in-contains-inline-005.xht": [ - "a405159d3ad1841125d71fb1da1f20b48a4be773", - "reftest" - ], - "css/css-block/run-in-contains-inline-006.xht": [ - "36ec63fd75a421d0fe020a97a786cd368ad7d247", - "reftest" - ], - "css/css-block/run-in-contains-inline-007.xht": [ - "f7496dd5eefa7fda7438936dcaeff54a95a8aa0d", - "reftest" - ], - "css/css-block/run-in-contains-inline-block-001.xht": [ - "bf9e2c4e86d11e99389f283977b2c5b112e73587", - "reftest" - ], - "css/css-block/run-in-contains-inline-table-001.xht": [ - "e7d121beeb034e758fb5efa0082dc93b3efedbf1", - "reftest" - ], - "css/css-block/run-in-contains-relpos-block-001.xht": [ - "675a88d85b722cc515fb158584b7572cc140fb4e", - "reftest" - ], - "css/css-block/run-in-contains-relpos-block-002.xht": [ - "2be9a77b6a4e838cc08fcfc8f9920ddc28261381", - "reftest" - ], - "css/css-block/run-in-contains-relpos-block-003.xht": [ - "c60fcf48a612655bea93d03a072f21c072f8c0f0", - "reftest" - ], - "css/css-block/run-in-contains-run-in-001.xht": [ - "440555c995389809c51c646d540bf5d48d300e70", - "reftest" - ], - "css/css-block/run-in-contains-run-in-002.xht": [ - "04fa874c1d0d2a26de77421e484ef222def2ea24", - "reftest" - ], - "css/css-block/run-in-contains-run-in-003.xht": [ - "d9777e903841d7473f21e7d8132194fd2670aac4", - "reftest" - ], - "css/css-block/run-in-contains-table-001.xht": [ - "89f16b25b8c73fd543936890c24e6359f14a0d26", - "reftest" - ], - "css/css-block/run-in-contains-table-002.xht": [ - "c681daf1640dfae048990cb4ffe6a66783d6efff", - "reftest" - ], - "css/css-block/run-in-contains-table-003.xht": [ - "452fe200c9b557ba8a5425d352c52f718dd01c5d", - "reftest" - ], - "css/css-block/run-in-contains-table-caption-001.xht": [ - "555a7a80b7b13ed6694e6752702098088beefcb7", - "reftest" - ], - "css/css-block/run-in-contains-table-cell-001.xht": [ - "f48afe1c718d9b6d17a6d0ae866ee47e5e9daf46", - "reftest" - ], - "css/css-block/run-in-contains-table-column-001.xht": [ - "5211a09e5126d906b54970831fafae37fd361903", - "reftest" - ], - "css/css-block/run-in-contains-table-column-group-001.xht": [ - "506b7828e6d6d602f5a47b0a67555bd8efeec352", - "reftest" - ], - "css/css-block/run-in-contains-table-inside-inline-001.xht": [ - "1a080c99fd25e1095b4664aa5f001d10eeea371e", - "reftest" - ], - "css/css-block/run-in-contains-table-inside-inline-002.xht": [ - "9937c034bdb0df12da9f2d6305ab9c5ab70b91fd", - "reftest" - ], - "css/css-block/run-in-contains-table-inside-inline-003.xht": [ - "da81ad5da653c2d560371b339a9dae72b33fbdae", - "reftest" - ], - "css/css-block/run-in-contains-table-row-001.xht": [ - "7f8c6603b1ab5fd9a3845769eefda2c367a20c02", - "reftest" - ], - "css/css-block/run-in-contains-table-row-group-001.xht": [ - "24a7f43411f93088fd94d0322eb05a0cec39c31c", - "reftest" - ], - "css/css-block/run-in-display-none-between-001.xht": [ - "b41224b028d9ae055937b119af885dfb5c4a5e43", - "reftest" - ], - "css/css-block/run-in-display-none-between-002.xht": [ - "8ae5b5743c4c54adcac5b4aeef00f3706147cf57", - "reftest" - ], - "css/css-block/run-in-display-none-between-003.xht": [ - "76901ba7cda655b286e0d384efc94314175e44a9", - "reftest" - ], - "css/css-block/run-in-fixedpos-between-001.xht": [ - "898efaa60daf1d5174b884cf862c1e82ee3fcc43", - "reftest" - ], - "css/css-block/run-in-fixedpos-between-002.xht": [ - "419a3aed33847413f5a7761d24c4597dd11c6eb8", - "reftest" - ], - "css/css-block/run-in-fixedpos-between-003.xht": [ - "429c6d9258d12321dfc5b754e2b4ae75a3015c98", - "reftest" - ], - "css/css-block/run-in-float-between-001.xht": [ - "3698456919cf966b8dd2ba8d5fae67cc5f1cdb4b", - "reftest" - ], - "css/css-block/run-in-float-between-002.xht": [ - "44ad6dcae26aba095987e299b81af4568d4ef7b1", - "reftest" - ], - "css/css-block/run-in-float-between-003.xht": [ - "d561aa7cb5206de8c3c314160c19814d800640ad", - "reftest" - ], - "css/css-block/run-in-inherit-001-ref.xht": [ - "697462c36a68eb8f60abed93a5be18b58bcf0626", - "support" - ], - "css/css-block/run-in-inherit-001.xht": [ - "f2382fbf93f981da1a585c60e9b377c29329a47c", - "reftest" - ], - "css/css-block/run-in-inheritance-001.xht": [ - "c3496a363e7ff9fff53261d8878523fa2687b8e6", - "visual" - ], - "css/css-block/run-in-inline-between-001.xht": [ - "4ea2d35766d3ae38fb2eecbc1c47ae36896a4b47", - "reftest" - ], - "css/css-block/run-in-inline-between-002.xht": [ - "f1c06805cb2b657e3816837e00f45c3e4bfe4ea9", - "reftest" - ], - "css/css-block/run-in-inline-between-003.xht": [ - "3c9fefe6a78fc7707e4148f9e4a083126036135c", - "reftest" - ], - "css/css-block/run-in-inline-block-between-001.xht": [ - "63bb102ca896d3c1d95a798c647d4692f21bb96f", - "reftest" - ], - "css/css-block/run-in-inline-block-between-002.xht": [ - "80c99eaa8dfd7e3ae7a18a8be5a6076ed32863a7", - "reftest" - ], - "css/css-block/run-in-inline-block-between-003.xht": [ - "787b437e8448491b487fdef488dc1fff6e13c608", - "reftest" - ], - "css/css-block/run-in-inline-table-between-001.xht": [ - "76f06b29154391ac6a94dc709e91b2ab3fe421d0", - "reftest" - ], - "css/css-block/run-in-inline-table-between-002.xht": [ - "14398c440ddc0ebc8b649f19d83fd52a9bba1055", - "reftest" - ], - "css/css-block/run-in-inline-table-between-003.xht": [ - "0bd512b2a4f512fa2e991fa947966a0ad6f74f81", - "reftest" - ], - "css/css-block/run-in-linebox-001.xht": [ - "62239e5b0ef406a4d2eacf31cfb52d1c70f380d1", - "visual" - ], - "css/css-block/run-in-linebox-002.xht": [ - "5a195c18d8f5b4121a5a87bc9d6bbf9bd863054c", - "visual" - ], - "css/css-block/run-in-listitem-between-001.xht": [ - "9a1bd8d93df3eda014ac0d009f3ec3c04201c5cb", - "reftest" - ], - "css/css-block/run-in-listitem-between-002.xht": [ - "2b1ad094020092479869a101d67964651db56cb3", - "reftest" - ], - "css/css-block/run-in-listitem-between-003.xht": [ - "9bae8b25156e91b853c23eb15a70a91689b704c3", - "reftest" - ], - "css/css-block/run-in-pre-ref.xht": [ - "865e5119c67a888f29e39928703eb3eb5b504b50", - "support" - ], - "css/css-block/run-in-relpos-between-001.xht": [ - "18b879ea165db1e5f2ed01932296eda41d191b42", - "reftest" - ], - "css/css-block/run-in-relpos-between-002.xht": [ - "d6397646005cf36745e392cc594a84005af830c2", - "reftest" - ], - "css/css-block/run-in-relpos-between-003.xht": [ - "814503160217e264ae2d1f8e56dbd02a86ddb672", - "reftest" - ], - "css/css-block/run-in-replaced-001-ref.xht": [ - "b09db13a8b6f0eaaa0d3e131181f0a39996bde4c", - "support" - ], - "css/css-block/run-in-replaced-001.xht": [ - "cc3f7375e8dd13b8d0ceb718c76d8ce65fe249cd", - "reftest" - ], - "css/css-block/run-in-restyle-001.xht": [ - "5c98c0ad78d612a4c69ad57ef721edaff8b169d2", - "reftest" - ], - "css/css-block/run-in-restyle-002.xht": [ - "01a20be11ad94ad9f1b5dd6f0669b2204424dc27", - "reftest" - ], - "css/css-block/run-in-restyle-003.xht": [ - "7b2a2bec64ebb168810307923fd585230ea32dec", - "reftest" - ], - "css/css-block/run-in-run-in-between-001.xht": [ - "31b481c5e327aa5dee982f945ddacb293706bbf3", - "reftest" - ], - "css/css-block/run-in-run-in-between-002.xht": [ - "7ff81653276feab32759c15c08547833aca86196", - "reftest" - ], - "css/css-block/run-in-run-in-between-003.xht": [ - "5983122a9e015f2f08dc0cb565194869fc23d505", - "reftest" - ], - "css/css-block/run-in-run-in-between-004.xht": [ - "a0e8126ec2ef495c62b48649c4b7c3eb766d4b8c", - "reftest" - ], - "css/css-block/run-in-run-in-between-005.xht": [ - "1adb32a3078b7fb14015c6e5699545bf39f2a10f", - "reftest" - ], - "css/css-block/run-in-run-in-between-006.xht": [ - "8dc1e460d109bb643382c4c39047f823d7b83a2a", - "reftest" - ], - "css/css-block/run-in-run-in-between-007.xht": [ - "2a9efa67d02de0d9e687b6bb986a1593779866de", - "reftest" - ], - "css/css-block/run-in-run-in-between-008.xht": [ - "4b3cf802de5cfe62f840fb43e1588d2ee0225f85", - "reftest" - ], - "css/css-block/run-in-table-between-001.xht": [ - "5523b17d807abc82410cd68e1eeb9df64c497483", - "reftest" - ], - "css/css-block/run-in-table-between-002.xht": [ - "2a3123b181e1840be435a47de3f9dfc5e0fbfa1a", - "reftest" - ], - "css/css-block/run-in-table-between-003.xht": [ - "e815c990a75d09b1f899389d5766ffe88ef2b420", - "reftest" - ], - "css/css-block/run-in-table-cell-between-001.xht": [ - "5a64485f150b9486ea8fc8b44b36eba0281843e4", - "reftest" - ], - "css/css-block/run-in-table-cell-between-002.xht": [ - "e2f59a56f7d1ed153b10c7b2f471cdda5c3f2fdc", - "reftest" - ], - "css/css-block/run-in-table-cell-between-003.xht": [ - "9575344b73ff90ee0a05e34f5981d757004b0f38", - "reftest" - ], - "css/css-block/run-in-table-row-between-001.xht": [ - "c920f933e6e9c5c7c255cdc1c2f430e01563c9ea", - "reftest" - ], - "css/css-block/run-in-table-row-between-002.xht": [ - "aa84045c62142d355f8a33b44ce06823cf70e058", - "reftest" - ], - "css/css-block/run-in-table-row-between-003.xht": [ - "cc9b62f52ffa918b1889ae1d4927212fe61327da", - "reftest" - ], - "css/css-block/run-in-text-between-001.xht": [ - "6c067847c8447b757c1cf7eca13cccb4591d7e8f", - "reftest" - ], - "css/css-block/run-in-text-between-002.xht": [ - "9f07e1ed65b5967d410210bcd6881fe7a3dd26a4", - "reftest" - ], - "css/css-block/run-in-text-between-003.xht": [ - "b71cecbbdda717bfe03a16b1ff06429b625187ef", - "reftest" - ], - "css/css-block/run-in-text-between-004.xht": [ - "380f0d7df62fec663a6e56d0a2861f9a48f9c477", - "reftest" - ], - "css/css-block/run-in-text-between-005.xht": [ - "a40c10072687534c2f57c3911647a64995dfd51f", - "reftest" - ], - "css/css-block/run-in-text-ref.xht": [ - "4162c4ee8fe9a3609065054e1aff017e89608c61", - "support" - ], - "css/css-block/support/black15x15.png": [ - "9252cae16138e45c07796fa5a10b6100ae703eaa", - "support" - ], - "css/css-block/support/blue15x15.png": [ - "eb48032c07bfeb1d3b6be6e5c9c34d2fe2180767", - "support" - ], - "css/css-block/support/blue96x96.png": [ - "99949c515749e66f471c3589ee7a0ef518aaccb5", - "support" - ], - "css/css-block/support/green15x15.png": [ - "de1830c21195763f7327f270b14b6d50dfdfb21d", - "support" - ], - "css/css-block/support/swatch-blue.png": [ - "e79958e10feeeed3db88dee9bae9ea80055593c5", - "support" - ], - "css/css-block/table-anonymous-block-001.xht": [ - "4f471b69edd2465deffc9d925a74ee0b30ad6824", - "visual" - ], - "css/css-block/table-layout-applies-to-004.xht": [ - "97f74eaf88a289c89d9c08e1c6865d28806cfbbb", - "visual" - ], - "css/css-block/text-align-applies-to-004.xht": [ - "e223bc1cc7a84ac02fc8b9ee157903bf3b3c9d3f", - "visual" - ], - "css/css-block/text-decoration-applies-to-004.xht": [ - "93eaff37aac086249c2f23d25289d4bd86f5f6da", - "reftest" - ], - "css/css-block/text-indent-applies-to-004.xht": [ - "86911ad06c2b5172e6aa5cf793661dac00ad02ac", - "visual" - ], - "css/css-block/text-transform-applies-to-004.xht": [ - "a0fdc00076eda2506592514656f7cb8ad66be948", - "reftest" - ], - "css/css-block/top-applies-to-011.xht": [ - "2b585ecb53fd1c84ef92a93ab66ccbc921f34440", - "visual" - ], - "css/css-block/unicode-bidi-applies-to-011.xht": [ - "11fab4558a7a3d43bf3f53759d02cc8834af7110", - "visual" - ], - "css/css-block/vertical-align-applies-to-011.xht": [ - "99f448c1a05cbd9bb9bd1cec7797812608aec98e", - "visual" - ], - "css/css-block/visibility-applies-to-011.xht": [ - "20695d8ba19bac1a499d973d5185e05b0bd4c1d8", - "visual" - ], - "css/css-block/white-space-applies-to-004.xht": [ - "f387077d9b2071510cfbafcc5bf6476c0342a89c", - "visual" - ], - "css/css-block/width-applies-to-011.xht": [ - "52820db0b9c9219535a52fe8a39c29139f2b4294", - "reftest" - ], - "css/css-block/word-spacing-applies-to-004.xht": [ - "ea4e80bc4e560a727ac60983e17b85fcdfaa06e0", - "visual" - ], - "css/css-block/z-index-applies-to-011.xht": [ - "71adc3eabed66929d71c1003ea9d5e10fee4f1a5", - "visual" - ], "css/css-break/break-before-always-001.xht": [ - "4dab2b2a55f0636df539abe73688480c78e6901d", + "926ed3f96ba7b5c6dee79ea417746cbd60342579", "visual" ], "css/css-cascade/OWNERS": [ @@ -467853,7 +472801,7 @@ "support" ], "css/css-color/blacktext-ref.html": [ - "89c791a3d59db9086af0eaab70052bfa69898740", + "5541159a1753a7e249c36d31f65e47d02e98f848", "support" ], "css/css-color/border-bottom-color.xht": [ @@ -467877,111 +472825,195 @@ "reftest" ], "css/css-color/color-001.html": [ - "648bebf2d7f06bfa25de3446ed288e2ae13fb68f", + "7b4dfc7ef8867e578571db07d05ca18c77936c89", "reftest" ], "css/css-color/color-002.html": [ - "733b41bdddc8c8d6f1a1a3b61d13da22f0c30e0a", + "3ec299abc57c6ff6a55c604c751182abdadd6c8a", "reftest" ], "css/css-color/color-003.html": [ - "3c50885ef6132633e2f1976bbbfaecda21036980", + "ec85953fb0594db50a69ca9952092aeab403cf2c", "reftest" ], + "css/css-color/color-resolving-hsl.html": [ + "672137820a0289306d53b3866ffa1f00daacc019", + "testharness" + ], + "css/css-color/color-resolving-keywords.html": [ + "2789a985787f59179c9bf1ad49ccb8dbbb8fea11", + "testharness" + ], + "css/css-color/color-resolving.html": [ + "6eb90c067520ae0d2a9e52bccba6e03981007958", + "testharness" + ], "css/css-color/currentcolor-001.html": [ - "60faf68f62cf5908218af340b6f4986d46df1c69", + "9563fc2934a198076ba32ec8659f0eca0515d953", "reftest" ], "css/css-color/currentcolor-002.html": [ - "050328d9f03f4db7f06dcdc330b5218b3e2ccdc7", + "aa684b5e5cb28456a345a315b1de546b8e6cd512", "reftest" ], + "css/css-color/greensquare-ref.html": [ + "5427df5d60b9ae063094858cfc8a7d3fcf22361a", + "support" + ], "css/css-color/greentext-ref.html": [ "249e669a27d0b23de6267626566c5ce8af58bc25", "support" ], "css/css-color/hex-001.html": [ - "00628d82c36f5f40d85d81a2f1b288e7ff9bec0f", + "283cee2f6d5f11a89504abae29a3dece7495f177", "reftest" ], "css/css-color/hex-002.html": [ - "885e4684bc1c9e8cf9c0879f4852f17a7be4c6e0", + "2d8036af7162bb8d5bf6f58aeb208e5b59a5c603", "reftest" ], + "css/css-color/hex-003-ref.html": [ + "ae310bf928918fbfaeb9321492d64ca51b8d5b9d", + "support" + ], "css/css-color/hex-003.html": [ - "36f6270be7b0e549fc523437651d3e2818293ce2", - "visual" + "00a369523764c1e142b1443e334f9e2bb757c641", + "reftest" ], "css/css-color/hex-004.html": [ - "3373d1578c9ee3c123dab1fef0930c950fc0f7cb", - "visual" + "1faab141bd125d7e6652deed6ca23771989580cf", + "reftest" + ], + "css/css-color/hsl-001.html": [ + "fa05f869ed6143538c863ca399affee8e12e33d5", + "reftest" + ], + "css/css-color/hsl-002.html": [ + "e4ae3cf55bf9c28e6caaeb32f33910c7d83a85d8", + "reftest" + ], + "css/css-color/hsl-003.html": [ + "2c2098102a8515449d82b152d4f56dbf405d05b9", + "reftest" + ], + "css/css-color/hsl-004.html": [ + "e4d1bf5ebdf8073e56d471808f3e38972fef551e", + "reftest" + ], + "css/css-color/hsl-005.html": [ + "942d3daaf06d625bb567a0349fee304b5a556f53", + "reftest" + ], + "css/css-color/hsl-006.html": [ + "9a5e95f174ca185439f681b42d460af24ec64786", + "reftest" + ], + "css/css-color/hsl-007.html": [ + "95f2428b37fd02dfb83e3b9b962c3a15bffbeedb", + "reftest" + ], + "css/css-color/hsl-008.html": [ + "aa39a32dba60c9073dfe370cbedf4a048772429a", + "reftest" + ], + "css/css-color/hsla-001.html": [ + "a25a2a4b85ddc4bf416241902f507063137b2661", + "reftest" + ], + "css/css-color/hsla-002.html": [ + "13b556990055a877180547042a55cfd179f36238", + "reftest" + ], + "css/css-color/hsla-003.html": [ + "6dfa73021a4d7557c15051e2047023288df3e713", + "reftest" + ], + "css/css-color/hsla-004.html": [ + "c3d1639b537d79c9cf778f2bb512fa9e23f6bf1b", + "reftest" + ], + "css/css-color/hsla-005.html": [ + "953e2dd5ec00c16b77510b62f9e349bdf837154e", + "reftest" + ], + "css/css-color/hsla-006.html": [ + "7ff9ba828aec73405305ced18c9293d86b50690d", + "reftest" + ], + "css/css-color/hsla-007.html": [ + "6e1fd3eef32751dc914448a565f222cadbbeb356", + "reftest" + ], + "css/css-color/hsla-008.html": [ + "279600290a3969b44259ea5f5c53253998c6adbe", + "reftest" ], "css/css-color/htaccess": [ "b7599c7f62cb964ae36008d5f7fa4b82b14cc3e9", "support" ], "css/css-color/lab-001.html": [ - "d5b7ae9e433101eca928b8ad4cfadc051ee2ccc2", + "a2a7c21f7a14b48cbeaaff2d88058ed3fee5d93d", "reftest" ], "css/css-color/lab-002.html": [ - "877761ad909cac559305c225f7e556288d031188", + "d3019fc562d3e2ae69e6efd3dbf4d0e1e3f8b1ad", "reftest" ], "css/css-color/lab-003.html": [ - "84158f12dfb72223d37e3b5559eb157f28a6217b", + "0723ed9d6c7414565e3dfed19b133f8450d6c092", "reftest" ], "css/css-color/lab-004.html": [ - "ae569fde05db02779297c871c507d6f5881e0676", + "51f4804db8a2f9e0e388c81cb1fee589e1bbdd28", "reftest" ], "css/css-color/lab-005.html": [ - "da99776896644f5b1ec799e4e4fd5e3bf2c6d5c8", + "db07745d8a25a48ea3bcf1b8d3ea56c58cdbc9af", "reftest" ], "css/css-color/lab-006.html": [ - "cfcdd14e2116de527a0dd961dcbaca89f8b027bd", + "eea09960176bb28aba7a05bde9acacb1960db649", "reftest" ], "css/css-color/lab-007.html": [ - "6f875b291924b0e4268bca4f4292a5a51001de78", + "c65ede9c328ddf85fc607a5ac78fd4897d25c926", "reftest" ], "css/css-color/lch-001.html": [ - "8149a8db744fe40d3ad76fd8091c2d0bece691d4", + "5b18f33c3947d8d9be59b886442f6e51248c5db6", "reftest" ], "css/css-color/lch-002.html": [ - "decd69eb8ce41f0e717b6eb3b219428fe1ee96ea", + "71aa14524a1b605daef298be6ac18f91a5740098", "reftest" ], "css/css-color/lch-003.html": [ - "bbba716dad9213c444a62c20ee1d6c4bf6b581d9", + "95d2f1189d42df113b964377bc69aa29cce3d134", "reftest" ], "css/css-color/lch-004.html": [ - "6e4e639970fdc83935f4a3adc10be76bc90a3c82", + "5e3588caa84df218f959bcf3fa98908e7a97c5a2", "reftest" ], "css/css-color/lch-005.html": [ - "4d4477a4dd83778dbedd67502175cee5d2de809f", + "9ed500d2841d09b3db270f4c4c6624e231fa5915", "reftest" ], "css/css-color/lch-006.html": [ - "9ef709aa95792f6e5acb7df3ef68f9e36f46d664", + "7eb1d1e686a1bc99621e2ecaa3b691eb7b81915b", "reftest" ], "css/css-color/lch-007.html": [ - "8f9a89d13ba8b510bd1b1d9db4ef3e68ea1f68e4", + "597f775935650c4259de1cdc85afdacb496aa3bb", "reftest" ], "css/css-color/named-001.html": [ - "b128c069ecd946774cd1a99636616b4608ce9126", + "fad454c9b86d70e19fb89265c8e131ff381ed2a0", "reftest" ], "css/css-color/rebeccapurple-ref.html": [ - "17e2ef8ba560dbe1791473759fb8580528c8df79", + "e089e2daad5e5db7131015bf45739e64050c6b36", "support" ], "css/css-color/rgb-001.html": [ @@ -468064,29 +473096,45 @@ "6ef52952d60deab37c102778a0fb56db704d98ed", "reftest" ], + "css/css-color/t32-opacity-basic-0.0-a-ref.html": [ + "97a8963a38c6dbbb18a594f11c9bb2c7e5f0a2b1", + "support" + ], "css/css-color/t32-opacity-basic-0.0-a.xht": [ - "641b6fe0e8b58160019ac388a1882258c8c3b119", - "visual" + "36abb11ff05c7968832d741f9a02269ce87ff141", + "reftest" ], "css/css-color/t32-opacity-basic-0.6-a.xht": [ "9d9df3be674bb5f1337be87670d46c0eed026e67", "visual" ], + "css/css-color/t32-opacity-basic-1.0-a-ref.html": [ + "0d121aca3970b1271f2b4849dfe49ef5798e7920", + "support" + ], "css/css-color/t32-opacity-basic-1.0-a.xht": [ - "a7a452594764791117888b0dcd3739d42ffd5796", - "visual" + "182ecc55a7ea82037c5999cbd51b51aab1c7809a", + "reftest" ], "css/css-color/t32-opacity-clamping-0.0-b.xht": [ - "7c70a818e5bb401e2960972859c52c159c95b876", - "visual" + "3e797a55789abf7162b65f30bbf550a27a7ee314", + "reftest" + ], + "css/css-color/t32-opacity-clamping-1.0-b-ref.html": [ + "c138f6411fd49193a8cbbe74c920dc64c2851a43", + "support" ], "css/css-color/t32-opacity-clamping-1.0-b.xht": [ - "aa6bfc4d262295dbc51b9bb0487c969eae00bddc", - "visual" + "b8fa4d8d0e54a0a2fc8f945af7f436181fa30b7b", + "reftest" + ], + "css/css-color/t32-opacity-offscreen-b-ref.html": [ + "f727493bfcd31d29a98b0b69982c85e7785bdf23", + "support" ], "css/css-color/t32-opacity-offscreen-b.xht": [ - "47f51b98cb3789796bec5e8eccf3a304c2cfb0c4", - "visual" + "dc3520769d1c6b310602423121d7cbe7a6349bbb", + "reftest" ], "css/css-color/t32-opacity-offscreen-multiple-boxes-1-c-ref.html": [ "3594dd7b57e2b39cab4cb628f6477b2b2a4f8cfb", @@ -468104,21 +473152,33 @@ "e02af1fea5690440983c959a6dd94fef08f41ad7", "reftest" ], + "css/css-color/t32-opacity-offscreen-with-alpha-c-ref.html": [ + "d1b756d83fdf8e3aa27a37a600c0939166b1ce43", + "support" + ], "css/css-color/t32-opacity-offscreen-with-alpha-c.xht": [ - "bd319bbe03dabc9b0bf609a9ed179a4fd8f50ba2", - "visual" + "8834024cf1e7d6743af492fd1d1526963b795186", + "reftest" ], "css/css-color/t32-opacity-zorder-c.xht": [ "d9c0793e3afa75b3e5b7860b1f0361b25a2490f4", "visual" ], + "css/css-color/t41-html4-keywords-a-ref.html": [ + "fe35d8991f77bec0c5b9e29354001650fc0939e3", + "support" + ], "css/css-color/t41-html4-keywords-a.xht": [ - "bd840b00197a086e255e50efe597725f70f167ef", - "visual" + "e08edc3b93fbfd9b7161aa0cc28485af280b8a3e", + "reftest" + ], + "css/css-color/t421-rgb-clip-outside-gamut-b-ref.html": [ + "8806ba740a49bef0d53dc49bfb24a525373bf64a", + "support" ], "css/css-color/t421-rgb-clip-outside-gamut-b.xht": [ - "1a8665f07bc06176ec3e395656db26a87ca1884b", - "visual" + "6e82b4076c59aa8a9c43f26c07dd14c33e0bc39c", + "reftest" ], "css/css-color/t421-rgb-func-int-a.xht": [ "affae2fcb347e5945b7341b8228d8e1009729977", @@ -468144,6 +473204,10 @@ "84148b6e86b2a3a68aacdec844019436d0f836c7", "reftest" ], + "css/css-color/t421-rgb-hex3-expand-b-ref.html": [ + "dbbee69e8d5443b8ef7a4efd2401c5c24b3e81cb", + "support" + ], "css/css-color/t421-rgb-hex3-expand-b.xht": [ "771ed736fef0db765beb042a658e55784c96c843", "visual" @@ -468152,13 +473216,17 @@ "ee949724f35b9e5579f821bbff4a708b2528dd7d", "reftest" ], + "css/css-color/t421-rgb-values-meaning-b-ref.html": [ + "dfdf69248220eb810031c2be74d8a58ee7990eac", + "support" + ], "css/css-color/t421-rgb-values-meaning-b.xht": [ - "ee4de49d2eb086958078f75ad87c1111f7de7ad7", - "visual" + "39c64ce7bd432b452fa970ff3147cf2eb5938c80", + "reftest" ], "css/css-color/t422-rgba-a0.0-a.xht": [ - "c99a9fc1f4193b0757a5ab704425ee761eadba16", - "visual" + "9c724ccc138d206374d86de3c07f75097d05c8e3", + "reftest" ], "css/css-color/t422-rgba-a0.6-a.xht": [ "b113473c73598e0ac6f54669c0b69bf35315dd74", @@ -468240,9 +473308,13 @@ "52cd48c468414a3e6d94a31c0bab6f5d04bfcc3c", "reftest" ], + "css/css-color/t422-rgba-values-meaning-b-ref.html": [ + "68e97f16df077b9103bfaf9380b6741141391982", + "support" + ], "css/css-color/t422-rgba-values-meaning-b.xht": [ - "cf37fdfa70940f3892d1bae3882a99a4512f58aa", - "visual" + "acf8b78878f7e802ea942ef971bd1488ad7c3421", + "reftest" ], "css/css-color/t423-transparent-1-a.xht": [ "3cc81ffe93d23180f24b7379c37276214074846b", @@ -468272,9 +473344,13 @@ "0ed35609de1852fa2870276606ab042291bd02bb", "reftest" ], + "css/css-color/t424-hsl-h-rotating-b-ref.html": [ + "9ca080fa1c31a9c7245c0d6451d8965500e77efd", + "support" + ], "css/css-color/t424-hsl-h-rotating-b.xht": [ - "acae31c06007d39c80b2796c99c1946ccde209bb", - "visual" + "b4f0e1c01af1a7c3c9ab31a34307e8f1ac70ec55", + "reftest" ], "css/css-color/t424-hsl-parsing-f-ref.html": [ "286da104ec5ceaac14c64fec235b2cc109ae6d3a", @@ -468416,13 +473492,17 @@ "257c0df648f50c198036a710151aca334522fed5", "reftest" ], + "css/css-color/t425-hsla-h-rotating-b-ref.html": [ + "cd455e72ebe236dc65f86dc9f480d9952c6730b7", + "support" + ], "css/css-color/t425-hsla-h-rotating-b.xht": [ - "07a0c79524074b22ac7ae73f9bcb56d8ba2bc70d", - "visual" + "1be1bd816dc4e2ee02a129879dfc53e571222a82", + "reftest" ], "css/css-color/t425-hsla-onscreen-b.xht": [ - "de76f1a5104324c95c59eee4cdb2601790e178c5", - "visual" + "544cf0bbf9cf4330090f559b0f5609b3dc44015c", + "reftest" ], "css/css-color/t425-hsla-onscreen-multiple-boxes-c.xht": [ "d2dc37794501b0ef2b05409c89367c4e01ac4ccb", @@ -468440,9 +473520,13 @@ "a9e194307d3ed4ee0f9aacf3c780598bd18d7d40", "reftest" ], + "css/css-color/t43-svg-keywords-a-ref.html": [ + "9119ed188422f341e6f6f7befbcac55cc24d890b", + "support" + ], "css/css-color/t43-svg-keywords-a.xht": [ - "b779696e6c036e877bb84cd978f1e944ce0fd788", - "visual" + "13a33016ff37bc8750efad1c4ef7357427d69f3f", + "reftest" ], "css/css-color/t44-currentcolor-background-b-ref.html": [ "53ee23e6007353180358a3291698fa66ae3d43b7", @@ -468473,7 +473557,7 @@ "visual" ], "css/css-color/whitetext-ref.html": [ - "fceb01c868ef9ac8be432bec04c9ef1c9939221d", + "e832afff6067587e429b47ed0ea1756a4bad3b81", "support" ], "css/css-conditional/OWNERS": [ @@ -468661,9 +473745,17 @@ "support" ], "css/css-conditional/test_group_insertRule.html": [ - "948230661efe702e443fe7e973d7c4995144588e", + "c805d45e2361bd67ebf1ca0605807d7384b09a7d", "testharness" ], + "css/css-contain/contain-style-counters-ref.html": [ + "295abc8d8c2490f3ff16566e49e9c77bf125461f", + "support" + ], + "css/css-contain/contain-style-counters.html": [ + "056b3597f3555c803c74a8f6277a06626efd12ea", + "reftest" + ], "css/css-counter-styles/OWNERS": [ "820cad495f069d1badb3a727b9a2514269c6008e", "support" @@ -469328,6 +474420,10 @@ "ab66821c508ced9656c769ff2647c7f9d57e4b15", "reftest" ], + "css/css-display/display-contents-before-after-003.html": [ + "2c15d52fdcb0ef9de97beb7bff8fdd2a733f1d67", + "reftest" + ], "css/css-display/display-contents-block-001.html": [ "c26501b3a2da59dd1615a492d580e26e401da485", "reftest" @@ -469340,10 +474436,18 @@ "a2ebae461e59f93107b1abcf88f38fa2e484371c", "reftest" ], + "css/css-display/display-contents-button.html": [ + "31f559d839f47e4034910ecf9224cccb3d44cac4", + "reftest" + ], "css/css-display/display-contents-computed-style.html": [ "bf523ee19c5ff481a3f91f8eb124eb83301738c5", "testharness" ], + "css/css-display/display-contents-details.html": [ + "d1f62084c5adc3ba7a86306704f804d4cbe0428c", + "reftest" + ], "css/css-display/display-contents-dynamic-before-after-001.html": [ "9142d9f1ad5b5e9a5f5705a44c962084f023a3c6", "reftest" @@ -469408,6 +474512,14 @@ "4fe143c25be9ecc08e58428f0c588f72c5cb8a3f", "reftest" ], + "css/css-display/display-contents-dynamic-pseudo-insertion-001-ref.html": [ + "d64e6fa233d294236f1a773e2d5a3ea214c64d25", + "support" + ], + "css/css-display/display-contents-dynamic-pseudo-insertion-001.html": [ + "221fb940d34860f62541ad53bb4b3834f3552577", + "reftest" + ], "css/css-display/display-contents-dynamic-table-001-inline.html": [ "5c105a711c083e61eefc4121c707d3ca2ffda3ec", "reftest" @@ -469424,14 +474536,26 @@ "c874f59947d37659e640d4e0abb8a0dc0f03927d", "reftest" ], + "css/css-display/display-contents-fieldset.html": [ + "5532214fa9e6d5b8a6423701760204f96efd65fe", + "reftest" + ], "css/css-display/display-contents-first-letter-001.html": [ "acfaf8f68595c7eb36585309b9d6b0bc5c0ffe41", "reftest" ], + "css/css-display/display-contents-first-letter-002.html": [ + "26a464c21e2dc798ef1b0187e93959b80633acc3", + "reftest" + ], "css/css-display/display-contents-first-line-001.html": [ "19f4bc895d895a6dd62b638960b4b7f2f26f5752", "reftest" ], + "css/css-display/display-contents-first-line-002.html": [ + "2344b7ec5bf451951069ff9ac3587a6338bd3196", + "reftest" + ], "css/css-display/display-contents-flex-001-ref.html": [ "30689a922a0172d3379e947a47b55e49d95c83cb", "support" @@ -469468,6 +474592,14 @@ "f235a8a06a76d156322822961609a9366f573536", "reftest" ], + "css/css-display/display-contents-line-height-ref.html": [ + "68d18b2d72b79547a2433ec8c7b230907906a0d4", + "support" + ], + "css/css-display/display-contents-line-height.html": [ + "6efd30ecfce1a5f1b2175847a36ea6cc4af148b2", + "reftest" + ], "css/css-display/display-contents-list-001-ref.html": [ "e5c5e9599b5f52c3ee9662bb70ae0c3c35b06530", "support" @@ -469504,14 +474636,6 @@ "f9d1eaa996cfe84ba9600383bd6c38d179fcbe91", "support" ], - "css/css-display/display-contents-replaced-001-ref.html": [ - "09008a1d912eb30702be95db99b8e5fd6604a768", - "support" - ], - "css/css-display/display-contents-replaced-001.html": [ - "4030618381ad36d2c03be81b3b97cdb87977ddec", - "reftest" - ], "css/css-display/display-contents-state-change-001-ref.html": [ "f7e25855cc7ef1896a9a52005d3c1379bf74746b", "support" @@ -469520,6 +474644,14 @@ "0a689fbe90be794772c66d59b033d15336e6dfe3", "reftest" ], + "css/css-display/display-contents-svg-elements-ref.html": [ + "3e4ddf5f740d8fa688bcbb24201be0a6d4349017", + "support" + ], + "css/css-display/display-contents-svg-elements.html": [ + "93573e17090a860bb09c2a208d925afac9cb17fd", + "reftest" + ], "css/css-display/display-contents-table-001-ref.html": [ "9de4ee8151dbfa3c8e2c381ddd213e51b04f70c1", "support" @@ -469540,6 +474672,14 @@ "95db05421f7ca48ed528db9fa2c23cfd5ccbac97", "reftest" ], + "css/css-display/display-contents-text-inherit-ref.html": [ + "b248e78a0255b923c4ed4aa269e65f53b6386bf4", + "support" + ], + "css/css-display/display-contents-text-inherit.html": [ + "c88c1d5fe8d2895ba3774d09ccb7a6adbe6c391b", + "reftest" + ], "css/css-display/display-contents-text-only-001-ref.html": [ "31474dc32adce5d808657170841e3307215f8105", "support" @@ -469556,6 +474696,10 @@ "f51f4df4bc1e93e84fc53a0d3352f737f6a68c0f", "reftest" ], + "css/css-display/display-contents-unusual-html-elements-none.html": [ + "dc354fb4f1896f655186cf57dd100f475a4ce5f0", + "reftest" + ], "css/css-display/display-flow-root-001-ref.html": [ "a9d3c569ae10db047d3f6ff3b0888a6d74cece61", "support" @@ -469564,6 +474708,970 @@ "f7d3cda238b0209165a77571c59af0701bcede17", "reftest" ], + "css/css-display/run-in/OWNERS": [ + "6634529fb114ab2e29cb2fa4a633289ee9038c22", + "support" + ], + "css/css-display/run-in/after-content-display-004.xht": [ + "61fd73789062cb65193cd3e2ab535151b2565b8b", + "visual" + ], + "css/css-display/run-in/anonymous-box-generation-002.xht": [ + "d8b897bec271896fa3362a6aef4a2c628ebbe0b3", + "visual" + ], + "css/css-display/run-in/background-applies-to-011.xht": [ + "a4f27fa89ec568aaeeccd6867b5dd1afcb4b86f6", + "visual" + ], + "css/css-display/run-in/background-attachment-applies-to-011.xht": [ + "02c5f4feaf50905f325b00d2635a77e631cbfe84", + "visual" + ], + "css/css-display/run-in/background-color-applies-to-011.xht": [ + "8b3b119f15080301b1314ea5b45e270b2823df89", + "visual" + ], + "css/css-display/run-in/background-image-applies-to-011.xht": [ + "9e9a51ef23a8968edc5d4a4c6f0305f6ddf0d7ed", + "visual" + ], + "css/css-display/run-in/background-position-applies-to-011.xht": [ + "ff1707da202a90261724386b16a401aef3b48f6e", + "visual" + ], + "css/css-display/run-in/background-repeat-applies-to-011.xht": [ + "88339d4a1b2cfc2fdff0905e592dcfaf75750cbb", + "visual" + ], + "css/css-display/run-in/before-content-display-004.xht": [ + "d7f0c8005d0ab64c13b48c0589c1c0083bcb254b", + "visual" + ], + "css/css-display/run-in/border-applies-to-011.xht": [ + "36eded364e030b01fe560e74e50f8fa8c118a433", + "visual" + ], + "css/css-display/run-in/border-bottom-applies-to-011.xht": [ + "daad8099c06632a6423a90a913fef6643bef2366", + "visual" + ], + "css/css-display/run-in/border-bottom-color-applies-to-011.xht": [ + "1f06ae35fa63cdc01c50754e945135cd65c81336", + "visual" + ], + "css/css-display/run-in/border-bottom-style-applies-to-011.xht": [ + "f14782efe820b83b706b3ff6ecf1893bff256e42", + "visual" + ], + "css/css-display/run-in/border-bottom-width-applies-to-011.xht": [ + "20389e139890e0e699712d9d9fc967ea0cb81d97", + "visual" + ], + "css/css-display/run-in/border-collapse-applies-to-004.xht": [ + "44cbf688dbc21665f0cab3f608521293fc562796", + "visual" + ], + "css/css-display/run-in/border-color-applies-to-011.xht": [ + "29ae73e9211b753a7d687ba7e73e30daf052d169", + "visual" + ], + "css/css-display/run-in/border-left-applies-to-011.xht": [ + "74d022f4145b07d71c0ac5cd008df29138ae4d31", + "visual" + ], + "css/css-display/run-in/border-left-color-applies-to-011.xht": [ + "08bd2a4ec6c575b8121e96bbdb8a0b2aa74140e3", + "visual" + ], + "css/css-display/run-in/border-left-style-applies-to-011.xht": [ + "6270c843418d4eb40cccb1705ab2b17ac0f92f3d", + "visual" + ], + "css/css-display/run-in/border-left-width-applies-to-011.xht": [ + "7496c6f5f5b46eb69de37176935cca76ad56d6bb", + "visual" + ], + "css/css-display/run-in/border-right-applies-to-011.xht": [ + "78cd49b2e855a61cecb4e1b523841cab00081643", + "visual" + ], + "css/css-display/run-in/border-right-color-applies-to-011.xht": [ + "e2391f060977badec62709241a824f97e597eccd", + "visual" + ], + "css/css-display/run-in/border-right-style-applies-to-011.xht": [ + "ae3f43f85ef5266eeda294bf4524d125e871a317", + "visual" + ], + "css/css-display/run-in/border-right-width-applies-to-011.xht": [ + "3209cbf4c1aa5d5c023ed13a17eac529052652a8", + "visual" + ], + "css/css-display/run-in/border-spacing-applies-to-004.xht": [ + "862913eace05677ad332a5c76532599694bf69f6", + "visual" + ], + "css/css-display/run-in/border-style-applies-to-011.xht": [ + "2ddc53bf2d5b8ab1e5c3b16e48ae5a2036fe31ea", + "visual" + ], + "css/css-display/run-in/border-top-applies-to-011.xht": [ + "ba40b08236b9c5993613af13f8dd96d3932c8475", + "visual" + ], + "css/css-display/run-in/border-top-color-applies-to-011.xht": [ + "b5184bc4fde674a806dccd7a061bd86fdb2f15a0", + "visual" + ], + "css/css-display/run-in/border-top-style-applies-to-011.xht": [ + "75e780e649cac1c0e695ac8275a8a588751b939a", + "visual" + ], + "css/css-display/run-in/border-top-width-applies-to-011.xht": [ + "9d5bedf58e1f861eab96f9d0b9fe90b58e021413", + "visual" + ], + "css/css-display/run-in/border-width-applies-to-011.xht": [ + "a7126e39d2d60e8f4d2f018cea4d001b8cc94066", + "visual" + ], + "css/css-display/run-in/bottom-applies-to-011.xht": [ + "f8e7490e71cf3899de316e306cea3947a17e1f77", + "visual" + ], + "css/css-display/run-in/caption-side-applies-to-004.xht": [ + "ce42ae349ae0e76af642f7e7ad19c812690562df", + "visual" + ], + "css/css-display/run-in/clear-applies-to-011.xht": [ + "3279ebd7562dcbf8c29f872e4d3ce76447c6d9c8", + "visual" + ], + "css/css-display/run-in/clear-runin-001.xht": [ + "bcaed5391dc08f90de390194e84df4db9b0d8e38", + "visual" + ], + "css/css-display/run-in/color-applies-to-011.xht": [ + "605a38365b79fa452ab47c9d1b7e77e68bc96218", + "visual" + ], + "css/css-display/run-in/counter-increment-applies-to-011.xht": [ + "868b48e97ad5644be25a5456cf5c9529f01e72e1", + "reftest" + ], + "css/css-display/run-in/counter-reset-applies-to-011.xht": [ + "7f634aa09cfad1aaa1e9fb7fa9e316fa33608da8", + "reftest" + ], + "css/css-display/run-in/cursor-applies-to-011.xht": [ + "cc19264db7880b0a52412e501cb2852d33fd175d", + "manual" + ], + "css/css-display/run-in/direction-applies-to-011.xht": [ + "44512ff84708807b22f18a79bb18623a4b933f27", + "visual" + ], + "css/css-display/run-in/display-004.xht": [ + "7471ec0ca8d4f375feb49136e468dc06ab52f265", + "visual" + ], + "css/css-display/run-in/empty-cells-applies-to-004.xht": [ + "1a5763fed630b9d731f2af9961514be9af9f907e", + "visual" + ], + "css/css-display/run-in/first-line-pseudo-009.xht": [ + "5636f5b08a197f797debed5dea6726315578828f", + "visual" + ], + "css/css-display/run-in/float-applies-to-011.xht": [ + "01efe6f3b3298581cb45d2850b1f9732868fd381", + "visual" + ], + "css/css-display/run-in/font-applies-to-004.xht": [ + "9b51369f7b55b2be28ae1c472a446e0de5e476e0", + "visual" + ], + "css/css-display/run-in/font-family-applies-to-004.xht": [ + "627f012fde5832fa4fc098b2b1423e4db05ce95b", + "visual" + ], + "css/css-display/run-in/font-size-applies-to-004.xht": [ + "a3bcca3e7c843c4e0fa6ccb72a2b5ce6a193eecf", + "visual" + ], + "css/css-display/run-in/font-style-applies-to-004.xht": [ + "777b8cb354110c153f8319035c1fe5c9d345a890", + "reftest" + ], + "css/css-display/run-in/font-variant-applies-to-004.xht": [ + "cf8abd6c2c6b0140672662d13a5609b8a903d0b2", + "reftest" + ], + "css/css-display/run-in/font-weight-applies-to-004.xht": [ + "65df6e8576ac3677d9a496919c4ef438b82732af", + "reftest" + ], + "css/css-display/run-in/height-applies-to-011.xht": [ + "dd0d58d2cf6409c453e3671be60704be870bb4d9", + "reftest" + ], + "css/css-display/run-in/left-applies-to-011.xht": [ + "ac86f465cdda1d482a5d336e3055d219b7547b9c", + "visual" + ], + "css/css-display/run-in/letter-spacing-applies-to-004.xht": [ + "cfd1860e79789d3f6b083fcbfd87863f9c5d6bdf", + "reftest" + ], + "css/css-display/run-in/line-height-applies-to-011.xht": [ + "5a504d5186b825f7a3ce231e7467319ecde7864c", + "visual" + ], + "css/css-display/run-in/list-style-applies-to-011.xht": [ + "01a3a5f312f88eaf8e2db2b63547b62fc3d40c30", + "reftest" + ], + "css/css-display/run-in/list-style-image-applies-to-011.xht": [ + "e6d6ef7fcfe75338a9f4c5d74bcf8695602417d8", + "visual" + ], + "css/css-display/run-in/list-style-position-applies-to-011.xht": [ + "86092ff94df9f7268dce918a9edcc6ff86b570e0", + "visual" + ], + "css/css-display/run-in/list-style-type-applies-to-011.xht": [ + "4a32082111b2e4ce95fe634b6533d9150345d9d2", + "reftest" + ], + "css/css-display/run-in/margin-applies-to-011.xht": [ + "23b14b25f9629a21eb30d27e9d8dadb15fc05b4e", + "visual" + ], + "css/css-display/run-in/margin-bottom-applies-to-011.xht": [ + "c528dcd41815a387a9e3625821135da92d7f032b", + "visual" + ], + "css/css-display/run-in/margin-left-applies-to-011.xht": [ + "124c70029386ebd9a72571a2177d968544d46421", + "visual" + ], + "css/css-display/run-in/margin-right-applies-to-011.xht": [ + "e819e775b2b1395c5f8210bb37beee1f1f8859b9", + "visual" + ], + "css/css-display/run-in/margin-top-applies-to-011.xht": [ + "dd48bef2f6e5fec6a57cef62997affd1a9d882c7", + "visual" + ], + "css/css-display/run-in/max-height-applies-to-011.xht": [ + "8d828771e67e4024c7d048b788b6111f49cf8be7", + "reftest" + ], + "css/css-display/run-in/max-width-applies-to-011.xht": [ + "4e1a5517a853ccedaa8e2d8e93dfcf8692d6d228", + "reftest" + ], + "css/css-display/run-in/min-height-applies-to-011.xht": [ + "07465372180e85e3d265f445a2fcd6c9b967bd14", + "reftest" + ], + "css/css-display/run-in/min-width-applies-to-011.xht": [ + "c4088a9a0785e4ab882e66f8e5e54888aec562ae", + "reftest" + ], + "css/css-display/run-in/outline-applies-to-011.xht": [ + "191fa8aafcab7760a159b1e4bb4f1e763d79ec22", + "visual" + ], + "css/css-display/run-in/outline-color-applies-to-011.xht": [ + "c8ef9366d397901fc7cfc60fcfeb7e779cc2b629", + "visual" + ], + "css/css-display/run-in/outline-style-applies-to-011.xht": [ + "395b8328ab7ffe7a8e542b377383c6f2fc23e168", + "visual" + ], + "css/css-display/run-in/outline-width-applies-to-011.xht": [ + "d367fcd30a2a5cace628c6414bdaea814c64434f", + "visual" + ], + "css/css-display/run-in/overflow-applies-to-011.xht": [ + "94ec0236bb7babe73b3bfa3135ef59077792a14c", + "visual" + ], + "css/css-display/run-in/padding-applies-to-011.xht": [ + "06043f0bc1ee56f9c9aa14ee894c7f71ae66d08c", + "visual" + ], + "css/css-display/run-in/padding-bottom-applies-to-011.xht": [ + "1f99d22839b620ead278902451b4393d16320cdf", + "visual" + ], + "css/css-display/run-in/padding-left-applies-to-011.xht": [ + "c46dcccd743de4c4af7e159cdab344e9e6e8c943", + "visual" + ], + "css/css-display/run-in/padding-right-applies-to-011.xht": [ + "b828450be59f1a3f52a60dec63f98255b21901ed", + "visual" + ], + "css/css-display/run-in/padding-top-applies-to-011.xht": [ + "9674c7b62e79e1cd886db2b4b84f5cbb5514aece", + "visual" + ], + "css/css-display/run-in/position-applies-to-011.xht": [ + "0720bf370b26ef35c9e2ea50c9faead2c98b8139", + "visual" + ], + "css/css-display/run-in/quotes-applies-to-011.xht": [ + "42ac25a7df37605934ea5ce84a74b43829dcfce8", + "reftest" + ], + "css/css-display/run-in/right-applies-to-011.xht": [ + "a80a4cee631686ec8df21372dacd609be35b8fa6", + "visual" + ], + "css/css-display/run-in/run-in-001.xht": [ + "b0a4627e8ac492cd231537db0bdc18dc27dc7104", + "visual" + ], + "css/css-display/run-in/run-in-002.xht": [ + "544419a0449424193f44b911e248fbfd0de23246", + "visual" + ], + "css/css-display/run-in/run-in-003.xht": [ + "e9a318519677aab01514814a6ba97c9a936807fb", + "visual" + ], + "css/css-display/run-in/run-in-004.xht": [ + "7b0837c9ee4571e49f97b083b855fcd691865bb3", + "visual" + ], + "css/css-display/run-in/run-in-005.xht": [ + "5b97ec05a44c1d7cf7895808255ba2fc18c80f86", + "visual" + ], + "css/css-display/run-in/run-in-006.xht": [ + "a59419542724e65457923d0389004a3eec2a4f77", + "visual" + ], + "css/css-display/run-in/run-in-007.xht": [ + "c175c5311ac085143da2e59f54f5774ed5f2f5e9", + "visual" + ], + "css/css-display/run-in/run-in-008.xht": [ + "1d0865927beea6342fff5c4fc69040acc9489512", + "visual" + ], + "css/css-display/run-in/run-in-009.xht": [ + "71095c3996aff8d47fe520ff8fee2fa3b1cb2ebf", + "visual" + ], + "css/css-display/run-in/run-in-010.xht": [ + "49213be77399f1a831d5b4b1a2f34fddeaa79b22", + "visual" + ], + "css/css-display/run-in/run-in-011.xht": [ + "1974e33d93c187081046429312c76ea134df919e", + "visual" + ], + "css/css-display/run-in/run-in-012.xht": [ + "ee5dac6b692fd283d7a097682dadfa6b626a05e1", + "visual" + ], + "css/css-display/run-in/run-in-013.xht": [ + "11bc7fde7caf907343151062bb9ae809bae8c82d", + "visual" + ], + "css/css-display/run-in/run-in-abspos-between-001.xht": [ + "3e1ad3faad361d1d2d593768a443910cf4cd490b", + "reftest" + ], + "css/css-display/run-in/run-in-abspos-between-002.xht": [ + "c107b4fb41bd56638a0eb720131f91d4e5538a78", + "reftest" + ], + "css/css-display/run-in/run-in-abspos-between-003.xht": [ + "23dea7a79da74d238e1c25a8c28296de817bc59b", + "reftest" + ], + "css/css-display/run-in/run-in-basic-001.xht": [ + "0c34f3144766492c0cb309877d6db143697d9e02", + "reftest" + ], + "css/css-display/run-in/run-in-basic-002.xht": [ + "09c62f1052efe44790ec822550e8e3cd835beb6a", + "reftest" + ], + "css/css-display/run-in/run-in-basic-003.xht": [ + "087430960604e40634bba7dc932f788570b8c598", + "reftest" + ], + "css/css-display/run-in/run-in-basic-004.xht": [ + "3831b02ab852d1d9f0c9417921ab4ca927896dc4", + "reftest" + ], + "css/css-display/run-in/run-in-basic-005.xht": [ + "b2135f56d2885505eb44dcaaf2160ce29df7e4fa", + "reftest" + ], + "css/css-display/run-in/run-in-basic-006.xht": [ + "01817fa44e367c4a7a020513aeb7c3456161cdd5", + "reftest" + ], + "css/css-display/run-in/run-in-basic-007-ref.xht": [ + "11014cb21bcdf13e85c4d0086df9a25507613808", + "support" + ], + "css/css-display/run-in/run-in-basic-007.xht": [ + "43dd105bde7f2e41c15d36b33e6554e391dc079f", + "reftest" + ], + "css/css-display/run-in/run-in-basic-008.xht": [ + "f24259a5fed7bf8cab18b9184e35212e02800c96", + "reftest" + ], + "css/css-display/run-in/run-in-basic-009.xht": [ + "e98daeb42c3a54d32b97d843addfa5d2dda44828", + "reftest" + ], + "css/css-display/run-in/run-in-basic-010.xht": [ + "0bc99c24b856b18ea3fa55869db75a67de43ab8d", + "reftest" + ], + "css/css-display/run-in/run-in-basic-011.xht": [ + "a1b654d27c1dab2ad1e4703b67e38d3e9bd2a188", + "reftest" + ], + "css/css-display/run-in/run-in-basic-012.xht": [ + "c81ee8a2132c0ba8a6b21724d096cdafb847378b", + "reftest" + ], + "css/css-display/run-in/run-in-basic-013.xht": [ + "2531d2898252313a9fe2f58723b88dd8fc687db3", + "reftest" + ], + "css/css-display/run-in/run-in-basic-014.xht": [ + "59d9c7c29da0b266a4ff93650fb5d6a7855ec4e8", + "reftest" + ], + "css/css-display/run-in/run-in-basic-015.xht": [ + "8a07cf400198531a7967b5902c2bc2d54619ab43", + "reftest" + ], + "css/css-display/run-in/run-in-basic-016.xht": [ + "6e253d56c74265591f9f8f56975698e88c2f14fc", + "reftest" + ], + "css/css-display/run-in/run-in-basic-017.xht": [ + "a2146b35df1dc7bd6a6ea30600576d66523c1934", + "reftest" + ], + "css/css-display/run-in/run-in-basic-018.xht": [ + "62720b81190790760a9bc1fab01a5643cdf10395", + "reftest" + ], + "css/css-display/run-in/run-in-basic-ref.xht": [ + "5c7bf6627792ff8dfa7898148318478fc9397673", + "support" + ], + "css/css-display/run-in/run-in-block-between-001.xht": [ + "8bd7a8465542fdddf4a766566058ea858094f3c0", + "reftest" + ], + "css/css-display/run-in/run-in-block-between-002.xht": [ + "5dc15f0706212f0231f83f98f6625041f8cbd2f1", + "reftest" + ], + "css/css-display/run-in/run-in-block-between-003.xht": [ + "4a6ffa1bc42e3730571f20877d486ee8787168a5", + "reftest" + ], + "css/css-display/run-in/run-in-block-ref.xht": [ + "071c80df59c30b1d27eb71bf640dc1851c82caae", + "support" + ], + "css/css-display/run-in/run-in-breaking-001-ref.xht": [ + "2340373520e5da7655abe63565a265dc5cb033b9", + "support" + ], + "css/css-display/run-in/run-in-breaking-001.xht": [ + "5fc81726a11c8dacd0836d7c58e6d3b2e6520de9", + "reftest" + ], + "css/css-display/run-in/run-in-breaking-002-ref.xht": [ + "0a7d186899713e3176f1fec521fdba32aec23c75", + "support" + ], + "css/css-display/run-in/run-in-breaking-002.xht": [ + "845947b845f9ac605a6be41e2159c0f5940017da", + "reftest" + ], + "css/css-display/run-in/run-in-clear-001.xht": [ + "7a2c163d274376ebc920d4861a6050f2ee150ae7", + "reftest" + ], + "css/css-display/run-in/run-in-clear-002.xht": [ + "150555e798c6a601b272f4f399ac59bf01181d49", + "reftest" + ], + "css/css-display/run-in/run-in-contains-abspos-001.xht": [ + "505db18a1ef6306f55d3ccb0da91468eb1832e45", + "reftest" + ], + "css/css-display/run-in/run-in-contains-block-001.xht": [ + "14a094004359b5d82a346789d943a10986a219ca", + "reftest" + ], + "css/css-display/run-in/run-in-contains-block-002.xht": [ + "da1db69ceba2cbeb435c05d2b0db72400e7da3d6", + "reftest" + ], + "css/css-display/run-in/run-in-contains-block-003.xht": [ + "3cd68ce6725aea4a8dc0d9c0a2c0f9a6d11fd9d9", + "reftest" + ], + "css/css-display/run-in/run-in-contains-block-004.xht": [ + "7db957af8ab1c8baa83fe1c80030038c24a1a7f5", + "reftest" + ], + "css/css-display/run-in/run-in-contains-block-005.xht": [ + "f9edbb5b1931152f0fc59a49fa7ceaf562907e10", + "reftest" + ], + "css/css-display/run-in/run-in-contains-block-inside-inline-001.xht": [ + "8acc13aafb56c42ea28056d89c75ec7abf5ded8a", + "reftest" + ], + "css/css-display/run-in/run-in-contains-block-inside-inline-002.xht": [ + "c2819892d00974d39407022d3999dc0e3a99cc86", + "reftest" + ], + "css/css-display/run-in/run-in-contains-block-inside-inline-003.xht": [ + "66cbe19763f9d390ec7c059ea290abc8594cdde8", + "reftest" + ], + "css/css-display/run-in/run-in-contains-float-001.xht": [ + "c761acc50f08e90f703a81ae8f22ff6e42709491", + "reftest" + ], + "css/css-display/run-in/run-in-contains-inline-001.xht": [ + "4d7b0268d78bfbd575a2b83d0c220bb9773a0b68", + "reftest" + ], + "css/css-display/run-in/run-in-contains-inline-002.xht": [ + "51c1489ef21996a11c5fb2b316fb33e0382eedb9", + "reftest" + ], + "css/css-display/run-in/run-in-contains-inline-003.xht": [ + "cc4c7b96db888e2c4b5c72500b826d8594b2e131", + "reftest" + ], + "css/css-display/run-in/run-in-contains-inline-004.xht": [ + "153dba85a8e212106ba545d91e769bfa7ed01f75", + "reftest" + ], + "css/css-display/run-in/run-in-contains-inline-005.xht": [ + "a405159d3ad1841125d71fb1da1f20b48a4be773", + "reftest" + ], + "css/css-display/run-in/run-in-contains-inline-006.xht": [ + "36ec63fd75a421d0fe020a97a786cd368ad7d247", + "reftest" + ], + "css/css-display/run-in/run-in-contains-inline-007.xht": [ + "f7496dd5eefa7fda7438936dcaeff54a95a8aa0d", + "reftest" + ], + "css/css-display/run-in/run-in-contains-inline-block-001.xht": [ + "bf9e2c4e86d11e99389f283977b2c5b112e73587", + "reftest" + ], + "css/css-display/run-in/run-in-contains-inline-table-001.xht": [ + "e7d121beeb034e758fb5efa0082dc93b3efedbf1", + "reftest" + ], + "css/css-display/run-in/run-in-contains-relpos-block-001.xht": [ + "675a88d85b722cc515fb158584b7572cc140fb4e", + "reftest" + ], + "css/css-display/run-in/run-in-contains-relpos-block-002.xht": [ + "2be9a77b6a4e838cc08fcfc8f9920ddc28261381", + "reftest" + ], + "css/css-display/run-in/run-in-contains-relpos-block-003.xht": [ + "c60fcf48a612655bea93d03a072f21c072f8c0f0", + "reftest" + ], + "css/css-display/run-in/run-in-contains-run-in-001.xht": [ + "440555c995389809c51c646d540bf5d48d300e70", + "reftest" + ], + "css/css-display/run-in/run-in-contains-run-in-002.xht": [ + "04fa874c1d0d2a26de77421e484ef222def2ea24", + "reftest" + ], + "css/css-display/run-in/run-in-contains-run-in-003.xht": [ + "d9777e903841d7473f21e7d8132194fd2670aac4", + "reftest" + ], + "css/css-display/run-in/run-in-contains-table-001.xht": [ + "89f16b25b8c73fd543936890c24e6359f14a0d26", + "reftest" + ], + "css/css-display/run-in/run-in-contains-table-002.xht": [ + "c681daf1640dfae048990cb4ffe6a66783d6efff", + "reftest" + ], + "css/css-display/run-in/run-in-contains-table-003.xht": [ + "452fe200c9b557ba8a5425d352c52f718dd01c5d", + "reftest" + ], + "css/css-display/run-in/run-in-contains-table-caption-001.xht": [ + "555a7a80b7b13ed6694e6752702098088beefcb7", + "reftest" + ], + "css/css-display/run-in/run-in-contains-table-cell-001.xht": [ + "f48afe1c718d9b6d17a6d0ae866ee47e5e9daf46", + "reftest" + ], + "css/css-display/run-in/run-in-contains-table-column-001.xht": [ + "5211a09e5126d906b54970831fafae37fd361903", + "reftest" + ], + "css/css-display/run-in/run-in-contains-table-column-group-001.xht": [ + "506b7828e6d6d602f5a47b0a67555bd8efeec352", + "reftest" + ], + "css/css-display/run-in/run-in-contains-table-inside-inline-001.xht": [ + "1a080c99fd25e1095b4664aa5f001d10eeea371e", + "reftest" + ], + "css/css-display/run-in/run-in-contains-table-inside-inline-002.xht": [ + "9937c034bdb0df12da9f2d6305ab9c5ab70b91fd", + "reftest" + ], + "css/css-display/run-in/run-in-contains-table-inside-inline-003.xht": [ + "da81ad5da653c2d560371b339a9dae72b33fbdae", + "reftest" + ], + "css/css-display/run-in/run-in-contains-table-row-001.xht": [ + "7f8c6603b1ab5fd9a3845769eefda2c367a20c02", + "reftest" + ], + "css/css-display/run-in/run-in-contains-table-row-group-001.xht": [ + "24a7f43411f93088fd94d0322eb05a0cec39c31c", + "reftest" + ], + "css/css-display/run-in/run-in-display-none-between-001.xht": [ + "b41224b028d9ae055937b119af885dfb5c4a5e43", + "reftest" + ], + "css/css-display/run-in/run-in-display-none-between-002.xht": [ + "8ae5b5743c4c54adcac5b4aeef00f3706147cf57", + "reftest" + ], + "css/css-display/run-in/run-in-display-none-between-003.xht": [ + "76901ba7cda655b286e0d384efc94314175e44a9", + "reftest" + ], + "css/css-display/run-in/run-in-fixedpos-between-001.xht": [ + "898efaa60daf1d5174b884cf862c1e82ee3fcc43", + "reftest" + ], + "css/css-display/run-in/run-in-fixedpos-between-002.xht": [ + "419a3aed33847413f5a7761d24c4597dd11c6eb8", + "reftest" + ], + "css/css-display/run-in/run-in-fixedpos-between-003.xht": [ + "429c6d9258d12321dfc5b754e2b4ae75a3015c98", + "reftest" + ], + "css/css-display/run-in/run-in-float-between-001.xht": [ + "3698456919cf966b8dd2ba8d5fae67cc5f1cdb4b", + "reftest" + ], + "css/css-display/run-in/run-in-float-between-002.xht": [ + "44ad6dcae26aba095987e299b81af4568d4ef7b1", + "reftest" + ], + "css/css-display/run-in/run-in-float-between-003.xht": [ + "d561aa7cb5206de8c3c314160c19814d800640ad", + "reftest" + ], + "css/css-display/run-in/run-in-inherit-001-ref.xht": [ + "697462c36a68eb8f60abed93a5be18b58bcf0626", + "support" + ], + "css/css-display/run-in/run-in-inherit-001.xht": [ + "f2382fbf93f981da1a585c60e9b377c29329a47c", + "reftest" + ], + "css/css-display/run-in/run-in-inheritance-001.xht": [ + "c3496a363e7ff9fff53261d8878523fa2687b8e6", + "visual" + ], + "css/css-display/run-in/run-in-inline-between-001.xht": [ + "4ea2d35766d3ae38fb2eecbc1c47ae36896a4b47", + "reftest" + ], + "css/css-display/run-in/run-in-inline-between-002.xht": [ + "f1c06805cb2b657e3816837e00f45c3e4bfe4ea9", + "reftest" + ], + "css/css-display/run-in/run-in-inline-between-003.xht": [ + "3c9fefe6a78fc7707e4148f9e4a083126036135c", + "reftest" + ], + "css/css-display/run-in/run-in-inline-block-between-001.xht": [ + "63bb102ca896d3c1d95a798c647d4692f21bb96f", + "reftest" + ], + "css/css-display/run-in/run-in-inline-block-between-002.xht": [ + "80c99eaa8dfd7e3ae7a18a8be5a6076ed32863a7", + "reftest" + ], + "css/css-display/run-in/run-in-inline-block-between-003.xht": [ + "787b437e8448491b487fdef488dc1fff6e13c608", + "reftest" + ], + "css/css-display/run-in/run-in-inline-table-between-001.xht": [ + "76f06b29154391ac6a94dc709e91b2ab3fe421d0", + "reftest" + ], + "css/css-display/run-in/run-in-inline-table-between-002.xht": [ + "14398c440ddc0ebc8b649f19d83fd52a9bba1055", + "reftest" + ], + "css/css-display/run-in/run-in-inline-table-between-003.xht": [ + "0bd512b2a4f512fa2e991fa947966a0ad6f74f81", + "reftest" + ], + "css/css-display/run-in/run-in-linebox-001.xht": [ + "62239e5b0ef406a4d2eacf31cfb52d1c70f380d1", + "visual" + ], + "css/css-display/run-in/run-in-linebox-002.xht": [ + "5a195c18d8f5b4121a5a87bc9d6bbf9bd863054c", + "visual" + ], + "css/css-display/run-in/run-in-listitem-between-001.xht": [ + "9a1bd8d93df3eda014ac0d009f3ec3c04201c5cb", + "reftest" + ], + "css/css-display/run-in/run-in-listitem-between-002.xht": [ + "2b1ad094020092479869a101d67964651db56cb3", + "reftest" + ], + "css/css-display/run-in/run-in-listitem-between-003.xht": [ + "9bae8b25156e91b853c23eb15a70a91689b704c3", + "reftest" + ], + "css/css-display/run-in/run-in-pre-ref.xht": [ + "865e5119c67a888f29e39928703eb3eb5b504b50", + "support" + ], + "css/css-display/run-in/run-in-relpos-between-001.xht": [ + "18b879ea165db1e5f2ed01932296eda41d191b42", + "reftest" + ], + "css/css-display/run-in/run-in-relpos-between-002.xht": [ + "d6397646005cf36745e392cc594a84005af830c2", + "reftest" + ], + "css/css-display/run-in/run-in-relpos-between-003.xht": [ + "814503160217e264ae2d1f8e56dbd02a86ddb672", + "reftest" + ], + "css/css-display/run-in/run-in-replaced-001-ref.xht": [ + "b09db13a8b6f0eaaa0d3e131181f0a39996bde4c", + "support" + ], + "css/css-display/run-in/run-in-replaced-001.xht": [ + "cc3f7375e8dd13b8d0ceb718c76d8ce65fe249cd", + "reftest" + ], + "css/css-display/run-in/run-in-restyle-001.xht": [ + "5c98c0ad78d612a4c69ad57ef721edaff8b169d2", + "reftest" + ], + "css/css-display/run-in/run-in-restyle-002.xht": [ + "01a20be11ad94ad9f1b5dd6f0669b2204424dc27", + "reftest" + ], + "css/css-display/run-in/run-in-restyle-003.xht": [ + "7b2a2bec64ebb168810307923fd585230ea32dec", + "reftest" + ], + "css/css-display/run-in/run-in-run-in-between-001.xht": [ + "31b481c5e327aa5dee982f945ddacb293706bbf3", + "reftest" + ], + "css/css-display/run-in/run-in-run-in-between-002.xht": [ + "7ff81653276feab32759c15c08547833aca86196", + "reftest" + ], + "css/css-display/run-in/run-in-run-in-between-003.xht": [ + "5983122a9e015f2f08dc0cb565194869fc23d505", + "reftest" + ], + "css/css-display/run-in/run-in-run-in-between-004.xht": [ + "a0e8126ec2ef495c62b48649c4b7c3eb766d4b8c", + "reftest" + ], + "css/css-display/run-in/run-in-run-in-between-005.xht": [ + "1adb32a3078b7fb14015c6e5699545bf39f2a10f", + "reftest" + ], + "css/css-display/run-in/run-in-run-in-between-006.xht": [ + "8dc1e460d109bb643382c4c39047f823d7b83a2a", + "reftest" + ], + "css/css-display/run-in/run-in-run-in-between-007.xht": [ + "2a9efa67d02de0d9e687b6bb986a1593779866de", + "reftest" + ], + "css/css-display/run-in/run-in-run-in-between-008.xht": [ + "4b3cf802de5cfe62f840fb43e1588d2ee0225f85", + "reftest" + ], + "css/css-display/run-in/run-in-table-between-001.xht": [ + "5523b17d807abc82410cd68e1eeb9df64c497483", + "reftest" + ], + "css/css-display/run-in/run-in-table-between-002.xht": [ + "2a3123b181e1840be435a47de3f9dfc5e0fbfa1a", + "reftest" + ], + "css/css-display/run-in/run-in-table-between-003.xht": [ + "e815c990a75d09b1f899389d5766ffe88ef2b420", + "reftest" + ], + "css/css-display/run-in/run-in-table-cell-between-001.xht": [ + "5a64485f150b9486ea8fc8b44b36eba0281843e4", + "reftest" + ], + "css/css-display/run-in/run-in-table-cell-between-002.xht": [ + "e2f59a56f7d1ed153b10c7b2f471cdda5c3f2fdc", + "reftest" + ], + "css/css-display/run-in/run-in-table-cell-between-003.xht": [ + "9575344b73ff90ee0a05e34f5981d757004b0f38", + "reftest" + ], + "css/css-display/run-in/run-in-table-row-between-001.xht": [ + "c920f933e6e9c5c7c255cdc1c2f430e01563c9ea", + "reftest" + ], + "css/css-display/run-in/run-in-table-row-between-002.xht": [ + "aa84045c62142d355f8a33b44ce06823cf70e058", + "reftest" + ], + "css/css-display/run-in/run-in-table-row-between-003.xht": [ + "cc9b62f52ffa918b1889ae1d4927212fe61327da", + "reftest" + ], + "css/css-display/run-in/run-in-text-between-001.xht": [ + "6c067847c8447b757c1cf7eca13cccb4591d7e8f", + "reftest" + ], + "css/css-display/run-in/run-in-text-between-002.xht": [ + "9f07e1ed65b5967d410210bcd6881fe7a3dd26a4", + "reftest" + ], + "css/css-display/run-in/run-in-text-between-003.xht": [ + "b71cecbbdda717bfe03a16b1ff06429b625187ef", + "reftest" + ], + "css/css-display/run-in/run-in-text-between-004.xht": [ + "380f0d7df62fec663a6e56d0a2861f9a48f9c477", + "reftest" + ], + "css/css-display/run-in/run-in-text-between-005.xht": [ + "a40c10072687534c2f57c3911647a64995dfd51f", + "reftest" + ], + "css/css-display/run-in/run-in-text-ref.xht": [ + "4162c4ee8fe9a3609065054e1aff017e89608c61", + "support" + ], + "css/css-display/run-in/support/black15x15.png": [ + "9252cae16138e45c07796fa5a10b6100ae703eaa", + "support" + ], + "css/css-display/run-in/support/blue15x15.png": [ + "eb48032c07bfeb1d3b6be6e5c9c34d2fe2180767", + "support" + ], + "css/css-display/run-in/support/blue96x96.png": [ + "99949c515749e66f471c3589ee7a0ef518aaccb5", + "support" + ], + "css/css-display/run-in/support/green15x15.png": [ + "de1830c21195763f7327f270b14b6d50dfdfb21d", + "support" + ], + "css/css-display/run-in/support/swatch-blue.png": [ + "e79958e10feeeed3db88dee9bae9ea80055593c5", + "support" + ], + "css/css-display/run-in/table-anonymous-block-001.xht": [ + "4f471b69edd2465deffc9d925a74ee0b30ad6824", + "visual" + ], + "css/css-display/run-in/table-layout-applies-to-004.xht": [ + "97f74eaf88a289c89d9c08e1c6865d28806cfbbb", + "visual" + ], + "css/css-display/run-in/text-align-applies-to-004.xht": [ + "e223bc1cc7a84ac02fc8b9ee157903bf3b3c9d3f", + "visual" + ], + "css/css-display/run-in/text-decoration-applies-to-004.xht": [ + "38ae3b84fa8182edde9764d68d9783c4f046cc56", + "reftest" + ], + "css/css-display/run-in/text-indent-applies-to-004.xht": [ + "86911ad06c2b5172e6aa5cf793661dac00ad02ac", + "visual" + ], + "css/css-display/run-in/text-transform-applies-to-004.xht": [ + "aa82154d3f6db37736e98cc5b89f5b8ffca81fb9", + "reftest" + ], + "css/css-display/run-in/top-applies-to-011.xht": [ + "2b585ecb53fd1c84ef92a93ab66ccbc921f34440", + "visual" + ], + "css/css-display/run-in/unicode-bidi-applies-to-011.xht": [ + "11fab4558a7a3d43bf3f53759d02cc8834af7110", + "visual" + ], + "css/css-display/run-in/vertical-align-applies-to-011.xht": [ + "99f448c1a05cbd9bb9bd1cec7797812608aec98e", + "visual" + ], + "css/css-display/run-in/visibility-applies-to-011.xht": [ + "20695d8ba19bac1a499d973d5185e05b0bd4c1d8", + "visual" + ], + "css/css-display/run-in/white-space-applies-to-004.xht": [ + "f387077d9b2071510cfbafcc5bf6476c0342a89c", + "visual" + ], + "css/css-display/run-in/width-applies-to-011.xht": [ + "8befc8e83d65818546a39a6950b602bd854fe049", + "reftest" + ], + "css/css-display/run-in/word-spacing-applies-to-004.xht": [ + "ea4e80bc4e560a727ac60983e17b85fcdfaa06e0", + "visual" + ], + "css/css-display/run-in/z-index-applies-to-011.xht": [ + "71adc3eabed66929d71c1003ea9d5e10fee4f1a5", + "visual" + ], "css/css-display/support/acid.css": [ "5be41ca173eada98ac9b52b3b00732347690934e", "support" @@ -469776,6 +475884,34 @@ "55ac1cc272d6feaba627f45e402671e7bc83487d", "reftest" ], + "css/css-flexbox/anonymous-flex-item-001.html": [ + "9f89496f6e78f756d9ab4121bd032aea9b1a391a", + "reftest" + ], + "css/css-flexbox/anonymous-flex-item-002.html": [ + "8bdb3608043b55769a271795dcc9c93fbd4d54cb", + "reftest" + ], + "css/css-flexbox/anonymous-flex-item-003.html": [ + "03705ffe4b6521b7a66852923ab12cd55428e726", + "reftest" + ], + "css/css-flexbox/anonymous-flex-item-004.html": [ + "d27625d34f2efa147415ef4e78f01cdc154ea579", + "reftest" + ], + "css/css-flexbox/anonymous-flex-item-005.html": [ + "c967afaa14aff2a6d2a32346c12b3c1b4fbdc7c6", + "reftest" + ], + "css/css-flexbox/anonymous-flex-item-006.html": [ + "d3d0c005dc2b121906f40e9a093d0feec9182355", + "reftest" + ], + "css/css-flexbox/anonymous-flex-item-ref.html": [ + "e8b1580d36b15778ca903fefa1ccccaef31b099f", + "support" + ], "css/css-flexbox/auto-margins-001-ref.html": [ "dfc6fe046906c564110225d01572aa6aa1e40858", "support" @@ -472220,6 +478356,14 @@ "8a868450fe85cd33deaf1e0960fa607125ead2dd", "testharness" ], + "css/css-flexbox/percentage-heights-004-ref.html": [ + "19ed01c4b89e39f9ab6c72085e9a29ed30b2f0c2", + "support" + ], + "css/css-flexbox/percentage-heights-004.html": [ + "210a01e299109975376cef799599967709758481", + "reftest" + ], "css/css-flexbox/percentage-widths-001-ref.html": [ "a139951dbeb1676b7add9a43d154595dc2e9859b", "support" @@ -472588,6 +478732,14 @@ "078e1dd6dd61d36cec239ed75d02051f61fe60a5", "support" ], + "css/css-flexbox/table-as-item-narrow-content.html": [ + "ccee1a24278c3177809a09009c2f15973908fa83", + "reftest" + ], + "css/css-flexbox/table-as-item-wide-content.html": [ + "b25764f22999464e3e65780f01f4adb784ce56d2", + "reftest" + ], "css/css-flexbox/ttwf-reftest-flex-align-content-center.html": [ "4e094e9c286479386a39eacfc975b78bef311c63", "reftest" @@ -472676,6 +478828,98 @@ "b4992b381f6a8f83ee043f379e614b43c7ead393", "reftest" ], + "css/css-fonts/first-available-font-001-ref.html": [ + "b908d93443cee9e64628e85a29d288d567f19e5a", + "support" + ], + "css/css-fonts/first-available-font-001.html": [ + "b766a6b03eda1f84317330e4144efda1fe11877e", + "reftest" + ], + "css/css-fonts/first-available-font-002-ref.html": [ + "1d2b31f4624182d4e1451a7af73e11a049faba75", + "support" + ], + "css/css-fonts/first-available-font-002.html": [ + "85d82a4b714deac3ab2dc15cf1c90d340039ea0e", + "reftest" + ], + "css/css-fonts/first-available-font-003-ref.html": [ + "561cd0ffcb017ae0a5cd8489cc335afaa43fd95d", + "support" + ], + "css/css-fonts/first-available-font-003.html": [ + "60fa4838cce77f2516689b368cf9058adcab22e9", + "reftest" + ], + "css/css-fonts/first-available-font-004.html": [ + "449a20a6fecb03821cdb5253fa09a70340b8321c", + "reftest" + ], + "css/css-fonts/first-available-font-005-ref.html": [ + "460dc6967318b4c75c9776ef4d4e76e39f51534e", + "support" + ], + "css/css-fonts/first-available-font-005.html": [ + "6c4d33aa1d766da74c5d0ad6cbcda3793c3df926", + "reftest" + ], + "css/css-fonts/first-available-font-006.html": [ + "9cf39bd6493745a35b586046ffb3ad98334ba1b7", + "reftest" + ], + "css/css-fonts/first-available-font-007.html": [ + "955b6034a43ed937c87df87b35e37d6cdb4f1e0d", + "reftest" + ], + "css/css-fonts/font-default-01-ref.html": [ + "4c9d7b41e3677da2c9fab71098a34463f4ecdf06", + "support" + ], + "css/css-fonts/font-default-01.html": [ + "631cc38f77f522b8f7483313e6f72478048c7f5b", + "reftest" + ], + "css/css-fonts/font-default-02-ref.html": [ + "c82b34b553a4884e8855e72d53fbb4e2a188150d", + "support" + ], + "css/css-fonts/font-default-02.html": [ + "65c7f00a58f50eaa8318197ead5bfd090a3b9fe3", + "reftest" + ], + "css/css-fonts/font-default-03-ref.html": [ + "9d058bd5f6ff7c1ae78c30971d4ccbc300bb9659", + "support" + ], + "css/css-fonts/font-default-03.html": [ + "6904aa08cd31f40a1025cdca5fd67c80adb766c2", + "reftest" + ], + "css/css-fonts/font-default-04-a-ref.html": [ + "e19a9893bd2a3324359fee3221463fde0cda83c1", + "support" + ], + "css/css-fonts/font-default-04-b-ref.html": [ + "be7941d593507cacc4dd0e6f7ea965da5028e17a", + "support" + ], + "css/css-fonts/font-default-04-c-ref.html": [ + "d7cbdc050d5bf76b2d2d1e9ef7e6bf2b0ab949fc", + "support" + ], + "css/css-fonts/font-default-04.html": [ + "4f5d1d1f375f61a09d30ef28deda1b2a54f4c620", + "reftest" + ], + "css/css-fonts/font-display/font-display-change-ref.html": [ + "e155492a8b8dbaa1477fddfaeea520b3a8b3fd37", + "support" + ], + "css/css-fonts/font-display/font-display-change.html": [ + "c5fd3f31aca59b36b12aea67bfcd13f9fd5751b6", + "reftest" + ], "css/css-fonts/font-display/font-display-failure-fallback.html": [ "9fbf0c808f338c5d668554ab62f10cfe0ca93c91", "testharness" @@ -473025,7 +479269,7 @@ "support" ], "css/css-fonts/font-variant-01.html": [ - "0d0a249db6c2ddaad1e4de702834020aa4ab45fa", + "6803a83b4ab93a9ad442a0e339d536edd85ab5df", "reftest" ], "css/css-fonts/font-variant-02-ref.html": [ @@ -473033,7 +479277,7 @@ "support" ], "css/css-fonts/font-variant-02.html": [ - "4fd6a59d04fde5e82ec12fa4c89bf07c611ddd21", + "74980d099860a038f1e42ad62cb7f2eb8cbca02c", "reftest" ], "css/css-fonts/font-variant-03-ref.html": [ @@ -473041,7 +479285,7 @@ "support" ], "css/css-fonts/font-variant-03.html": [ - "78e21fc51d91d4ee0ec8e0838dab863a08aa1f83", + "c42d2410101bf0be8832a0f84ce6ee4b75e96a66", "reftest" ], "css/css-fonts/font-variant-04-ref.html": [ @@ -473049,7 +479293,7 @@ "support" ], "css/css-fonts/font-variant-04.html": [ - "0431694dc7064c9af5c1881484796b750b15b63c", + "b5417f15f571c21e754df033a597193384cf8610", "reftest" ], "css/css-fonts/font-variant-alternates-01-ref.html": [ @@ -473196,6 +479440,10 @@ "de45acb63b567c5318b014ebab07098ca8c317b6", "reftest" ], + "css/css-fonts/font-variant-alternates-parsing.html": [ + "5a15ca070dbddff6e28995c13db825244080fc25", + "testharness" + ], "css/css-fonts/font-variant-caps-01-ref.html": [ "dfc1e1995e9841ecfa8889ad25c6ef7a6a2d992f", "support" @@ -473672,10 +479920,18 @@ "415b835abaaab822aab11880354296e7356bbb0a", "support" ], + "css/css-fonts/support/AD.woff": [ + "2bff1f1a01ce7c959341300952b2467e87e60dd5", + "support" + ], "css/css-fonts/support/README": [ "c46bfcee920aef0b9167764ec78c699ed217c8f2", "support" ], + "css/css-fonts/support/Revalia.woff": [ + "f2b20022818e53e9c9c5f22bcc52703c6858eb1c", + "support" + ], "css/css-fonts/support/bar_with_corner_dot.png": [ "76cb66964d085f70c0c91635c9369ea8fb41f2a3", "support" @@ -479896,6 +486152,34 @@ "9aa0e70e845521fd7127581a4cd017e1ba3dc15c", "reftest" ], + "css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-001.html": [ + "b15d1db43efd2b8f15aab17dbbcf3afc262baa76", + "testharness" + ], + "css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-002.html": [ + "6efd2dfea5027aca510f7a92e8cec16b3fddef2d", + "testharness" + ], + "css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-003.html": [ + "d485183a7ea0bfcf92503a3e420ae68470593995", + "testharness" + ], + "css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-004.html": [ + "aacc2daef0aae211a8ffa433ff6684d037afd4c8", + "testharness" + ], + "css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-005.html": [ + "fc2cfee0c523129d8cb0bbee1685786a72031e84", + "testharness" + ], + "css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-006.html": [ + "7408735464c2da7fa7916ee5a739518866e5b7a2", + "testharness" + ], + "css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-007.html": [ + "4c50565bb7adf5074f57da937954c3e95ee00d7a", + "testharness" + ], "css/css-grid/abspos/grid-positioned-items-background-001-ref.html": [ "4094fef3dedb631dfb06f600ce44ccfbfdb78d02", "support" @@ -480416,6 +486700,10 @@ "e9dccb31be383803835caebaffb42242aeb4941a", "testharness" ], + "css/css-grid/alignment/grid-column-axis-alignment-positioned-items-017.html": [ + "6c58deabf758bee4d8223403d0f7edffede54f64", + "testharness" + ], "css/css-grid/alignment/grid-content-distribution-001.html": [ "5622a264eb2dbd6cf621ac97aa4a8ae5db82c6b3", "reftest" @@ -480720,6 +487008,10 @@ "9b9190bbcc6ce8f74480918a68fb73e6849fb441", "testharness" ], + "css/css-grid/alignment/grid-row-axis-alignment-positioned-items-017.html": [ + "c75eb3edc97f8f01429a26698337c6e3b869563b", + "testharness" + ], "css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-001.html": [ "cafc54256ea9d0cbf8990a0e04904c7ada8c5894", "testharness" @@ -481145,11 +487437,11 @@ "testharness" ], "css/css-grid/grid-definition/grid-template-columns-fit-content-001-ref.html": [ - "518f7a0d17c565fda7903d1abfac794fbc03191d", + "5f2f68b7cf046593760e6668a3d7fca58bae263e", "support" ], "css/css-grid/grid-definition/grid-template-columns-fit-content-001.html": [ - "64c4a2aef9e86f623fede6185ba1d6b4eaa2be17", + "adffbd4b734ae719675cb5bee7fd6bc3fbde5d5b", "reftest" ], "css/css-grid/grid-definition/grid-template-columns-rows-resolved-values-001.html": [ @@ -481157,7 +487449,7 @@ "testharness" ], "css/css-grid/grid-definition/grid-template-rows-fit-content-001-ref.html": [ - "8aa844e9ae3fb1f8b359b8dcc43bbf605bc726c4", + "0599be38ec7525b925d2c42dad8f6c09efff1612", "support" ], "css/css-grid/grid-definition/grid-template-rows-fit-content-001.html": [ @@ -481168,6 +487460,10 @@ "7d6dc5106777942ad83e6bc570368af113f32d5f", "support" ], + "css/css-grid/grid-items/explicitly-sized-grid-item-as-table.html": [ + "2d713db8aa5f79164259a2c7b2b3f6b89f8aeed4", + "reftest" + ], "css/css-grid/grid-items/grid-inline-items-001.html": [ "026bebd69ed8b67da6b08de73b6f6bf2c1cdae7d", "reftest" @@ -481385,11 +487681,11 @@ "reftest" ], "css/css-grid/grid-items/grid-minimum-size-grid-items-017.html": [ - "14950654a15677b2845d6e40738872f10a627f9f", + "72c56c685b4251feac161d7928a2ebbfdbf1ac78", "reftest" ], "css/css-grid/grid-items/grid-minimum-size-grid-items-018.html": [ - "10b954d9b6ddf50a0c910caa7ce6924fa15c006a", + "800c76ae88f02741160c06039cfc0c122aa50f43", "reftest" ], "css/css-grid/grid-items/grid-minimum-size-grid-items-019.html": [ @@ -481404,6 +487700,14 @@ "205f2292e788eee87490530488e2f1575e809ade", "testharness" ], + "css/css-grid/grid-items/grid-minimum-size-grid-items-022.html": [ + "c2aca9084809e053c5f96dbe4eff7a7131fdde5a", + "testharness" + ], + "css/css-grid/grid-items/grid-minimum-size-grid-items-023.html": [ + "40fe5eeb537a999e24ae7b653b364e58e2d59e35", + "testharness" + ], "css/css-grid/grid-items/grid-order-property-auto-placement-001.html": [ "15a3eec22bb5f55e3e7a73730e95011f4efbaf73", "reftest" @@ -481517,7 +487821,7 @@ "support" ], "css/css-grid/grid-layout-properties.html": [ - "3ab6d064073e659de4fa0ceb1d2b20a5d0cd42ab", + "d30ee96245cf3d25bffc64347a4ee60bfb2b2049", "testharness" ], "css/css-grid/grid-model/display-grid.html": [ @@ -481536,6 +487840,14 @@ "f94336e80a72225b05970dec330508c33445c87a", "testharness" ], + "css/css-grid/grid-model/grid-container-ignores-first-letter-001.html": [ + "e46492228ce6fdf83d9661c06db745e9c6689bb4", + "testharness" + ], + "css/css-grid/grid-model/grid-container-ignores-first-line-001.html": [ + "8e8895681b8f7e8f5d416faedf5b081f7fc42243", + "testharness" + ], "css/css-grid/grid-model/grid-display-grid-001.html": [ "4eb94a6ac52aec622d55911c68677263d9533246", "reftest" @@ -481620,6 +487932,14 @@ "2075376b219560fbf9b9e6c3cb125ba2d066e966", "reftest" ], + "css/css-grid/grid-model/grid-item-accepts-first-letter-001.html": [ + "bc3aa0022584b2dc6253aeb1bbca50b6b7c05f54", + "testharness" + ], + "css/css-grid/grid-model/grid-item-accepts-first-line-001.html": [ + "0af2d39207188e1398e69f1e2d81848ba1bee2ee", + "testharness" + ], "css/css-grid/grid-model/grid-margins-no-collapse-001.html": [ "f68bfb76a8158d9bd8c9e3ef2e8aab11401b0360", "reftest" @@ -481693,15 +488013,15 @@ "support" ], "css/css-grid/reference/grid-collapsed-row-gutters-ref.html": [ - "917e355f17681c9f511fc5cfbfe7996cddb05f6b", + "15a431efb881d37ce24ab376ee3709bd4333bb11", "support" ], "css/css-grid/reference/grid-different-gutters-ref.html": [ - "d37b7409505ce811a7a76db76ab7185c611fd278", + "bd1aecfb426cde332794b9657a7d7a905ff1b292", "support" ], "css/css-grid/reference/grid-equal-gutters-ref.html": [ - "61df6964c4743d585e47e0e683c55b5cf3f10c92", + "9db6eaa6f9569ada08d3c231ec364f4d7e7faf6b", "support" ], "css/css-grid/reference/grid-filled-blue-yellow-green-overlapped-100px-squares.html": [ @@ -482068,6 +488388,26 @@ "d9c8054b356c9273a054a83abeb9be0626c23921", "support" ], + "css/css-lists/counter-7-ref.html": [ + "6391e214ad5262afaab7cd6caaf57e7f2506fb4d", + "support" + ], + "css/css-lists/counter-increment-inside-display-contents.html": [ + "d137a61e9cdacdf9130412675f0365e78719e93e", + "reftest" + ], + "css/css-lists/counter-reset-increment-display-contents.html": [ + "7e8737c7342ada38a67c25bebf7731ab906a6161", + "reftest" + ], + "css/css-lists/counter-reset-increment-display-none.html": [ + "dce0a0b569b475c150c7d8dcbcee19bed57beee6", + "reftest" + ], + "css/css-lists/counter-reset-inside-display-contents.html": [ + "8b5c11c194f7038209d9f9aa9d844d496e89658e", + "reftest" + ], "css/css-lists/list-style-type-armenian-002.xht": [ "93eca7b91e63950fc593fdcdf8e6900f89a8c609", "visual" @@ -482829,7 +489169,7 @@ "reftest" ], "css/css-masking/clip/clip-rect-auto-001.html": [ - "d69112f2753d67ce03f9562a5177c402952619d0", + "e736cd6a808b66b8eefc9f7713d958834b32c1b0", "reftest" ], "css/css-masking/clip/clip-rect-auto-002.html": [ @@ -482857,7 +489197,7 @@ "reftest" ], "css/css-masking/clip/clip-rect-comma-002.html": [ - "60ad4c9641c8a20c51bfe826dde19e6756c3275a", + "70d6467b21e7a4b82665231413624b100e1b0926", "reftest" ], "css/css-masking/clip/clip-rect-comma-003.html": [ @@ -482877,7 +489217,7 @@ "support" ], "css/css-masking/clip/reference/clip-horizontal-stripe-ref.html": [ - "d52b44feeaa257ce0df29de754c1c5ea83a00a1d", + "beb646fbeacdcb1339925b6d58a51bfbb1ede256", "support" ], "css/css-masking/clip/reference/clip-no-clipping-ref.html": [ @@ -482917,7 +489257,7 @@ "reftest" ], "css/css-multicol/OWNERS": [ - "721c176d7b1e3d610405ea043c93288f7c09ebd0", + "7dc7d3872831592215162aff9196d55032c5c31f", "support" ], "css/css-multicol/multicol-basic-001.html": [ @@ -482969,13 +489309,9 @@ "reftest" ], "css/css-multicol/multicol-br-inside-avoidcolumn-001.xht": [ - "f2fe604ad53155fe3ba1eaaaadad7d4842aef239", + "934a25d72288a1400325662a7b3b9c47ceadd88d", "reftest" ], - "css/css-multicol/multicol-br-inside-avoidcolumn-ref.xht": [ - "d6c09e048d1a938cbf814a9e88b9ba0877b0222f", - "support" - ], "css/css-multicol/multicol-break-000-ref.xht": [ "213ce08f5d1294ce5ed571eca674886e20a10bde", "support" @@ -482985,11 +489321,11 @@ "reftest" ], "css/css-multicol/multicol-break-001-ref.xht": [ - "9063897562e11c61d96174d63fa1111f42c40aa3", + "a7826c6d21887999991961d09e61fb4569378470", "support" ], "css/css-multicol/multicol-break-001.xht": [ - "225895c702c7e5b91d9f167463410b795bd5bc2d", + "435a5b7f4bb2013c837b0bd67b16e67fa0e609f4", "reftest" ], "css/css-multicol/multicol-clip-001-ref.xht": [ @@ -483092,14 +489428,6 @@ "6703b66b9696faa2d9efb86c93a5127952d52484", "reftest" ], - "css/css-multicol/multicol-count-computed-001.xht": [ - "0b899eed278c7427523cdabd0b4f73d1f70f4c8a", - "reftest" - ], - "css/css-multicol/multicol-count-computed-002.xht": [ - "76581613fb9ec4c0cf786361cb9f5b3d2977537b", - "reftest" - ], "css/css-multicol/multicol-count-computed-003-ref.xht": [ "80e54fbeedd11f39d9041d45d266cf87a69d28b1", "support" @@ -483120,30 +489448,6 @@ "fdc0811616680d44203af48c16fcbd91f5e2d9ea", "reftest" ], - "css/css-multicol/multicol-count-computed-2-ref.xht": [ - "c56592171fc03c060391ed79cdc07504e3331110", - "support" - ], - "css/css-multicol/multicol-count-computed-ref.xht": [ - "6709a84fd18a48dfb086fc16f9c5c88e428ba19d", - "support" - ], - "css/css-multicol/multicol-count-large-001.xht": [ - "c2a6c85790cc1bb26a55ac35ce7c180540bcf303", - "reftest" - ], - "css/css-multicol/multicol-count-large-002.xht": [ - "016c0844708c869edffdf611d7e667ed18fc044c", - "reftest" - ], - "css/css-multicol/multicol-count-large-2-ref.xht": [ - "892602e263ebef316e45bb0ab539bf7dc8fbfde6", - "support" - ], - "css/css-multicol/multicol-count-large-ref.xht": [ - "d3aacae3172978f58c957e99553b1ab3edea2188", - "support" - ], "css/css-multicol/multicol-count-negative-001.xht": [ "cfd975860e259b71f8034c5d46f895af3b87b8c3", "reftest" @@ -483209,25 +489513,17 @@ "reftest" ], "css/css-multicol/multicol-fill-auto-block-children-002-ref.xht": [ - "8deeba9e92df8ce4bb47e5cf3a0ccd1e1bc28b43", + "f11616ee8273a29f09430115311b455f8bad4d41", "support" ], "css/css-multicol/multicol-fill-auto-block-children-002.xht": [ - "33c1a5516a1c5697e0e8fd71c77345291dead62d", + "6aad056909cb697560558d7511d970cc47e10514", "reftest" ], "css/css-multicol/multicol-fill-auto-block-children-ref.xht": [ "f63446929f6a4a1f7ba2dba47af786c487fa03d7", "support" ], - "css/css-multicol/multicol-fill-auto-ref.xht": [ - "d97337c9c5fe4ff3ab4472b1c0f9f459f9d7cf8e", - "support" - ], - "css/css-multicol/multicol-fill-auto.xht": [ - "54fe8ec972a87ea83b6ea770ac5975bcb1868412", - "reftest" - ], "css/css-multicol/multicol-fill-balance-001-ref.xht": [ "dfdc227760f0fb524232d65ee792f108d32fc7de", "support" @@ -483236,10 +489532,6 @@ "cd580ac2b2ddf85cb1f3e14b554e4e3ce357f012", "reftest" ], - "css/css-multicol/multicol-fill-ref.xht": [ - "a5f5c85453df52637a510c3f6ae5e5c65fdec50c", - "support" - ], "css/css-multicol/multicol-gap-000-ref.xht": [ "1fe1e1d56fb2336ae63544a4bb568ee6f6daa053", "support" @@ -483268,6 +489560,18 @@ "16067366a3c1922e9c8415b21e513edd47c2305f", "reftest" ], + "css/css-multicol/multicol-gap-animation-001.html": [ + "5f2cf6d10c4624d44e81bfa9e9c97bcaf229ca80", + "testharness" + ], + "css/css-multicol/multicol-gap-animation-002.html": [ + "5e83250f2f2ff49682eae68056330aa3b4c673c7", + "testharness" + ], + "css/css-multicol/multicol-gap-animation-003.html": [ + "6d5c81b2277c34bac89e8cde247dd9aabbdd505f", + "testharness" + ], "css/css-multicol/multicol-gap-fraction-001-ref.xht": [ "91139e0fa20ce6211d5199ba60312f5f7ab308d8", "support" @@ -483276,6 +489580,10 @@ "9d12dc2b311ab4bf2dfda4565fcdfab0008754c5", "reftest" ], + "css/css-multicol/multicol-gap-fraction-002.html": [ + "67b2d75607ac68ad08012ad282ac4234946a1051", + "reftest" + ], "css/css-multicol/multicol-gap-large-001-ref.xht": [ "a502a720a1ac5a28f3857caf36ccb2a9fec02776", "support" @@ -483305,11 +489613,11 @@ "reftest" ], "css/css-multicol/multicol-height-block-child-001-ref.xht": [ - "c5dff10fd039a8e642e19a5a21da05d33d491945", + "44429ae1c09226083fd84aa26c617e7ee71a6e91", "support" ], "css/css-multicol/multicol-height-block-child-001.xht": [ - "7f8870a893846cb52f69bd4259cbc96646723702", + "5cf388bfc8537ce63bae3148cc9702f556e6852b", "reftest" ], "css/css-multicol/multicol-inherit-001-ref.xht": [ @@ -483332,18 +489640,10 @@ "bfb8f201623a96cf2737bef1ba1c0d6b08bc54e4", "reftest" ], - "css/css-multicol/multicol-inherit-004.xht": [ - "eaf2a8ba48e8f8dc5ead28a675bfa5ff478df734", - "reftest" - ], "css/css-multicol/multicol-inherit-3-ref.xht": [ "56158a2fdc63c2e534672679c81c8de93a5730d1", "support" ], - "css/css-multicol/multicol-inherit-4-ref.xht": [ - "0423d597aaed6efc746fd7c9cccc21b3901cfae8", - "support" - ], "css/css-multicol/multicol-list-item-001-ref.xht": [ "6f5adc6cc216feef55920d97595d32cf68be5ed4", "support" @@ -483385,11 +489685,11 @@ "reftest" ], "css/css-multicol/multicol-nested-column-rule-001-ref.xht": [ - "e045b4bb02989ec16c6b1fc10bd9717b9daf0224", + "d53e71b2a82e6d519fa7fffcc62ba832717cd7a5", "support" ], "css/css-multicol/multicol-nested-column-rule-001.xht": [ - "2052bad4a14f5d52b369751d5a7eee955dcca92b", + "7157a7f0a6dc740d9a12561118c2aa71923511c7", "reftest" ], "css/css-multicol/multicol-nested-margin-001-ref.xht": [ @@ -483557,7 +489857,7 @@ "reftest" ], "css/css-multicol/multicol-rule-fraction-3-ref.xht": [ - "95c5bb1a096aa9e2508561849528200c6e794783", + "840335fafb6bbf23f2cff696145c5e4f093a077f", "support" ], "css/css-multicol/multicol-rule-groove-000-ref.xht": [ @@ -483625,7 +489925,7 @@ "support" ], "css/css-multicol/multicol-rule-samelength-001.xht": [ - "cd4022578abdf3520e603336c7f812a9a5315926", + "f76c5c3a3989ba945c36f9b5f60d65157675ff65", "reftest" ], "css/css-multicol/multicol-rule-shorthand-001.xht": [ @@ -483656,30 +489956,6 @@ "b16e79ec96569a463be9b47b2f8f7f214f8500f7", "support" ], - "css/css-multicol/multicol-rule-style-groove-001-ref.xht": [ - "2529f1c9842f1bc415221dddc350b5f96a84c25a", - "support" - ], - "css/css-multicol/multicol-rule-style-groove-001.xht": [ - "e6e56b0328c105ff123c33d3d552f00922e490d2", - "reftest" - ], - "css/css-multicol/multicol-rule-style-inset-001.xht": [ - "40dba383e061009d8a63a3b239534a51f777d86d", - "reftest" - ], - "css/css-multicol/multicol-rule-style-outset-001.xht": [ - "c2a1d8fef6176e0d87198a8784bb9ea7e3eef94a", - "reftest" - ], - "css/css-multicol/multicol-rule-style-ridge-001-ref.xht": [ - "f09150d0eb9cca3c1479d7e240624e7913fb0a18", - "support" - ], - "css/css-multicol/multicol-rule-style-ridge-001.xht": [ - "b75870bee5f5ec6f4669f9de58ea95393c686752", - "reftest" - ], "css/css-multicol/multicol-shorthand-001.xht": [ "2be00be60652208da1a87c2175b02f1fbda381c9", "reftest" @@ -483709,7 +489985,7 @@ "reftest" ], "css/css-multicol/multicol-span-all-003.xht": [ - "79ab6a7b47537d3dadcd0aa707ad045563d03165", + "c88e3393a8c0a214ed11e85736d35b5a383a03ac", "reftest" ], "css/css-multicol/multicol-span-all-block-sibling-003.xht": [ @@ -483720,22 +489996,6 @@ "60152a8e281cefc766c4313f707ad12da60504fa", "support" ], - "css/css-multicol/multicol-span-all-child-001-ref.xht": [ - "59a8a527b2f443c77d8b97ce8d7a2c538a80c688", - "support" - ], - "css/css-multicol/multicol-span-all-child-001.xht": [ - "24bfd53c6017627df936b137d499af5ece0d20ca", - "reftest" - ], - "css/css-multicol/multicol-span-all-child-002-ref.xht": [ - "7c41deb3000f9c7076b947d1b0195ef24e49d9ce", - "support" - ], - "css/css-multicol/multicol-span-all-child-002.xht": [ - "913856821a569f7f6927fc0e042b6c4f87e90765", - "reftest" - ], "css/css-multicol/multicol-span-all-margin-001-ref.xht": [ "e9950c32ce08fb3a56925c548c6efd1698dd10fe", "support" @@ -483772,14 +490032,6 @@ "8bdc105a0b441556da0b287dd5d6b98a3fedc7ad", "reftest" ], - "css/css-multicol/multicol-span-all-margin-nested-003.xht": [ - "a8f61138dc6e68e7910a29e4eaeac6f2d20adae4", - "reftest" - ], - "css/css-multicol/multicol-span-all-margin-nested-3-ref.xht": [ - "d18c55ffc3c4a490ebe37c2c5fdf8e22e8710800", - "support" - ], "css/css-multicol/multicol-span-all-margin-nested-firstchild-001.xht": [ "d912a7254753afebe5ade2f58af29484d2fd8d51", "reftest" @@ -483825,11 +490077,11 @@ "reftest" ], "css/css-multicol/multicol-table-cell-vertical-align-001.xht": [ - "c60f477324d7ca5b73f19b637c965c20cc6764b4", + "b6323036968dbf0584f94e116bb019347c0d6a42", "reftest" ], "css/css-multicol/multicol-table-cell-vertical-align-ref.xht": [ - "6376bfbeb38858740053cdc384a5a8d2d49d0c7e", + "7515baa6b82894146207efaae85aaf832ff41a36", "support" ], "css/css-multicol/multicol-width-001-ref.xht": [ @@ -483852,6 +490104,14 @@ "39784428d2c56586d65f81a413aba4002d6ee752", "reftest" ], + "css/css-multicol/multicol-width-ch-001.xht": [ + "28b3c4f81e92185bbc9f26c9e594bdfb8cc994df", + "reftest" + ], + "css/css-multicol/multicol-width-ch-ref.xht": [ + "0a6035ffd02299dfd16336d6c8919c54b2293e21", + "support" + ], "css/css-multicol/multicol-width-count-001.xht": [ "4d09efe797f9b164e19fda16d6491fa99a855141", "reftest" @@ -483860,14 +490120,6 @@ "3fd4fd27cd2432bf388f08fb009cd5cd7cded59f", "reftest" ], - "css/css-multicol/multicol-width-ems-001.xht": [ - "1de2ecbb10805a48b831091cbee976b653899316", - "reftest" - ], - "css/css-multicol/multicol-width-ems-ref.xht": [ - "16f14c6750b7afa4deb8b2c0e70a602723753794", - "support" - ], "css/css-multicol/multicol-width-invalid-001-ref.xht": [ "da0d8783395284175b7f7b2ece6f8050aae10829", "support" @@ -483893,15 +490145,15 @@ "support" ], "css/css-multicol/multicol-width-small-001.xht": [ - "0962e4c7c6f3698ccbf6c82fa0664b9817ffe208", + "c552224d18ceccc91b84936e3e7355ec513c0d3a", "reftest" ], "css/css-multicol/multicol-zero-height-001-ref.xht": [ - "77a1ed4066efbb3d248a899f327b3de37723f5db", + "12787b95e22d180606eb24b9cf43eaeb0ca9fe3f", "support" ], "css/css-multicol/multicol-zero-height-001.xht": [ - "88922e252f8ec0437ee747fe161f12983e94bd6f", + "81373bbae307e030054a54a6685793ae794e07f0", "reftest" ], "css/css-multicol/reference/multicol-basic-005-ref.xht": [ @@ -484228,6 +490480,14 @@ "0cba1aed016d08e4706bffb8a4f4169c9cfd2108", "visual" ], + "css/css-overflow/input-scrollable-region-001.html": [ + "f51bc673da28b0471018cdf945b4449ab00ce717", + "reftest" + ], + "css/css-overflow/reference/input-scrollable-region-001-ref.html": [ + "31e24bb1a2cb6f42703cc05e055fcb345c770a22", + "support" + ], "css/css-page/OWNERS": [ "d4ee6029cc9c064e0e8b2c76becf3b59c4f7b62b", "support" @@ -484548,6 +490808,14 @@ "368a9d855ffc46457e6c54cddfbc934e92096ee0", "reftest" ], + "css/css-paint-api/geometry-with-float-size-ref.html": [ + "4ccf13c66fbd9ce8a2f04eab8b5f6cd24a6601fa", + "support" + ], + "css/css-paint-api/geometry-with-float-size.https.html": [ + "911b7945792a8d3157cf183e4eb02e6e10ffa80a", + "reftest" + ], "css/css-paint-api/hidpi/device-pixel-ratio-ref.html": [ "18f9d4d369de750ceb92c2e275ede5fcb3bf6f49", "support" @@ -484765,7 +491033,7 @@ "support" ], "css/css-paint-api/registered-properties-in-custom-paint.https.html": [ - "3855c8c28ea3a24bade81080f3f288ef75243dce", + "4eee3e45f32779df4464132fa43717a3afc135b2", "reftest" ], "css/css-paint-api/style-background-image-ref.html": [ @@ -484773,7 +491041,7 @@ "support" ], "css/css-paint-api/style-background-image.https.html": [ - "a3202db04922cc2527436fa319ea9e8432eecdcd", + "54f213635749ffeae4d21a5e3d4391901fbfe984", "reftest" ], "css/css-paint-api/style-before-pseudo-ref.html": [ @@ -484781,7 +491049,7 @@ "support" ], "css/css-paint-api/style-before-pseudo.https.html": [ - "7808e4e86a0556202a0e2ea5574d60c94bf2c537", + "7e8263880905e254e7c27274d6314ba23bd1cb04", "reftest" ], "css/css-paint-api/style-first-letter-pseudo-ref.html": [ @@ -485004,6 +491272,10 @@ "88e35164b6ede3adf9727989cf59ff9956bdbae7", "reftest" ], + "css/css-position/position-sticky-offset-overflow.html": [ + "cab620b2008a9df57abc6907b1199e35a4099241", + "testharness" + ], "css/css-position/position-sticky-offset-top-left.html": [ "a25b64d016644c272ea92b6129a59eefb21d2fa0", "testharness" @@ -485044,6 +491316,14 @@ "ac1e643ac9f03d0fe415c3f52a4db7c407dd3537", "reftest" ], + "css/css-position/position-sticky-table-parts-ref.html": [ + "fb0cfd30f01c7184753057a9b98560e7b5b53f4b", + "support" + ], + "css/css-position/position-sticky-table-parts.html": [ + "1558a0c2e628727143fb3368490a180947a631f9", + "reftest" + ], "css/css-position/position-sticky-table-tfoot-bottom-ref.html": [ "b902bec7e12fd6d9cad02c61f332a44f5818f8ee", "support" @@ -485177,11 +491457,11 @@ "reftest" ], "css/css-pseudo/marker-font-properties-ref.html": [ - "d83c1ae2c21ad4c20961725589481f046e108a99", + "4aadcf9f85ad69757f8cde95a198bf7c4ab118d1", "support" ], "css/css-pseudo/marker-font-properties.html": [ - "ac3d673508fb9578d0a1d363b82021df8a1b9fbd", + "7d4739f2252956461b38d8b8566a84ead3c1d8b1", "reftest" ], "css/css-pseudo/marker-inherit-values-ref.html": [ @@ -488185,7 +494465,7 @@ "testharness" ], "css/css-shapes/shape-outside/values/shape-image-threshold-003.html": [ - "2e81c6f4c0a29148086e50052edd03566fe231b4", + "d0415a0b89188f1456b0c2d58e26d8dbed9d9188", "testharness" ], "css/css-shapes/shape-outside/values/shape-margin-000.html": [ @@ -488704,10 +494984,6 @@ "3db4dec22e96cce52c575f4adb7a05f79917d4ea", "support" ], - "css/css-style-attr/reference/ref-green-on-green2.xht": [ - "9a4067fbea6534ad20a0354457eb7ade8053bbf6", - "support" - ], "css/css-style-attr/reference/ref-green.html": [ "8bc36f756c7ae32af5c52021c92bb04d1a0de876", "support" @@ -488781,7 +495057,7 @@ "reftest" ], "css/css-style-attr/style-attr-urls-003.xht": [ - "3131ef4985d72c3a70461d451ff0f6b2a253895f", + "e7575e77570089b0b73e518e94fc3d69ce1184cc", "reftest" ], "css/css-style-attr/support/1x1-green.png": [ @@ -489384,10 +495660,42 @@ "9eeb49d2d78c3f81825de0d9e24de2a097275175", "testharness" ], + "css/css-tables/zero-rowspan-001-ref.html": [ + "b7886acdf8a380f85ebbcab0ded1e927fd509600", + "support" + ], + "css/css-tables/zero-rowspan-001.html": [ + "829a239706861a54c5df555d201dc420c4f10e3b", + "reftest" + ], + "css/css-tables/zero-rowspan-002-ref.html": [ + "07e79fd25abfc9bf0564131759fdda36596146d5", + "support" + ], + "css/css-tables/zero-rowspan-002.html": [ + "8af937e93ee34799939632b4aed0083cb7d2c0ca", + "reftest" + ], "css/css-text-decor/OWNERS": [ "a19d2032ed9435567cd11ccbb860515ad5d14f71", "support" ], + "css/css-text-decor/line-through-vertical.html": [ + "d3fb9b272eafcfd36cefcc6a030c6ae3795a669c", + "reftest" + ], + "css/css-text-decor/reference/line-through-vertical-ref.html": [ + "f38d583fbcd41470cefb566d7b18c49758b2ebd2", + "support" + ], + "css/css-text-decor/reference/text-decoration-color-recalc-ref.html": [ + "f97bae89c262da57e45294db7638159114047da3", + "support" + ], + "css/css-text-decor/reference/text-decoration-color-ref.html": [ + "4ef765ae8d80ac3eab177109e9bd5b2b7142880f", + "support" + ], "css/css-text-decor/reference/text-decoration-line-010-ref.xht": [ "ba55218db818b208176448c9ae0adb4ee101ea53", "support" @@ -489404,6 +495712,22 @@ "065a1c1af6c12c7d2043c3d318330ba3028cdd87", "support" ], + "css/css-text-decor/reference/text-decoration-line-recalc-ref.html": [ + "8e8c434546c5f4b6184d935f16b8e1479c39eb11", + "support" + ], + "css/css-text-decor/reference/text-decoration-line-ref.html": [ + "3612462ad5a2c5447adf1fc80f6aa2b4ee5cb001", + "support" + ], + "css/css-text-decor/reference/text-decoration-style-multiple-ref.html": [ + "e23906652f3abb2123d70b11a7002262ba661f8b", + "support" + ], + "css/css-text-decor/reference/text-decoration-style-recalc-ref.html": [ + "6c6057bb2fd3e94e6141426a9de282120e354bb5", + "support" + ], "css/css-text-decor/reference/text-emphasis-color-001-ref.xht": [ "999f10b2466d839871ca9e974de158b84f5e2a90", "support" @@ -489492,6 +495816,14 @@ "fa665f1520b2148805c182feda36860ef5647c65", "support" ], + "css/css-text-decor/text-decoration-color-recalc.html": [ + "333110782c52aa29f0ac547164cf754025a285b9", + "reftest" + ], + "css/css-text-decor/text-decoration-color.html": [ + "7a11633ef29f67fc2242a265a63749bd9e5c1cfe", + "reftest" + ], "css/css-text-decor/text-decoration-line-010.xht": [ "f6c9486f8482db4566b88ccaa4ace97dec8062b1", "reftest" @@ -489512,10 +495844,30 @@ "e0d6dbb039133f5aee07cc8dd3d96942727bdec0", "manual" ], + "css/css-text-decor/text-decoration-line-recalc.html": [ + "ab48a5baca2e14a4618dc57f2b96badf98dfd077", + "reftest" + ], + "css/css-text-decor/text-decoration-line.html": [ + "2b56bc3ac545e449d4beff61d5c7c1fd97060042", + "reftest" + ], + "css/css-text-decor/text-decoration-serialization.tentative.html": [ + "9266aa2318ae1e023fd287cf3f89e3f62851a8b2", + "testharness" + ], "css/css-text-decor/text-decoration-skip-ink.html": [ "a633a231d8fd6b5408add5fab972046651889b09", "testharness" ], + "css/css-text-decor/text-decoration-style-multiple.html": [ + "4f6e24cfb87dd4b8efb51154e70fbc14e35124da", + "reftest" + ], + "css/css-text-decor/text-decoration-style-recalc.html": [ + "9dbfa25a35ae3959b51b28f71a29cbd9188322b3", + "reftest" + ], "css/css-text-decor/text-decoration-visibility-001.xht": [ "98b6617c1bc20a207de477eb33defb8922192e17", "visual" @@ -495877,8 +502229,8 @@ "visual" ], "css/css-transforms/css-transform-inherit-scale.html": [ - "79bf0552c20649ba4f4c8442176ce349616bf750", - "visual" + "1afd10f480afbd37ba7f55daae31003146fd22c1", + "reftest" ], "css/css-transforms/css-transform-property-existence.html": [ "c34a6640c14cb4267030b85277060a160fe78b78", @@ -498245,7 +504597,7 @@ "support" ], "css/css-transforms/transform-2d-getComputedStyle-001.html": [ - "0ecbf50593b1516a04578fd0bb1c9da207eee968", + "b4ed47027bac6bafad816e6bf8d5b179b8c5a90d", "testharness" ], "css/css-transforms/transform-3d-rotateY-stair-above-001.xht": [ @@ -498344,6 +504696,38 @@ "ce510cf7f18b469b45a3176d92b56ad91fd79f3c", "support" ], + "css/css-transforms/transform-box/fill-box-mutation.html": [ + "80011b1eba63c4b374e4aeed1990ed4707955704", + "reftest" + ], + "css/css-transforms/transform-box/fill-box.html": [ + "76eadff35072aeca5d276a62c13f2a259d13347f", + "reftest" + ], + "css/css-transforms/transform-box/support/greensquare200x200.html": [ + "f58dd69d9f2997d23ed30f45296751115205aec6", + "support" + ], + "css/css-transforms/transform-box/value-changed.html": [ + "dc7ddb4aaf7a37cf4619795e64a54472607b2de2", + "reftest" + ], + "css/css-transforms/transform-box/view-box-nested.html": [ + "88856f064883fb794c83278333f8ea0df992111f", + "reftest" + ], + "css/css-transforms/transform-box/view-box-viewbox-nested.html": [ + "9e0cfd6e001d551ca530d736c5aebfb2c3076178", + "reftest" + ], + "css/css-transforms/transform-box/view-box-viewbox.html": [ + "0e552a16a701bb982d31375559fa4d595729b4c6", + "reftest" + ], + "css/css-transforms/transform-box/view-box.html": [ + "90101f67d24beab0c86e940bde79dfb553902e85", + "reftest" + ], "css/css-transforms/transform-compound-001.html": [ "511cf5f6aaf6ca25dd6afd5286df771535fb1abc", "reftest" @@ -500989,23 +507373,23 @@ "support" ], "css/css-transitions/before-DOMContentLoaded-001.html": [ - "ce73650ab61ae0244f7d7aab2aef1a30c4ed66cc", + "d9a08984058da3dbedada7d0dff2d4743e3dd15b", "testharness" ], "css/css-transitions/before-load-001.html": [ - "eb57025c206784ff80e57d558b41fa5f195dc8ec", + "7f5f54505f119b0b491df50fcf23d60909f41126", "testharness" ], "css/css-transitions/changing-while-transition.html": [ - "961c630579d590e3fd8e270ea8b63b9495a4d60b", + "49ca30de94a41c9228189c44267bdf36a6e8bde2", "testharness" ], "css/css-transitions/currentcolor-animation-001.html": [ - "91cab6789a46df4fb4b1e2baeddf3aa9eaea378f", + "aee4e4f0e0154f9390333e4db21904a2cda67b52", "testharness" ], "css/css-transitions/detached-container-001.html": [ - "09b5e9b570fcb9ca52ec9bb8d651e0c22fbe4980", + "45f59afdc4636ed26417999abf206382a2913968", "testharness" ], "css/css-transitions/events-001.html": [ @@ -501037,43 +507421,43 @@ "testharness" ], "css/css-transitions/hidden-container-001.html": [ - "a256ef1efbfd088de9771835ecec7b5aefcc1495", + "971be3c362daabff565737c0d98be96e2356adb8", "testharness" ], "css/css-transitions/properties-value-001.html": [ - "ce0c9c0f5ebb844fd931e5b5e3345b3dab6531c0", + "66853fd915a18b3a8eb78e5d551fc7eb529b72cf", "testharness" ], "css/css-transitions/properties-value-002.html": [ - "f4558ff21eb2f06df7b6127ec7d1b0c3944647af", + "e2b14b1a6a08e6453f5b040e7be1212b13aa92e2", "testharness" ], "css/css-transitions/properties-value-003.html": [ - "bb593998dbb2d0e8cc2cf20dcf0dc70a6bf0d4fb", + "71274e78c1c5fc7ced69e9d9bb2fcf076c3806dd", "testharness" ], "css/css-transitions/properties-value-auto-001.html": [ - "436ce4d98c82a6cacb9e1a242013bb1803a84c87", + "4e1c0fa89888d91e1b5085cb19624eba843a5905", "testharness" ], "css/css-transitions/properties-value-implicit-001.html": [ - "5d00e4d4ab32234b66d20feb177b06f74b1a2864", + "30fdd86871362bfdca019a5c339f80ebff49d2b2", "testharness" ], "css/css-transitions/properties-value-inherit-001.html": [ - "0f2b37271a64887682e10c37123867f9f14c4af8", + "63ddc6510fa07988df7f11d6d0070563ded61887", "testharness" ], "css/css-transitions/properties-value-inherit-002.html": [ - "722ebf1da22eab5920d3e4b7704bb80247ad3bcd", + "da354ecb506958e9b0d8c1224b05e19f551cb072", "testharness" ], "css/css-transitions/properties-value-inherit-003.html": [ - "c5704809d884d5f6216191543e7d0809cf913b27", + "85156d3741f742f7d621b27354d941d72bc949f1", "testharness" ], "css/css-transitions/pseudo-elements-001.html": [ - "4f42cf7e196e1a7afb25a231fb3ce64e8c9bd194", + "43108935a5bf1e23ed8a61688843c7246b77b752", "testharness" ], "css/css-transitions/reference/transition-test-ref.html": [ @@ -501285,7 +507669,7 @@ "support" ], "css/css-transitions/transition-001.html": [ - "806d0704847c4d383a09afe8a2c26c9b6ecca30b", + "2068fe442683e6242633527409c89940d4e04bda", "testharness" ], "css/css-transitions/transition-delay-000.html": [ @@ -501293,7 +507677,7 @@ "manual" ], "css/css-transitions/transition-delay-001.html": [ - "54ee8c0690235dc4028a485d26edfbdcd05a405b", + "8da706562352ef5aa455be87a1a35246513976d5", "testharness" ], "css/css-transitions/transition-delay-002.html": [ @@ -501305,7 +507689,7 @@ "manual" ], "css/css-transitions/transition-duration-001.html": [ - "8fe9e0c26be9546616a5fb478cb923ba01443534", + "9d8ed6ae2885604c7358936ac3890085e4cd9943", "testharness" ], "css/css-transitions/transition-duration-002.html": [ @@ -501321,11 +507705,11 @@ "manual" ], "css/css-transitions/transition-property-001.html": [ - "365990e00895d721f63d1922de7a135d0e1da442", + "8977177635cae901a9f7540c94c6cc74f0ca8d6f", "testharness" ], "css/css-transitions/transition-property-002.html": [ - "aec901f17b242ea20e4f9a0000afc721e3b1afe5", + "e4019e8e5ec748cdf5c1112ab87fcfb8478c6410", "testharness" ], "css/css-transitions/transition-property-003.html": [ @@ -501505,7 +507889,7 @@ "reftest" ], "css/css-transitions/transition-timing-function-001.html": [ - "4311e0f7879579130ebf9a540b3b116ed3a9c6d1", + "4b2e7ebb296da03f72f509e3cbc8d647c162c449", "testharness" ], "css/css-transitions/transition-timing-function-002.html": [ @@ -501573,7 +507957,7 @@ "testharness" ], "css/css-typed-om/factory-absolute-length.html": [ - "a0049b74fea0fc581ca9896792cbc35568e68771", + "2d4f84c4ad1121b5415edcbaab6918a933dfdd60", "testharness" ], "css/css-typed-om/factory-duration.html": [ @@ -501585,7 +507969,15 @@ "testharness" ], "css/css-typed-om/styleMap-update-function.html": [ - "537fbd8e64906ce91b3ed387ede6abdc790750a3", + "a1dee75d914b68753af742ce8e6dbbac0397a9a6", + "testharness" + ], + "css/css-typed-om/stylevalue-objects/interface.html": [ + "5c9086db5b7f3a9d6e3109f1ce47385ad345f474", + "testharness" + ], + "css/css-typed-om/stylevalue-subclasses/cssKeywordValue-interface.html": [ + "53394d04d67fa9526240c2c0af8b71f54a60a0c3", "testharness" ], "css/css-ui/OWNERS": [ @@ -503957,7 +510349,7 @@ "testharness" ], "css/css-values/calc-unit-analysis.html": [ - "995e7d094cb02f142d28ff0ca7de9d98f9a298e3", + "c5fd567b4fa257ce53c48ebf8c444bf382459fec", "testharness" ], "css/css-values/ch-unit-001.html": [ @@ -504000,14 +510392,6 @@ "ea1f5256caff0fc42f8dbf843322e51189cee065", "reftest" ], - "css/css-values/iframe/vh-support-transform-origin-iframe.html": [ - "e295875de4bc58b51c45db9a87648749bdfc7e8d", - "visual" - ], - "css/css-values/iframe/vh-support-transform-translate-iframe.html": [ - "3d8502cd78bacbdddb771bed8f028c880f9b105b", - "visual" - ], "css/css-values/initial-background-color.html": [ "5e071d71a9cc355a62d0165b4ca2840ba0ab8c66", "reftest" @@ -504220,6 +510604,14 @@ "078e1dd6dd61d36cec239ed75d02051f61fe60a5", "support" ], + "css/css-values/support/vh-support-transform-origin-iframe.html": [ + "e295875de4bc58b51c45db9a87648749bdfc7e8d", + "support" + ], + "css/css-values/support/vh-support-transform-translate-iframe.html": [ + "3d8502cd78bacbdddb771bed8f028c880f9b105b", + "support" + ], "css/css-values/support/vh_not_refreshing_on_chrome_iframe.html": [ "95f9582bf94c0bc60ddee79415b763af8762faf0", "support" @@ -504265,11 +510657,11 @@ "reftest" ], "css/css-values/vh-support-transform-origin.html": [ - "2fc033c3d515ae1afd364f72818cd814d15779c8", + "2ddd949c507d93d280e61fc3aaed35463ee1fed0", "reftest" ], "css/css-values/vh-support-transform-translate.html": [ - "11ade5a7670dbfe781dfaa14d9a2476a586ce34c", + "337a80ea54be900454c296910d38254bf20589e6", "reftest" ], "css/css-values/vh-support.html": [ @@ -504333,7 +510725,7 @@ "support" ], "css/css-variables/test_variable_legal_values.html": [ - "a6ffd6e1e3479aad164dcf678e7382b365473448", + "fb40b2d7cf51500c180568709cedb5203c2e7ebf", "testharness" ], "css/css-variables/variable-animation-from-to.html": [ @@ -506009,8 +512401,8 @@ "reftest" ], "css/css-writing-modes/bidi-table-001.html": [ - "cfad37ee8ded9dc4eec6aa5d615c73bba9ca039f", - "visual" + "f6a6a6ddac6c82a0734ec8af418c140ead454c1d", + "reftest" ], "css/css-writing-modes/bidi-unset-001.html": [ "3558315a55357f817a95aa0ecbd8d62a8b1ae7a9", @@ -506341,8 +512733,8 @@ "visual" ], "css/css-writing-modes/block-plaintext-006.html": [ - "cadc2347f3c345f4e1ea08ec1950641416585a07", - "visual" + "de33a946a26b9ab6f4b04b486ca02cbfc2944d90", + "reftest" ], "css/css-writing-modes/border-conflict-element-vlr-003.xht": [ "2272a00893c883362930f93fff7677c1cde6532e", @@ -510929,7 +517321,7 @@ "testharness" ], "css/cssom-view/elementFromPosition.html": [ - "2bb07e21ddfbc24dabc39fa261c720a36f56a933", + "f033a1ec4b1f0636897c4ee16b67c1c13f0eac4e", "testharness" ], "css/cssom-view/elementScroll.html": [ @@ -511001,7 +517393,7 @@ "testharness" ], "css/cssom-view/offsetParent_element_test.html": [ - "b2261ec702116c211ab5ac6fbb53698dfe60a7be", + "2c3a4481d0ed7773420bf2059047d1d337c899dd", "testharness" ], "css/cssom-view/offsetTopLeftInScrollableParent.html": [ @@ -511009,7 +517401,7 @@ "testharness" ], "css/cssom-view/overscrollBehavior-manual.html": [ - "ca369af991f1e1c34116f2effe0d53a806ed9df5", + "65cb71ca6b606dc8b0b527c58902566539e771b2", "manual" ], "css/cssom-view/resources/elementsFromPoint.js": [ @@ -511024,6 +517416,10 @@ "0a8784c474ccdd4a3e76cb936855a8ef59566217", "support" ], + "css/cssom-view/scroll-behavior-smooth.html": [ + "966ebff69f91c0ea92f4bc2f943df9ef9dc3bcf9", + "testharness" + ], "css/cssom-view/scrollIntoView-shadow.html": [ "3c4a18992105fd7bf19cbf29f0b6d80cb12ca98c", "testharness" @@ -511032,12 +517428,20 @@ "0561564f185dcaf2ad3a8e14e081efb3c2c273e3", "testharness" ], + "css/cssom-view/scrollTop-display-change-ref.html": [ + "bb9079ba597cbcc27604cf8cc5556b4e6e0cda93", + "support" + ], + "css/cssom-view/scrollTop-display-change.html": [ + "68d33e9669be4db95ea9016a8893212e588189fd", + "reftest" + ], "css/cssom-view/scrollWidthHeight.xht": [ - "06ec592720f3db3c04cdd792177179b11a097a23", + "503316b6ea12a881566cce0e2e78ddfc942297f0", "testharness" ], "css/cssom-view/scrollWidthHeightWhenNotScrollable.xht": [ - "dfac20693a9d2bcbc74e372177b1a04472de8f8f", + "897d0db30122018a1b71c52d12f16c41ea845954", "testharness" ], "css/cssom-view/scrolling-no-browsing-context.html": [ @@ -511253,7 +517657,7 @@ "testharness" ], "css/cssom-view/window-interface.xht": [ - "4d8c4ddb997d85ca2c971602a3096f57565c01eb", + "b51ac4828be890736faee8ce42fd95c4bbb844ef", "testharness" ], "css/cssom-view/window-screen-height-immutable.html": [ @@ -511309,7 +517713,7 @@ "testharness" ], "css/cssom/MediaList2.xhtml": [ - "277ec40d3a64d9881e594901a6bcdcd6b70405db", + "c7481f3c0fe943abb6d67004d6c4aaff12180e34", "testharness" ], "css/cssom/OWNERS": [ @@ -511321,7 +517725,7 @@ "testharness" ], "css/cssom/computed-style-001.html": [ - "a940a84552ddcd716af743e0e8746c7582b5c760", + "0331a648e6b0d56f0e7365f1ff7d991ea77ce3e4", "testharness" ], "css/cssom/css-style-attribute-modifications.html": [ @@ -511373,7 +517777,7 @@ "testharness" ], "css/cssom/getComputedStyle-pseudo.html": [ - "98f4a9a445621ae328a317402bdfb62c83de6b43", + "a2033405d6852cdeb4c3b8cf628f7c1d8f7cd1aa", "testharness" ], "css/cssom/historical.html": [ @@ -511389,7 +517793,7 @@ "testharness" ], "css/cssom/inline-style-001.html": [ - "377c8610bc597d47a93f70a9cf95b3c7657d8319", + "da50f9738f161a0bb9af5a5636634346bb683fa9", "testharness" ], "css/cssom/insertRule-charset-no-index.html": [ @@ -511412,20 +517816,28 @@ "c1dfd96239986c9c57d7b07caebbd1fc9654e0b9", "testharness" ], + "css/cssom/medialist-dynamic-001-ref.html": [ + "bdf98c994adcebff3a3434260dfe71e99c8441e1", + "support" + ], + "css/cssom/medialist-dynamic-001.html": [ + "8c62d1e6b5791b68240551c0c9cd115f4d16a892", + "reftest" + ], "css/cssom/medialist-interfaces-001.html": [ - "dfaea262508d72d123006409174e3e21832a305f", + "32d486ecdd41418e734be028c150b0183b8d3316", "testharness" ], "css/cssom/medialist-interfaces-002.html": [ - "114fac94342afe2e7fe432a67c4b0bbf03d24bc4", + "20d4d9e76e0331816aed5f70182dee6966e568e7", "testharness" ], "css/cssom/medialist-interfaces-003.html": [ - "b9ddd611cc585202b1e76382666b04197af334b0", + "42c6fb48a67af381e09995e27dcd8795557345dd", "testharness" ], "css/cssom/medialist-interfaces-004.html": [ - "e3cdc88670ca46b3752fd8118d94dae2cc95258d", + "9558544a6785ac732150b8a50bedbaf3615fa890", "testharness" ], "css/cssom/overflow-serialization.html": [ @@ -511460,16 +517872,20 @@ "5e83f084efc82184c3052a40bb4a061fd4a1336f", "testharness" ], + "css/cssom/setproperty-null-undefined.html": [ + "8521d827e1e641c3b856854c38eac66a97ddf690", + "testharness" + ], "css/cssom/shorthand-serialization.html": [ "bd514834dbd48c267c16a4329af6fec7f6cbc081", "testharness" ], "css/cssom/style-sheet-interfaces-001.html": [ - "e77ec7de74baa901cc15a3b90d2b29125c282562", + "6dbb52cd85cb3bbc711a3569e0f253d7086a43a0", "testharness" ], "css/cssom/style-sheet-interfaces-002.html": [ - "875598ca4271d4adaa11fbb01981b290e6235019", + "8fc091c20efd7fc71c6c357278977ee6137fd8d4", "testharness" ], "css/cssom/stylesheet-replacedata-dynamic-ref.html": [ @@ -511673,7 +518089,7 @@ "support" ], "css/cssom/ttwf-cssom-doc-ext-load-count.html": [ - "800db5cd4f7342d8c4e5309d4035182ce42f7251", + "035984ef66730a2f87c08dbcba76a2620cf70775", "testharness" ], "css/cssom/ttwf-cssom-doc-ext-load-tree-order.html": [ @@ -512645,19 +519061,19 @@ "reftest" ], "css/mediaqueries/mq-calc-002.html": [ - "58c831e53e5aed91da4ba4ed1375a25624f5d9b8", + "6b77bc8b8fec58a8fa0d246532a86282ee30a81a", "reftest" ], "css/mediaqueries/mq-calc-003.html": [ - "41fe79a4d2fd208c8f9b503efed122e2f6d25f25", + "21320b601e3c91f1d4e8ad72e53861af2c184f18", "reftest" ], "css/mediaqueries/mq-calc-004.html": [ - "9602d9f7bd90031890850032572a25ab51c2ed17", + "7cad13aa87e8a0d95dc9e35eb7d1dec7930939fb", "reftest" ], "css/mediaqueries/mq-calc-005.html": [ - "154fc9c31ab6b50f54214bc2198a7e5d8c66b2a1", + "75334bbcf4ef412b9976c59e1efe2177ad62b465", "reftest" ], "css/mediaqueries/mq-invalid-media-type-001.html": [ @@ -512681,19 +519097,19 @@ "support" ], "css/mediaqueries/relative-units-001.html": [ - "e776e9d66ce2a71e9dc156c8e9566ab51ee632c9", + "d5a9cddad47e67048e8ba5d54c3cd0abca93efbe", "reftest" ], "css/mediaqueries/relative-units-002.html": [ - "c533d6fead2ed27d02b826aeba0d8abbb45031a2", + "1542d3980b34ff68437c734a98dd6452eae51eb0", "reftest" ], "css/mediaqueries/relative-units-003.html": [ - "e42e3e16ae2cc3c2c9679c653fcb9d6ab49e1c15", + "12e3a8ff864ad507bd9f7ad860434682b9c23cba", "reftest" ], "css/mediaqueries/relative-units-004.html": [ - "1db0c6b7ee4aa554328cda73a7fab0bd373598c8", + "8cf95c93cfdb225588ffa2218a2f5948a48bb849", "reftest" ], "css/mediaqueries/support/media_queries_iframe.html": [ @@ -512705,7 +519121,7 @@ "support" ], "css/mediaqueries/test_media_queries.html": [ - "4f4f13f66e77a41e97ee5035568f1e0944ec8b2e", + "7b0a2c7025dd0bd6aee14935760f88cd1f09c7dc", "testharness" ], "css/motion/animation/offset-anchor-interpolation.html": [ @@ -512716,6 +519132,26 @@ "f242f67f0d1a1c25a871d4ae949d42f9d1df0027", "testharness" ], + "css/motion/animation/offset-path-interpolation-001.html": [ + "89e4b811c0125ead111206b150b26c97e684ad5b", + "testharness" + ], + "css/motion/animation/offset-path-interpolation-002.html": [ + "63ad6fda28ca9e980c55467de211bb39569b9c62", + "testharness" + ], + "css/motion/animation/offset-path-interpolation-003.html": [ + "f6b4dbbb04e9e22358aaa121b7a718e71e0fa973", + "testharness" + ], + "css/motion/animation/offset-path-interpolation-004.html": [ + "dee154d12679ba899879dae5ee35f05f408bfab9", + "testharness" + ], + "css/motion/animation/offset-path-interpolation-005.html": [ + "1d688f56be81a4c5197590c4930608b95e535952", + "testharness" + ], "css/motion/animation/offset-position-interpolation.html": [ "6c21c93c0715af758033d7b582f072988b379b15", "testharness" @@ -512820,6 +519256,10 @@ "4aced258fbe6ada965f2a0707fad78878af7f162", "support" ], + "css/reference/nothing.html": [ + "c761e386839fbcc7eb1fc9c66f8839b3cd15ec95", + "support" + ], "css/reference/only_pass_parens_semicolon.html": [ "eec4a0a2b3f8f77c8b7c124e33617ce42c6e5209", "support" @@ -512868,6 +519308,10 @@ "c5f3a64d83b3f35ac627d9428eeb03668ad2865e", "support" ], + "css/reference/ref-filled-green-100px-square-only.html": [ + "b78537c1c18697493412ca96bbb6e6d67304e0d7", + "support" + ], "css/reference/ref-filled-green-100px-square.xht": [ "2f6ee60666fbb65497dc8749683d66ae543bad12", "support" @@ -512908,6 +519352,14 @@ "b45da5560d0eb821b5552f1b67fab5cead4508b1", "support" ], + "css/selectors/any-link-dynamic-001-ref.html": [ + "342d89969da0ca3782efacee0ecbf882c718d6c6", + "support" + ], + "css/selectors/any-link-dynamic-001.html": [ + "c33602e863151182d29afd88a8878374bb118b69", + "reftest" + ], "css/selectors/attribute-selectors/attribute-case/cssom.html": [ "d5e05750213fbf7959125d64e9ea1a26948ba91d", "testharness" @@ -514492,6 +520944,10 @@ "394ad01c928f8a15796bc6c29cdbc5e2dc37fd52", "testharness" ], + "css/selectors/invalidation/any-link-pseudo.html": [ + "9593a7d2dddc79525edb801748a28b1a5a1837c7", + "testharness" + ], "css/selectors/missing-right-token.html": [ "d961e801f7df57161cd8c7b5a4b26ae24013c3e9", "testharness" @@ -523109,7 +529565,7 @@ "testharness" ], "custom-elements/parser/parser-uses-registry-of-owner-document.html": [ - "492b05763f5c94429bc2ea6cc2db9cb01417695a", + "a62669ffcc75d54df38b65e33463566238c8644c", "testharness" ], "custom-elements/reaction-timing.html": [ @@ -523137,7 +529593,7 @@ "testharness" ], "custom-elements/reactions/Document.html": [ - "ab7d3d84305f1261e41a76d08296950fd3e5a483", + "96a008a0fe4513986fec1d1329b0f90689b1d504", "testharness" ], "custom-elements/reactions/Element.html": [ @@ -523220,6 +529676,10 @@ "e966b6c608ee9b4183e040b8be7adb2b73722c7b", "support" ], + "custom-elements/reactions/with-exceptions.html": [ + "b72ee82a3d98c61683e62c4834f54269898e12d5", + "testharness" + ], "custom-elements/resources/custom-elements-helpers.js": [ "875838d63f7d44c7a958a03c494ba709c53816c9", "support" @@ -523228,6 +529688,10 @@ "c436e35464c8c32f3afb191c46ef599b4986a395", "support" ], + "custom-elements/resources/my-custom-element-html-document.html": [ + "8d2ac097525aca96f01e3bf73f5e3c144d43fa27", + "support" + ], "custom-elements/upgrading.html": [ "da38f84be26bb7f33d949f65ebe26153f9631b45", "testharness" @@ -523625,7 +530089,7 @@ "testharness" ], "dom/events/Event-subclasses-constructors.html": [ - "5da96a9be09ad5dc69438ba9bd6b2ab58cf77ca1", + "52382c89b67be3c3fbb8bccccb6f75a4aaa7975b", "testharness" ], "dom/events/Event-timestamp-high-resolution.html": [ @@ -523669,7 +530133,7 @@ "support" ], "dom/events/EventListener-invoke-legacy.html": [ - "e56b332acb454ab76964b78588536777946ddff8", + "13cb3802cb2722417b876ded17fddd222c69564a", "testharness" ], "dom/events/EventListenerOptions-capture.html": [ @@ -523697,7 +530161,7 @@ "testharness" ], "dom/historical.html": [ - "99cd2739cdfcb5b2c6bf0df098abdfcc4203b891", + "ccf3d9d2d8eb3e7353ecedd8a4d8ba232f9374ec", "testharness" ], "dom/interface-objects.html": [ @@ -525697,7 +532161,7 @@ "testharness" ], "encoding/big5-encoder.html": [ - "b9635c43ce159e1961106b039dce0e3d04fade34", + "c5fec0f733b77620267488917cf54554c766801f", "testharness" ], "encoding/eof-shift_jis-ref.html": [ @@ -525737,7 +532201,7 @@ "testharness" ], "encoding/gbk-encoder.html": [ - "30bdfc96ffaff0277ceca69aad43d82d5ac691b6", + "d099c6f374df5e68dd44bd6fe6115c415e74e91c", "testharness" ], "encoding/idlharness.html": [ @@ -526876,191 +533340,191 @@ "4cdfcbd7d8243d6cb61dbeb73535cc561cc44766", "support" ], - "encrypted-media/clearkey-check-initdata-type.html": [ + "encrypted-media/clearkey-check-initdata-type.https.html": [ "edf050cdd617f5e1b9de04c3c77b2bb92b22a74f", "testharness" ], - "encrypted-media/clearkey-events-session-closed-event.html": [ + "encrypted-media/clearkey-events-session-closed-event.https.html": [ "df3718598584c8ac59be5d4b8ef85083e1e9ddcf", "testharness" ], - "encrypted-media/clearkey-events.html": [ + "encrypted-media/clearkey-events.https.html": [ "75c9904a525c4bb1ec495445660671ad5279f0a7", "testharness" ], - "encrypted-media/clearkey-generate-request-disallowed-input.html": [ + "encrypted-media/clearkey-generate-request-disallowed-input.https.html": [ "4426b44b87b52f17c8dff8027c61e3e39ac9e321", "testharness" ], - "encrypted-media/clearkey-invalid-license.html": [ + "encrypted-media/clearkey-invalid-license.https.html": [ "4fa0b5af9fce24e3f6abd932f2352ff4deb0f90f", "testharness" ], - "encrypted-media/clearkey-keystatuses-multiple-sessions.html": [ + "encrypted-media/clearkey-keystatuses-multiple-sessions.https.html": [ "aa361d04cfd38448bde43102860cb67c92378217", "testharness" ], - "encrypted-media/clearkey-keystatuses.html": [ + "encrypted-media/clearkey-keystatuses.https.html": [ "0da720e35be9913eff72ca4686d09447a8b0baae", "testharness" ], - "encrypted-media/clearkey-mp4-playback-destroy-persistent-license.html": [ + "encrypted-media/clearkey-mp4-playback-destroy-persistent-license.https.html": [ "31f911c3795711d1ff315baa035adbf9b82063b1", "testharness" ], - "encrypted-media/clearkey-mp4-playback-persistent-license-events.html": [ + "encrypted-media/clearkey-mp4-playback-persistent-license-events.https.html": [ "77839f9d494a4ab72d19ab6d0f8c87600af78b83", "testharness" ], - "encrypted-media/clearkey-mp4-playback-persistent-license.html": [ + "encrypted-media/clearkey-mp4-playback-persistent-license.https.html": [ "82870fec532dfca22931614b62104d82f361948d", "testharness" ], - "encrypted-media/clearkey-mp4-playback-persistent-usage-record-events.html": [ + "encrypted-media/clearkey-mp4-playback-persistent-usage-record-events.https.html": [ "778a2d9d48f080b497359f18f7fe5505fc1a95a6", "testharness" ], - "encrypted-media/clearkey-mp4-playback-persistent-usage-record.html": [ + "encrypted-media/clearkey-mp4-playback-persistent-usage-record.https.html": [ "0ba42cf14754d5f5a72b1bed5c4e584d98367a13", "testharness" ], - "encrypted-media/clearkey-mp4-playback-retrieve-destroy-persistent-license.html": [ + "encrypted-media/clearkey-mp4-playback-retrieve-destroy-persistent-license.https.html": [ "fe1e7fd17a30f52936fb533e6553f09cbd9ce954", "testharness" ], - "encrypted-media/clearkey-mp4-playback-retrieve-persistent-license.html": [ + "encrypted-media/clearkey-mp4-playback-retrieve-persistent-license.https.html": [ "c82925a064bcd0eadb81a6b92a7fac35e76b35d8", "testharness" ], - "encrypted-media/clearkey-mp4-playback-retrieve-persistent-usage-record.html": [ + "encrypted-media/clearkey-mp4-playback-retrieve-persistent-usage-record.https.html": [ "3db3dfc846598a30218f740201e48ca6112f4d93", "testharness" ], - "encrypted-media/clearkey-mp4-playback-temporary-clear-encrypted.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-clear-encrypted.https.html": [ "bade72126b9a42409ef2b1901b84aef7778b2eac", "testharness" ], - "encrypted-media/clearkey-mp4-playback-temporary-encrypted-clear-sources.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-encrypted-clear-sources.https.html": [ "df277e779299caa92f7b82d2f8a51eb71a77eba1", "testharness" ], - "encrypted-media/clearkey-mp4-playback-temporary-encrypted-clear.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-encrypted-clear.https.html": [ "8a2c68dafa32348f869ffeffaa8952123f4cb539", "testharness" ], - "encrypted-media/clearkey-mp4-playback-temporary-events.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-events.https.html": [ "8a4fdf2f0ae55cc9b4c137ada2c2721701a34e89", "testharness" ], - "encrypted-media/clearkey-mp4-playback-temporary-multikey-sequential-readyState.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-multikey-sequential-readyState.https.html": [ "4252b999d028092862f18663a9ab8fe654439b8c", "testharness" ], - "encrypted-media/clearkey-mp4-playback-temporary-multikey-sequential.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-multikey-sequential.https.html": [ "3d6d572a21f7380bd69fa52360dfbde527241440", "testharness" ], - "encrypted-media/clearkey-mp4-playback-temporary-multikey.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-multikey.https.html": [ "8649ac8a23f45a0c8f34a31e3df58b8da786f68e", "testharness" ], - "encrypted-media/clearkey-mp4-playback-temporary-multisession.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-multisession.https.html": [ "6e12223723edeb54e41128c1c86b9ae04091b448", "testharness" ], - "encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-after-src.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-after-src.https.html": [ "0acbe39273cd4dfffc0580ae821b4f880323ef35", "testharness" ], - "encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-after-update.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-after-update.https.html": [ "a416bd41c485e4f0e48ad870cc4ddad40d194509", "testharness" ], - "encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-immediately.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-immediately.https.html": [ "a1051de265005fd205ab71ccc863ab429fe1b11e", "testharness" ], - "encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-onencrypted.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-onencrypted.https.html": [ "c2356c4d5fc4be3d6b096f1cc9ca026b9d2989d1", "testharness" ], - "encrypted-media/clearkey-mp4-playback-temporary-two-videos.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-two-videos.https.html": [ "03954e9c2ddc20b37d858bdcb29d4fb197fc2f9a", "testharness" ], - "encrypted-media/clearkey-mp4-playback-temporary-waitingforkey.html": [ + "encrypted-media/clearkey-mp4-playback-temporary-waitingforkey.https.html": [ "2b195d087a715ed3b5d9803dded1b9d25c135789", "testharness" ], - "encrypted-media/clearkey-mp4-playback-temporary.html": [ + "encrypted-media/clearkey-mp4-playback-temporary.https.html": [ "2d2c14ac3e4147c2ce54665ac84c102906df15bc", "testharness" ], - "encrypted-media/clearkey-mp4-requestmediakeysystemaccess.html": [ + "encrypted-media/clearkey-mp4-requestmediakeysystemaccess.https.html": [ "ccd431ebc1212c33953f273a4a1665124da3b2f1", "testharness" ], - "encrypted-media/clearkey-mp4-reset-src-after-setmediakeys.html": [ + "encrypted-media/clearkey-mp4-reset-src-after-setmediakeys.https.html": [ "ea428a6fd609c5f3243b0cb89171f23484475c60", "testharness" ], - "encrypted-media/clearkey-mp4-setmediakeys-again-after-playback.html": [ + "encrypted-media/clearkey-mp4-setmediakeys-again-after-playback.https.html": [ "09b19346bccb01a63e3b1a509f0104f99a5723a8", "testharness" ], - "encrypted-media/clearkey-mp4-setmediakeys-again-after-resetting-src.html": [ + "encrypted-media/clearkey-mp4-setmediakeys-again-after-resetting-src.https.html": [ "cba1dca366654371b3b2d046c3505d10235b9e8d", "testharness" ], - "encrypted-media/clearkey-mp4-setmediakeys-at-same-time.html": [ + "encrypted-media/clearkey-mp4-setmediakeys-at-same-time.https.html": [ "6c3e3659fe5fd7ae063371f13e6a284cdcc06019", "testharness" ], - "encrypted-media/clearkey-mp4-setmediakeys-multiple-times-with-different-mediakeys.html": [ + "encrypted-media/clearkey-mp4-setmediakeys-multiple-times-with-different-mediakeys.https.html": [ "9edb8596073d8dd0a34db9398e0966f29d73b425", "testharness" ], - "encrypted-media/clearkey-mp4-setmediakeys-multiple-times-with-the-same-mediakeys.html": [ + "encrypted-media/clearkey-mp4-setmediakeys-multiple-times-with-the-same-mediakeys.https.html": [ "9e177ca8da585c867cf3b9c8f08afaa914c203bc", "testharness" ], - "encrypted-media/clearkey-mp4-setmediakeys-to-multiple-video-elements.html": [ + "encrypted-media/clearkey-mp4-setmediakeys-to-multiple-video-elements.https.html": [ "161653f14df5c4c883922a253457cc3e711dc997", "testharness" ], - "encrypted-media/clearkey-mp4-setmediakeys.html": [ + "encrypted-media/clearkey-mp4-setmediakeys.https.html": [ "a3a30ffbe0c946b3dd3f50f46c819c94aefcb470", "testharness" ], - "encrypted-media/clearkey-mp4-syntax-mediakeys.html": [ + "encrypted-media/clearkey-mp4-syntax-mediakeys.https.html": [ "d8cd90ecb4094e6866796edb40e50a0bfecf03d2", "testharness" ], - "encrypted-media/clearkey-mp4-syntax-mediakeysession.html": [ + "encrypted-media/clearkey-mp4-syntax-mediakeysession.https.html": [ "040914ccaba738cfc9a97f4c4a839883cde8bcef", "testharness" ], - "encrypted-media/clearkey-mp4-syntax-mediakeysystemaccess.html": [ + "encrypted-media/clearkey-mp4-syntax-mediakeysystemaccess.https.html": [ "b7115f8d8bbd2da5f4b2635f66909fd4e4252747", "testharness" ], - "encrypted-media/clearkey-mp4-unique-origin.html": [ + "encrypted-media/clearkey-mp4-unique-origin.https.html": [ "26d01bff637c6321f4d12aa8a50722f3e30b3b40", "testharness" ], - "encrypted-media/clearkey-mp4-update-disallowed-input.html": [ + "encrypted-media/clearkey-mp4-update-disallowed-input.https.html": [ "7396b7380f22845aaf66da67be5ce19a93a90259", "testharness" ], - "encrypted-media/clearkey-mp4-waiting-for-a-key.html": [ + "encrypted-media/clearkey-mp4-waiting-for-a-key.https.html": [ "349ae6a759b23051e83c7dbbf96c4938d2482429", "testharness" ], - "encrypted-media/clearkey-not-callable-after-createsession.html": [ + "encrypted-media/clearkey-not-callable-after-createsession.https.html": [ "2f0a96c7fa9927f95ff1634cb08457ef305d4e7f", "testharness" ], - "encrypted-media/clearkey-update-non-ascii-input.html": [ + "encrypted-media/clearkey-update-non-ascii-input.https.html": [ "93e7cb2f9fa4e5d0696e3f9e02e88c2adf41fbd9", "testharness" ], @@ -527108,199 +533572,199 @@ "0fb6d575a357dd5fdc4544a55cb8ef4e25f0f449", "support" ], - "encrypted-media/drm-check-initdata-type.html": [ + "encrypted-media/drm-check-initdata-type.https.html": [ "ae0f79ae94465890ded3e3a6bfd60f320b23ad44", "testharness" ], - "encrypted-media/drm-events-session-closed-event.html": [ + "encrypted-media/drm-events-session-closed-event.https.html": [ "b5061558a5860289fd81ab806179fc3bdde06d22", "testharness" ], - "encrypted-media/drm-events.html": [ + "encrypted-media/drm-events.https.html": [ "aca0d0624fc6cf16eac0c86723aa680c2fa8006c", "testharness" ], - "encrypted-media/drm-expiration.html": [ + "encrypted-media/drm-expiration.https.html": [ "d071ca11388305cd8296f1183b1c5f3e3804c468", "testharness" ], - "encrypted-media/drm-generate-request-disallowed-input.html": [ + "encrypted-media/drm-generate-request-disallowed-input.https.html": [ "4d5e1c39a7dec2ae4c2f8706d54696d456180ed4", "testharness" ], - "encrypted-media/drm-invalid-license.html": [ + "encrypted-media/drm-invalid-license.https.html": [ "74afa97cd841401cd4b8ed18ea83499f410d17bf", "testharness" ], - "encrypted-media/drm-keystatuses-multiple-sessions.html": [ + "encrypted-media/drm-keystatuses-multiple-sessions.https.html": [ "2ec2ce19b8f1f52ee33450f89cec546d4524403e", "testharness" ], - "encrypted-media/drm-keystatuses.html": [ + "encrypted-media/drm-keystatuses.https.html": [ "777476ed7189626623fe6046e67a6d9359ce5783", "testharness" ], - "encrypted-media/drm-mp4-onencrypted.html": [ + "encrypted-media/drm-mp4-onencrypted.https.html": [ "400ea20b213af0d1b5f415744ec3d48534fce7e7", "testharness" ], - "encrypted-media/drm-mp4-playback-destroy-persistent-license.html": [ + "encrypted-media/drm-mp4-playback-destroy-persistent-license.https.html": [ "b1bd421f82ee615d7a994256363d7daf1990f74e", "testharness" ], - "encrypted-media/drm-mp4-playback-persistent-license-events.html": [ + "encrypted-media/drm-mp4-playback-persistent-license-events.https.html": [ "5f2bf9c9cc1404be0f7c948c436a60483d662600", "testharness" ], - "encrypted-media/drm-mp4-playback-persistent-license.html": [ + "encrypted-media/drm-mp4-playback-persistent-license.https.html": [ "421ab3065f65e9cd88ba318a50bbbf84beef4966", "testharness" ], - "encrypted-media/drm-mp4-playback-persistent-usage-record-events.html": [ + "encrypted-media/drm-mp4-playback-persistent-usage-record-events.https.html": [ "508a4e777bd6c050028e76b8ebfb8da36e92f613", "testharness" ], - "encrypted-media/drm-mp4-playback-persistent-usage-record.html": [ + "encrypted-media/drm-mp4-playback-persistent-usage-record.https.html": [ "bac4592aa70ea169e6424d571293dcbf10be9eda", "testharness" ], - "encrypted-media/drm-mp4-playback-retrieve-destroy-persistent-license.html": [ + "encrypted-media/drm-mp4-playback-retrieve-destroy-persistent-license.https.html": [ "4be63a706c6af42c22a2d8eef94d227ca7af5cbb", "testharness" ], - "encrypted-media/drm-mp4-playback-retrieve-persistent-license.html": [ + "encrypted-media/drm-mp4-playback-retrieve-persistent-license.https.html": [ "3c605d585e46f34b9cea3cda2caae72e93bb00ef", "testharness" ], - "encrypted-media/drm-mp4-playback-retrieve-persistent-usage-record.html": [ + "encrypted-media/drm-mp4-playback-retrieve-persistent-usage-record.https.html": [ "8783b5efb95e95f5547acb29fb5950ebdde498e8", "testharness" ], - "encrypted-media/drm-mp4-playback-temporary-clear-encrypted.html": [ + "encrypted-media/drm-mp4-playback-temporary-clear-encrypted.https.html": [ "b1825fbafaa400cd8672ca34d36e30ded98d2b9b", "testharness" ], - "encrypted-media/drm-mp4-playback-temporary-encrypted-clear-sources.html": [ + "encrypted-media/drm-mp4-playback-temporary-encrypted-clear-sources.https.html": [ "db48c1ef4d91eaec6787c6c95e2dbb9faaf41965", "testharness" ], - "encrypted-media/drm-mp4-playback-temporary-encrypted-clear.html": [ + "encrypted-media/drm-mp4-playback-temporary-encrypted-clear.https.html": [ "5f23926a2ed2692b3fee95ef613e02668b919106", "testharness" ], - "encrypted-media/drm-mp4-playback-temporary-events.html": [ + "encrypted-media/drm-mp4-playback-temporary-events.https.html": [ "b893677d6c12f1b05f564dbbf1c43362da9ff6e7", "testharness" ], - "encrypted-media/drm-mp4-playback-temporary-expired.html": [ + "encrypted-media/drm-mp4-playback-temporary-expired.https.html": [ "cb4a33c98fed06054e4acce8a65a0dc8e6d1b4c3", "testharness" ], - "encrypted-media/drm-mp4-playback-temporary-multikey-sequential-readyState.html": [ + "encrypted-media/drm-mp4-playback-temporary-multikey-sequential-readyState.https.html": [ "320fb185d71e4f76cc865c63ff99f508d994465c", "testharness" ], - "encrypted-media/drm-mp4-playback-temporary-multikey-sequential.html": [ + "encrypted-media/drm-mp4-playback-temporary-multikey-sequential.https.html": [ "e4616953865577bd08ba566f0487c5e7a793d291", "testharness" ], - "encrypted-media/drm-mp4-playback-temporary-multikey.html": [ + "encrypted-media/drm-mp4-playback-temporary-multikey.https.html": [ "b7fd2a7ec0adc0b5be46242af0df83fab9dda5af", "testharness" ], - "encrypted-media/drm-mp4-playback-temporary-multisession.html": [ + "encrypted-media/drm-mp4-playback-temporary-multisession.https.html": [ "15a0b2950e25edcbff1b5b2e3d5807cb91d9e531", "testharness" ], - "encrypted-media/drm-mp4-playback-temporary-setMediaKeys-after-src.html": [ + "encrypted-media/drm-mp4-playback-temporary-setMediaKeys-after-src.https.html": [ "09ba82feb85a73a1aa275164bfacd722f893075e", "testharness" ], - "encrypted-media/drm-mp4-playback-temporary-setMediaKeys-after-update.html": [ + "encrypted-media/drm-mp4-playback-temporary-setMediaKeys-after-update.https.html": [ "d6ba354d7c2c02775827fa1f896af5b4916a77fd", "testharness" ], - "encrypted-media/drm-mp4-playback-temporary-setMediaKeys-immediately.html": [ + "encrypted-media/drm-mp4-playback-temporary-setMediaKeys-immediately.https.html": [ "eae1bd6fba6709856bf43e9506abf2128f79ced7", "testharness" ], - "encrypted-media/drm-mp4-playback-temporary-setMediaKeys-onencrypted.html": [ + "encrypted-media/drm-mp4-playback-temporary-setMediaKeys-onencrypted.https.html": [ "52facbc71172a79ab84416ae249780abfa48e970", "testharness" ], - "encrypted-media/drm-mp4-playback-temporary-two-videos.html": [ + "encrypted-media/drm-mp4-playback-temporary-two-videos.https.html": [ "a8fb7e599f125c4ea3f665a9cc8be0b91a3df076", "testharness" ], - "encrypted-media/drm-mp4-playback-temporary-waitingforkey.html": [ + "encrypted-media/drm-mp4-playback-temporary-waitingforkey.https.html": [ "82d4432235e45c61cca1fa371dcb83dfe99a3060", "testharness" ], - "encrypted-media/drm-mp4-playback-temporary.html": [ + "encrypted-media/drm-mp4-playback-temporary.https.html": [ "14db930f09d86257aea6d653805b600da772726d", "testharness" ], - "encrypted-media/drm-mp4-requestmediakeysystemaccess.html": [ + "encrypted-media/drm-mp4-requestmediakeysystemaccess.https.html": [ "2119ef0d22c25f8f3704732c6908ed2c5ac87e03", "testharness" ], - "encrypted-media/drm-mp4-reset-src-after-setmediakeys.html": [ + "encrypted-media/drm-mp4-reset-src-after-setmediakeys.https.html": [ "f3c6f6c10c7dc7938a9c90309aecc7643de3603a", "testharness" ], - "encrypted-media/drm-mp4-setmediakeys-again-after-playback.html": [ + "encrypted-media/drm-mp4-setmediakeys-again-after-playback.https.html": [ "d0799ef8ecf2198e97af8863828cf00455ccb643", "testharness" ], - "encrypted-media/drm-mp4-setmediakeys-again-after-resetting-src.html": [ + "encrypted-media/drm-mp4-setmediakeys-again-after-resetting-src.https.html": [ "60cf1a74b1aa5eff4c817d78a6bf133588e9c9ec", "testharness" ], - "encrypted-media/drm-mp4-setmediakeys-at-same-time.html": [ + "encrypted-media/drm-mp4-setmediakeys-at-same-time.https.html": [ "a475403fef02570be2815cc02572fc2afe7b6d55", "testharness" ], - "encrypted-media/drm-mp4-setmediakeys-multiple-times-with-different-mediakeys.html": [ + "encrypted-media/drm-mp4-setmediakeys-multiple-times-with-different-mediakeys.https.html": [ "0011bd6d2447f59d19844cb27c0248846dfc4a56", "testharness" ], - "encrypted-media/drm-mp4-setmediakeys-multiple-times-with-the-same-mediakeys.html": [ + "encrypted-media/drm-mp4-setmediakeys-multiple-times-with-the-same-mediakeys.https.html": [ "6b60d7967a71112f476700d8ce3570b40cf51f08", "testharness" ], - "encrypted-media/drm-mp4-setmediakeys-to-multiple-video-elements.html": [ + "encrypted-media/drm-mp4-setmediakeys-to-multiple-video-elements.https.html": [ "2681878f110de7841fba6123ceb785820b596474", "testharness" ], - "encrypted-media/drm-mp4-setmediakeys.html": [ + "encrypted-media/drm-mp4-setmediakeys.https.html": [ "c66a641651351e92d47a6e149618117eeabfaff8", "testharness" ], - "encrypted-media/drm-mp4-syntax-mediakeys.html": [ + "encrypted-media/drm-mp4-syntax-mediakeys.https.html": [ "ab9db64508f7181eef25898cfceacdc351c299ef", "testharness" ], - "encrypted-media/drm-mp4-syntax-mediakeysession.html": [ + "encrypted-media/drm-mp4-syntax-mediakeysession.https.html": [ "51fcd7900ced0c4c50ef1b1fc8f50e69db021f55", "testharness" ], - "encrypted-media/drm-mp4-syntax-mediakeysystemaccess.html": [ + "encrypted-media/drm-mp4-syntax-mediakeysystemaccess.https.html": [ "3718f25e30379509466117157f5ab7af705458a3", "testharness" ], - "encrypted-media/drm-mp4-unique-origin.html": [ + "encrypted-media/drm-mp4-unique-origin.https.html": [ "f1a76980453dfce0c9e27774c2763295c2f8eb11", "testharness" ], - "encrypted-media/drm-mp4-waiting-for-a-key.html": [ + "encrypted-media/drm-mp4-waiting-for-a-key.https.html": [ "52e710dd8e9f90e0a1a2a922bba042ea6e53a439", "testharness" ], - "encrypted-media/drm-not-callable-after-createsession.html": [ + "encrypted-media/drm-not-callable-after-createsession.https.html": [ "82c70015b32240304ab410b4a57791bb3d8c45e5", "testharness" ], - "encrypted-media/drm-temporary-license-type.html": [ + "encrypted-media/drm-temporary-license-type.https.html": [ "85124d35b37f14c143e1fcb2965f131a8f2a3391", "testharness" ], @@ -527308,8 +533772,8 @@ "d7627e2017ae8ac994a6bc8a2a00df0dd2332c59", "testharness" ], - "encrypted-media/idlharness.html": [ - "69456d56a5485b04465f4f6ee4abc80388703fd9", + "encrypted-media/idlharness.https.html": [ + "eece848c772a39b29d6d8ece532e7807d737f50d", "testharness" ], "encrypted-media/polyfill/cast-polyfill.js": [ @@ -527341,27 +533805,27 @@ "support" ], "encrypted-media/resources/clearkey-retrieve-destroy-persistent-license.html": [ - "a7638aacda006d42a622fc604d1b428443eb7722", + "ed8678213a798f04b01decf94014121986ec544a", "support" ], "encrypted-media/resources/clearkey-retrieve-persistent-license.html": [ - "20355904d2f71d222c4837da1331d643ab5d0098", + "04f30afdd5aa85dfa66e7b1424489276c7b3e8a8", "support" ], "encrypted-media/resources/drm-retrieve-destroy-persistent-license.html": [ - "0058c9807f20acbc5762c99b42e5406dddb88216", + "c628a38a59d96614b36ca396c8ce822c4bcb8a68", "support" ], "encrypted-media/resources/drm-retrieve-persistent-license.html": [ - "44dd2ebae1e0fb9997b9c4dc9ae6bf7cd24b87c7", + "21258d2eb390b5843e93563bd3a702d633c6585a", "support" ], "encrypted-media/resources/drm-retrieve-persistent-usage-record.html": [ - "f17de07ac51e592b88bddbfe87689a7699ec5a07", + "6bf8b93750744b323a584a767c2bebb68c74fb6b", "support" ], "encrypted-media/resources/retrieve-persistent-usage-record.html": [ - "855c3c92754d777c85167f15314de212b69daf4d", + "33818bb3302ccd50b2af5eafb2c5c05eb337a655", "support" ], "encrypted-media/scripts/check-initdata-type.js": [ @@ -527429,11 +533893,11 @@ "support" ], "encrypted-media/scripts/playback-retrieve-persistent-license.js": [ - "bdd878f11a98e79058e2a7b0fab56f9b2006f5a8", + "a729fe90e843d8344db1e3c6c4a235d5bb9da59a", "support" ], "encrypted-media/scripts/playback-retrieve-persistent-usage-record.js": [ - "319a9a73255aca2b77a5f9f384ba5de5d7ebfbb3", + "bfe606669dc2c87c3813c119860f00317102a5bd", "support" ], "encrypted-media/scripts/playback-temporary-encrypted-clear-sources.js": [ @@ -527525,7 +533989,7 @@ "support" ], "encrypted-media/scripts/unique-origin.js": [ - "781b4c4e6e48f3941e52856e3d5486b7b4a1a7a9", + "ddbdf009d11297918fe66e0b58498bd863be8333", "support" ], "encrypted-media/scripts/update-disallowed-input.js": [ @@ -527973,11 +534437,39 @@ "support" ], "feature-policy/README.md": [ - "711c323f1690b0dbe780461241ad825cdd3cf274", + "67e317403163eb2f7b4d9599d21da97635fc14cf", + "support" + ], + "feature-policy/autoplay-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html": [ + "4dc3b753b880e3c36b346fef5f605ca30a26081c", + "testharness" + ], + "feature-policy/autoplay-allowed-by-feature-policy-attribute.https.sub.html": [ + "09531b990314460b4ee70b3535f27dafd654e5bc", + "testharness" + ], + "feature-policy/autoplay-allowed-by-feature-policy.https.sub.html": [ + "a7c55fc4a17ba1e33a1758359c866345070ed8cd", + "testharness" + ], + "feature-policy/autoplay-allowed-by-feature-policy.https.sub.html.headers": [ + "c563cecd38f12aaaf24c56d578e0cc9d7e7ad87f", + "support" + ], + "feature-policy/autoplay-default-feature-policy.https.sub.html": [ + "946f76ab8d48394b33b9980b1411eee1fbf8e083", + "testharness" + ], + "feature-policy/autoplay-disabled-by-feature-policy.https.sub.html": [ + "172558a2135fc066b69d91d4b340a3fc5e49d2c1", + "testharness" + ], + "feature-policy/autoplay-disabled-by-feature-policy.https.sub.html.headers": [ + "4239ec4ef240e199f15a38145d478d2c0aa43ad2", "support" ], "feature-policy/payment-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html": [ - "8595732f7794f10107ef234fe6e37cc12c80eeaa", + "22d155755cd7aaff8a1c40c597468066f01eb13b", "testharness" ], "feature-policy/payment-allowed-by-feature-policy-attribute.https.sub.html": [ @@ -528004,6 +534496,18 @@ "09f612159dc367bad5febc8e0a724f0a284517d5", "support" ], + "feature-policy/resources/autoplay.js": [ + "6b1dd45e19dff4759b4d165cdfd59970e4212058", + "support" + ], + "feature-policy/resources/feature-policy-autoplay.html": [ + "34eb416a1b8981460d2055108b255bec7f639f04", + "support" + ], + "feature-policy/resources/feature-policy-generic-sensor.html": [ + "5d4a1f3eaf253211128f35990a94e1e0c91c1391", + "support" + ], "feature-policy/resources/feature-policy-payment.html": [ "958b32f77b02f2ff80cf174aadac62237d79056b", "support" @@ -528209,7 +534713,7 @@ "testharness" ], "fetch/api/cors/cors-expose-star.js": [ - "2403a7d229377d03230f32383e71960e32a84271", + "338dc1bf4cfe3b61209b5ffd362ecc3175890c1b", "support" ], "fetch/api/cors/cors-filtering-worker.html": [ @@ -528489,7 +534993,7 @@ "testharness" ], "fetch/api/redirect/redirect-method.js": [ - "d663a3e4f32d0b48cf33d31a83c841ef55b52032", + "6e1d7ec853ecc7f15af9119cd1ff30027fd6beb2", "support" ], "fetch/api/redirect/redirect-mode-worker.html": [ @@ -528544,6 +535048,42 @@ "3099fb27913f11a983f955cb2a883a882911bfe4", "support" ], + "fetch/api/request/destination/fetch-destination.https.html": [ + "94437d1ca32c798817b73be9d726b171c68252b0", + "testharness" + ], + "fetch/api/request/destination/resources/dummy": [ + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "support" + ], + "fetch/api/request/destination/resources/dummy.png": [ + "fa547a180b73a5422d52c1702c9d1e43b1083f9c", + "support" + ], + "fetch/api/request/destination/resources/dummy_audio.mp3": [ + "b9171c72fedef62f2b3b0ade70b6d085ba94f7e5", + "support" + ], + "fetch/api/request/destination/resources/dummy_audio.oga": [ + "167093849b93b142723513ac72a725c97da635a8", + "support" + ], + "fetch/api/request/destination/resources/dummy_video.mp4": [ + "c9828d21efc0898635b693bf3e2f34041d7e8ddb", + "support" + ], + "fetch/api/request/destination/resources/dummy_video.ogv": [ + "cb9a48e1d53911d5be214320adfbf7596632a316", + "support" + ], + "fetch/api/request/destination/resources/empty.https.html": [ + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "support" + ], + "fetch/api/request/destination/resources/fetch-destination-worker.js": [ + "e10bc6423b2ee29387b1153546ae765449aa1ae4", + "support" + ], "fetch/api/request/multi-globals/current/current.html": [ "2d9ab238e07a88d19365f78bfd5db84d32854de1", "support" @@ -528621,7 +535161,7 @@ "testharness" ], "fetch/api/request/request-idl.html": [ - "b2f1431738bd7f389ab43cf8c10aed3b0d12abb8", + "679ff0c44a0ece1c480f5296e738b7a15f4c79cb", "testharness" ], "fetch/api/request/request-init-001.sub.html": [ @@ -528637,7 +535177,7 @@ "testharness" ], "fetch/api/request/request-keepalive-quota.html": [ - "d839fec1d761688db807be2dfddf6b8b6932c46b", + "0b9786a3878a361ba8ec3291216d475bd5148541", "testharness" ], "fetch/api/request/request-keepalive.html": [ @@ -528741,7 +535281,7 @@ "support" ], "fetch/api/resources/trickle.py": [ - "adb1bc80366cf924cfe13f6c73555d999d1d8e4f", + "87a83b390ae91e4419dc580d8426277be48c92d8", "support" ], "fetch/api/resources/utils.js": [ @@ -528789,7 +535329,7 @@ "testharness" ], "fetch/api/response/response-idl.html": [ - "e0e32634b7e0271ff3566cb66b358e46c9fb8d21", + "d94cfadf60dc146f80f7c1dc9937d7841600f9ef", "testharness" ], "fetch/api/response/response-init-001.html": [ @@ -528897,7 +535437,7 @@ "testharness" ], "fetch/nosniff/resources/css.py": [ - "0c3da6d761e72fe49ed883935d84cd4bc4db86bc", + "4ae9ff638587fcc96472709e31466a469061a3b0", "support" ], "fetch/nosniff/resources/image.py": [ @@ -528941,7 +535481,7 @@ "testharness" ], "fetch/nosniff/stylesheet.html": [ - "707b1031fc7594d49b6f1487c8ef71864791ea80", + "2c5801cbf150010da8ef42a1f9e37b93540a8f04", "testharness" ], "fetch/nosniff/worker.html": [ @@ -529424,6 +535964,10 @@ "f6f0dbc8a505896a0e7ec7aca2746bbd5c1eb7d9", "testharness" ], + "fullscreen/model/move-to-fullscreen-iframe-manual.html": [ + "0fc5409f5e44177e1153fb61c25506c05114dc35", + "manual" + ], "fullscreen/model/move-to-iframe-manual.html": [ "818cb1b5db729db4959591dc75d4bb1ae3c7542d", "manual" @@ -529460,6 +536004,10 @@ "0cdfe5cf8321b6c46a75a2f75f6224970368d4ae", "support" ], + "fullscreen/rendering/ua-style-iframe-manual.html": [ + "5264e24899d4cf72c54edd39d47715beebebe355", + "manual" + ], "fullscreen/trusted-click.js": [ "e401e8e8bcd97446991398d6021a9bd712c923c5", "support" @@ -529496,8 +536044,12 @@ "99bcfb42c91e084a3b847ab4bab2bad80e548540", "testharness" ], + "generic-sensor/generic-sensor-feature-policy-test.sub.js": [ + "c7c9c4d1c578f267cbb4241d7ea7a981be6f49ee", + "support" + ], "generic-sensor/generic-sensor-tests.js": [ - "09c6bf8a8fe005d467b522d5daf254c34c60b925", + "2209b4cc293aefecded2d325b664d494820d38af", "support" ], "generic-sensor/idlharness.https.html": [ @@ -529564,14 +536116,90 @@ "ca3036737a662e8673477b1a09b6fce89f0f98f4", "testharness" ], + "geolocation-sensor/GeolocationSensor-disabled-by-feature-policy.https.html": [ + "ae1bdcf06fbf8dc8189950593b83bdd749e37880", + "testharness" + ], + "geolocation-sensor/GeolocationSensor-disabled-by-feature-policy.https.html.headers": [ + "0c75673594dd70e5f27fdc7f56a7ca1bb2d3f7ec", + "support" + ], + "geolocation-sensor/GeolocationSensor-enabled-by-feature-policy-attribute-redirect-on-load.https.html": [ + "6b0ea48ea2fb1cb6b81348bf5e28618716a34166", + "testharness" + ], + "geolocation-sensor/GeolocationSensor-enabled-by-feature-policy-attribute.https.html": [ + "f1b108ddd2f5b1ea915410f4cdb28c2e1a812cf9", + "testharness" + ], + "geolocation-sensor/GeolocationSensor-enabled-by-feature-policy.https.html": [ + "35fea3e77f992df2861bea97405e9c75f7a1f994", + "testharness" + ], + "geolocation-sensor/GeolocationSensor-enabled-by-feature-policy.https.html.headers": [ + "6e06db043adf50307b8fa209a7008fdb7d290921", + "support" + ], + "geolocation-sensor/GeolocationSensor-enabled-on-self-origin-by-feature-policy.https.html": [ + "a9da2c50d4bde9eb24ef343979afcbc6547684e2", + "testharness" + ], + "geolocation-sensor/GeolocationSensor-enabled-on-self-origin-by-feature-policy.https.html.headers": [ + "1c523e7cd5741e4a515119b129b041b11cbc92cc", + "support" + ], + "geolocation-sensor/GeolocationSensor.https.html": [ + "c9d32faca641ec784acf9096a079d73781330216", + "testharness" + ], + "geolocation-sensor/GeolocationSensor_insecure_context.html": [ + "58fd65d3a72e6734392381fe225e3fbd7007fc06", + "testharness" + ], + "geolocation-sensor/GeolocationSensor_onerror-manual.https.html": [ + "2b7aac7d60271e12ce71f6293405ffafb471c8c8", + "manual" + ], "geolocation-sensor/OWNERS": [ - "8a972af50fbb0a8cc4688385174a28e5d7a29734", + "fabf35173a8bd10c7e5ffe348dd92532199ab51a", "support" ], "geolocation-sensor/idlharness.https.html": [ - "2f7f2b6879eab3add1ea962b02eb264ebb3f0154", + "ea9edf12752af0a97cd9fe825ae927bd07090a56", "testharness" ], + "gyroscope/Gyroscope-disabled-by-feature-policy.https.html": [ + "03457271ec8c254bf74f89afa7532a595b837404", + "testharness" + ], + "gyroscope/Gyroscope-disabled-by-feature-policy.https.html.headers": [ + "b4767ccc5e319ec08705af56990c8d8093640ff0", + "support" + ], + "gyroscope/Gyroscope-enabled-by-feature-policy-attribute-redirect-on-load.https.html": [ + "68df44bc71f1aaba74188f70dc916e9ee1dcc330", + "testharness" + ], + "gyroscope/Gyroscope-enabled-by-feature-policy-attribute.https.html": [ + "e7c53323038c11a977e547ebe9d7ae94646f1a06", + "testharness" + ], + "gyroscope/Gyroscope-enabled-by-feature-policy.https.html": [ + "e4e170946a0289e8b1b6be83083aeeb92ddc4a8f", + "testharness" + ], + "gyroscope/Gyroscope-enabled-by-feature-policy.https.html.headers": [ + "b0ce79c08e8b5908485a8bb4c6d86e8d20b2a44c", + "support" + ], + "gyroscope/Gyroscope-enabled-on-self-origin-by-feature-policy.https.html": [ + "f48401e0e04294624ebb864224a6d2126e849870", + "testharness" + ], + "gyroscope/Gyroscope-enabled-on-self-origin-by-feature-policy.https.html.headers": [ + "59acbd3ef447d2197c4a9af2837dbacdf1e31885", + "support" + ], "gyroscope/Gyroscope.https.html": [ "504abfa42529e08576e49c3296464bcea5fe0b8a", "testharness" @@ -529601,13 +536229,17 @@ "testharness" ], "hr-time/idlharness.html": [ - "337a75247a6b53a7649c7fdf41c2dcdcf093ac11", + "f2cdcba041df089206cc9c811167c41a771905df", "testharness" ], "hr-time/monotonic-clock.any.js": [ "4aef47650d5cbc750393c3ac9423dbff24a15917", "testharness" ], + "hr-time/performance-tojson.html": [ + "2d45889944dab7b0489a03a649a70e1177bca428", + "testharness" + ], "hr-time/resources/now_frame.html": [ "031edb78f5ab21f51005fdb30a99a605669254ce", "support" @@ -529921,7 +536553,7 @@ "testharness" ], "html/browsers/browsing-the-web/history-traversal/PopStateEvent.html": [ - "5a9c575a86adbbbca30734992b4d80c22f3973a1", + "f150a04f6eaed460e3f979c879683ef4ff44e02c", "testharness" ], "html/browsers/browsing-the-web/history-traversal/browsing_context_name-0.html": [ @@ -529973,7 +536605,7 @@ "testharness" ], "html/browsers/browsing-the-web/history-traversal/hashchange_event.html": [ - "c337192292ab48083ede981bcfad4a15c5eb7478", + "4471d424840818a9e3bc5507680a20a6707530b9", "testharness" ], "html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/resources/blank1.html": [ @@ -530001,7 +536633,7 @@ "testharness" ], "html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/scroll-restoration-fragment-scrolling-cross-origin.html": [ - "0f8425ba4fcdd12e357ec975c6439c89c72c1c3e", + "a94f2df91002c5cf36e6a4607c2f95e3ba130c30", "testharness" ], "html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/scroll-restoration-fragment-scrolling-samedoc.html": [ @@ -530329,7 +536961,7 @@ "testharness" ], "html/browsers/browsing-the-web/read-media/pageload-video.html": [ - "2d8749e1d5f585ba60ce0a20367d116d126df475", + "2ae6e21db438a657afd934bb8fb8a21de5f5f2cf", "testharness" ], "html/browsers/browsing-the-web/read-multipart-x-mixed-replace/.gitkeep": [ @@ -531381,7 +538013,7 @@ "support" ], "html/browsers/history/the-session-history-of-browsing-contexts/navigation-in-onload.tentative.html": [ - "63421792e4f1f654149d48775b1f2574398bba1a", + "fbb1c40a56f513dd66084f780eb650664188ec4f", "testharness" ], "html/browsers/history/the-session-history-of-browsing-contexts/navigation-in-onload_form-submission-1.tentative.html": [ @@ -531389,7 +538021,7 @@ "support" ], "html/browsers/history/the-session-history-of-browsing-contexts/navigation-in-onload_form-submission-2.tentative.html": [ - "e45de51132ab221732295759e9f704466fd22557", + "35a8b04947b420a51e31fbc74ab0d6cd058a443a", "support" ], "html/browsers/history/the-session-history-of-browsing-contexts/navigation-in-onload_form-submission-dynamic-iframe.tentative.html": [ @@ -531704,6 +538336,10 @@ "ba143e41121916fba5522d5e1dca29d04ab5f4ce", "support" ], + "html/browsers/sandboxing/noscript-iframe.html": [ + "cfa4043bfda350a0906cd94f3c9c9a3578e72575", + "support" + ], "html/browsers/sandboxing/sandbox-allow-same-origin.html": [ "3aa5996022d6ca80f085981190811efc490aa2e0", "testharness" @@ -531720,6 +538356,14 @@ "bbb480a9ca5139877fbab165f9356b2a67305a9c", "testharness" ], + "html/browsers/sandboxing/sandbox-parse-noscript-ref.html": [ + "4f185501effadf33e7d90e4c3990ec06ee936b43", + "support" + ], + "html/browsers/sandboxing/sandbox-parse-noscript.html": [ + "b6345b32377ff05bc7e5261b2fc14e8c875b2245", + "reftest" + ], "html/browsers/the-window-object/.gitkeep": [ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" @@ -532305,7 +538949,7 @@ "testharness" ], "html/browsers/windows/browsing-context.html": [ - "ad718fb943e000ad5d2f376ea5ac8a011661ab37", + "8fe21ad8cdacd39594f6d01880689d1c94c617b2", "testharness" ], "html/browsers/windows/groupings-of-browsing-contexts/.gitkeep": [ @@ -533209,11 +539853,11 @@ "testharness" ], "html/dom/elements-embedded.js": [ - "2c20b7d2856d8f7f72b7835b2677ed47abc43629", + "99489e3a8ac2be0d7dcfb22f7f45c30b00511358", "support" ], "html/dom/elements-forms.js": [ - "ed722f36a003a8407c1c4a13f8c75880c4fa9c11", + "062e50a0665b90c3b77aaca744b65036054569f5", "support" ], "html/dom/elements-grouping.js": [ @@ -533221,11 +539865,11 @@ "support" ], "html/dom/elements-metadata.js": [ - "f7d5c16c0e69c67a1b49b7a4ed28c14e4f3cf469", + "4fac3184d50253baecd987ded8b1bb86d82967d9", "support" ], "html/dom/elements-misc.js": [ - "42b4ea21148dd17c442932ba8cb5e6e49db81a93", + "700331e76eb4de08018ef2939c750567e6a1ead5", "support" ], "html/dom/elements-obsolete.js": [ @@ -534101,7 +540745,7 @@ "testharness" ], "html/dom/reflection.js": [ - "4d841fe21eb604a563fc4d864e7db13c43de4621", + "b26e0872e1b4d6e8aba7d18e2740eb6c5ecf311c", "support" ], "html/dom/resources/self-origin-subframe.html": [ @@ -534116,6 +540760,10 @@ "482b716c4e76fd71e99720e3b82658a5db010a5a", "testharness" ], + "html/dom/usvstring-reflection.html": [ + "f12c4ee1c2b07b2cc559b672436450c349ef8498", + "testharness" + ], "html/editing/.gitkeep": [ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" @@ -538200,6 +544848,26 @@ "175e662819cfcc1f528fd8c0e3ed149eeba02e70", "reftest" ], + "html/form-elements/the-textarea-element/multiline-placeholder-cr.html": [ + "e8f7683568ad37b625fb32d97e80f4e15a9b6f66", + "reftest" + ], + "html/form-elements/the-textarea-element/multiline-placeholder-crlf.html": [ + "e0fbe39e2376e17611ec89f6f9a1b79b912cfe1a", + "reftest" + ], + "html/form-elements/the-textarea-element/multiline-placeholder-ref.html": [ + "69fe9939aea706500232485a2e105ae67fca6783", + "support" + ], + "html/form-elements/the-textarea-element/multiline-placeholder.html": [ + "3372eef00fd32ced307dbfa63f4b5c9cc6363f94", + "reftest" + ], + "html/form-elements/the-textarea-element/support/placeholder.css": [ + "3b200a40e2b7ba13f060772e821328db1de82cd0", + "support" + ], "html/iana/.gitkeep": [ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" @@ -538728,6 +545396,22 @@ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" ], + "html/input/the-placeholder-attribute/multiline-cr.html": [ + "687054d9b221998ff4c4071ccc0733faeeb129b7", + "reftest" + ], + "html/input/the-placeholder-attribute/multiline-crlf.html": [ + "f953c175dce74670a915534fb513feb960fb5152", + "reftest" + ], + "html/input/the-placeholder-attribute/multiline-ref.html": [ + "e497f7bbe3359c11265619a439dc97756131e827", + "support" + ], + "html/input/the-placeholder-attribute/multiline.html": [ + "bc7c64db1dfdb3084a7c3606005a41fd71a20a9b", + "reftest" + ], "html/introduction/.gitkeep": [ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" @@ -540348,6 +547032,10 @@ "03c507419d6aca82952aeaf21bb6ab732cb379ff", "testharness" ], + "html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLMediaElement/crossOrigin.html": [ + "17313a24fb209ad5a79910f92fb295357b07eed3", + "testharness" + ], "html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLMediaElement/textTracks.html": [ "88948beef7ec893585ada062daeafad4554afa92", "testharness" @@ -540365,7 +547053,7 @@ "testharness" ], "html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLTrackElement/readyState.html": [ - "4ec33f119348303282ffe7c7e2b5538b2b63db87", + "1b18c4e70f84197083ab79c2868ec750d4d72168", "testharness" ], "html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLTrackElement/src.html": [ @@ -540420,6 +547108,10 @@ "d539c5792d2c2816b5953d6aa76c78a33f2eb89c", "testharness" ], + "html/semantics/embedded-content/media-elements/interfaces/TextTrackCue/constructor.html": [ + "21807b992193648f9d9ae3619b437521f9ea5bfc", + "testharness" + ], "html/semantics/embedded-content/media-elements/interfaces/TextTrackCue/endTime.html": [ "e713191a3603ca8ecfabe1afeb69ee0dd0dd2959", "testharness" @@ -540976,6 +547668,246 @@ "ac9c4dbaad4c8740e384629696ac4ae16a560b00", "support" ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/align-positioning-bad.vtt": [ + "b2662fae4fd302fa2e5ad7ff8a6431ac93ae6629", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/align-positioning.vtt": [ + "8128961a5a57e9eff6d09fdb7a89dab39141d301", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/align-text-line-position-bad.vtt": [ + "5c5d32740e44043d7f8f2a384223840fe132c6f9", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/align-text-line-position.vtt": [ + "3a3d06cf92020726080c5980eb23007c5033e137", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/alignment-bad.vtt": [ + "8e595d046661094c5bee5b62ee2d4ccce9c3db37", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/alignment-ltr.vtt": [ + "28a410f7cee1329cfa19acb71a4a86a393b54234", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/alignment.vtt": [ + "18c8baeed94a38eb9310db3bbfbf8cff5d59cd14", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/bom.vtt": [ + "2278f4ae0dd2697d522e725241e1a1357017bb6d", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/captions-fast.vtt": [ + "68ae570e941a5b8993c163a84aca0f758d65ab01", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/captions-gaps.vtt": [ + "fa81809c654054d8f9d4e942782e7a4bc2826ed9", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/captions-html.vtt": [ + "fd0df8d0f2800bd9097fe7a293a12c47ed1ad3bd", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/captions.vtt": [ + "14d8e68a891fa652c44711158c1f4fe652c841b1", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/class-bad.vtt": [ + "48b56cffac57d58ed363c6de43123cf46b9a61c4", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/class.vtt": [ + "e3ebad0f6068acc7fd11a5969c1753c4ef86c1b9", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cue-id-error.vtt": [ + "e1e8e96b61a5ef48aec96a6c605929f39300e9d9", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cue-id.vtt": [ + "f67139c3fea2a888cd10500ee4ac1d3882d5df01", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cue-no-id-error.vtt": [ + "4353f327dbfcfec5bcf99aaad28fde328b0c34a8", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cue-no-id.vtt": [ + "6954c71972bfbdab36c94c44190cc2259971adb0", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cue-recovery-cuetext.vtt": [ + "befc0d2b1bfb79cd79c2b09af9d35f1db02e59ff", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cue-recovery-header.vtt": [ + "8ba9c1290b73e11a46b983c10848d14c82a70062", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cue-recovery-note.vtt": [ + "842da18a789e67bd1dd78c3389581552e0e23c68", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cue-size-align-bad.vtt": [ + "a1bf60ed37f7bce2e3a5bec919664633780e60ed", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cue-size-align.vtt": [ + "0da4144c1b7ac7c363a5ff3c27708480fe6c560c", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cue-size-bad.vtt": [ + "c665e6044bdcc16956fabb78720a2c59028d9e2a", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cue-size.vtt": [ + "fee519ec5f5afc13be7c7f5a4387e746135c3747", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cues-no-separation.vtt": [ + "251de0c5026da00c2b18469ee99924cf70ad1b4e", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cues-overlapping.vtt": [ + "8966b84320ad89eb883946392dd2a6bc3d12711d", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/cues.vtt": [ + "4fc146831b7c10f721b77a4bdec99953aa40454b", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/default-styles.vtt": [ + "db041f1a659ab39530144bb68e0ab76d14ca9b90", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/degenerate-cues.vtt": [ + "01c28a312767c6ca41751a58b227dc80bbff54dc", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/empty-cue.vtt": [ + "65fdbcdc5a88cc9208cfd5b0bf2e1396b23432a7", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/entities-wrong.vtt": [ + "9941f3c18ac34d852ab7f882c06d10a874453c14", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/entities.vtt": [ + "5913b038e7d6341b19c21d0bb81008057656d929", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/interspersed-non-cue.vtt": [ + "bfe46bfea8af95d5dc54324ac9e202eb9e5e0b2b", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/iso2022jp3.vtt": [ + "e929f8e1755f72ecae96dd40430bc07c5a4a433c", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/large-timestamp.vtt": [ + "0b8a4e4d4d5fdbf5a873e5ecc134469393bf3b7c", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/line-position-bad.vtt": [ + "d75633c173c91a1f8a6a0fe1d173165ae92905f1", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/line-position.vtt": [ + "eb83dd089934f5e72039eebd57ed17f775408377", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/markup-bad.vtt": [ + "7caf06d65f3e6c9ba305b4a2b162efbeb68b7a86", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/markup.vtt": [ + "25514f3b659150b7536890cf5bbaff19c57437fe", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/metadata-area.vtt": [ + "778ac955bd2e01b8c6c8fdf540c99f4513390f5e", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/metadata.vtt": [ + "ea18a5275465fd2eaf68f066f085551c3035ccaa", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/missed-cues.vtt": [ + "28c9acd7f24cc07d15c0685bdef1d435ffbbc89a", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/no-newline-at-eof.vtt": [ + "9cc9424c093198fedb44a2361f704ce299288f71", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/no-timings.vtt": [ + "63bb8c56d7e75cc84b4e6b06b476fb4d9b395316", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/no-webvtt.vtt": [ + "9d5d51eddc30891a0b25a628fffad6bc19d720de", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/positioning-bad.vtt": [ + "59571852499c3cf14cddc874d1344754e3bb007f", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/positioning-ltr.vtt": [ + "9fe212e89eb20c152574de81823b7fdf01900b2d", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/positioning.vtt": [ + "91f3c4375e6fe9f4968e9059ecec21c4743cf483", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/settings-bad-separation.vtt": [ + "0733d08db0cf06caac571b388a811899f79252d4", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/settings.vtt": [ + "af042c5468830fbdcd9b9c7cbc32eb0c6d660311", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/simple-captions.vtt": [ + "fa3e12c456c77d1327b90b1a8f32416245268e7a", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/sorted-dispatch.vtt": [ + "6555a536c404112c6057458edfad26d398f95d19", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/timestamp-bad.vtt": [ + "6852fb1bfcddce00b4acba93716d7358957a74e5", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/timestamp.vtt": [ + "ed03dac0cac2e0b79c8b98e1e460b24fb7b2daeb", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/timings-hour-error.vtt": [ + "e2cf1290a06473ac1592e8da4d8261d392f14606", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/timings-hour.vtt": [ + "a846d7e878ab08d111e4d68dd67b02d210db0273", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/timings-no-hour-errors.vtt": [ + "4c80839a264bc93e3787211790e6062f35ad1f22", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/timings-no-hour.vtt": [ + "09948fb59cd9e1702ba869f0b444ca36d1ec0bf2", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/timings-whitespace.vtt": [ + "2d9b2479193680a334da8001254f17105b7a13aa", + "support" + ], "html/semantics/embedded-content/media-elements/track/track-element/resources/track.de.vtt": [ "f83f36449d6a7e9db28bba9e39dc7a4bf7458927", "support" @@ -540992,22 +547924,310 @@ "329c3f585e5e89dfc1f44fde85a1d9601e61aef2", "support" ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/unsupported-markup.vtt": [ + "e6f5fddd1ff13f6e9f81931af691a0ad1c9a55a9", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/utf8.vtt": [ + "b15aef44ae1726c362448bc561899c7dc554a767", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/valign-bad.vtt": [ + "3517a6189833600e6db45a8c7fed79d38859b1c1", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/valign-ltr.vtt": [ + "2c1f48f5098da305b6fe6c362a94c4a2a5e13c38", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/valign.vtt": [ + "357f4306f5b5c83b712d0a0bbb098827c3802196", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/voice-bad.vtt": [ + "f80e328090068ef96781468e107de3afe947d840", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/voice.vtt": [ + "61997c207efb09802c9022fcea544f4196094df6", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/vp8-vorbis-webvtt.webm": [ + "aae8ea4cf4b4fa88b0e88094f2e64c63df4bceb9", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/webvtt-file.vtt": [ + "943c4ca7d7ba197815ad5732222558e30195b022", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/resources/webvtt-rubbish.vtt": [ + "e0522c50ed645cbc7d483d5c410ae5d925ef4b47", + "support" + ], "html/semantics/embedded-content/media-elements/track/track-element/src-clear-cues.html": [ "9e5b2fa642544c20e04d542d9a8f701d1fa2d165", "testharness" ], + "html/semantics/embedded-content/media-elements/track/track-element/track-active-cues.html": [ + "ee900652dced5cb21fde825760c7ee3450ffba00", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-add-remove-cue.html": [ + "74ce8542b9041d77633c59484916186ced0f065f", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-add-track.html": [ + "ba19b96decf95cb69fe8da86ace3b6c757edc269", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-addtrack-kind.html": [ + "a760d3d1b73313db91a6551bdf0061cf0729186d", + "testharness" + ], "html/semantics/embedded-content/media-elements/track/track-element/track-api-texttracks.html": [ "f7576ff332cac04a4e2b663b6fdd40aef154b6b5", "testharness" ], + "html/semantics/embedded-content/media-elements/track/track-element/track-cue-empty.html": [ + "8836253fa3f97ff0b8b4c7af2078f667d2bd0738", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-cue-inline.html": [ + "1af5ab84eeec88145bccec3adc829c41a27aa647", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-cue-mutable-fragment.html": [ + "08de3e2e541f95a91f984d90d4a078d45cb057c4", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-cue-mutable.html": [ + "c8ab03c7d84d150befa8152e552d99e889ce4ec0", + "testharness" + ], "html/semantics/embedded-content/media-elements/track/track-element/track-cue-order.html": [ "eeab6b02e728aea21878cf72664929766be057b7", "testharness" ], + "html/semantics/embedded-content/media-elements/track/track-element/track-cues-missed.html": [ + "a87ad9da0dad43e1b68183feeabce59a5c864087", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-cues-pause-on-exit.html": [ + "ec7abb777a4ae9276bd047e66c3c3560e881ed38", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-cues-seeking.html": [ + "8efe764fcdcfa0568b7566e1855f115282dc9800", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-cues-sorted-before-dispatch.html": [ + "314f2768b879dfd1496992d7cb13c724331cf609", + "testharness" + ], "html/semantics/embedded-content/media-elements/track/track-element/track-data-url.html": [ "e9c8849350512b1247543939ee0e529947e47c2d", "testharness" ], + "html/semantics/embedded-content/media-elements/track/track-element/track-disabled-addcue.html": [ + "50932e2a3ce52440fa5e3af935f11120267bc4dd", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-disabled.html": [ + "7e62481158e3d571c7180b5c80376336ff77615a", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-element-dom-change.html": [ + "04ade2498b9ea6d3f576e47867a5ac6c91c3e424", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-element-src-change-error.html": [ + "f8b49876351834df6f98b73d79039ec45a9940d1", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-element-src-change.html": [ + "b6d8d45a74cb90c0a4a63ca169867982ac235b15", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-helpers.js": [ + "b84cd1d9f96ee9b00cef2bd219e6da5b1ba1df8b", + "support" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-large-timestamp.html": [ + "fd1683cc93142f971a2b0c37321adf2e9911a4b8", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-load-error-readyState.html": [ + "6736b48cb3b591479c9589e50261290541177c51", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-load-from-element-readyState.html": [ + "82ae61caf89327293f566acc794f9c193aec122f", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-load-from-src-readyState.html": [ + "a4a3afae537fca943d343add9780ae3eb1f160bc", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-mode-disabled.html": [ + "e79126149eb97f0975a32fdaec6225d4c6c74957", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-mode-not-changed-by-new-track.html": [ + "2a494b59e2ec82dc881b913aaae4e773f47afb22", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-mode-triggers-loading.html": [ + "82b09068a101ec059a383a6b656eb85788e90fa3", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-mode.html": [ + "0fd7a0385671be222873aac3b1ebd4f21f4000ae", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-remove-active-cue.html": [ + "dd3ab2e0e4f4ac3b4f83e5dfd539dd9c3aa5c961", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-remove-by-setting-innerHTML.html": [ + "9ab3f009fe7464e26df571ec8e66dde7205fa0db", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-remove-insert-ready-state.html": [ + "9d6735eaf36145ceeefec0630f30be49ff37d676", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-remove-quickly.html": [ + "e955322b149ecb74471bc972a4662972fa287516", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-remove-track.html": [ + "931cfc4d06107dfccb001fbeaeef987cca528747", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-align-positioning.html": [ + "9283a8233cfc10c0c1745815b3f6bd970ffdde2a", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-align-text-line-position.html": [ + "5985538ecba666dd2bcf1287e60f267c83d64a6e", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-alignment.html": [ + "fa581025c7ca552f23441869eb76bffcf1cd7f7a", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-blank-lines.html": [ + "2266bc2a923ceb56a90abd034087efe24a958c3b", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-bom.html": [ + "26343f09d663d1558881507f89eecc606304b41f", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-class-markup.html": [ + "8876395c46181acafb7712b1fcdff7cae28c0b18", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-identifiers.html": [ + "d21e8cd62cc5a7bf9275b2f46282cd3f73714c21", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-no-id.html": [ + "f12b9b7384f445b817f1d049d7bff05ec0f2d3d9", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-recovery.html": [ + "ba273b161cbdd6cfeec6be75f08bb510a13bf9e1", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-size-align.html": [ + "519039bd4e00da6802f03f9a9695b96019ef6df0", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-size.html": [ + "5f91fd3c078343aee9ee72c1b60bf8a8f82682e2", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-degenerate-cues.html": [ + "bcc7f1b103a7d0896ba19a84de6b41f4758a8837", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-empty-cue.html": [ + "d8b948ecac4da42f43896cda9902718130a5a0e6", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-entities.html": [ + "b995f43c4dfef791a95bc0dfcd30721e955fce85", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-header-comment.html": [ + "3e83c514cb2d18b2238f03e3d85a21f69a60d5c0", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-interspersed-non-cue.html": [ + "ee7e65642ed06f89c2413278fad652dcfb78d740", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-line-position.html": [ + "410feb59cf264571fb347bbfcb1f14150bbaea8f", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-magic-header.html": [ + "ef8442f73c4aae5728a8790d6a7dbc075bb09a25", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-markup.html": [ + "6d8f7b9e8e3cb87581844b5dd61e46cc508b616c", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-newlines.html": [ + "24d79495469c698e1e0296b503e44a3ee6b5db34", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-no-timings.html": [ + "baa44683fe0d00e691f536309a7772347301d57a", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-positioning.html": [ + "852584f301e1ab52359e3344120149d65a35d5f7", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-settings.html": [ + "25f3286199d565d58b3e4545a5f3cbb212541a34", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-timestamp.html": [ + "d18cd2431e189249d1210ba5ef87c081f3d355ee", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-timings-hour.html": [ + "b52de7d267cce4c480353c188173c6bbc5e3e70e", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-timings-no-hours.html": [ + "ebae3e9d5dc11b91b53439ee4871df86c3a80822", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-timings-whitespace.html": [ + "c42b3e45318e167bf00edf77528d56e2d107d5e8", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-unsupported-markup.html": [ + "c43ab0c10e1de3af01f6137c044c73cfcbc6d339", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-utf8.html": [ + "65241920becf512c35f78b335de90c00af03195d", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-valign.html": [ + "4f6e049d97dc81065df13e66e40cf945ff0914dd", + "testharness" + ], + "html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-voice.html": [ + "c016678eb1f14aad834d4e6e3bbca1818760284a", + "testharness" + ], "html/semantics/embedded-content/media-elements/user-interface/muted.html": [ "74deefbbc4b8f96ff4856db1c32c6428183cc040", "testharness" @@ -541069,7 +548289,7 @@ "testharness" ], "html/semantics/embedded-content/the-area-element/area-download-click.html": [ - "b3172223ac173b65870f5d061cc8600a67956e10", + "693a6830b022c9b57a6bc06259f2312d049a22e7", "testharness" ], "html/semantics/embedded-content/the-area-element/area-processing.html": [ @@ -541084,6 +548304,10 @@ "25afa430800ce1439fddd06920a64353c8559764", "testharness" ], + "html/semantics/embedded-content/the-area-element/resources/area-download-click.html": [ + "4dee38d117f36f1e22648fa74f02fe87488aa31b", + "support" + ], "html/semantics/embedded-content/the-area-element/support/hit-test.js": [ "d6128e676d8584222248b03ae2e868136377d799", "support" @@ -542881,7 +550105,7 @@ "testharness" ], "html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange.html": [ - "a3f85905acb42372806d07259e09d75e2fd8db1f", + "4ca73ff5658b3512784e9e1b236c78861ca4ecc9", "testharness" ], "html/semantics/forms/the-button-element/.gitkeep": [ @@ -543413,7 +550637,7 @@ "testharness" ], "html/semantics/forms/the-progress-element/progress.html": [ - "ae4f3f8d86b720ba8f6c1fe7443cc425519de5da", + "786e7998c0a1e10ba76b26a87d45ea9c3c9893b4", "testharness" ], "html/semantics/forms/the-progress-element/progress.window.js": [ @@ -543436,6 +550660,10 @@ "b5a01e973e4d4c97c6fa06bd9fd1e535e8c622e8", "testharness" ], + "html/semantics/forms/the-select-element/select-add.html": [ + "1ce71758263439d50dbabb5f1e78fafa6c7ba35b", + "testharness" + ], "html/semantics/forms/the-select-element/select-ask-for-reset.html": [ "e9689464e9ffa86ac5cd9364a4e8fb9ed6af065e", "testharness" @@ -543465,7 +550693,7 @@ "testharness" ], "html/semantics/forms/the-select-element/selected-index.html": [ - "0753a7487a10bde3b879d4c2ed10ba3d0260a48a", + "3dbf338e9065f7f4ad2abfbaa55cf50329768cc2", "testharness" ], "html/semantics/forms/the-textarea-element/.gitkeep": [ @@ -543836,6 +551064,10 @@ "8fe77deb43d14d0a6b306dc903d56dcda1e80d50", "testharness" ], + "html/semantics/interactive-elements/the-dialog-element/abspos-dialog-layout.html": [ + "898d5888cea62972b9810606595949cac792ce0d", + "testharness" + ], "html/semantics/interactive-elements/the-dialog-element/centering-iframe.sub.html": [ "eb00778210365e13b33e194da1b9e870d7e39153", "support" @@ -543872,10 +551104,22 @@ "1b77c8ff31c1a38afb3a9fa9bf77bf85ac4a264b", "testharness" ], + "html/semantics/interactive-elements/the-dialog-element/dialog-scrolled-viewport.html": [ + "529cf6c2cf2daf031f7d41aef93e6f5645e30ec2", + "testharness" + ], "html/semantics/interactive-elements/the-dialog-element/dialog-showModal.html": [ "c00ac5b6d038b45b1a7cfbef94a4527757fa74e6", "testharness" ], + "html/semantics/interactive-elements/the-dialog-element/inert-does-not-match-disabled-selector.html": [ + "f0187a4040dbbd430b6945947475c152f1eeed7b", + "testharness" + ], + "html/semantics/interactive-elements/the-dialog-element/inert-node-is-unfocusable.html": [ + "93879f898f01060ffd6c6d67543f4cc5b7de6ac0", + "testharness" + ], "html/semantics/interactive-elements/the-dialog-element/resources/common.js": [ "15580f3e0243093710d4914224ca3963992e3f5b", "support" @@ -544056,6 +551300,10 @@ "1fe7fe27c3680b24fbbb9c09c849ecb007637d3f", "testharness" ], + "html/semantics/scripting-1/the-script-element/defer.js": [ + "a3a0ec93c287c9925d8da6303ae99af3953f81b8", + "support" + ], "html/semantics/scripting-1/the-script-element/execution-timing/001.html": [ "d23ee4e0c5c00c5d7d4391ebb346536706667759", "testharness" @@ -544800,6 +552048,42 @@ "364c6d3b48ef8143d62d6f6bb02aa5554b0bd367", "testharness" ], + "html/semantics/scripting-1/the-script-element/module/choice-of-error-1.html": [ + "b7c603ed3b3acdcb45f4274f5c7a85d13f251994", + "testharness" + ], + "html/semantics/scripting-1/the-script-element/module/choice-of-error-1a.js": [ + "addc3cbacaa9a439d8cd082677ce3df8a3e1e861", + "support" + ], + "html/semantics/scripting-1/the-script-element/module/choice-of-error-1b.js": [ + "cf2e69b160a03622816b7e9ed8b3396a10cd3756", + "support" + ], + "html/semantics/scripting-1/the-script-element/module/choice-of-error-2.html": [ + "9e4650e461e3436316233e769a0cde49179e46fe", + "testharness" + ], + "html/semantics/scripting-1/the-script-element/module/choice-of-error-2a.js": [ + "849aec6ec6b5a556c991c95e8715b9112022d5fd", + "support" + ], + "html/semantics/scripting-1/the-script-element/module/choice-of-error-2b.js": [ + "6e5ed4042eeb4bc49c9c6f339cec73acbd5eda44", + "support" + ], + "html/semantics/scripting-1/the-script-element/module/choice-of-error-3.html": [ + "65dc20f79e348097cec23b814d2b2f918214647b", + "testharness" + ], + "html/semantics/scripting-1/the-script-element/module/choice-of-error-3a.js": [ + "5a6fa0aa0d9836150cd0c49c6c52c66844974033", + "support" + ], + "html/semantics/scripting-1/the-script-element/module/choice-of-error-3b.js": [ + "55f3f75425cd6277852f89148285a618fba542f6", + "support" + ], "html/semantics/scripting-1/the-script-element/module/compilation-error-1.html": [ "e36eda2e9941e0cfefbfd867d36da6de4dfe7b2e", "testharness" @@ -544889,7 +552173,7 @@ "testharness" ], "html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html": [ - "24f8c20c79cdaa6d81e9447e4f616ec5626d36ca", + "9d59895901b04cbef1b7263da1b974336bfa524f", "testharness" ], "html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports.html": [ @@ -544920,26 +552204,94 @@ "997859fce8ed8854053d089a78ab999b3f88a072", "testharness" ], - "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-classic.html": [ - "c5e3bf053403a49ee72c7464b1c1d0758f0fc8be", + "html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/Function.js": [ + "be1ecd94299f35bb000eb5e9df53e9c057231982", + "support" + ], + "html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/eval.js": [ + "686728d887fbb65f9b5c7498edf1a1dfc6611ebd", + "support" + ], + "html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/inline-event-handlers-UA-code.js": [ + "b2f41c32fc88183500ab3069a51894d62873dd7b", + "support" + ], + "html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/reflected-inline-event-handlers.js": [ + "15125c9e98e59d191acee4dcadece1b2986d7ec1", + "support" + ], + "html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/setTimeout.js": [ + "03ee5763c6e62da7d49e058edb58292f4f496a3f", + "support" + ], + "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-classic.html": [ + "70f97beb38cf958bd2234e3b580712c8436b8095", "testharness" ], - "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-module.html": [ - "a33d3b405b1a826f51dadb18431c855b13aee612", + "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-module.html": [ + "7386a90307c33bdaad34002c865b4ad8793c10a2", + "testharness" + ], + "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-classic.html": [ + "928c333bf9c50213175095ceb06f1afdd690bd8a", + "testharness" + ], + "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-module.html": [ + "1daf837d2d9ee258dfc5c9648b1a0f5b0b6e93e4", "testharness" ], "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-classic.html": [ "e22e6f200162000f043d114c89def6667097d13d", "testharness" ], + "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-classic.html": [ + "0295db34d953b716151726188ac467a948f0d955", + "testharness" + ], + "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-module.html": [ + "cfc2375f7a8abe67eae4213b2f0c5224ba25337d", + "testharness" + ], "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-module.html": [ "b332499d43e0768b5ddf1d5dbb5cd8ca702c3c64", "testharness" ], + "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-classic.html": [ + "20a6c6de42fe72fe375ccd8c9c8763191afa78f9", + "testharness" + ], + "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-module.html": [ + "93f2cc8f3e88e0cbf508acd64f9a28bdcaff25b0", + "testharness" + ], "html/semantics/scripting-1/the-script-element/module/error-and-slow-dependency.html": [ "32455a1418d94fa68368bae3b1c0291204f6b4e3", "testharness" ], + "html/semantics/scripting-1/the-script-element/module/error-type-1.html": [ + "f376310fd56bf105c9c9cbe822a706e60faf4284", + "testharness" + ], + "html/semantics/scripting-1/the-script-element/module/error-type-1.js": [ + "917c96082ae3686c6409004ecafeba24bab9603a", + "support" + ], + "html/semantics/scripting-1/the-script-element/module/error-type-2.html": [ + "80bd1639df6d35b3e5eeeec009e1eb85000f0037", + "testharness" + ], + "html/semantics/scripting-1/the-script-element/module/error-type-2.js": [ + "6f2248a9d0bfd63251c838df4c92e7174a55605d", + "support" + ], + "html/semantics/scripting-1/the-script-element/module/error-type-3.html": [ + "f71b506e6a9bf1b9bf1cb8db518a590f7e7c90ed", + "testharness" + ], + "html/semantics/scripting-1/the-script-element/module/error-type-3.js": [ + "3c76f2c8466a6fb5cc307c0fc03e5d759e4c99c1", + "support" + ], "html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-common.js": [ "ff9af4e5253db096cd5de8d2e7ed74cd05ed2561", "support" @@ -545117,7 +552469,7 @@ "testharness" ], "html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html": [ - "2b4fa3b558dccb50bf0aee12a78e3320501ea1b5", + "b48335aa61dc13c34d2a77806f20663e2156bc6f", "testharness" ], "html/semantics/scripting-1/the-script-element/module/instantiation-error-1.js": [ @@ -545125,15 +552477,15 @@ "support" ], "html/semantics/scripting-1/the-script-element/module/instantiation-error-2.html": [ - "70271ef6fbf9f6e4f6e61438691b6fce317137e9", + "e2c860b1b348148fc6b9d77f918894b1bac42c94", "testharness" ], "html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html": [ - "80fa90a214bb4839703c36f9db36e07f3a2ca7f2", + "996d1aa45c5975e13ac0f1e9c9249b3d452ed2e2", "testharness" ], "html/semantics/scripting-1/the-script-element/module/instantiation-error-4.html": [ - "dbb8eb640576cd4f658e32dec441919e943f8d21", + "224fe5510f09c3dd6d58f9dcf61b4d6fca04c96c", "testharness" ], "html/semantics/scripting-1/the-script-element/module/instantiation-error-4a.js": [ @@ -545153,7 +552505,7 @@ "support" ], "html/semantics/scripting-1/the-script-element/module/instantiation-error-5.html": [ - "fcc8da57e88ee87592a02888c54bb6d66e5172f6", + "7239ae9f5705f7baf5630e67cf4bfdc6c25b108d", "testharness" ], "html/semantics/scripting-1/the-script-element/module/instantiation-error-5a.js": [ @@ -545292,6 +552644,26 @@ "4ce8bcce2537785c41f054175119e39169ed6110", "testharness" ], + "html/semantics/scripting-1/the-script-element/module/referrer-no-referrer.sub.html": [ + "24c02b3a6564a12611bbccd1fa80fa5632ff4efe", + "testharness" + ], + "html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub.html": [ + "77ba562a5284c421c4baeaf810215bc0d54adf01", + "testharness" + ], + "html/semantics/scripting-1/the-script-element/module/referrer-origin.sub.html": [ + "aeba47babafecffdd618a4758d6883cb47b0eff8", + "testharness" + ], + "html/semantics/scripting-1/the-script-element/module/referrer-same-origin.sub.html": [ + "6a931d34d1415144c1faac0d0135faebd8a2151a", + "testharness" + ], + "html/semantics/scripting-1/the-script-element/module/referrer-unsafe-url.sub.html": [ + "abd1f2d309b721f7bbb1f3ca07ae77a204f4ed66", + "testharness" + ], "html/semantics/scripting-1/the-script-element/module/resources/404-but-js.asis": [ "a83137f4c22cadb41ca631a8a8cca17c01021f34", "support" @@ -545320,6 +552692,18 @@ "263589f24f862c862ac8f47ba2de71b77bd9e5bd", "support" ], + "html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js": [ + "6c49153dcd5e4ca5084f0b61eff3b3618a56ef3b", + "support" + ], + "html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js.headers": [ + "90d51a5e46cc58404dd5ec1e9e4e10934a6c0707", + "support" + ], + "html/semantics/scripting-1/the-script-element/module/resources/import-remote-origin-referrer-checker.sub.js": [ + "c0f62a331cb7197a6abf1b465afd35b624d722fa", + "support" + ], "html/semantics/scripting-1/the-script-element/module/resources/import-utf8-with-charset-header.js": [ "23ca0a693a1d6ee4eca34bf27c55764e769437c6", "support" @@ -545340,6 +552724,10 @@ "edf619abb179fc343162bc585c4582ab0d4b0c8f", "support" ], + "html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py": [ + "a148d34314c2734fd49bf69d201006618fdac78f", + "support" + ], "html/semantics/scripting-1/the-script-element/module/script-for-event.html": [ "c225684e0c7d09f9628aab589c8673b140994243", "testharness" @@ -545400,6 +552788,10 @@ "d071fd2e76896c4b66636f359d4426fe101f6d0f", "support" ], + "html/semantics/scripting-1/the-script-element/module/throw2.js": [ + "34c282c0357c639400877b65bf21f30db3b99ea5", + "support" + ], "html/semantics/scripting-1/the-script-element/nomodule-reflect.html": [ "ac2b3c16e9e9263cd4c14de205b63709c14ec2e3", "testharness" @@ -545484,6 +552876,10 @@ "e3209904d340a7f9803af6828cd830f2bd26cbc5", "testharness" ], + "html/semantics/scripting-1/the-script-element/script-defer.html": [ + "c9e0e3a71a522a42be3b3da51999c9762d06e3e6", + "testharness" + ], "html/semantics/scripting-1/the-script-element/script-for-event-xhtml.xhtml": [ "e7de020976ea907ce3a0460f0ad3ba6ad322b5ed", "testharness" @@ -546125,11 +553521,11 @@ "support" ], "html/semantics/text-level-semantics/the-a-element/a-download-click-404.html": [ - "9c9b5c7f78d9c06707d4aaca8256f1fb3da9f06f", + "a5368cce11f6fcaf4d220fabe17685ca1cc4953d", "testharness" ], "html/semantics/text-level-semantics/the-a-element/a-download-click.html": [ - "64cd3f544c42f21c33456e000788aeaab2fed3eb", + "d1ff2de258b01a46afb04901c53b0603ce92cc9f", "testharness" ], "html/semantics/text-level-semantics/the-a-element/a-stringifier.html": [ @@ -546156,6 +553552,10 @@ "f703d9a7ce1e09e0c9ef9ea2bd2cd2b318613f6d", "support" ], + "html/semantics/text-level-semantics/the-a-element/resources/a-download-click.html": [ + "187ff7074f9d52e59177a3c3dafabe2823b60257", + "support" + ], "html/semantics/text-level-semantics/the-abbr-element/.gitkeep": [ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" @@ -546164,6 +553564,14 @@ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" ], + "html/semantics/text-level-semantics/the-b-element/b-usage-notref.html": [ + "325d5278bce87086f1a1e4a8ba5181ffd9604d9b", + "support" + ], + "html/semantics/text-level-semantics/the-b-element/b-usage.html": [ + "7e600b3b69a8d8afe1939262a4e83d0b22a5e3b6", + "reftest" + ], "html/semantics/text-level-semantics/the-bdi-element/.gitkeep": [ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" @@ -546388,6 +553796,14 @@ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" ], + "html/semantics/text-level-semantics/the-ruby-element/ruby-usage-notref.html": [ + "2db31a9c9bb7a301dbb579332a7870315e4521f8", + "support" + ], + "html/semantics/text-level-semantics/the-ruby-element/ruby-usage.html": [ + "c20a6cff72623ce86f1139dff58faa88f42673f4", + "reftest" + ], "html/semantics/text-level-semantics/the-s-element/.gitkeep": [ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" @@ -547141,7 +554557,7 @@ "testharness" ], "html/webappapis/animation-frames/idlharness.html": [ - "03aebad24e8289a02f8336931825dc34039e83cc", + "8210ec5e16b79035472198220d39596404dab310", "testharness" ], "html/webappapis/animation-frames/same-dispatch-time.html": [ @@ -547309,7 +554725,7 @@ "testharness" ], "html/webappapis/scripting/events/event-handler-spec-example.html": [ - "8d4d0bfdf447591695ac134cd243277ea2326c84", + "a0ab0a1eb5a6aa3cffcb06e2f8ea97ddfcaa6c52", "testharness" ], "html/webappapis/scripting/events/eventhandler-cancellation.html": [ @@ -547637,7 +555053,7 @@ "testharness" ], "html/webappapis/system-state-and-capabilities/the-navigator-object/protocol.html": [ - "9ab91396894612ad2a71643cd5253fcc8572983a", + "d87ec96d53353fc63b9d3db4775414c6335cdd2d", "testharness" ], "html/webappapis/the-windoworworkerglobalscope-mixin/Worker_Self_Origin.html": [ @@ -547737,7 +555153,7 @@ "testharness" ], "http/resources/securedimage.py": [ - "bc4c7a8b5eef0e082a5fa7c8c763957d92730747", + "b03f45c4dad3a9cd0f0fb67a99a79be3ba64b199", "support" ], "imagebitmap-renderingcontext/bitmaprenderer-as-imagesource.html": [ @@ -547936,12 +555352,16 @@ "946f23f945163bf9f9da080291b21473f6e1cbd0", "support" ], - "infrastructure/assumptions/ahem-ref.html": [ - "65ecf705ea9804f42a2503941afe96a0c06dd3b7", + "infrastructure/assumptions/ahem-notref.html": [ + "944e5db7eb0d7274ed547002410c25c9fbdc20b3", "support" ], + "infrastructure/assumptions/ahem-ref.html": [ + "427377782d24933d87d2b33538a178eaf4d911be", + "reftest_node" + ], "infrastructure/assumptions/ahem.html": [ - "770fd700c20d041fcfc2d01b53b3f0671c95ec15", + "ca9b8811c489f8fa27e74f3e64937da7c28bf434", "reftest" ], "infrastructure/assumptions/canvas-background-ref.html": [ @@ -547981,7 +555401,7 @@ "reftest" ], "infrastructure/assumptions/tools/ahem-generate-table.py": [ - "7057b804e191b4c1a53df3b631042f9726eb8309", + "24ddd1f2cbd478653820899aa63c35f02d0a551c", "support" ], "infrastructure/assumptions/tools/build.sh": [ @@ -548077,7 +555497,7 @@ "support" ], "interfaces/dom.idl": [ - "915affb8d20dcc9055d3f453efbb893d14fc529b", + "52236516620dac45213fa06dc169f0c02e63a0c5", "support" ], "interfaces/fullscreen.idl": [ @@ -548089,7 +555509,7 @@ "support" ], "interfaces/geolocation-sensor.idl": [ - "3927181a988c0a95cff9813d5074112265e9d263", + "158edb1945e5b3cefdb92953c6b3caf191d86986", "support" ], "interfaces/geometry.idl": [ @@ -548100,8 +555520,12 @@ "77d4d59d0e83928f02b4652636d64df448b388d1", "support" ], + "interfaces/hr-time.idl": [ + "61bd84c720a00b5dfaff8a98ace54cb476a4ed18", + "support" + ], "interfaces/html.idl": [ - "30bf215678945a0b5732673d0364cbd64867095e", + "b93b108cc7ce46595b701a6631b5b8536f0e7eb2", "support" ], "interfaces/magnetometer.idl": [ @@ -548149,7 +555573,7 @@ "support" ], "interfaces/webrtc-pc.idl": [ - "67ca220dbed4271371f67a7a7e2a0a9734288ab6", + "f3bcd13429b9ab477f7b2422fa4e3ede0bfac88a", "support" ], "interfaces/webusb.idl": [ @@ -548369,7 +555793,7 @@ "testharness" ], "longtask-timing/longtask-in-childiframe-crossorigin.html": [ - "1a461ce9d7283157047127312135a218044ec5c0", + "218c69b5395af1590fea4216ec71aae5434e265d", "testharness" ], "longtask-timing/longtask-in-childiframe.html": [ @@ -548381,7 +555805,7 @@ "testharness" ], "longtask-timing/longtask-in-parentiframe.html": [ - "7b1a7373902b68ebcf8f5119cfe7904dd32acd03", + "4914c53c30b9670e103db4bee78b80d8d35af968", "testharness" ], "longtask-timing/longtask-in-raf.html": [ @@ -548389,11 +555813,15 @@ "testharness" ], "longtask-timing/longtask-in-sibling-iframe-crossorigin.html": [ - "6f9971d082ffa24a31e57697ea6bf929b237c62b", + "4443396532adac8bc3a9012553bc7dedc328d710", "testharness" ], "longtask-timing/longtask-in-sibling-iframe.html": [ - "24fd1e4ce58d824d29a65edc913075ca98fe71d6", + "e9c7f9671fba6eba939a3241bbddffb2a6c2bb13", + "testharness" + ], + "longtask-timing/longtask-tojson.html": [ + "c80d01bb7d3825dbdad09137b47ab4e5327f7fbf", "testharness" ], "longtask-timing/resources/makelongtask.js": [ @@ -548405,7 +555833,7 @@ "support" ], "longtask-timing/resources/subframe-observing-longtask.html": [ - "f2f852a5ec5aeb478b578948a301210f9ad12878", + "f1dc339127ee2441a6dbcbde4bbbcd1861801208", "support" ], "longtask-timing/resources/subframe-with-longtask.html": [ @@ -548420,16 +555848,48 @@ "2901b02184fb36d620782fb7fd4a565124580e81", "support" ], + "magnetometer/Magnetometer-disabled-by-feature-policy.https.html": [ + "e7c3f45ece750fd22149ea34ee968a6f7f795ac3", + "testharness" + ], + "magnetometer/Magnetometer-disabled-by-feature-policy.https.html.headers": [ + "9a930b1268bf30ce845ba6671dbb2f44faa92bb2", + "support" + ], + "magnetometer/Magnetometer-enabled-by-feature-policy-attribute-redirect-on-load.https.html": [ + "d9963541021955e037dec0b443e4a80f4ffe4ee0", + "testharness" + ], + "magnetometer/Magnetometer-enabled-by-feature-policy-attribute.https.html": [ + "2ff0ea0df581c878201bc89e05dfc3e82ffadc01", + "testharness" + ], + "magnetometer/Magnetometer-enabled-by-feature-policy.https.html": [ + "ef9490c36c40ee6fe2f1bb09c6fd30519d70796c", + "testharness" + ], + "magnetometer/Magnetometer-enabled-by-feature-policy.https.html.headers": [ + "2be01ba1805ae8fd8038a70763b29e2070a96f78", + "support" + ], + "magnetometer/Magnetometer-enabled-on-self-origin-by-feature-policy.https.html": [ + "3e96f42d58b119e42b261f0ae641f56a7c685f47", + "testharness" + ], + "magnetometer/Magnetometer-enabled-on-self-origin-by-feature-policy.https.html.headers": [ + "2099d254fa4bb019404df56ec1a99e84459c77e2", + "support" + ], "magnetometer/Magnetometer.https.html": [ - "3fbdbbd6c3db9b1a44d7490101bea34045f1945e", + "240e7d0af55b8681f2f45ca22283634acc406325", "testharness" ], "magnetometer/Magnetometer_insecure_context.html": [ - "417e00b969ea887ee4d3d4d9b0dc7af4d786e365", + "0eeb95340d7c74a0243eac8d3f004b6e06b87a92", "testharness" ], "magnetometer/Magnetometer_onerror-manual.https.html": [ - "6adfb807ff2c1b24dad702b21f636e7805543704", + "da4e6b8975beecdcae24da26920a56a652f781e4", "manual" ], "magnetometer/OWNERS": [ @@ -548569,139 +556029,139 @@ "testharness" ], "mathml/relations/css-styling/mathvariant-bold-fraktur-ref.html": [ - "40e52bb1ecb0845350bf5189f7dcd3b0da412247", + "fa251bee74521ce8b994e41eee3b1bc5b688bcab", "support" ], "mathml/relations/css-styling/mathvariant-bold-fraktur.html": [ - "3915dde4053df2960a4611dbc9974cbd73c23c54", + "330fd8e22586c5063f4d6cb19679c99e38ab43fc", "reftest" ], "mathml/relations/css-styling/mathvariant-bold-italic-ref.html": [ - "2cbec8cdbfb8dd88f28c46ee027d451730529367", + "be1bcdd743e3239a5653aeb3b79c5cd247526601", "support" ], "mathml/relations/css-styling/mathvariant-bold-italic.html": [ - "ef64020b7a0b19c718680fba0de4d36269842a36", + "bda1fae3d50812ca2f8d2d6a4d2ac9de27ae9a61", "reftest" ], "mathml/relations/css-styling/mathvariant-bold-ref.html": [ - "3569268cf64f013a44fbc20e1c967324d6e682ab", + "109e487d88b404d5ee2b93cd8957ed6f3d3fc8b0", "support" ], "mathml/relations/css-styling/mathvariant-bold-sans-serif-ref.html": [ - "95167d752b578e5c4dd754f7d873c225056fc8de", + "dcdc13abb1c6dff74ff49a2a90b0947e240419a5", "support" ], "mathml/relations/css-styling/mathvariant-bold-sans-serif.html": [ - "0c0be201714de4c1cf205c365331d49d8799347f", + "6fb64e6e9238974f8a0243fde67a6bf61b76bc5f", "reftest" ], "mathml/relations/css-styling/mathvariant-bold-script-ref.html": [ - "e882071165d8108fea748be4823260302ef0bb19", + "fc121463c63e74c00ed21d6c708a4fbbbdfe812f", "support" ], "mathml/relations/css-styling/mathvariant-bold-script.html": [ - "30730343ac624b27392bf1a4fc49f9ef3273c0b5", + "8e808e39f8f4183b237032ddbafe79574bb76255", "reftest" ], "mathml/relations/css-styling/mathvariant-bold.html": [ - "c52ff122dc0fa7b9c37ca6b95364c212ff475033", + "9ff9f0b9c5dd91c1f7a1cc8dc1112247c9f5480b", "reftest" ], "mathml/relations/css-styling/mathvariant-double-struck-ref.html": [ - "f2d0b2f7469926fc7144a8f4576f891b0864da21", + "30d9cea222663a7356c18a6c50f4899d9b031ba3", "support" ], "mathml/relations/css-styling/mathvariant-double-struck.html": [ - "50015cb963ac68bfcb51d35adcac9057e62bf2b9", + "ea4e3d48c63e70c547c0ae48c9222ed59337ddae", "reftest" ], "mathml/relations/css-styling/mathvariant-fraktur-ref.html": [ - "2ae8154b3af0d85f3d3f6535aa1b010d5461e24b", + "3b282059025b62e8a2215f42b4b0d44e22df04f4", "support" ], "mathml/relations/css-styling/mathvariant-fraktur.html": [ - "630006bc1643063c56736c5ba187a1fa3582b9b1", + "8d5370ce182f7aabc36e00f3a7cf9db85562a439", "reftest" ], "mathml/relations/css-styling/mathvariant-initial-ref.html": [ - "64d17f049b2ecfa195b6d8fd4981e8dec1d93239", + "2081d39bb893c3706c1fb04920528c87b04e1984", "support" ], "mathml/relations/css-styling/mathvariant-initial.html": [ - "97a650b9e6e2850ad50c25f1a9689a705ce2d613", + "b0ba80237bbd87151f32b478ee40e0db03624a0f", "reftest" ], "mathml/relations/css-styling/mathvariant-italic-ref.html": [ - "d0b6d7386fc49e3a12bb435337fe8b13a6bec6dd", + "396b57a917ab987981448147ca943bfd1325338b", "support" ], "mathml/relations/css-styling/mathvariant-italic.html": [ - "96c4b5cb3c1050b01191af462d1c9bcf2d6e7825", + "2b30f12c18c48679b776d43f11e60af84ab2da98", "reftest" ], "mathml/relations/css-styling/mathvariant-looped-ref.html": [ - "ac54af1752395cfb327d19d81d1fff4090ffe012", + "0117e2b19a34fd78ba30adc0c61ab87c378ad084", "support" ], "mathml/relations/css-styling/mathvariant-looped.html": [ - "336fd6c7018b87d48a65b16839c2e9acdec15be9", + "1329a965d5ad23d1cb6ff0b32c8acba4dc12d094", "reftest" ], "mathml/relations/css-styling/mathvariant-monospace-ref.html": [ - "489036f178eae6a525c9fe2169ad415177ab43d8", + "08381a23b783380059c333a652c8566b60e23c58", "support" ], "mathml/relations/css-styling/mathvariant-monospace.html": [ - "4a7ae605eca6e9db5d75a66274c6c00727402ba2", + "e9be2e98731c8a3d2f5db4baa9823c67459e53da", "reftest" ], "mathml/relations/css-styling/mathvariant-sans-serif-bold-italic-ref.html": [ - "e6f97248889b2f8bb56088e47a1d201259fc7105", + "a2f25713ca05a8a3cc2c53f90698d7f7af8d29aa", "support" ], "mathml/relations/css-styling/mathvariant-sans-serif-bold-italic.html": [ - "5c1be25a2cb8f38c6f5cbbf3b4ef45a9350509d5", + "f7cb0d9e8feae82ce7bf22a654bd848b69ed0be3", "reftest" ], "mathml/relations/css-styling/mathvariant-sans-serif-italic-ref.html": [ - "dfa452732d4cc9889db307683e140705638cd859", + "f7b6a41c2bf8f07aae4637167505af3dee1d5367", "support" ], "mathml/relations/css-styling/mathvariant-sans-serif-italic.html": [ - "2499fea7af08b4ca4d7eb33cb2d8de7b4fae794c", + "15832d96f720c7175e94043c7c8a63ba97c32818", "reftest" ], "mathml/relations/css-styling/mathvariant-sans-serif-ref.html": [ - "d178cc3954b7bc4190f743a77a7b60193bc0b593", + "6108ffa455435a222746104a582539b7e018754f", "support" ], "mathml/relations/css-styling/mathvariant-sans-serif.html": [ - "3db38fed4f252fb896f03a1c0b562d8dcba13181", + "34850eac5b5bb52eb024033d3ad8aec019604a63", "reftest" ], "mathml/relations/css-styling/mathvariant-script-ref.html": [ - "21949960ba7656b0318102126423217870b64b1e", + "5cde52d1011ce23f1b27632237a01181c9ed93ff", "support" ], "mathml/relations/css-styling/mathvariant-script.html": [ - "a4ae7f0e3c49b32666b97709d314abd1c789df26", + "312d2bb7704c2194ace3660a7ccbadce527ab5a3", "reftest" ], "mathml/relations/css-styling/mathvariant-stretched-ref.html": [ - "7a8a969c582e53f329e4a48cead5d5852403565a", + "e12b152facef44aba781d57593e63e9ef2bd6883", "support" ], "mathml/relations/css-styling/mathvariant-stretched.html": [ - "e9c229ca6189eed571e244123110ee5bec07282b", + "bd83169e1c88e4e49a71c29fd2c5b48e7e2dbc86", "reftest" ], "mathml/relations/css-styling/mathvariant-tailed-ref.html": [ - "94c4c9a8946ca2df797d5f4a570f9046179e65f4", + "deda9219cd87c16edf341f1313b9981a36f69102", "support" ], "mathml/relations/css-styling/mathvariant-tailed.html": [ - "d7f523065d5480705a5a16d23e797665d163ff21", + "c51e8b7f0df2f273753d985fc65b90d0ef2a2364", "reftest" ], "mathml/relations/css-styling/visibility-1-ref.html": [ @@ -548800,20 +556260,20 @@ "e3be84d69ecef76bb21d8d1135e24c8265f040e5", "reftest" ], - "mathml/relations/html5-tree/unique-identifier-1-iframe.html": [ + "mathml/relations/html5-tree/unique-identifier-1-iframe-1.html": [ "4bcb11441203d9c147e0be7da821e2dd0b9f4507", "support" ], - "mathml/relations/html5-tree/unique-identifier-1-ref-iframe.html": [ + "mathml/relations/html5-tree/unique-identifier-1-iframe-2.html": [ "22a82eb8f312a3f2461d75e480197e0c2894c10e", "support" ], "mathml/relations/html5-tree/unique-identifier-1-ref.html": [ - "2b8e4f0079792594f764a05f8ad032985a9ede65", + "f03271e615e182893a13b6f5b55a9dc05abcec41", "support" ], "mathml/relations/html5-tree/unique-identifier-1.html": [ - "4a966f83afa727682fe392da126aa042e2520f96", + "05c9bbfc6e8c7a1c003f1721cdd1540b89ab107e", "reftest" ], "mathml/relations/html5-tree/unique-identifier-2.html": [ @@ -548853,7 +556313,7 @@ "support" ], "mathml/tools/mathvariant-transforms.py": [ - "413f1df7163f28b93702491e7aa538758c278572", + "27fa2d287a5d407322ba3d1d795acae8df7b0a92", "support" ], "mathml/tools/radicals.py": [ @@ -548901,11 +556361,11 @@ "support" ], "media-capabilities/decodingInfo.html": [ - "80c20b9a3c3c055aff8afa64472e44b2e7c4c34c", + "3cafa5d2375c8f42abee8f22293705eaa6dca019", "testharness" ], "media-capabilities/idlharness.html": [ - "0c34bb1872cc16b21c8c1f33d6dfd796f59500c8", + "396430dee8bc806e95a218e03f767b34efe8fe83", "testharness" ], "media-source/OWNERS": [ @@ -549352,6 +556812,14 @@ "30004bfb49495e067cf71c702ac5985d24589c06", "support" ], + "media/counting.mp4": [ + "ee7fc48592720df569acc537d3d3b04b28f72d0b", + "support" + ], + "media/counting.ogv": [ + "caa14c32214a9cac3bac4273c0b89148e3f79f50", + "support" + ], "media/foo.vtt": [ "fbfdfb2648866047d0fa2a4ad4fde3462a491857", "support" @@ -549408,6 +556876,14 @@ "30080b0409424f065a1b286709c87c04c29fbb22", "support" ], + "media/test.mp4": [ + "94bb77512a183c8f32c8fcac0637c2e0b1cd2411", + "support" + ], + "media/test.ogv": [ + "1edab53c83e53140002aa2a6349d0226be7f5c74", + "support" + ], "media/white.mp4": [ "577f031289beb30fa38824950ea297818bab8e81", "support" @@ -549417,15 +556893,15 @@ "support" ], "mediacapture-fromelement/capture.html": [ - "d5ccd840a00ed4a77dda172663cd39a035565873", + "ff450ec02ee509df7a022a490bfc818c20983743", "testharness" ], "mediacapture-fromelement/creation.html": [ - "f21413b0d01844dd41776c9a3b417a665b497e20", + "18289cfde81c16db6d3e728623113be0bde3454f", "testharness" ], "mediacapture-fromelement/ended.html": [ - "5d400556089e656fdf481a033cfadf0a2dc1f2e3", + "c816abe4302804f8e3ba65bad23443812111acb1", "testharness" ], "mediacapture-fromelement/idlharness.html": [ @@ -549541,7 +557017,7 @@ "testharness" ], "mediacapture-streams/MediaStreamTrack-MediaElement-disabled-video-is-black.https.html": [ - "9f8b4811f67bd0c9ed67327e9589db68432e3117", + "e3358344a76f874b68bdba743f113caa3b61ec88", "testharness" ], "mediacapture-streams/MediaStreamTrack-end-manual.https.html": [ @@ -549581,7 +557057,7 @@ "support" ], "mediasession/idlharness.html": [ - "9aa84a0143daf03d9a95108d0407fda2443c9849", + "8db3276ecfd3f02e55b89171f61e45e6af540614", "testharness" ], "mediasession/mediametadata.html": [ @@ -549596,6 +557072,42 @@ "70a1f9e81faa3dbbe320a71a008e4594a29878a8", "testharness" ], + "mimesniff/OWNERS": [ + "69591fe91d93bf0a6b171734b119274a8c69bbde", + "support" + ], + "mimesniff/README.md": [ + "d0b95d2e21e80df8b65d5bc8217f79d862229ae2", + "support" + ], + "mimesniff/mime-types/README.md": [ + "f3cd8bf009de6ceb297af8bfdecb851f817fa02d", + "support" + ], + "mimesniff/mime-types/charset-parameter.window.js": [ + "baa985ca1fd0aed6644d9d1cef21764cfe826a8b", + "testharness" + ], + "mimesniff/mime-types/parsing.any.js": [ + "b40a3e56406cd6f3303877b1da07a74d0d2f9deb", + "testharness" + ], + "mimesniff/mime-types/resources/generated-mime-types.json": [ + "e4610646e4a1a417e9fccf868150aed3c5688942", + "support" + ], + "mimesniff/mime-types/resources/generated-mime-types.py": [ + "1a3357e9bd14bc90cfa45f6844a270b7b3b93db4", + "support" + ], + "mimesniff/mime-types/resources/mime-charset.py": [ + "635c7dd3564ddec8c7a18c9eb1dae4c01cab75c4", + "support" + ], + "mimesniff/mime-types/resources/mime-types.json": [ + "e036eb74e27d8f35c411bb4d29d0b0621778e882", + "support" + ], "mixed-content/OWNERS": [ "167112f19752c9c180831820b6e348427606b63b", "support" @@ -550104,51 +557616,51 @@ "0e215b6c8f95aea079d53dca4e18e513c50ef9c0", "testharness" ], - "mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/keep-scheme-redirect/optionally-blockable/opt-in-blocks.https.html": [ - "013eb078c215d37a8a52f266beaf9d3871fee401", + "mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/keep-scheme-redirect/blockable/opt-in-blocks.https.html": [ + "1adabf38a9a679da7696f12d61ce50c4c75bec16", "testharness" ], - "mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/keep-scheme-redirect/optionally-blockable/opt-in-blocks.https.html.headers": [ + "mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/keep-scheme-redirect/blockable/opt-in-blocks.https.html.headers": [ "562977daf4fd9e09dc6153058804bc247cbe5354", "support" ], - "mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/no-redirect/optionally-blockable/opt-in-blocks.https.html": [ - "c10fe679c6cb2d69d5c6eaaa985d7d0aebf9e86a", + "mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/no-redirect/blockable/opt-in-blocks.https.html": [ + "41049d21e59f6b84f45096796e6b3d1e8ca25553", "testharness" ], - "mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/no-redirect/optionally-blockable/opt-in-blocks.https.html.headers": [ + "mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/no-redirect/blockable/opt-in-blocks.https.html.headers": [ "562977daf4fd9e09dc6153058804bc247cbe5354", "support" ], - "mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/swap-scheme-redirect/optionally-blockable/opt-in-blocks.https.html": [ - "f07bd06527b7c4210c408a3593f5142f5ad47213", + "mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/swap-scheme-redirect/blockable/opt-in-blocks.https.html": [ + "1d240c95fbfd0394b5458e1dae0394bdbf2bb4e1", "testharness" ], - "mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/swap-scheme-redirect/optionally-blockable/opt-in-blocks.https.html.headers": [ + "mixed-content/link-prefetch-tag/http-csp/cross-origin-http/top-level/swap-scheme-redirect/blockable/opt-in-blocks.https.html.headers": [ "562977daf4fd9e09dc6153058804bc247cbe5354", "support" ], - "mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/keep-scheme-redirect/optionally-blockable/opt-in-blocks.https.html": [ - "82b2035593f5408f7c3e53b640cca2f14214c606", + "mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/keep-scheme-redirect/blockable/opt-in-blocks.https.html": [ + "4fb46872ee82b2d2355069dac1e56599b76e429f", "testharness" ], - "mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/keep-scheme-redirect/optionally-blockable/opt-in-blocks.https.html.headers": [ + "mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/keep-scheme-redirect/blockable/opt-in-blocks.https.html.headers": [ "562977daf4fd9e09dc6153058804bc247cbe5354", "support" ], - "mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/no-redirect/optionally-blockable/opt-in-blocks.https.html": [ - "0671d48855fd3fc222e13579c7b9cc10ec822898", + "mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/no-redirect/blockable/opt-in-blocks.https.html": [ + "2fa674993a988fa52ceffe2168536387997fa205", "testharness" ], - "mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/no-redirect/optionally-blockable/opt-in-blocks.https.html.headers": [ + "mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/no-redirect/blockable/opt-in-blocks.https.html.headers": [ "562977daf4fd9e09dc6153058804bc247cbe5354", "support" ], - "mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/swap-scheme-redirect/optionally-blockable/opt-in-blocks.https.html": [ - "11a64084b74832bef705a46b1ef006b2e51d9bca", + "mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/swap-scheme-redirect/blockable/opt-in-blocks.https.html": [ + "d6a6c64b7c530b04edd4ddf553ce5db363a5dfdd", "testharness" ], - "mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/swap-scheme-redirect/optionally-blockable/opt-in-blocks.https.html.headers": [ + "mixed-content/link-prefetch-tag/http-csp/same-host-http/top-level/swap-scheme-redirect/blockable/opt-in-blocks.https.html.headers": [ "562977daf4fd9e09dc6153058804bc247cbe5354", "support" ], @@ -550168,40 +557680,40 @@ "562977daf4fd9e09dc6153058804bc247cbe5354", "support" ], - "mixed-content/link-prefetch-tag/meta-csp/cross-origin-http/top-level/no-redirect/optionally-blockable/opt-in-blocks.https.html": [ - "bc56ec3ab4cc4e13527189fb43f36ebb27fa71c0", + "mixed-content/link-prefetch-tag/meta-csp/cross-origin-http/top-level/no-redirect/blockable/opt-in-blocks.https.html": [ + "92ae912bff02681d40f206c2c9b11c1f9e8e192c", "testharness" ], - "mixed-content/link-prefetch-tag/meta-csp/same-host-http/top-level/no-redirect/optionally-blockable/opt-in-blocks.https.html": [ - "ce3eb59ff993f2731c6af61806217caf7f6c3bbd", + "mixed-content/link-prefetch-tag/meta-csp/same-host-http/top-level/no-redirect/blockable/opt-in-blocks.https.html": [ + "925c41353886a9abf6d96c4679635a91a74408db", "testharness" ], "mixed-content/link-prefetch-tag/meta-csp/same-host-https/top-level/no-redirect/allowed/allowed.https.html": [ "d1fea7e4b5e32b88797cdfaea1deaced699e3a80", "testharness" ], - "mixed-content/link-prefetch-tag/no-opt-in/cross-origin-http/top-level/keep-scheme-redirect/optionally-blockable/no-opt-in-allows.https.html": [ - "baed43b2d575d296fea4d71452adea468bd02fc0", + "mixed-content/link-prefetch-tag/no-opt-in/cross-origin-http/top-level/keep-scheme-redirect/blockable/no-opt-in-blocks.https.html": [ + "b4c2ffb1cdc781e479582136d58b32d071efed26", "testharness" ], - "mixed-content/link-prefetch-tag/no-opt-in/cross-origin-http/top-level/no-redirect/optionally-blockable/no-opt-in-allows.https.html": [ - "8995bfa6816c2697dc449675768727abd5ecb266", + "mixed-content/link-prefetch-tag/no-opt-in/cross-origin-http/top-level/no-redirect/blockable/no-opt-in-blocks.https.html": [ + "4a9452a6b58037094692565900cb3370c9f360f9", "testharness" ], - "mixed-content/link-prefetch-tag/no-opt-in/cross-origin-http/top-level/swap-scheme-redirect/optionally-blockable/no-opt-in-allows.https.html": [ - "2b4266e2798cffa4df8085d85dc6192151125d13", + "mixed-content/link-prefetch-tag/no-opt-in/cross-origin-http/top-level/swap-scheme-redirect/blockable/no-opt-in-blocks.https.html": [ + "8f406983e28a48e47288eff8a120cec7ef603b67", "testharness" ], - "mixed-content/link-prefetch-tag/no-opt-in/same-host-http/top-level/keep-scheme-redirect/optionally-blockable/no-opt-in-allows.https.html": [ - "34f1424d91ee6bbe1f0c6aa46e307104443f70bd", + "mixed-content/link-prefetch-tag/no-opt-in/same-host-http/top-level/keep-scheme-redirect/blockable/no-opt-in-blocks.https.html": [ + "842695f8ba053fd92766d65f27bcbc18442abbaa", "testharness" ], - "mixed-content/link-prefetch-tag/no-opt-in/same-host-http/top-level/no-redirect/optionally-blockable/no-opt-in-allows.https.html": [ - "62a276c360cb5540fe5decc2f388d4c667007a9b", + "mixed-content/link-prefetch-tag/no-opt-in/same-host-http/top-level/no-redirect/blockable/no-opt-in-blocks.https.html": [ + "ee62d9adad2f7be55ed6274c6609aa03387bc8b1", "testharness" ], - "mixed-content/link-prefetch-tag/no-opt-in/same-host-http/top-level/swap-scheme-redirect/optionally-blockable/no-opt-in-allows.https.html": [ - "b98e1a5a55b229fabc73ff520e93d1aae5786a84", + "mixed-content/link-prefetch-tag/no-opt-in/same-host-http/top-level/swap-scheme-redirect/blockable/no-opt-in-blocks.https.html": [ + "ced5cade402abdd4fd34b295a8c72dd674b2c6e7", "testharness" ], "mixed-content/link-prefetch-tag/no-opt-in/same-host-https/top-level/keep-scheme-redirect/allowed/allowed.https.html": [ @@ -550537,11 +558049,11 @@ "testharness" ], "mixed-content/spec.src.json": [ - "5edaa65af1b7d9f8941442dfec71e087d521c22e", + "1e46012ca5e1f0892e6c80572fa28c5358596c57", "support" ], "mixed-content/spec_json.js": [ - "212f362ad9a8828575eaca2b003a83a2276b3faa", + "f3b78849f97e307c39f81cf9cebb01b367c91b79", "support" ], "mixed-content/video-tag/http-csp/cross-origin-http/top-level/keep-scheme-redirect/optionally-blockable/opt-in-blocks.https.html": [ @@ -550981,7 +558493,7 @@ "support" ], "navigation-timing/idlharness.html": [ - "d05e1d10939fa6509bd7299d03d32d59f69a03f6", + "7b09fdf79c4166eaf21bcf2f92973c80b2864f32", "testharness" ], "navigation-timing/nav2_data_uri.html": [ @@ -557312,12 +564824,44 @@ "6948dbbdc88ffd9aa84ad5a6c822b354809561b2", "manual" ], + "orientation-sensor/AbsoluteOrientationSensor-disabled-by-feature-policy.https.html": [ + "a87d0228b022235fd00eb345cc39f764afd8a64a", + "testharness" + ], + "orientation-sensor/AbsoluteOrientationSensor-disabled-by-feature-policy.https.html.headers": [ + "86af2e7ee455898629df466e7084ab6e909ec313", + "support" + ], + "orientation-sensor/AbsoluteOrientationSensor-enabled-by-feature-policy-attribute-redirect-on-load.https.html": [ + "7b827dd86f0ec3fd63e7f37d90c9eb85a61be8e2", + "testharness" + ], + "orientation-sensor/AbsoluteOrientationSensor-enabled-by-feature-policy-attribute.https.html": [ + "7bd1a53f63f8ce9cf4421dd173ee9772dd8ab739", + "testharness" + ], + "orientation-sensor/AbsoluteOrientationSensor-enabled-by-feature-policy.https.html": [ + "8eaf4b91ba622a454a1f4bae08b5e59905b0deeb", + "testharness" + ], + "orientation-sensor/AbsoluteOrientationSensor-enabled-by-feature-policy.https.html.headers": [ + "f96008f4d28eec8c158a31c8e5c2bbc9ff55ef05", + "support" + ], + "orientation-sensor/AbsoluteOrientationSensor-enabled-on-self-origin-by-feature-policy.https.html": [ + "02840fd195f2891fcb9d2159e92dad004ec94608", + "testharness" + ], + "orientation-sensor/AbsoluteOrientationSensor-enabled-on-self-origin-by-feature-policy.https.html.headers": [ + "cb27e0f09caa38fc80b29580be4b0c06c1024a18", + "support" + ], "orientation-sensor/OWNERS": [ "b119dbb984792f33c6e7463f3105d37c3c3b7ad8", "support" ], "orientation-sensor/OrientationSensor.https.html": [ - "145b750c49bf703c68bcf4ad645448bc284d393b", + "ea9a61f9d526183071a0336e11ca844f59c284a9", "testharness" ], "orientation-sensor/OrientationSensor_insecure_context.html": [ @@ -557328,6 +564872,38 @@ "6f0eb976affc21e49f48c42c1bd9d9eb0083ee40", "manual" ], + "orientation-sensor/RelativeOrientationSensor-disabled-by-feature-policy.https.html": [ + "721b7ba79a90408c073a00383e84966368602b0e", + "testharness" + ], + "orientation-sensor/RelativeOrientationSensor-disabled-by-feature-policy.https.html.headers": [ + "8795ff5458374246ec69928cf9545cb17be3c641", + "support" + ], + "orientation-sensor/RelativeOrientationSensor-enabled-by-feature-policy-attribute-redirect-on-load.https.html": [ + "69bcd956cb76f80481eb867a34fc755f96963d4c", + "testharness" + ], + "orientation-sensor/RelativeOrientationSensor-enabled-by-feature-policy-attribute.https.html": [ + "2c86a4a1a9d71e1ebc8909cedc3cd11a82d59db1", + "testharness" + ], + "orientation-sensor/RelativeOrientationSensor-enabled-by-feature-policy.https.html": [ + "14c83011b5ebcc04b64a3b958e272801f7cd2895", + "testharness" + ], + "orientation-sensor/RelativeOrientationSensor-enabled-by-feature-policy.https.html.headers": [ + "644b0398e76ea06dd5cd012338555b608da02122", + "support" + ], + "orientation-sensor/RelativeOrientationSensor-enabled-on-self-origin-by-feature-policy.https.html": [ + "a469f03dcf3ce4c8b93fe1498935c6507b1bde87", + "testharness" + ], + "orientation-sensor/RelativeOrientationSensor-enabled-on-self-origin-by-feature-policy.https.html.headers": [ + "e6e93a77c618e8477d79f6cf1ff05d0f5865821c", + "support" + ], "orientation-sensor/idlharness.https.html": [ "30f9a5f56c1eb360be09b2a7f2fd1d5148469e12", "testharness" @@ -557413,7 +564989,7 @@ "testharness" ], "paint-timing/child-painting-first-image.html": [ - "53429c63e77999dbcc633ff45469b869d2005d5e", + "a2b3a8fd7cf8a700f7dd6b7f044eb6d6deb9ceee", "testharness" ], "paint-timing/first-contentful-bg-image.html": [ @@ -557468,6 +565044,10 @@ "14013a37d0f6496ab3d793c4c51eb8d22c1aec57", "support" ], + "paint-timing/sibling-painting-first-image.html": [ + "e820a430d03a1ceb40f96f91982eea9ed1d6ac75", + "testharness" + ], "payment-handler/OWNERS": [ "c5e5d0fd086bbe946f99aa8836785c81a2bccb3d", "support" @@ -557609,7 +565189,7 @@ "testharness" ], "payment-request/payment-request-constructor.https.html": [ - "1cda9bee85f3afe53e492a7f0e98b12cbfcd9b98", + "511c4d25939d344f187fe4a8daa4a8ff926b613d", "testharness" ], "payment-request/payment-request-ctor-currency-code-checks.https.html": [ @@ -557624,6 +565204,10 @@ "9a8a1ffc3cd7ba3c29380c4a9962bd17f35087c3", "testharness" ], + "payment-request/payment-request-not-exposed.https.worker.js": [ + "b1c3cdc182cb967ec11b1cad826b333511203d77", + "testharness" + ], "payment-request/payment-request-onshippingaddresschange-attribute.https.html": [ "c9e3679232a83abe6a9eefcb28e3387d2c7810e5", "testharness" @@ -557724,6 +565308,10 @@ "30e6893af2cda301efb45fa7cfe16cec04701445", "testharness" ], + "performance-timeline/performanceentry-tojson.html": [ + "bc8a6f3fb13af9df11781a21b96f342e7d7ddf4e", + "testharness" + ], "performance-timeline/performanceobservers.js": [ "0faeecf506da5b8a5c722a1ce8c7b5854227bca0", "support" @@ -557789,7 +565377,7 @@ "manual" ], "pointerevents/extension/idlharness.html": [ - "64ed6d6c201773f0b5ab4b81369a2d601fe3363a", + "83ee5397ece0126d71c235cecb554b024e3515d1", "testharness" ], "pointerevents/extension/pointerevent_coalesced_events_attributes-manual.html": [ @@ -557805,7 +565393,7 @@ "manual" ], "pointerevents/idlharness.html": [ - "6ca74eb661910c27ed6cb8bbbb819b749007a75f", + "7db1757e519a8ebb9123dd150f17bf5c6f23e311", "testharness" ], "pointerevents/pointerevent_attributes_hoverable_pointers-manual.html": [ @@ -558168,6 +565756,10 @@ "9e687345acc5b9966172bab7da04e3e7019e34c5", "manual" ], + "preload/OWNERS": [ + "fefa8b1bf9f0411b14792bc392711a38a71e91d2", + "support" + ], "preload/avoid-delaying-onload-link-preload.html": [ "7f7c89ffad6f9bc2909d56e36b238ffcba260849", "testharness" @@ -558192,10 +565784,6 @@ "b69da90e272530d4f42bf6d9c5b3b772d1ffce48", "testharness" ], - "preload/fetch-destination.https.html": [ - "d24a50f1f0a52371f84ec35ccc1d99df63c7da44", - "testharness" - ], "preload/link-header-on-subresource.html": [ "ea2f018b648d77b13b8010b4ebe63cdc5f846603", "testharness" @@ -558225,7 +565813,7 @@ "support" ], "preload/modulepreload.html": [ - "82adb9e31fca47cf16908fc41890d74979f1680f", + "05d5b064cf231613ef1942eaa77803da37fabea4", "testharness" ], "preload/onerror-event.html": [ @@ -558308,10 +565896,6 @@ "ac876cf9750337fcde99e547f5dc1223bb200772", "support" ], - "preload/resources/fetch-destination-worker.js": [ - "04e1fd5f1b1829ab9df389f9497681c585b42b78", - "support" - ], "preload/resources/foo.vtt": [ "fbfdfb2648866047d0fa2a4ad4fde3462a491857", "support" @@ -558617,58 +566201,54 @@ "support" ], "proximity/idlharness.html": [ - "f18af9519e53f3d0932d563681e6cc047aad91e3", + "8505e5ef30a561c82b7732fd24789387cf8f654e", "testharness" ], - "quirks-mode/OWNERS": [ - "adc83b19e793491b1c6ea0fd8b46cd9f32e592fc", - "support" - ], - "quirks-mode/active-and-hover-manual.html": [ + "quirks/active-and-hover-manual.html": [ "b82c3af04387a133935d1eed50be37fdc34474b2", "manual" ], - "quirks-mode/blocks-ignore-line-height.html": [ + "quirks/blocks-ignore-line-height.html": [ "01c5b2e89c88d4145429e8860eaa88f728d0601b", "testharness" ], - "quirks-mode/classname-query-after-sibling-adoption.html": [ + "quirks/classname-query-after-sibling-adoption.html": [ "a9fd790c46562057d00b9a042f548d28259042d0", "testharness" ], - "quirks-mode/hashless-hex-color.html": [ + "quirks/hashless-hex-color.html": [ "161c0bfaabbfb59c426e855b9dcfa746ea9e8f95", "testharness" ], - "quirks-mode/historical/list-item-bullet-size-ref.html": [ + "quirks/historical/list-item-bullet-size-ref.html": [ "2579fff5cb55faf66c71dfed695f05db8774d98d", "support" ], - "quirks-mode/historical/list-item-bullet-size.html": [ + "quirks/historical/list-item-bullet-size.html": [ "4874e6e43c91378da1ecf1d4e9534339e8bed9ec", "reftest" ], - "quirks-mode/line-height-calculation.html": [ + "quirks/line-height-calculation.html": [ "aa1ccb57bd83d8dd5f61a5571ae790993a3708c0", "testharness" ], - "quirks-mode/percentage-height-calculation.html": [ + "quirks/percentage-height-calculation.html": [ "de9964d89f79db9a85df6bf65b5bc039aa244380", "testharness" ], - "quirks-mode/supports.html": [ + "quirks/supports.html": [ "cac590a930dab33ba0ab7981c31b868861931493", "testharness" ], - "quirks-mode/table-cell-nowrap-minimum-width-calculation.html": [ + "quirks/table-cell-nowrap-minimum-width-calculation.html": [ "958b1856aa89ee5d5600163b22a75333be2c099e", "testharness" ], - "quirks-mode/table-cell-width-calculation.html": [ + "quirks/table-cell-width-calculation.html": [ "b7a8466a3842237ddf9446bd3ab49de043001526", "testharness" ], - "quirks-mode/unitless-length.html": [ + "quirks/unitless-length.html": [ "578d2aed4afa7cd6739610d353aebc591d832418", "testharness" ], @@ -566201,7 +573781,7 @@ "testharness" ], "requestidlecallback/idlharness.html": [ - "970dac3de43bddedb88e22c438fc01f76a6b9a41", + "99fabb2abdc8aef189bd8c972a7501223517f932", "testharness" ], "requestidlecallback/resources/post_name_on_load.html": [ @@ -566252,6 +573832,10 @@ "b15a57e2eee61f2748bf758e6f3e06e84234f1e3", "support" ], + "resource-timing/resource-timing-tojson.html": [ + "643ce44bcf4a279853f07bde1abb376314e0b3bf", + "testharness" + ], "resource-timing/resource-timing.html": [ "eb3e3064aa55df9ce9a0679a51d0b01d2fb63422", "testharness" @@ -566505,7 +574089,7 @@ "support" ], "secure-contexts/shared-worker-insecure-first.https.html": [ - "81c9cd152b620dd70b11b72db021f4324dad16fa", + "7f227dd604a4568946475b5dfee87d04329fd169", "testharness" ], "secure-contexts/shared-worker-secure-first.https.html": [ @@ -566717,7 +574301,7 @@ "support" ], "server-timing/resources/blue.png.sub.headers": [ - "7ae842dc0c2e6a26e68aea5867214eb2dbd2b08b", + "549289fb534722e17eea4477638e8da59e043c13", "support" ], "server-timing/resources/green.png": [ @@ -566725,7 +574309,7 @@ "support" ], "server-timing/resources/green.png.sub.headers": [ - "827dfe4dedd1d3854048b1b13e336200a05cc0da", + "ed768e3cc679a1fef5c47088443fdaec83838394", "support" ], "server-timing/test_server_timing.html": [ @@ -566733,11 +574317,11 @@ "testharness" ], "server-timing/test_server_timing.html.sub.headers": [ - "ffca8e9271c6760a63ca331c541799a537411994", + "77000d65537ef522a3471002118a120d2faf296a", "support" ], "service-workers/OWNERS": [ - "b74dce201157af7f50d382583674e1b979237f9b", + "84acd30c6a2c1cea23afd9f046ee5c34ae885828", "support" ], "service-workers/cache-storage/OWNERS": [ @@ -566793,7 +574377,7 @@ "support" ], "service-workers/cache-storage/script-tests/cache-match.js": [ - "0204ef8205dd31a9af01b3dacd0f2608fa6eb35d", + "2e56e6185845e752fb828e20e2f1e10143c95073", "support" ], "service-workers/cache-storage/script-tests/cache-matchAll.js": [ @@ -566869,7 +574453,7 @@ "testharness" ], "service-workers/cache-storage/window/cache-match.https.html": [ - "511502a763c53d3fd642aca9e1e1c0c4b610f8ce", + "43346c7dbd6592a33c35146d7ea6fa4495f9a353", "testharness" ], "service-workers/cache-storage/window/cache-matchAll.https.html": [ @@ -567032,6 +574616,10 @@ "f574c7a96a1ca766445cd0b427b9963b18c62795", "testharness" ], + "service-workers/service-worker/about-blank-replacement.https.html": [ + "345259908d040e4f5d810ae7089dab8a8c909b0a", + "testharness" + ], "service-workers/service-worker/activate-event-after-install-state-change.https.html": [ "9d1971d9b5dcb52a14a0d2313065e27766c0489a", "testharness" @@ -567156,6 +574744,10 @@ "9c2e160f95d2915a961bd7da840ac53779c9387d", "testharness" ], + "service-workers/service-worker/fetch-cors-exposed-header-names.https.html": [ + "2013c1862eb3fd63187f570239a0cc64001fc34c", + "testharness" + ], "service-workers/service-worker/fetch-cors-xhr.https.html": [ "448c071ddeaaaf828800d8fad20d8ce672e56590", "testharness" @@ -567188,12 +574780,16 @@ "ce7e7cf76aace24a92d455cdb6b54fc9048960e8", "testharness" ], + "service-workers/service-worker/fetch-event-respond-with-custom-response.https.html": [ + "fc304fa03a33021e4141d940835824883415279e", + "testharness" + ], "service-workers/service-worker/fetch-event-respond-with-partial-stream.https.html": [ "c0e976149cf49c09f52b81159d2a48c301a4aa4b", "testharness" ], "service-workers/service-worker/fetch-event-respond-with-readable-stream.https.html": [ - "cf31c2b1cba37a016dc9e9a3ddb2429a5d518052", + "37c7959e58af70f3feea0f4fb46d778734a0296b", "testharness" ], "service-workers/service-worker/fetch-event-respond-with-response-body-with-invalid-chunk.https.html": [ @@ -567288,22 +574884,6 @@ "04eeedc3f074aff32281a438acda62b7a6d86e2d", "testharness" ], - "service-workers/service-worker/foreign-fetch-basics.https.html": [ - "6600d201f205fe3586cbfab088cf9f2be7d96b87", - "testharness" - ], - "service-workers/service-worker/foreign-fetch-cors.https.html": [ - "aac5e2b6b096af5fb5edd9b8c5193774089afac2", - "testharness" - ], - "service-workers/service-worker/foreign-fetch-event.https.html": [ - "8fbf910205f175a457846100deb34a01c02b00ab", - "testharness" - ], - "service-workers/service-worker/foreign-fetch-workers.https.html": [ - "4838204f935a89eccb333e347dd56f30846460fe", - "testharness" - ], "service-workers/service-worker/getregistration.https.html": [ "989c30567eb1dd650dc7e2bf807e18961c991087", "testharness" @@ -567316,10 +574896,6 @@ "95aee5b0d561467fb5da27f62210be9808539706", "testharness" ], - "service-workers/service-worker/iframe-sandbox-register-link-element.https.html": [ - "6cafc3245c88f7d96f6a4672b327d3b58ee4a0ee", - "testharness" - ], "service-workers/service-worker/immutable-prototype-serviceworker.https.html": [ "5c17042fa54cd1fdba6f7aae513412d4a223b432", "testharness" @@ -567368,30 +574944,6 @@ "3c75caa66d3906602d10b07ff22e7d0f210cfee9", "testharness" ], - "service-workers/service-worker/link-element-register-basic.https.html": [ - "c38709eafae1c43fb6de9c90ad41634bfb749d14", - "testharness" - ], - "service-workers/service-worker/link-element-register-mime-types.https.html": [ - "7f09c63104e39c76638e9193ac07e383ac0435ad", - "testharness" - ], - "service-workers/service-worker/link-element-register-scope.https.html": [ - "c29407cfdce522c6a576d866ece6fffe831c85ac", - "testharness" - ], - "service-workers/service-worker/link-element-register-script-url.https.html": [ - "f3920a47686a1e4792f097f52cf51531dccd58a8", - "testharness" - ], - "service-workers/service-worker/link-element-register-script.https.html": [ - "9751dfe02dff339124352311115e61b19e7edf66", - "testharness" - ], - "service-workers/service-worker/link-element-register-security-error.https.html": [ - "026a444eb0ff60e7885f70c7a4c3fa03a2510de3", - "testharness" - ], "service-workers/service-worker/mime-sniffing.https.html": [ "d61a859a111dea758efb91480817fa1a029c152b", "testharness" @@ -567541,7 +575093,7 @@ "testharness" ], "service-workers/service-worker/navigation-redirect.https.html": [ - "f8e79356467abba33e8008054c32baabc770fe65", + "109f463deeaad2d60d4dab644c782ad633e97a7d", "testharness" ], "service-workers/service-worker/onactivate-script-error.https.html": [ @@ -567577,7 +575129,7 @@ "testharness" ], "service-workers/service-worker/postmessage.https.html": [ - "ea380417fcad1583f764473c554bf519e5beecde", + "dfd851992c1ab3be263bce6f669fceda47d0f410", "testharness" ], "service-workers/service-worker/ready.https.html": [ @@ -567604,14 +575156,6 @@ "864f5435fc40124dbe2c1ffb0e1942fee58228d2", "testharness" ], - "service-workers/service-worker/register-foreign-fetch-errors.https.html": [ - "785f0ea662160a5b7b3fe6a7580e62f793e100cf", - "testharness" - ], - "service-workers/service-worker/register-link-header.https.html": [ - "fa97635d3a16a0f2a0a0bae8e4b81c8b5100d9cd", - "testharness" - ], "service-workers/service-worker/register-same-scope-different-script-url.https.html": [ "2d337b2252fc4235830de53fcb3dc280d3aca82c", "testharness" @@ -567661,7 +575205,7 @@ "testharness" ], "service-workers/service-worker/registration-updateviacache.https.html": [ - "90c97975a11fc639e775d26e9d0354d514ae7a9b", + "c1caf6840bc36eed4f4ece8e42702151e08b3754", "testharness" ], "service-workers/service-worker/rejections.https.html": [ @@ -567673,13 +575217,33 @@ "testharness" ], "service-workers/service-worker/resource-timing.https.html": [ - "9ca1caf0b8216eda8956be0d98eb7b5ab2d92a43", + "a835a0baeb4fcc0c44e6be28502f89308464acc5", "testharness" ], "service-workers/service-worker/resources/404.py": [ "567d0a7de3ef54adaa8339bb04632a2ecfcc57a5", "support" ], + "service-workers/service-worker/resources/about-blank-replacement-frame.py": [ + "2f22a4c92cfb7c7e8cfbe6f168872c2f5875867d", + "support" + ], + "service-workers/service-worker/resources/about-blank-replacement-ping-frame.py": [ + "d632f7a565cb9619db802bff4cbc61310f6ddf4d", + "support" + ], + "service-workers/service-worker/resources/about-blank-replacement-popup-frame.py": [ + "498a08b652ec0d867e8d2e173be954f69354a208", + "support" + ], + "service-workers/service-worker/resources/about-blank-replacement-uncontrolled-nested-frame.html": [ + "ab2ce3693bbc40943b7390c8d76f3601f52410ca", + "support" + ], + "service-workers/service-worker/resources/about-blank-replacement-worker.js": [ + "487ea5fe465410ba3e88f3c8bd657009a99e6ad0", + "support" + ], "service-workers/service-worker/resources/appcache-ordering.install.html": [ "2fbe9f464383783774f08276b8e2cc7103fee83c", "support" @@ -567777,7 +575341,7 @@ "support" ], "service-workers/service-worker/resources/clients-get-worker.js": [ - "a48201939523eb5eb0357a8354f7770f44b941a0", + "bc72471e16df1507a2cebd4c32f7f995299ebd4e", "support" ], "service-workers/service-worker/resources/clients-matchall-client-types-dedicated-worker.js": [ @@ -567872,6 +575436,10 @@ "aee62d5b6ee22664c493036c879ed8d530b5ba1d", "support" ], + "service-workers/service-worker/resources/fetch-cors-exposed-header-names-worker.js": [ + "39aa0c0af84872b5910afd933bfb1642fc28a60d", + "support" + ], "service-workers/service-worker/resources/fetch-cors-xhr-iframe.html": [ "604a64021a30d3cb9ecef7c3d8d6ec14bc75f5e8", "support" @@ -567908,16 +575476,16 @@ "b58b92a145a89f71c414de5e837c1db026beb1d6", "support" ], + "service-workers/service-worker/resources/fetch-event-respond-with-custom-response-worker.js": [ + "a5d0d55ccfa7c3c4c285153aa14b81ef205329c9", + "support" + ], "service-workers/service-worker/resources/fetch-event-respond-with-partial-stream-worker.js": [ "6054d723ad0d0d310b02841b696d2357e7137398", "support" ], - "service-workers/service-worker/resources/fetch-event-respond-with-readable-stream-iframe.html": [ - "16fe2d0f84bb7898f7a89182e24001b3bc64775e", - "support" - ], "service-workers/service-worker/resources/fetch-event-respond-with-readable-stream-worker.js": [ - "7f120661c9b24647f33dc41c36610ad3a1afef6a", + "052da5a0a6b26098fe745fd6d9ca8de0f4dfdc5b", "support" ], "service-workers/service-worker/resources/fetch-event-respond-with-response-body-with-invalid-chunk-iframe.html": [ @@ -567933,7 +575501,7 @@ "support" ], "service-workers/service-worker/resources/fetch-event-test-worker.js": [ - "c8493c87ef1877a9a5dcb1335187233b78d44485", + "bba096216d8fbca6d4ddb6b7e9352a095a5e5db8", "support" ], "service-workers/service-worker/resources/fetch-event-within-sw-worker.js": [ @@ -568072,34 +575640,6 @@ "a557b92d3119f43bbbe10d46effc240d7f11c784", "support" ], - "service-workers/service-worker/resources/foreign-fetch-cors-worker.js": [ - "0bee2a7495fd8590c65fbdb10c02bb4024f729a9", - "support" - ], - "service-workers/service-worker/resources/foreign-fetch-event-worker.js": [ - "7e9998ebcf657391c041d2904c06048214602ac2", - "support" - ], - "service-workers/service-worker/resources/foreign-fetch-helper-iframe.html": [ - "42af5ea03adf25de9d5237a75e913ac726d72c3b", - "support" - ], - "service-workers/service-worker/resources/foreign-fetch-helper-script.js": [ - "6c1d3bdec7490bec2581fb8936170be95cb3e692", - "support" - ], - "service-workers/service-worker/resources/foreign-fetch-helper-worker.js": [ - "94061830f3d478ac53d9eeb03af662c3635f7860", - "support" - ], - "service-workers/service-worker/resources/foreign-fetch-helpers.js": [ - "ce8886f4e8b8e97155c76f7b4e69f1b872c1e7dd", - "support" - ], - "service-workers/service-worker/resources/foreign-fetch-worker.js": [ - "1464189c2e0ab1344227c69363aef9d44df98848", - "support" - ], "service-workers/service-worker/resources/frame-for-getregistrations.html": [ "c5f88c11333ff1faba5d57812a36553d174ab711", "support" @@ -568108,10 +575648,6 @@ "b1a69bedbfbcb8f5b38d35f637f75f167d80118a", "support" ], - "service-workers/service-worker/resources/iframe-register-link-element.html": [ - "9ea5eb8893ae3d75c18566f5862c66df6bc831c0", - "support" - ], "service-workers/service-worker/resources/immutable-prototype-serviceworker.js": [ "0a428649e0ceaaacdea5d156e829c63668bc3f72", "support" @@ -568152,16 +575688,12 @@ "fd486a19472f142bbd2909929a67ac3d39adc845", "support" ], - "service-workers/service-worker/resources/install-worker-helper.html": [ - "9682ae01719d07e5713307a26b1b825087c4cf65", - "support" - ], "service-workers/service-worker/resources/interfaces-idls.js": [ - "ffb2cb87ff6a02509423027f254a7057c3cbb23f", + "c14274bca020d4dfe3df95e0fd36eedae403f99d", "support" ], "service-workers/service-worker/resources/interfaces-worker.sub.js": [ - "0ac0f813b692f2e6ab6a8337427427d1c33a128f", + "229dd043c0e98e9f70f54277bba7c4c3db6d000d", "support" ], "service-workers/service-worker/resources/invalid-blobtype-iframe.https.html": [ @@ -568196,10 +575728,6 @@ "3af11938ec23e1989785be2da453922686e5ace1", "support" ], - "service-workers/service-worker/resources/link-header.py": [ - "5717930bd579b9a63f1b3619195d65b46aa044cf", - "support" - ], "service-workers/service-worker/resources/load_worker.js": [ "08525451705224fd78993adaed33a345d514c9a1", "support" @@ -568328,6 +575856,10 @@ "df15579b54fc14412435eee789c81a6523a394fc", "support" ], + "service-workers/service-worker/resources/pass.txt": [ + "27d2303f215d7d1a8f12f0b80b9b56a2cdf6c9a7", + "support" + ], "service-workers/service-worker/resources/performance-timeline-worker.js": [ "fc275abc58d82c338ff369ba62994bd3d5609a67", "support" @@ -568372,10 +575904,6 @@ "18ee27c8d6a5497bf16b3315ba9eee2b474154b5", "support" ], - "service-workers/service-worker/resources/register-foreign-fetch-errors-worker.js": [ - "20cbfcd09c00c81c0a3c433a6257f62237fecd64", - "support" - ], "service-workers/service-worker/resources/register-iframe.html": [ "b137bd995f0ca7b0ecc6ee6f5dc87a3a4e524364", "support" @@ -568424,8 +575952,8 @@ "c939271e717288203a5a298b95a7328100bd7c80", "support" ], - "service-workers/service-worker/resources/resource-timing-iframe.html": [ - "0fc85a13c536aad45a87fb073fdcebf371d4476d", + "service-workers/service-worker/resources/resource-timing-iframe.sub.html": [ + "c18c96a25dec48ae9d53359d4ca987ba857878a1", "support" ], "service-workers/service-worker/resources/resource-timing-worker.js": [ @@ -568448,6 +575976,14 @@ "d2d9bf76453767aaaf7df973a26bd507b6ab42aa", "support" ], + "service-workers/service-worker/resources/sandboxed-iframe-fetch-event-iframe.html": [ + "57b43f9bb4a11505dd11c187134519d60bc7c026", + "support" + ], + "service-workers/service-worker/resources/sandboxed-iframe-fetch-event-worker.js": [ + "f92786baf9a1ad0be21afd10f1343fd7220fd965", + "support" + ], "service-workers/service-worker/resources/sandboxed-iframe-navigator-serviceworker-iframe.html": [ "b935f6d8fea362c4aceb713fcde91343d3e4bfa7", "support" @@ -568497,7 +576033,7 @@ "support" ], "service-workers/service-worker/resources/test-helpers.sub.js": [ - "d1fae09808cce3b97e13ac73e7b781c5b51592a6", + "55acaa1edd73a39a834e1a1ee0952f47a03e3c78", "support" ], "service-workers/service-worker/resources/testharness-helpers.js": [ @@ -568568,6 +576104,10 @@ "e2e9b5d70f141e71f3617a11a336affea66662db", "testharness" ], + "service-workers/service-worker/sandboxed-iframe-fetch-event.https.html": [ + "04d08798c3d1b5b158951c4243a4ab68ebea42e9", + "testharness" + ], "service-workers/service-worker/sandboxed-iframe-navigator-serviceworker.https.html": [ "1573ac5b39502f4b736d951e9fb781a348f4f70d", "testharness" @@ -568944,6 +576484,10 @@ "61f7da763fa4eb6f21077868caf0a07a4a9e44ae", "testharness" ], + "shadow-dom/event-composed-path-after-dom-mutation.html": [ + "69ea3efc8230a0ed31968f24379289c6691d77d1", + "testharness" + ], "shadow-dom/event-composed-path-with-related-target.html": [ "6a5cbb21645faf8f18ed4b14799a6d01b326f998", "testharness" @@ -568957,7 +576501,7 @@ "testharness" ], "shadow-dom/event-inside-shadow-tree.html": [ - "e468ca13b5a76659fc163010ece09b7708acdc1a", + "cffa15908bacddff66f5584490e28dcea02483e9", "testharness" ], "shadow-dom/event-inside-slotted-node.html": [ @@ -569025,11 +576569,11 @@ "testharness" ], "shadow-dom/slots-fallback.html": [ - "d39644486f8c5307d8095cc32396ca146881320b", + "2899d1565ffcf998c24847e5b43f8e1f48a830a7", "testharness" ], "shadow-dom/slots.html": [ - "1eadf08acc6340f9ebd46d7df1ced3dedb1c5915", + "fdc26c0c0e8fa50ff4095e8acb273142edd01ce4", "testharness" ], "shadow-dom/untriaged/LICENSE": [ @@ -569356,6 +576900,10 @@ "6e5db2d0c2f5d2d8f1e2d04da953a3f2c50bec7a", "testharness" ], + "storage/estimate-parallel.https.html": [ + "6018a8d5ecb29b6c011b20a3afb38669e41f9323", + "testharness" + ], "storage/interfaces.https.html": [ "76fa61c3a87485266a7f9d6f66e5d08bb7881ff7", "testharness" @@ -569365,7 +576913,7 @@ "testharness" ], "storage/interfaces.idl": [ - "d3ac8afefe85ca580a514349060b8019f6fccc36", + "fe2e879ca5662f3b1714404734fd033faf3268ec", "support" ], "storage/opaque-origin.https.html": [ @@ -569701,7 +577249,7 @@ "testharness" ], "streams/readable-byte-streams/general.js": [ - "4617fdb8c1ef68600f476dadcf47090100fc9ce8", + "8d37d5948078b71d3f80e3799ea0dd6d818e933b", "support" ], "streams/readable-byte-streams/general.serviceworker.https.html": [ @@ -569721,7 +577269,7 @@ "testharness" ], "streams/readable-byte-streams/properties.js": [ - "4fd71882c2a1b8c35fb24a10599a6b90a0f32730", + "5eacc7507c71c43bb0f64dc8a7145cd9d3fda167", "support" ], "streams/readable-byte-streams/properties.serviceworker.https.html": [ @@ -569761,7 +577309,7 @@ "testharness" ], "streams/readable-streams/bad-underlying-sources.js": [ - "f6eeb95c1eb3cf9d60cb7e8f1b44a4c460c5bbaf", + "ad4715f225949b4405dea61c0bff003d572e8afa", "support" ], "streams/readable-streams/bad-underlying-sources.serviceworker.https.html": [ @@ -569901,7 +577449,7 @@ "testharness" ], "streams/readable-streams/general.js": [ - "e5ea14274f267ba4579627dd12b81e0863271328", + "72e37e692a88f6dd06f037f07e0d4fbd975f8aae", "support" ], "streams/readable-streams/general.serviceworker.https.html": [ @@ -569941,7 +577489,7 @@ "testharness" ], "streams/readable-streams/tee.js": [ - "857f81daaf24847be71386d53ecc992820104683", + "c51e839b1d3075975c428f7a1bea4a8e36caec2e", "support" ], "streams/readable-streams/tee.serviceworker.https.html": [ @@ -570128,6 +577676,26 @@ "477cc1ed4cc94ff6ee29dcd6f96c16768a2c7567", "testharness" ], + "streams/transform-streams/properties.dedicatedworker.html": [ + "0d766237560b16ddb1bfcd02e701089132f1b3ec", + "testharness" + ], + "streams/transform-streams/properties.html": [ + "82a278a1e8599b5bbd1ab8abadfb13d85f45aa5e", + "testharness" + ], + "streams/transform-streams/properties.js": [ + "8bf21998fc6b9d26e79e1fdf541a2efb8f566d36", + "support" + ], + "streams/transform-streams/properties.serviceworker.https.html": [ + "2ef8fc878249c429a89e0748e6a98fac47c1a99a", + "testharness" + ], + "streams/transform-streams/properties.sharedworker.html": [ + "5c855e897d1143092ecc10b58268e6a576882184", + "testharness" + ], "streams/transform-streams/reentrant-strategies.dedicatedworker.html": [ "6f9350ce1caf4fa9e6239693ec91b2249c2adab5", "testharness" @@ -570157,7 +577725,7 @@ "testharness" ], "streams/transform-streams/strategies.js": [ - "7ec0963bacab2e94607efc4e171431643ba1d6ff", + "9535bb4835eb3124d1c621e11c4ae4b5dff08365", "support" ], "streams/transform-streams/strategies.serviceworker.https.html": [ @@ -570217,7 +577785,7 @@ "testharness" ], "streams/writable-streams/bad-strategies.js": [ - "58cf46e9e07c61e2a7d170cb93837b9e16aa66e3", + "8eeca0627f291a0fd2ab6a21d882b66973a0502b", "support" ], "streams/writable-streams/bad-strategies.serviceworker.https.html": [ @@ -570237,7 +577805,7 @@ "testharness" ], "streams/writable-streams/bad-underlying-sinks.js": [ - "d031fddb5a84f15c60e09416cd8d45609828691e", + "f09d495d577ff9904adbcfc4746acfd5f70860ff", "support" ], "streams/writable-streams/bad-underlying-sinks.serviceworker.https.html": [ @@ -570417,7 +577985,7 @@ "testharness" ], "streams/writable-streams/properties.js": [ - "cc5f851c607b8dc681cbdacb20362689d7259dea", + "81af0a954d0c12677f28ea55636a3de5bf8d3cfa", "support" ], "streams/writable-streams/properties.serviceworker.https.html": [ @@ -570688,10 +578256,22 @@ "ce9e3471676d5a50b91f6b274d648b481e509223", "support" ], + "svg/extensibility/foreignObject/properties.svg": [ + "946999ca1917a5069103c025197c2903ab0bae64", + "testharness" + ], "svg/extensibility/interfaces/foreignObject-graphics.svg": [ "16a7ef4c64dab3706120a2221dd6bec5ca8e9062", "testharness" ], + "svg/foreignobject/position-svg-root-in-foreign-object-ref.html": [ + "1dc201dc096298f81fd21646fd3bc018c127d0c1", + "support" + ], + "svg/foreignobject/position-svg-root-in-foreign-object.html": [ + "c14ce9ff2df60975888de9c5cc31755325701d71", + "reftest" + ], "svg/historical.html": [ "f18f89f68fdf1266768700235f08e7181ce0e0e1", "testharness" @@ -570821,7 +578401,7 @@ "manual" ], "svg/import/animate-elem-33-t-manual.svg": [ - "b8b7fba97c72781ae8f4e383d72a1839d9981934", + "53612df3253d6eb90d6efefdaf1ec7eaee531fba", "manual" ], "svg/import/animate-elem-34-t-manual.svg": [ @@ -572897,7 +580477,7 @@ "support" ], "svg/interfaces.html": [ - "3f659056fc469cb96bccd516a596fb183f005e9f", + "6045de5e5dc7810f89ca2c9a526f9e4380ae365c", "testharness" ], "svg/linking/reftests/href-a-element-attr-change.html": [ @@ -573008,6 +580588,58 @@ "1367de727c679521d6b7237b97b86c5516e9363c", "support" ], + "svg/path/bearing/absolute-ref.svg": [ + "6ad5320a05fcc31fd2af98d2bbd0bd6fbc558daa", + "support" + ], + "svg/path/bearing/absolute.svg": [ + "e1c8d4bca5ab9519936a96521006baa176296c27", + "reftest" + ], + "svg/path/bearing/relative-ref.svg": [ + "6ad5320a05fcc31fd2af98d2bbd0bd6fbc558daa", + "support" + ], + "svg/path/bearing/relative.svg": [ + "75322c3ce1cc60339014301518a966e2e9f35360", + "reftest" + ], + "svg/path/bearing/zero-ref.svg": [ + "8a192b68d131f467d291b277c55c205972db1738", + "support" + ], + "svg/path/bearing/zero.svg": [ + "e7e8508ebb527e97e1f4e289652121b1d070c219", + "reftest" + ], + "svg/path/property/d-interpolation-discrete.svg": [ + "6e27bfe4467b16b9e8c29bb66894bbb9dfbaf077", + "testharness" + ], + "svg/path/property/d-interpolation-relative-absolute.svg": [ + "c67d063d92eb26e14138142a76b9b3640fb663bb", + "testharness" + ], + "svg/path/property/d-interpolation-single.svg": [ + "566a60053980aad644e656029177f8a6026deb03", + "testharness" + ], + "svg/path/property/getComputedStyle.svg": [ + "9914f645d2f34cf65cfad16b65d4308b9688e381", + "testharness" + ], + "svg/path/property/priority-ref.svg": [ + "ee3fa5281b093737f014acae082fbfa5b66737a6", + "support" + ], + "svg/path/property/priority.svg": [ + "c3f4fa37aaa87fb064a8962656e9ed53df4b1f8c", + "reftest" + ], + "svg/path/property/resources/interpolation-test-common.js": [ + "b85e9086b134478e4c4b468cb19cc4e57aca06ae", + "support" + ], "svg/shapes/rect-01-ref.html": [ "f22176bd9807ed4a8cb38ce8481e1aaaecd6bb9b", "support" @@ -573044,6 +580676,74 @@ "42ecd7bc94a3379d920687c79c12e2d3c55b9e98", "testharness" ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGClipPathElement.html": [ + "0f81d16badaade09929ca0b35faf89cc420ef199", + "testharness" + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGComponentTransferFunctionElement.html": [ + "22f7526c060cb0c83df59e428ed29cc2bce3ebf7", + "testharness" + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGFEBlendElement.html": [ + "e6f4a72c37fe814031e2dcd41d6657f8fe7850db", + "testharness" + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGFEColorMatrixElement.html": [ + "a553ecccebe90248889d6b8b9fc34938a99837d2", + "testharness" + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGFECompositeElement.html": [ + "129e0acf47ece9eaee3c3e9ab261ff40e3821c06", + "testharness" + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGFEConvolveMatrixElement.html": [ + "0324d2f34208aecc2f25a6d1bb9e4439dff2a1c5", + "testharness" + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGFEDisplacementMapElement.html": [ + "771cad718da79e918777adb71b08252328ac0b0b", + "testharness" + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGFEMorphologyElement.html": [ + "508373a8b938b92d92459a89b7eaae190c032f37", + "testharness" + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGFETurbulenceElement.html": [ + "4b9b753ac3f8f376a46b049f6f19b102647a7763", + "testharness" + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGFilterElement.html": [ + "4afbeed7802bc7fd7f9e0a0466d146c3de338c03", + "testharness" + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGGradientElement.html": [ + "231b67d164deefa59e7bf8287bf3e74e592fdbb1", + "testharness" + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGMarkerElement.html": [ + "456ed5965e68757c1856c82317f50320bb38bbe5", + "testharness" + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGMaskElement.html": [ + "ba88d01b12250036cf43f9a868ddf32f277aa1f8", + "testharness" + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGPatternElement.html": [ + "8d010c462455324b2acfccba1e6d1c09992c0692", + "testharness" + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGTextContentElement.html": [ + "9b2b9a359f58adf8fc072e6291d2a3ebc0777dff", + "testharness" + ], + "svg/types/scripted/SVGAnimatedEnumeration-SVGTextPathElement.html": [ + "e80379cf14711d78c7661684862139cecbca83ea", + "testharness" + ], + "svg/types/scripted/SVGAnimatedEnumeration.html": [ + "b2c5c52669b802412b085529a2babf0ec2ec3ee1", + "testharness" + ], "svg/types/scripted/SVGLength-px-with-context.html": [ "a605dba2368aa00a3cd3343739c05cdbbd930205", "testharness" @@ -573089,15 +580789,15 @@ "testharness" ], "touch-events/multi-touch-interactions-manual.html": [ - "cb701ce5ebfd16c62b774334d5375bc8d5e68f51", + "c9f99610d07a8bc64512d2f309f404a8da4b99d2", "manual" ], "touch-events/multi-touch-interactions.js": [ - "0947ffb2a11a171d8396d23898c04dac11222594", + "ebd23ef9b71a949ba6f45a08b342ec569626fd82", "support" ], "touch-events/multi-touch-interfaces-manual.html": [ - "51ff04d8bd977ca94eb5a4e51f60affa5dc1ff50", + "ed96c462404889ad1115b8efb65226282ce058bf", "manual" ], "touch-events/single-touch-manual.html": [ @@ -573524,6 +581224,10 @@ "6b1d7bce96ca023959d5248aa8af0aa83c6d3aa5", "testharness" ], + "uievents/mouse/layout_change_should_fire_mouseover-manual.html": [ + "4e96209d99278b974347c6bd636454b0e7daf3c4", + "manual" + ], "uievents/mouse/mouseevent_move_button-manual.html": [ "9cc673035fef3c2e8677e8d6679babfe8a1af854", "manual" @@ -573669,7 +581373,7 @@ "testharness" ], "url/setters_tests.json": [ - "4b01281c0f8811cf57f261f9328d7916c52f3619", + "8d58bd1c98f4d987e6abe66659c812591b197e60", "support" ], "url/toascii.json": [ @@ -573741,7 +581445,7 @@ "testharness" ], "url/urltestdata.json": [ - "d93eea5fddec950368ce502e2f895174b2b847f5", + "59d1f7c678f29a70df885bdfbf9d491899f0038c", "support" ], "user-timing/OWNERS": [ @@ -573993,55 +581697,55 @@ "support" ], "wai-aria/alertdialog_modal_false-manual.html": [ - "754cdc408ed8152fa00cb22ae9148798e3b6f719", + "68c8a71cadc32818bf2f4ae2e1b5b06c3dfbc169", "manual" ], "wai-aria/alertdialog_modal_true-manual.html": [ - "1cc6b8748e46ffbeaaf19123d489895049831393", + "81119cf76329ec2e7134a77ea964ad29a31fd5c4", "manual" ], "wai-aria/application_activedescendant-manual.html": [ - "d8308fd422f658779a864616093e904e42c847da", + "14fa698d19749083c7f3ca357e554495f22248c9", "manual" ], "wai-aria/application_activedescendant_value_changes-manual.html": [ - "4e71505531d12c69f9a982712c1d67cef0ef0f48", + "898ce622e52ed46ce58b8923a757d4c0f0a1705a", "manual" ], "wai-aria/aria-current_not_declared-manual.html": [ - "06f2576c3fe1e9ac32c7a85cd5e40342a3a4f253", + "0f63350ee33dd244b71b5b076211d2bf0fa1b20a", "manual" ], "wai-aria/aria-current_with_value_changes-manual.html": [ - "e8b6e2e2e5f690867e3334f7c45a4724d00a757f", + "9278b8da982531f967d200c5dcbd3d374c78458e", "manual" ], "wai-aria/aria-current_with_value_date-manual.html": [ - "13bb4f08afdc600bf5b13d3264985bb7815a346e", + "5142568284f266a990aaac4d3be3cdb7774cd815", "manual" ], "wai-aria/aria-current_with_value_location-manual.html": [ - "7aa384eb87ce58bdfb9dc1d937b1c8d32b47d813", + "9c74ddcabcd68a3a33c4b722a951d548e7381cb2", "manual" ], "wai-aria/aria-current_with_value_page-manual.html": [ - "91847017d79ff79ddbdfe694e8fea0da78ac579d", + "3e52165dbf19d8b51740b21b56a9ac8da9f22dbc", "manual" ], "wai-aria/aria-current_with_value_step-manual.html": [ - "749b289dfb529cbfb3b356540086f463965aae55", + "aa1d055ed14a4801b5b750531227f3b275be90e0", "manual" ], "wai-aria/aria-current_with_value_time-manual.html": [ - "f49a8f3a2467ad3bc0dc3cbaaf9e1cfa31766be1", + "46c451ab94f2d7df1d86ae9d5e34b8a484582744", "manual" ], "wai-aria/aria-current_with_value_true-manual.html": [ - "ec3f2cd6a59d63f6efe753d2ab34293cec84173e", + "cce63c887ce3da546bcf14b2238c8ec27abfaf49", "manual" ], "wai-aria/aria-current_with_value_unspecified-manual.html": [ - "3b5b8471080a303f0eca9e872bcf72ae9f141561", + "4bcd84c4da792c0cc9bdf4f9e70b4e403af06c96", "manual" ], "wai-aria/aria-details_pointing_to_details_element-manual.html": [ @@ -574053,15 +581757,15 @@ "manual" ], "wai-aria/article_in_feed_posinset_and_setsize-manual.html": [ - "9e09b859a5000bef790a60856cf5ca8e20766094", + "55b95ad109f110b888856193aeb949bbb48b2422", "manual" ], "wai-aria/article_in_feed_setsize_-1-manual.html": [ - "76452d5ae4d5945c45c9b7ebda1624af3eee591d", + "bc8588586ea12e4f6ea32bc993cb7e6820503273", "manual" ], "wai-aria/article_not_in_feed_posinset_and_setsize-manual.html": [ - "7f3b8130f9b8a421b48e25a67dd49a3760176d0f", + "ea70af19b8e0e3fc98b511161cabda07a9b1456d", "manual" ], "wai-aria/button_haspopup_dialog-manual.html": [ @@ -574101,127 +581805,127 @@ "manual" ], "wai-aria/button_haspopup_unspecified-manual.html": [ - "ba242824494f6269d0d2c992037748bcd481953f", + "abaf3e93a69898fd35917fcc98d8828dfa1b99a0", "manual" ], "wai-aria/button_roledescription_empty-manual.html": [ - "854033b2e291d4ed0e8553906305073aa5062fff", + "17b0e96fad091190986d6329e57c0a4ec6f29059", "manual" ], "wai-aria/button_roledescription_valid-manual.html": [ - "609c9df2513fd3447ba7677e5fc8bef73d834847", + "eb0a2a85cddceeb1bd107a4e4d43cc9ddfae5fbc", "manual" ], "wai-aria/button_roledescription_whitespace_only-manual.html": [ - "b65b913b13e8065cb2dc3ec11fd9802ef7c1dddb", + "b6d27fa239c4031ad4bb9fb93fc0eccf391c244b", "manual" ], "wai-aria/cell-manual.html": [ - "0ec4a1d6fa6fe674fd59e8ee12119a26c0617d55", + "2369dfd3f4f5b8e6af8f325b547f13ecb9e28859", "manual" ], "wai-aria/cell_aria-colspan_2_on_div-manual.html": [ - "20ed3d7c616a5df83b7ccb5348a0ec8910ea14e5", + "9783e733d27321c5c3f84d863043fe0849412a68", "manual" ], "wai-aria/cell_aria-colspan_2_on_td_html_colspan_3-manual.html": [ - "b7a0f0c405f7054650888757ef2e2414777d147a", + "cba6254e6306b3647733b1823b1f5543fb6064a9", "manual" ], "wai-aria/cell_aria-colspan_2_on_td_html_colspan_3_with_headers_and_border-manual.html": [ - "a9c6472baa2a60c2405be20e6cdfb25321d71a35", + "8c1afae9c0188db50ce4205892d23aedf565cc52", "manual" ], "wai-aria/cell_aria-colspan_2_on_td_html_colspan_3_with_three_actual_columns-manual.html": [ - "f11c49f1db6d5246a3e14923a9bfadb1f2bb5ca4", + "3392bae47ac091fc13dde3b0f456956862b51779", "manual" ], "wai-aria/cell_aria-colspan_2_on_td_with_html_colspan_not_specified-manual.html": [ - "49a9a8d79c91b840d4fa7c652437f34508c27825", + "d3a95edb251182a03f3484052a037bb406185118", "manual" ], "wai-aria/cell_aria-rowspan_2_on_div-manual.html": [ - "766a462e63e40ede31b5bcb28dfe4160199e4d6e", + "cb4f984d568e04062c9088a60dc0aacf889ea673", "manual" ], "wai-aria/cell_aria-rowspan_2_on_td_html_rowspan_3-manual.html": [ - "a906e8899c1131aeb6d12fac8ba6021d3ac35531", + "25e0bd008d159211311ee22406364943a93d05cb", "manual" ], "wai-aria/cell_aria-rowspan_2_on_td_html_rowspan_3_with_three_actual_rows-manual.html": [ - "f977cc8e1100ca85b4251c2c08e7ed259c856e4f", + "752117c6c50282b6e63f31ca2ebe28471c94f333", "manual" ], "wai-aria/cell_aria-rowspan_2_on_td_with_html_rowspan_not_specified-manual.html": [ - "62fc9761f1df3c93d97915ccb0296a27c4847b91", + "1fe80df91327bd67d4a16cf48b4c6b20e04d10b9", "manual" ], "wai-aria/cell_colindex_4-manual.html": [ - "2951c871b311f443b3ef63119299a3b7d15494e9", + "41702551c72d187a2d3f0605923065aaa635b302", "manual" ], "wai-aria/cell_rowindex_4-manual.html": [ - "0237b24b6e6cbfd5e35c20ddd3358821d57ab243", + "5fc16311adf938a1c3961d3e27254061ceab2570", "manual" ], "wai-aria/checkbox_readonly_false-manual.html": [ - "2ccf421bea917a7081b0e07179189ad47193cbe4", + "058bb4a14ac1a1893e0acbe12e4e1476299940c9", "manual" ], "wai-aria/checkbox_readonly_true-manual.html": [ - "7d58401c763fa71fb51351948ce90c32d77bef06", + "725838c76624e45f116938df24308807b042e4c5", "manual" ], "wai-aria/checkbox_readonly_unspecified-manual.html": [ - "b9c43e4c8c1913c6cdfc1e18a6cb4a26bd470555", + "d024eb792e244e844972a729983a63ddba4762b6", "manual" ], "wai-aria/columnheader_aria-colspan_2_on_div-manual.html": [ - "0e259f88585602885fd753d9b3ce732f9d31a4a5", + "8af44c7fa3c79d6f414bf5ee927e423770dd066e", "manual" ], "wai-aria/columnheader_aria-colspan_2_on_th_html_colspan_3-manual.html": [ - "7b7d5ec0b8a57880e9699d590acb212f69245b42", + "099b9973f09a33a0976693c9410efa4824767780", "manual" ], "wai-aria/columnheader_aria-colspan_2_on_th_html_colspan_3_with_three_actual_columns-manual.html": [ - "2aa3893e949c87bd709273a0ef30e46147b8b2eb", + "bef87265d36cfa93b037746087e9074c44743641", "manual" ], "wai-aria/columnheader_aria-colspan_2_on_th_with_html_colspan_not_specified-manual.html": [ - "5dd455653d81c7cf1bd9aea69cffea8a0d7a4aaa", + "272c32c2f62d34a87a626f788ab428e71ad7b3e5", "manual" ], "wai-aria/columnheader_aria-rowspan_2_on_div-manual.html": [ - "c8ad953daf6925bc14e04ad76e947cd27dee5c7e", + "88e831f09c24bb87c250643b272955973244966e", "manual" ], "wai-aria/columnheader_aria-rowspan_2_on_th_html_rowspan_3-manual.html": [ - "beb80b0e82adf83da89213b9d1f7126560dad7e2", + "9e95976e9856c87c4aab9ec18cedc1c2b18b7413", "manual" ], "wai-aria/columnheader_aria-rowspan_2_on_th_html_rowspan_3_with_three_actual_rows-manual.html": [ - "08e65dcc8fe5e6b641f9dcaa71c3ba0c98ede206", + "6391733367e9dbffe58c784e510d02850a2b8837", "manual" ], "wai-aria/columnheader_aria-rowspan_2_on_th_with_html_rowspan_not_specified-manual.html": [ - "2ad181f5319b77d9db45fcbdabc8934cb9fa24aa", + "c8d79061be3616bef54668c6788b86e029ecf563", "manual" ], "wai-aria/columnheader_colindex_4-manual.html": [ - "8289dc10e5f66c304fc370119bc29aaaa3e8ed8a", + "b5754c7fd7f67bbd0fe304a3c492805c8c808407", "manual" ], "wai-aria/columnheader_rowindex_4-manual.html": [ - "fee6e82ce2af5dccdec2c730ea9988cbc3d4e1d8", + "761ee820e9284c1b37683155a9b372ed0d3652df", "manual" ], "wai-aria/columnheader_selected_false_not_automatically_propagated-manual.html": [ - "e869f2b1aa85c5e2e203d5521f9b08feb1f663ca", + "a5194b21acc10f7ce439cc2730cd2c14884905da", "manual" ], "wai-aria/columnheader_selected_true_not_automatically_propagated-manual.html": [ - "04f91ea9c7bc2376fcb510a692b35d2a5070b590", + "5a2daef90b1ef37b62f66802e3e4611657443510", "manual" ], "wai-aria/combobox_controls_an_invalid_id-manual.html": [ @@ -574229,75 +581933,75 @@ "manual" ], "wai-aria/combobox_haspopup_dialog-manual.html": [ - "961821dd5ce25610394362df85805695295045bf", + "84712f94d0952c201ec3a510f07a5c30ea45fa90", "manual" ], "wai-aria/combobox_haspopup_false-manual.html": [ - "3f84b71eb40d187db111a82f0441d97cbc976a2e", + "cfd88ca222c07f255ed566c56660fc9681cce69c", "manual" ], "wai-aria/combobox_haspopup_grid-manual.html": [ - "018eb1a5e3acec237eaa2aff418b943e4db652e2", + "aa45fe6a5877bbfbe7a418513a5efe2279889313", "manual" ], "wai-aria/combobox_haspopup_listbox-manual.html": [ - "fb411bd4b8308fee78d6e1723b9de63751da4e1e", + "3e4c72e9b5601b834395a5dcd8c9e317e071f079", "manual" ], "wai-aria/combobox_haspopup_menu-manual.html": [ - "7becc965e84d0a68d15b3db779a7f9644bde46b4", + "c9a582516c3d701af6d73211315b713ac4f7953f", "manual" ], "wai-aria/combobox_haspopup_tree-manual.html": [ - "cca6e5a853d8609855cf1d230c174bc66abd5e86", + "c21fd5d22a2b9a6baa22a44bc5319412b35f89cd", "manual" ], "wai-aria/combobox_haspopup_true-manual.html": [ - "5586489253d14dba054db05683dfcaa0bb0da56a", + "5c37cccbe5a4a642d0344a61bf6949e0fb773fed", "manual" ], "wai-aria/combobox_haspopup_unspecified-manual.html": [ - "44e5de398426acb874cc1937e5183216ec35a712", + "2e7f0d5ed6da38621543c09019bbbab6e0a21a55", "manual" ], "wai-aria/combobox_orientation_horizontal-manual.html": [ - "5bcd8c6c417fd7893bd56f454d5c68ab39da454e", + "2c42a67ab05697533fae78a33406a9abd0397478", "manual" ], "wai-aria/combobox_orientation_unspecified-manual.html": [ - "38ce5005fbffaff4101e23118510309c044dc59b", + "59bbe7645fa43dcf8b05db1677fd4de4baf01e4a", "manual" ], "wai-aria/combobox_orientation_vertical-manual.html": [ - "b5c0f055a83c6ab23212c64f610c08def3e19e50", + "281ae8a1d54636527974d722341347e1c2df0d57", "manual" ], "wai-aria/combobox_readonly_false-manual.html": [ - "e7ddb2787f3cd24d722f41cbed0e46f1829a84fb", + "c0f42748cd164b12fb8b2a02afada5ecb88b93e0", "manual" ], "wai-aria/combobox_readonly_true-manual.html": [ - "a8ed48eb1686c4d7d36da309a76c772d894fd886", + "bc0c9f2f8bf72d41bdf94ed276e3ae58c5c988f7", "manual" ], "wai-aria/combobox_readonly_unspecified-manual.html": [ - "33d47bc7569c9deace942d36f85167af931943f9", + "c9d7c778a4249153fbd6ea7744e4231e3a4f58b2", "manual" ], "wai-aria/dialog_modal_false-manual.html": [ - "b4705c5d80e52baac15c0c068663a02a925660f0", + "58f1b7506b1b77d71943d9718584e961914dd746", "manual" ], "wai-aria/dialog_modal_true-manual.html": [ - "55dcbad3c1757ffa5fd666c4362ddbc499224064", + "db0066cf92f7eb9b2b209c078f5039992c4c1dab", "manual" ], "wai-aria/dialog_modal_unspecified-manual.html": [ - "a0405a2af36d1400d7a83aa2a5eeb6e92fdc1928", + "38fa5a8ff1627cbfb35978d190422eb2d50dab6d", "manual" ], "wai-aria/div_element_without_role_roledescription_valid-manual.html": [ - "a1878222bfe58fa9e40760d6ea8f362633875936", + "0856d271322865f790130e958c3f1529f7527e62", "manual" ], "wai-aria/errormessage_object_in_invalid_state-manual.html": [ @@ -574305,247 +582009,247 @@ "manual" ], "wai-aria/errormessage_object_in_valid_state-manual.html": [ - "ee7427b441edad9bc599fd287860eb28a6e56f14", + "a8cbccf6b396b44067876244f98d0b62f83774f5", "manual" ], "wai-aria/feed-manual.html": [ - "5314038686453e25354d5444fcbdf5ad945cc965", + "1ec93583fcd22913d4650b23f93df495ba7eb940", "manual" ], "wai-aria/figure-manual.html": [ - "296f20edcfa4c2de5826af97e18b846b920c30a6", + "e082e00d346e721471f03b73374b4c38526be0a9", "manual" ], "wai-aria/grid_aria-readonly_false_automatically_propagated-manual.html": [ - "56b668db545c7b8cb1599c3d205b28218e19cf74", + "13716046d5ca45cb13583922b40fabc705672b21", "manual" ], "wai-aria/grid_aria-readonly_true_automatically_propagated-manual.html": [ - "d02baf60fcebee6dd6e52e4884c8bb4e6729cfc1", + "96b04b9751b434510f85bbcb61af7875318e80fc", "manual" ], "wai-aria/grid_busy_false-manual.html": [ - "1e2a8ede68c23c6b308253546c3d25619318a4d9", + "9f5aba26e274bfac88ca011fd67afeefd82dc573", "manual" ], "wai-aria/grid_busy_true-manual.html": [ - "8734b76e71476acf2c71f9bb7a714f890fd337cd", + "fbd73fad52937eaecc80cceb381f2c460d961234", "manual" ], "wai-aria/grid_busy_value_changes-manual.html": [ - "e5df53e46628117c5fe0e12d58334c845a9e404f", + "f419a3519d0c3355e9262c2a4468a327f54dbd8d", "manual" ], "wai-aria/grid_colcount_8-manual.html": [ - "b66693301f389b525ad6e933c5474505b56ab7b3", + "25a8241b4c86a07ab24d639bd7465246ed6e342a", "manual" ], "wai-aria/grid_columnheader_readonly_false-manual.html": [ - "2c4a43cd02609acc031d33eb4e689648370abd59", + "25d164213bf6bceb17d8c1592a9e32aaec8bc879", "manual" ], "wai-aria/grid_columnheader_readonly_true-manual.html": [ - "f935328efc9d08b5af2e10f1259963b416bbaae6", + "369312f28ca1c8686177e634a449b2bf5f0089d0", "manual" ], "wai-aria/grid_columnheader_readonly_unspecified-manual.html": [ - "4cc660c0363fa6a4d4ab7542ee60a8f3617be879", + "45d9897d73f16fdc19ac25e6a304836d503e044b", "manual" ], "wai-aria/grid_columnheader_required_false-manual.html": [ - "5b2b2bb0ec6562b83dbf6356e6569d8c8ecf5217", + "e40b2a1e0b14713978b55b16bb87bc597f4b8550", "manual" ], "wai-aria/grid_columnheader_required_true-manual.html": [ - "45d1ab83024a4c88fa16985c58fe99ff44a8c3da", + "7d3b2cdacc03e0e9b575c57009eefd13d9bdb784", "manual" ], "wai-aria/grid_columnheader_required_unspecified-manual.html": [ - "4f516fcd837222a86d2ecfb431b36361c73dc8a2", + "866dc8878b90126c09538726413c7f768ee48dd4", "manual" ], "wai-aria/grid_rowcount_3-manual.html": [ - "beb0b7e7c70aec7a1c40c6a04bc0d58aff45d874", + "47a0ce3042898e15e03ee2746b6586767e76066f", "manual" ], "wai-aria/grid_rowheader_readonly_false-manual.html": [ - "cab82961b14adc4c99e9321c0dc94b38eea2028a", + "69ecf3bb059feb1d33475b0b762f2db4a9e46aa7", "manual" ], "wai-aria/grid_rowheader_readonly_true-manual.html": [ - "9ebdaa97febbe584b1e44bf048a29814a24381ea", + "6f2e76bfbb203ab92ede1fd6de820a4037d79c4f", "manual" ], "wai-aria/grid_rowheader_readonly_unspecified-manual.html": [ - "c50f645b458fba36b881bc85474ea7b3c1710e45", + "6b0d9a86da3b08110240bf212312e0d2152b74ef", "manual" ], "wai-aria/grid_rowheader_required_false-manual.html": [ - "56f954adf8783d91ce550c71b876850a3ea19521", + "33520550b7acf017941c8e2c22c02e085849de21", "manual" ], "wai-aria/grid_rowheader_required_true-manual.html": [ - "bd031d825385c77efea8479087b407cae84164c0", + "85eb3649a12956bb0f06f23642899f526e1fe693", "manual" ], "wai-aria/grid_rowheader_required_unspecified-manual.html": [ - "0ce55c3222ff79ccfe99dbb18332fc67d96eaaa9", + "948edf09c08b89aa6e3d11d4539a56a23bf7a6af", "manual" ], "wai-aria/gridcell_aria-colspan_2_on_div-manual.html": [ - "1a7d9b0cc28bfaef446972e0fd42f4f51c4be3fa", + "e463c3b895a445aa3ddeff7f6d53b86be8f2d405", "manual" ], "wai-aria/gridcell_aria-rowspan_2_on_div-manual.html": [ - "44a9be247679dd52a94f28a1d5147c953867fad0", + "dd18af945e17147bb2b639831c92900c0ec5d9ef", "manual" ], "wai-aria/gridcell_colindex_4-manual.html": [ - "3f2cc5549c8c48bed4482eef4d15016a866a432e", + "a6c675d773c11685b6bdb9a52141f483779277a9", "manual" ], "wai-aria/gridcell_rowindex_4-manual.html": [ - "3ab620afeb2de8c158c1420949d151a2e98f061d", + "29615e12a755dedd0c486028ea58b7a4210953cd", "manual" ], "wai-aria/group_hidden_undefined_element_not_rendered-manual.html": [ - "862b7a9ba1a34dbf9346b2fedeeb52a1a5502784", + "5a83d0417dbc93b6795ea0bd4f58080dbf70b1be", "manual" ], "wai-aria/group_hidden_undefined_element_rendered-manual.html": [ - "2adf0911f14a94eccd19cc8fdf71c7dc2ee4a2e7", + "b7d21c9cd9ce418ad1e85c90a72aaea74350bf5a", "manual" ], "wai-aria/heading_level_unspecified-manual.html": [ - "08fb0566ab4c31b346e61359a4726df4e358f3b5", + "3776012458f8cbdce68e503f2a56e79512e7825f", "manual" ], "wai-aria/keyshortcuts_multiple_shortcuts-manual.html": [ - "f9dc1d5552aadb665b546fe8b72783220b431c8a", + "d2ac7049387ae7bd4f0d38dfca46e38b4d0a68f7", "manual" ], "wai-aria/keyshortcuts_one_shortcut-manual.html": [ - "2bab844538a414aa5abb4768d50923bff544fcb0", + "cf820ebb599b8097edb69be4c1551b24ab43a55f", "manual" ], "wai-aria/listbox_busy_false-manual.html": [ - "5569cc12e3b9d2b8fde247c790d72e11015ae78b", + "44b35c288b1ba06c5d1c59599ef2c8be6b14b61d", "manual" ], "wai-aria/listbox_busy_true-manual.html": [ - "10359f9d21d1fce801fcdd959a12cc5d3f959515", + "b20396f47215f777c5351ac998b8e7d438a341a0", "manual" ], "wai-aria/listbox_orientation_horizontal-manual.html": [ - "4eac9ea9de1faaf6b4edf0d39453ed0c142d8229", + "8d6f01eb9bbd232968163683d086f81dabd6e03d", "manual" ], "wai-aria/listbox_orientation_unspecified-manual.html": [ - "4429e641a1c432347fa0989f1b4a912c238f81fd", + "757b5f1983cfddce21316ffc6efc8c7d3b473245", "manual" ], "wai-aria/listbox_orientation_vertical-manual.html": [ - "3392029434e2f8a8e65fc06960e47f62c3d3224e", + "9f3b0e23df678ea853a38fd036708a5c99b1dad8", "manual" ], "wai-aria/listbox_readonly_false-manual.html": [ - "13f5c9c82beafb26b084dffbf9765cbc1b09a717", + "6f5fc88fbcd65713a2b11d2995efe4fefa6bcdad", "manual" ], "wai-aria/listbox_readonly_true-manual.html": [ - "133b4d223e1c74ef642b8d627c3f04b7742cd4df", + "a9bec885bc448239ce5fc4810d1ba1ce3b374f2c", "manual" ], "wai-aria/listbox_readonly_unspecified-manual.html": [ - "4f4e9ef883e7bf9d5e4c719cfec417a4ba427a55", + "d9f6aabfe918604ad7358f9cd5dbd0c8660e0d51", "manual" ], "wai-aria/listitem_setsize_-1-manual.html": [ - "bde65a9d5a00ceed56cbce667a541570100c7279", + "52df1676c1c1ffc3083c1f4660a70df8ac8c5dec", "manual" ], "wai-aria/menu_orientation_horizontal-manual.html": [ - "cb4012affde2f37218f511c11e92a24e987eba89", + "207ea1baeac038d05aa63b4acfb2b4bfee95a6a1", "manual" ], "wai-aria/menu_orientation_unspecified-manual.html": [ - "24903e47b6a6ae1be0a49df8a2ea2abfffd5cf72", + "8667ad48461e0d9c48d48fbb32f9bbd6113ea218", "manual" ], "wai-aria/menu_orientation_vertical-manual.html": [ - "e7be595d08ccb2f6e94f1c5e3bd66e74f07a04e6", + "4946be44782f6172c2d3453cbe206e49c0685665", "manual" ], "wai-aria/menubar_busy_false-manual.html": [ - "f036c27a389e2680551846a5def6a9d56d398a43", + "8a03b7ae3025ab854b322c12d528162e3467d030", "manual" ], "wai-aria/menubar_busy_true-manual.html": [ - "27a589285c997241c506cbb4aa2a05b546422e8d", + "51e683d83464e09e894b5c037da9aa4e812fa7e4", "manual" ], "wai-aria/menubar_orientation_horizontal-manual.html": [ - "f38cd16c8da078230397b8845b0584a087bd6a83", + "0dce46771c55df1e9f2f2b00ac958e3602340759", "manual" ], "wai-aria/menubar_orientation_unspecified-manual.html": [ - "6281641a562dc090ec2a31cb3569d3a0708b7ec4", + "bc4dc9287e5a95fdd3fed9199499f2b947d036ee", "manual" ], "wai-aria/menubar_orientation_vertical-manual.html": [ - "a9f61de067b3e926fb51fd0c0f1d8007ccc33857", + "c7115c655a70aeb4d35ce1f9eac9a2c687123758", "manual" ], "wai-aria/menuitem_posinset_and_setsize-manual.html": [ - "b444b779d3f65b58bed822e6cc1440828f63557a", + "5dce1f03cc4961eed0ec6813b42653a1229b5d7b", "manual" ], "wai-aria/menuitemcheckbox_posinset_and_setsize-manual.html": [ - "39781006ca59817acf455d556b8c76cd6b489445", + "b0f48dfef7fc382d75bc1aea29bfb15c6bc1940e", "manual" ], "wai-aria/menuitemcheckbox_readonly_false-manual.html": [ - "b8841fa91199dcc5662c06780d31cb8261ff92a6", + "d207839d0ef1761a186aeefff4d7fa53a0f41040", "manual" ], "wai-aria/menuitemcheckbox_readonly_true-manual.html": [ - "71b4785cf69375262139df7f18025f55d97774e6", + "b6c26c26e07770f4279c530ce3354b449ffe4bfc", "manual" ], "wai-aria/menuitemcheckbox_readonly_unspecified-manual.html": [ - "3359f715e3d96cadb2eaf8f07904caeaff36846f", + "f5435462f1dbaa7e2493b453b5183bbbea333fbd", "manual" ], "wai-aria/menuitemradio_posinset_and_setsize-manual.html": [ - "81ced2031a3f8119f415b6ade261dc47b4c54852", + "3cc12d0ddcddecbf870a3a0615914b4c4ca3a741", "manual" ], "wai-aria/menuitemradio_readonly_false-manual.html": [ - "ae7976e8c538e0e712f9ad91ad056a78c258df11", + "88fc3c5514fa07e2ad3641224a3ebbb61778b2e8", "manual" ], "wai-aria/menuitemradio_readonly_true-manual.html": [ - "1b1959ce48d2f765952210b507213e7842c57152", + "5e082185bd8bfacca8da1dd7b2d147a6b1c528e1", "manual" ], "wai-aria/menuitemradio_readonly_unspecified-manual.html": [ - "1ba57d551c68d52dc75748717106f7c1a30204c4", + "e3b521691a02724bef7025eecfac91b47a71875d", "manual" ], "wai-aria/none-manual.html": [ - "2d2a19bfb7d55f8cb69fd8cbabf10f9d43fc36f7", + "6f177f7c60f6063074cb7b22ff4798818a088a57", "manual" ], "wai-aria/option_selected_false-manual.html": [ - "a9236aa03abaef97f1af1d9f3011b76d36100487", + "147b98f2d89560a1c4ab30166ac7df25392ff751", "manual" ], "wai-aria/option_selected_true-manual.html": [ - "fc5f2c6ddb47c33d9e732e0de6a023b25a196618", + "1e96b25c9464122c2fdd55c491c8c5f4d8d5041c", "manual" ], "wai-aria/option_selected_undefined-manual.html": [ - "7c7f968fdcfbacf6e63aff45f89cfc283de7259f", + "48e855811cefd7ea8d7744db5031fe32321978c5", "manual" ], "wai-aria/option_selected_value_changes-manual.html": [ @@ -574553,27 +582257,27 @@ "manual" ], "wai-aria/radiogroup_orientation_horizontal-manual.html": [ - "5b2f86e5454bf00e02c0b7a728524c7d7c30c55a", + "c373a9f15b9c108a03cec7662d92ca21b98cb006", "manual" ], "wai-aria/radiogroup_orientation_unspecified-manual.html": [ - "59b1f62489854443d46e1349f27261a36670fbe9", + "771cdca0240576bcc253df114799de995c81e0ad", "manual" ], "wai-aria/radiogroup_orientation_vertical-manual.html": [ - "a7c523b054a176f529b66b13bc26a987c7f9e5b6", + "efc922127513bda2d553331f33c4c077053b42e0", "manual" ], "wai-aria/radiogroup_readonly_false-manual.html": [ - "8ff1ac067d0d41ef96b629ecd66f00ed37ef9f27", + "be82d9478bf8d8f7292daaf0a53af4841c5a34a7", "manual" ], "wai-aria/radiogroup_readonly_true-manual.html": [ - "ab0a26eff7d0815ae76ca0ea38e57134703cfccd", + "b2bfef17fa599d5f25fac4811bbe43e615e117ee", "manual" ], "wai-aria/radiogroup_readonly_unspecified-manual.html": [ - "87bb3a459e24471da03f95c65ff283013e9bed83", + "0d4fc6e2740c3d8b0f20f4edd632637f5e7b9542", "manual" ], "wai-aria/region_with_name-manual.html": [ @@ -574585,35 +582289,35 @@ "manual" ], "wai-aria/row_colindex_4-manual.html": [ - "28ca687e2b8da7e3dd2e0fcb3dfc0bb5ffb63840", + "d3db5c738273004b2390a0ff49a8637425968626", "manual" ], "wai-aria/row_rowindex_4-manual.html": [ - "35f2f062b8997476241dac74c1996aecb401c1bc", + "e668877bd45fc7d249ad8915671d738bf0646cc8", "manual" ], "wai-aria/rowheader_aria-colspan_2_on_div-manual.html": [ - "80d410187bb0a6384322f95bd27c967191fef80e", + "3a6b424100bc0e94a6970a18ff21a5be54931721", "manual" ], "wai-aria/rowheader_aria-rowspan_2_on_div-manual.html": [ - "af1896c0909c5c486a622f31a4a64a11cfa1bf1d", + "4b50fd0b4054963cfc2711e2b7c6987aba1ec75a", "manual" ], "wai-aria/rowheader_colindex_4-manual.html": [ - "a4468840e263a5bf7224e058e7099377f418fe09", + "84c0f043ee5f87fc478fce61055d8bf3c8bdc4a6", "manual" ], "wai-aria/rowheader_rowindex_4-manual.html": [ - "a832405f0127c6761ad76ffd5141e4361a85c4ee", + "f4b4d80cc2c804cd03f85db6e2f01408662922b1", "manual" ], "wai-aria/rowheader_selected_false_not_automatically_propagated-manual.html": [ - "4a57e83377abd3d66d3d8d26232e702b6b53e87f", + "1ac89c790fc77941821d5b25fa9f80bbc4512421", "manual" ], "wai-aria/rowheader_selected_true_not_automatically_propagated-manual.html": [ - "b5fbf74482276815c2df2d0bd78beadafd6bd804", + "adedbbf77b2b1881dc97e41365ede3159b7c0745", "manual" ], "wai-aria/scripts/ATTAcomm.js": [ @@ -574625,27 +582329,27 @@ "support" ], "wai-aria/scrollbar_all_values_unspecified-manual.html": [ - "c6b90c5767929eb353fc0670886650562ee6eae6", + "4fe8f7a1640e7343ee583991b5bf93467aa2df52", "manual" ], "wai-aria/scrollbar_only_valuenow_unspecified-manual.html": [ - "4f501f675fe735b7d32929764beccb87648bf25b", + "476de611a9d3437254cbb75aafe0b74fc2eb40de", "manual" ], "wai-aria/scrollbar_orientation_unspecified-manual.html": [ - "951dc98f02cd790fa6fa0c540e4d03a3a88173ae", + "0b232b5bf4c14c11ae57f90b533cfbaae559a7ad", "manual" ], "wai-aria/searchbox-manual.html": [ - "0138026be588d9279fe7e086e1d672ef0266abde", + "feb163a6b4c81d6c76381aeae8048ed5578151bd", "manual" ], "wai-aria/searchbox_activedescendant-manual.html": [ - "1f7614531432509aaedc910bae517bfa3bb0867c", + "dd14675cec701d0f5c06c8bf03d5837aeebe9a7f", "manual" ], "wai-aria/searchbox_activedescendant_value_changes-manual.html": [ - "0e5e9c0947ba355f832d15609a3b8a73ba7a61ad", + "a8de5f8f1116e4009d158fc2e0c4dc2ebf0b30c5", "manual" ], "wai-aria/searchbox_autocomplete_both-manual.html": [ @@ -574665,199 +582369,199 @@ "manual" ], "wai-aria/searchbox_autocomplete_unspecified-manual.html": [ - "e0a9bff6a5e9c0eec42f0e5e0f0ad905ff7ff953", + "a92974567bbb8a7762abbcc726393cad8ccece73", "manual" ], "wai-aria/searchbox_multiline_false-manual.html": [ - "699b2b06af38cd8be622ccc75b6d7fbe80ee0b6e", + "d75e8e7b1f0abee0ff159a5085d399c29c3b8973", "manual" ], "wai-aria/searchbox_multiline_true-manual.html": [ - "7bb4f2752ef7e03bb217e8e1b12f4a40b638bde1", + "ae24cec0788402b73330d86c80f0e1a91def537a", "manual" ], "wai-aria/searchbox_multiline_unspecified-manual.html": [ - "f2f175d68df0e97b598ed7a47d44a53cd87b5b19", + "492dc789fed40c60776f8dffa6022c7bb6ac5f36", "manual" ], "wai-aria/searchbox_placeholder-manual.html": [ - "0e92a02e93b59778595fc4b6d1847fad1040c924", + "e417f86e61db8cfcea05661654a53a6846c33f90", "manual" ], "wai-aria/searchbox_readonly_false-manual.html": [ - "fc1678fc0b32e648e8e7b9a7b63570b09ca8d360", + "074c62ee94902d39ae5c934f0e60efb9d7316e92", "manual" ], "wai-aria/searchbox_readonly_true-manual.html": [ - "adb59b597333f72b18ebd3f2a81832544254d9de", + "00c08ed1b329fd47a8c3f95147436c525e552201", "manual" ], "wai-aria/searchbox_readonly_unspecified-manual.html": [ - "65c71f924f6f39e7fea8176c4a3fc88fe188a8bd", + "ea8a4407904b1e3e0157007ac960cf2899a24c68", "manual" ], "wai-aria/searchbox_required_false-manual.html": [ - "24e7a5f334ae398fdd6f64233b3ce9211894cc5e", + "d0bc17a378163abe1763b868434a6e3f1b44f963", "manual" ], "wai-aria/searchbox_required_true-manual.html": [ - "c3e7a012036938ce5a4f4dc05a6f6bc0b7416b37", + "30dcd28acda9f5aa6554b63bd2a3017cbc1fa575", "manual" ], "wai-aria/searchbox_required_unspecified-manual.html": [ - "d34be4256f960a77708588f48ab1a9e79db9b60e", + "24e3b6cb84507de31c4583bb74752873eaa16258", "manual" ], "wai-aria/separator_focusable_all_values_unspecified-manual.html": [ - "f46996bb772c14320ea7e10cb8df4faf6bf9861c", + "eff36944c37a10d6aaef3667e6fb0dcd83eeb3ac", "manual" ], "wai-aria/separator_focusable_only_valuenow_unspecified-manual.html": [ - "8c559244f82b6d5ae1fc8ddacfb51d56cf26aa53", + "50270b9571dec5504619eed1b126d3930de113d1", "manual" ], "wai-aria/separator_focusable_valuetext-manual.html": [ - "09ab4cb8eaabb21f727965f880dc2b82c28a270f", + "46b37611b28860f380d4ae3ae5cf8e94f8ff58fe", "manual" ], "wai-aria/separator_orientation_unspecified-manual.html": [ - "9b453b2ca005003e705a0ee8449a16380220e67f", + "72cf219215e0f9602f305200b211d4b3f846e780", "manual" ], "wai-aria/separator_unfocusable_all_values_unspecified-manual.html": [ - "a9c2ed95d25b3bf5d80d1ddbbae44a16abadf235", + "de8a98e36d471c02024d5e51402f73ab4bd19747", "manual" ], "wai-aria/separator_unfocusable_valuetext-manual.html": [ - "f4a30a6c4302e52e626ac509d4f094d4b602f6ee", + "cb5ded5679f9dee5737bbe56aca270863885b9ed", "manual" ], "wai-aria/slider_all_values_unspecified-manual.html": [ - "d2db25aca78f1ceeefcdfffd12e7d2e1ef53faef", + "0a151a69f4b3eac15d9af37f65782ab63c9f80c6", "manual" ], "wai-aria/slider_only_valuenow_unspecified-manual.html": [ - "cd760f95d6c09bc1783c5b98511d3bffb03318f4", + "b9ef4db978d658eb6b3abd661987160cc845abb7", "manual" ], "wai-aria/slider_orientation_unspecified-manual.html": [ - "933b0fc2abab6066680289a7cab1fa0e301b2270", + "2ac72cd52bf16d3d82cd061297653110d5879be3", "manual" ], "wai-aria/slider_readonly_false-manual.html": [ - "ec57379556314d03d41b1ebc70452b00d5ab92e6", + "d8aa26c156de9f4a97a4a31cf115a570813811b8", "manual" ], "wai-aria/slider_readonly_true-manual.html": [ - "55beb79ef5f7022741306fea89f75a027b01abca", + "954d5fb2adc0429a240d48fb5c323e6228a30fc8", "manual" ], "wai-aria/slider_readonly_unspecified-manual.html": [ - "07ea9b783b15a51be94553da194f6b6db024433f", + "8a98ae32d296dc966833679d638dbaf7ae18995e", "manual" ], "wai-aria/spinbutton_all_values_unspecified-manual.html": [ - "729333014db5518140bb08f62975ab1c12a2f72b", + "cb8639bbf923f16a1d626e194e8ebfbbd684f9fc", "manual" ], "wai-aria/spinbutton_only_aria-valuenow_unspecified-manual.html": [ - "3730099c5a4509a410781c7f11ddac12f604a0dc", + "3674425097ac4819c6ba9c1177dfac2b4e561d69", "manual" ], "wai-aria/spinbutton_readonly_false-manual.html": [ - "44ee2f47d72e7f7df372f9841bd8049ab5696348", + "0403e092e86dcb6378453b0127a9b54e634b28de", "manual" ], "wai-aria/spinbutton_readonly_true-manual.html": [ - "78cbceb43c560e143a91b658bd8f050d9ab79883", + "47193688d79a6f9d46c22646b237a98eb5690fe1", "manual" ], "wai-aria/spinbutton_readonly_unspecified-manual.html": [ - "902d7279671f0ff0e4b73513af163e79ab0448e2", + "fbf40e53e2f991c6aaf515659bf71c6a090a92ac", "manual" ], "wai-aria/switch_checked_false-manual.html": [ - "9ee1f6b66ff6e43d213a8c996cd93c31b294b8d0", + "36c819b01b491f4ecdf6b84fd672699eb9c345b9", "manual" ], "wai-aria/switch_checked_mixed-manual.html": [ - "e5b099f54de006e948a935b8d98d911377b7ff31", + "f1a95385e6d02c40d8714fc0ae7c363ca92874e5", "manual" ], "wai-aria/switch_checked_true-manual.html": [ - "3366919521e536e6f9d3b6489c6a51d95f45b3e5", + "80360ed1af6019dbcf507ca9b2583f473ac292e5", "manual" ], "wai-aria/switch_checked_undefined-manual.html": [ - "5dfc172e54c67598ce4b0c0df1add788f9a99d5f", + "0cb7f30250e94a430a1d6a823dc56d123ff9a26d", "manual" ], "wai-aria/switch_checked_value_changes-manual.html": [ - "7f85dcd0690edb960ebd2b3adace2682ff614dd7", + "42f4203b9c3dda7512e628603c2989a096fb3200", "manual" ], "wai-aria/switch_readonly_false-manual.html": [ - "76e454316863a8c989b0ee5b2ccab7320674f3eb", + "8aaf6c375293c37f652b10de9887341c75aae74b", "manual" ], "wai-aria/switch_readonly_true-manual.html": [ - "3b54c61992fbdf640cd972a84a2ceb35be62ff17", + "35e4ed5ac27e810cfed0fc23383e1ca57663e0b5", "manual" ], "wai-aria/switch_readonly_unspecified-manual.html": [ - "95e6d14c9306e80b4415e3518d6beba1f6eaa08c", + "52979509b5daa2aa436e28d609dbb2e186e39320", "manual" ], "wai-aria/tab_posinset_and_setsize-manual.html": [ - "442fb6861b70e2566f758a9385a473aa6c15981f", + "561a5b5d3785e26252b633da3900fb88af0705db", "manual" ], "wai-aria/table_colcount_-1-manual.html": [ - "9ed42e5dc32bdbedfe1852ffd7cbd66ac37df0bb", + "b387f7abc0b1f6bb98ff075ff161dd73e0b694cc", "manual" ], "wai-aria/table_colcount_8-manual.html": [ - "d5aaadf2fecad13b133beea57edcd9f28543df75", + "2935a284b72da21579cf03dd6192becb85143f87", "manual" ], "wai-aria/table_rowcount_-1-manual.html": [ - "c96a3fb3b42852171d6f2bd8c49d34f287e90ed2", + "c537fa6393815df461dcf979fa2ffd2170e688db", "manual" ], "wai-aria/table_rowcount_3-manual.html": [ - "4bff8cd970877b57ddedcf1f71b40ded7dbd0a96", + "7a00f028a3fb4d57f27acdf0033120ac1621cc55", "manual" ], "wai-aria/tablist_orientation_horizontal-manual.html": [ - "8d28e4582bb14282f678d1864771ae454ca69891", + "2874e38a586fe85df586eb4f63fd1b47ee5b9691", "manual" ], "wai-aria/tablist_orientation_unspecified-manual.html": [ - "214c8fdb2eb888844f762d62e3551448d822fa35", + "0f476db12e0a08e8f9a59a92f91ce2321be8194e", "manual" ], "wai-aria/tablist_orientation_vertical-manual.html": [ - "273cf3ae78293cff630a04a90d7eac6aad2476a4", + "8114fc4112021e280b3ae0d4148099c9a274bbec", "manual" ], "wai-aria/term_role-manual.html": [ - "d7b1c0188f53083cfebd2d87c79b632396325169", + "8f6b3bfa5c5c2edcad6b5de867a957ffcd021999", "manual" ], "wai-aria/textbox_placeholder-manual.html": [ - "f9227242ec8f69d8380781be4be14c96f1a780af", + "d027578eb8bab6f98a45fa37ecebf54ddf7310bc", "manual" ], "wai-aria/toolbar_orientation_horizontal-manual.html": [ - "9134ff1b2b7d54ffdad94c777bd764f457e7b7c3", + "e1a0e1b40d281ccabfa66b50eb7c20c396d4c1e9", "manual" ], "wai-aria/toolbar_orientation_unspecified-manual.html": [ - "415df0e6f4e3873ef988cef4fe398bd32f825743", + "7b4b9bdc5997a34558b4db149ffd53f017933dbc", "manual" ], "wai-aria/toolbar_orientation_vertical-manual.html": [ - "53624df73eb9115bd3e57b8194d4bb23f8ce7d7a", + "dc6cf78657dacad6c2a547c07df672b147d03b2a", "manual" ], "wai-aria/tools/convert_wiki.pl": [ @@ -574869,47 +582573,47 @@ "support" ], "wai-aria/tree_orientation_horizontal-manual.html": [ - "95a3a84f9380386ad8b0050d8aa227fe9e584e39", + "6a8bfea8cb1970f9b1a3db6cf226b1cf2028a1cf", "manual" ], "wai-aria/tree_orientation_unspecified-manual.html": [ - "9df862f7bc55d7d003b3607eae80b941e8f82d17", + "3561b3619dbc9e8f501eed1ba11a641748090b04", "manual" ], "wai-aria/tree_orientation_vertical-manual.html": [ - "9d43cbb3cd327485e5228b9fda834dacf08e31b3", + "76339d1518a278b4ee2f101fd3aec2d5d6d49736", "manual" ], "wai-aria/treegrid_colcount_8-manual.html": [ - "9022552296ca199d57141412c0ff0b147f8404ba", + "0570ea3de9fe899cd7f235dd594e84f286ed01e2", "manual" ], "wai-aria/treegrid_orientation_horizontal-manual.html": [ - "6265daaff71fc45f8ca14b9b6f197a1d412e3d30", + "3040b777d962f2bdfb45ee45a6a12df6faa9bfc7", "manual" ], "wai-aria/treegrid_orientation_unspecified-manual.html": [ - "bdb06eadbb33032340bf43359196a9b8631e258e", + "790b9a0ad5f7200b6ada1c6b2c8b809e3a0a8449", "manual" ], "wai-aria/treegrid_orientation_vertical-manual.html": [ - "1c7923e0c408a40d2cbd42a5b29a1c56ffa19f48", + "2cf7399d1a07559a25b24e9444dfca83797a1056", "manual" ], "wai-aria/treegrid_rowcount_3-manual.html": [ - "cd96f68e1a1b06d46023cae8dba0141d562b049e", + "7dd93febb3cf0264e0806146f24fc01bc65db093", "manual" ], "wai-aria/treeitem_selected_false-manual.html": [ - "325e783812c348e3b2797fbe3335057972bed6b0", + "f8415c67231925ead8b95d4c1d0b99e70631a118", "manual" ], "wai-aria/treeitem_selected_true-manual.html": [ - "cce5c060e2e7ad826dcce7996cf4496e48874085", + "036b95e2f0c9c94e95889486b98d778254c1a600", "manual" ], "wai-aria/treeitem_selected_undefined-manual.html": [ - "d8a7dacf9e21a1f5b25b4f17f575270cf593abcb", + "cbc6184c2b9cd7ee1e45a99b9aef9849b383fced", "manual" ], "wai-aria/treeitem_selected_value_changes-manual.html": [ @@ -574925,27 +582629,39 @@ "testharness" ], "wake-lock/wakelock-api.https.html": [ - "a80557f44c8381495d80030ee8868153bfffd3da", + "7941cce9345916fbdafe3dd0b3edde680320b01c", + "testharness" + ], + "wake-lock/wakelock-applicability-manual.https.html": [ + "bbed9a382c8e9a9a26f7690b06fdbffc5ef4a794", + "manual" + ], + "wake-lock/wakelock-cancel-twice.https.html": [ + "a9850a6eb525af1c37e06686df1b8a075f2456f8", "testharness" ], "wake-lock/wakelock-disabled-by-feature-policy.https.sub.html": [ - "5ba667dc3f35e64b39be7cc938cf1cb93fc6f464", + "d3786da8619cfc0409f979235af29e587e4c41bc", "testharness" ], "wake-lock/wakelock-disabled-by-feature-policy.https.sub.html.headers": [ "199fe1ce290a8570204cc58027f7b808d7ef3500", "support" ], + "wake-lock/wakelock-document-hidden.https.html": [ + "ae8838e5fb164218f7dbf431546ed20b820f7c0c", + "testharness" + ], "wake-lock/wakelock-enabled-by-feature-policy-attribute-redirect-on-load.https.sub.html": [ - "bba2a95be9eeba9a4b67a9db92dc7d793fc26759", + "6f7fd8d684092ad53058a2bdfe4ae4070a18e290", "testharness" ], "wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub.html": [ - "37f30f21addedbe30955eefe22f65302a2a97ed5", + "ca6f005d18f1193fc1bc141d58e76248e93b66d8", "testharness" ], "wake-lock/wakelock-enabled-by-feature-policy.https.sub.html": [ - "ee3386a75ce86ebec42032712acde03ebc064eda", + "98b988fc7fd156c756c4c430f2c50cd0110a124a", "testharness" ], "wake-lock/wakelock-enabled-by-feature-policy.https.sub.html.headers": [ @@ -574953,23 +582669,35 @@ "support" ], "wake-lock/wakelock-enabled-on-self-origin-by-feature-policy.https.sub.html": [ - "328c6459efefdb2ed1f33522c8c51c5aa2aa1496", + "f928dc7732050e52152ccfb1c5a9a4282216b70f", "testharness" ], "wake-lock/wakelock-enabled-on-self-origin-by-feature-policy.https.sub.html.headers": [ "7a77973dc947ef10abe33be288fd610c42d96e97", "support" ], - "wake-lock/wakelock-object-is-independent.https.html": [ - "b104d9af062710134b69474008b583706eee7978", + "wake-lock/wakelock-insecure-context.html": [ + "527a75868eab39b899113cae81601630f9850790", "testharness" ], "wake-lock/wakelock-onactivechange.https.html": [ - "c85d61aca951edc5378028c1c120222683744de6", + "cbf4c5d6351e01ccc1a3e0e3e05afb16968a7edd", + "testharness" + ], + "wake-lock/wakelock-promise.https.html": [ + "2cf40b55e8875b3d2d0dc215f0547e9fc8c23389", + "testharness" + ], + "wake-lock/wakelock-state-is-global.https.html": [ + "7a8179b74d81b3ebda85aa440c183358b0ebe50b", "testharness" ], "wake-lock/wakelock-type.https.html": [ - "6fac8079855d7aedb52aee508cb866de51c41c0c", + "583647213b49b7bc67cad08192db3e6abcd1de9f", + "testharness" + ], + "wake-lock/wakelockrequest-is-independent.https.html": [ + "caaf2634451eb9228c0b20f0ac817d7a3d3fa685", "testharness" ], "wasm/compile_worker.js": [ @@ -574985,7 +582713,7 @@ "support" ], "wasm/many-memories.window.js": [ - "591b015662a6d181677892ec9c87f39bb36bbc23", + "84e98a89e653c39dab16e096286457268dccd195", "testharness" ], "wasm/resources/blank.html": [ @@ -575021,7 +582749,7 @@ "support" ], "wasm/wasm_local_iframe_test.html": [ - "dd715a4da792b9d8d634536d938b278230c66df5", + "e7b86a731b7cf7c122a1e37118cebce7342291fc", "testharness" ], "wasm/wasm_serialization_tests.html": [ @@ -575045,239 +582773,235 @@ "support" ], "web-animations/README.md": [ - "d6cb0e31dc3cc6d83b5051cee38a0b8e118fd43f", + "6344565e53b2f9e8d6ee7658d1c5c5670e68fc98", "support" ], "web-animations/animation-model/animation-types/accumulation-per-property.html": [ - "316dd15ce99cbfb5754c236210ac9e04dfc0c7ba", + "b26f3961d1913de731906ff0eed9a8548df7bbb2", "testharness" ], "web-animations/animation-model/animation-types/addition-per-property.html": [ - "24fae46b5f7b47e1d098fa446037bf9cc52e050e", + "c16ee3be3338bd5831ff3eab455cbf6943aa8d5b", "testharness" ], - "web-animations/animation-model/animation-types/discrete-animation.html": [ - "5a63e9f2a369a476f56e3b792928083e83fab7ec", + "web-animations/animation-model/animation-types/discrete.html": [ + "f3e48d8ddd42f1eecb36af2a8e1cfade6d0a02d4", "testharness" ], "web-animations/animation-model/animation-types/interpolation-per-property.html": [ - "55100f7d505bc8cbc966ced0d1337ed78534a553", + "2bcb2919b3034042d8a61d7af5de099a42386451", "testharness" ], "web-animations/animation-model/animation-types/property-list.js": [ - "6a1aafd6077aa656cfba4bba48f7ceca8344b810", + "7f20ed34cf9c72b53db3206639367eff69f0e226", "support" ], "web-animations/animation-model/animation-types/property-types.js": [ - "4b9e06fc9014110a711c590f866a149d31a9a6fa", + "ceaeb9c4a67019e68423f7cde888067c3384d756", "support" ], + "web-animations/animation-model/animation-types/visibility.html": [ + "da3370704ca9e83a1171a64320a240e3145fab2c", + "testharness" + ], "web-animations/animation-model/combining-effects/effect-composition.html": [ - "8ac06085132d822e908d48de4c1109b66323f19f", + "5d6c3904de02eb3b6c890163ccdc6b8cb6499e56", "testharness" ], "web-animations/animation-model/keyframe-effects/effect-value-context.html": [ - "10d9ee521240475a1729c2facfcea8b50342614e", + "da405e4bfc35d5d0b4c151706b09eb1a84d2f0da", + "testharness" + ], + "web-animations/animation-model/keyframe-effects/effect-value-iteration-composite-operation.html": [ + "bda186b311457e58c48ca5cf4619f485a41f8e2d", "testharness" ], "web-animations/animation-model/keyframe-effects/effect-value-overlapping-keyframes.html": [ - "a79db70a385ad767263f285c9401b66611087e42", + "2b10d6fb1cb925290caf57e4cefc3c3f8161777c", "testharness" ], "web-animations/animation-model/keyframe-effects/effect-value-transformed-distance.html": [ - "a0f0dc7d2f4833a68c6f8a5f908c498b05c6b22e", - "testharness" - ], - "web-animations/animation-model/keyframe-effects/effect-value-visibility.html": [ - "b01c7c5145c183fdca80dec4ca1966b0f72a7003", + "8fd7dbbaf98947f8101c760e41d9cc909c844d2d", "testharness" ], "web-animations/interfaces/Animatable/animate-no-browsing-context.html": [ - "3a5538db728127970721e20e3b2eaea59fac3afc", + "5c30bc76f60eb479cba967f91c6a80af7df8e2e7", "testharness" ], "web-animations/interfaces/Animatable/animate.html": [ - "99868d179c69091aa63631a27d98df4ee957a746", + "8d76a26de47494600da40e756a26de61329ff3aa", "testharness" ], "web-animations/interfaces/Animatable/getAnimations.html": [ - "92503fce725fcffce188df9c8e1da9d9ca281213", + "9c03f9a6410dc8463a3e3acb3b6e38c26d79b097", "testharness" ], "web-animations/interfaces/Animation/cancel.html": [ - "a28589129c6a2665295695f786b7beb2dd887fb3", + "38d509e24fa224fc8b937e4a63dd1c404e72b466", "testharness" ], "web-animations/interfaces/Animation/constructor.html": [ - "20604949fc295efc398e297b9e4f755a116f0fbb", + "f4dc4fdca61255557ed346412e134745bce1a3ed", "testharness" ], "web-animations/interfaces/Animation/effect.html": [ - "9e2551bfd9238ff99f30eabbd119a05fcf6dbeb9", + "4445fc8bd2120fb1e212dfc6a1fcf786a531ee6f", "testharness" ], "web-animations/interfaces/Animation/finish.html": [ - "61ab2a2d822c25f2311756baeaaa98b44c3b3a62", + "64acecec8528b4d241d5dcb9248ef82eafa02810", "testharness" ], "web-animations/interfaces/Animation/finished.html": [ - "5e3d8fa48b2737202f6bd7c2e21589e904982a6f", + "ffcba3379db7094455a7798e4d5972d8e52caec5", "testharness" ], "web-animations/interfaces/Animation/id.html": [ - "395dad4a877ef4af20649d6bcfece102a22b3059", + "4e3dd92351d76c5c7d09ddd1ca025520f4c8875d", "testharness" ], "web-animations/interfaces/Animation/idlharness.html": [ - "b9784215a32d3d00d9a2c17c115ec9048d67c779", + "989e773dbf3d7d57f26b41108bc3d7f0b3ea3168", "testharness" ], "web-animations/interfaces/Animation/oncancel.html": [ - "0477d2fef7fc64bbc969b29d4ba542574c4c3706", + "82abc08a0b416f5198239464fb4fc01d2edd6e1c", "testharness" ], "web-animations/interfaces/Animation/onfinish.html": [ - "43ecf628f6e7a6088ad4cc25e3a6468957049ae0", + "db82fabeaf2b646647f134634fef30f05e5ec7f8", "testharness" ], "web-animations/interfaces/Animation/pause.html": [ - "8cadcbc313fd6ed171298529c71d555cc2c43a2d", + "f044cc7ac09c38f127e399f7d6f9a0714046aa8e", + "testharness" + ], + "web-animations/interfaces/Animation/pending.html": [ + "5677f7e8b076dc096d636aaaa4d4191c286f1d90", "testharness" ], "web-animations/interfaces/Animation/play.html": [ - "0c8069de75d1c15f1d8167b433ad4c7e51f424db", - "testharness" - ], - "web-animations/interfaces/Animation/playState.html": [ - "9dda649e8c668b4afbc6e683e2d853622650796a", + "54edbdd6c0e1953f8d0e2bfbb92bfe318114ab74", "testharness" ], "web-animations/interfaces/Animation/playbackRate.html": [ - "d0c73c24ed6ea6d43565ef81a3b200336a2133cd", + "27d289f603953b3e39322287fb2a55f84dd8dc54", "testharness" ], "web-animations/interfaces/Animation/ready.html": [ - "b23b76881f4d38c07710d0e59c1f6c8569de9060", + "bd4a18205791b2b0271a6266dba3ebc8482c835b", "testharness" ], "web-animations/interfaces/Animation/startTime.html": [ - "284d55c141e4a93def32393577888ffc215a8b15", + "01f669542434f03d37e9f148a4f3135fe3122d46", "testharness" ], "web-animations/interfaces/AnimationEffectTiming/delay.html": [ - "ee2d870fae13e77e500e7067b89dbb79bd2d209a", + "4de5b0a692d645961de27df67efa8257adb0a031", "testharness" ], "web-animations/interfaces/AnimationEffectTiming/direction.html": [ - "87eb8b9a7b954e0eb77566eefb3034cd6235296f", + "11398d5ea40bb4137b4f5d4e6e6238af64caf3c5", "testharness" ], "web-animations/interfaces/AnimationEffectTiming/duration.html": [ - "54858f64784c74a3d112e559fb765a1dbb9ba279", + "315810a1e73f9b4ef2cffea868fb766af5ee5c93", "testharness" ], "web-animations/interfaces/AnimationEffectTiming/easing.html": [ - "a4b8b1c715795d5e66c0e32c2415a2e8fb587147", + "b3ad4c78c9bce0e17db0ce780cd1260de1ce7cb0", "testharness" ], "web-animations/interfaces/AnimationEffectTiming/endDelay.html": [ - "fde46c549f70439c80e3990ebf6897d6d6dfb76e", + "b36d9c8a4e4082e6a75ac5d8f336cf474cd75aab", "testharness" ], "web-animations/interfaces/AnimationEffectTiming/fill.html": [ - "adc56d3ce3595154045cb87e1cb89fe7ce2096ba", + "1cef601cde33eea3b591a0826ad52f379bb31d0d", "testharness" ], - "web-animations/interfaces/AnimationEffectTiming/getAnimations.html": [ - "83175d02d1a09e91189fab2ccb19f8e0f242cb2a", - "testharness" - ], - "web-animations/interfaces/AnimationEffectTiming/getComputedStyle.html": [ - "28819fe9fe3d38ae6d4aa2b4db4f58e8a16f0588", + "web-animations/interfaces/AnimationEffectTiming/getComputedTiming.html": [ + "020e9faaae05de5a25829a05558ea72672b04f63", "testharness" ], "web-animations/interfaces/AnimationEffectTiming/idlharness.html": [ - "a4e72d3ebf93a0bb6934f887c3da250a2ab67b63", + "aa9823e5a06c76921b49aa5f5e61fd1dedfac3af", "testharness" ], "web-animations/interfaces/AnimationEffectTiming/iterationStart.html": [ - "05e327706937df8319e3a8c655ee743a15902ecd", + "734743adeec628da907ea2f6cc4ae3be3aab7329", "testharness" ], "web-animations/interfaces/AnimationEffectTiming/iterations.html": [ - "9a6eae75862dec36b7839dc68edc31891a651284", + "c8705eb209d8a4912b5d3fd94a05c763b7707eca", "testharness" ], "web-animations/interfaces/AnimationPlaybackEvent/constructor.html": [ - "1bc5f4dda96078a08a4b06ab0f6bf7b10e0acce3", + "5aff03b7fa469e5ec0dc02a389eca963ae24b470", "testharness" ], "web-animations/interfaces/AnimationPlaybackEvent/idlharness.html": [ - "37bd201a374913d0cd580b89b07688b5b655776d", + "bfdfc896fb5fe4451419464e35fe94b5e4938c2c", "testharness" ], "web-animations/interfaces/Document/getAnimations.html": [ - "bd39d7f28dd03ba22a32ce09226dc263180254eb", + "12fdbce3e75f5a7d7771d9337089255ef73f9712", "testharness" ], "web-animations/interfaces/Document/timeline.html": [ - "65303d138e6b9afdb5b28117ef8e1c6ba35903e3", + "2577a2d5c89fa0eec3cae2fd07b66e576ee6a483", "testharness" ], "web-animations/interfaces/DocumentTimeline/constructor.html": [ - "3a626b145f4eb77e816b9020f6fc67630088a00b", + "b11caf0a1766818a168a7f91b01ccd6ae9a7e4f0", "testharness" ], "web-animations/interfaces/DocumentTimeline/idlharness.html": [ - "fde7ae3f320a94619c9bb879d77d1de392212846", + "72cb7900f86611e9c2a1b0f4acd0f634555310b9", "testharness" ], "web-animations/interfaces/KeyframeEffect/composite.html": [ - "2580086b2da9b29d1645484c5ad4e59636a370e5", + "7dd18327d8da81914adaf443086891ba3646d882", "testharness" ], "web-animations/interfaces/KeyframeEffect/constructor.html": [ - "54a4185fd23ac4b3afe010157d4b8b766483d8f6", + "4a80ea073da0a9c62dcb9587676445a2fba234e1", "testharness" ], "web-animations/interfaces/KeyframeEffect/copy-constructor.html": [ - "65047bfed537a69659851a9fcdd7fb2ba5c4f790", - "testharness" - ], - "web-animations/interfaces/KeyframeEffect/getComputedTiming.html": [ - "c9dcf7c17010e5495007e000b33aeb4dc89f92b7", + "6ef462ddc696269f132d596188ffd5e8da1e1164", "testharness" ], "web-animations/interfaces/KeyframeEffect/idlharness.html": [ - "d51dfde748bfdf12a1b06452099ea74fe2951a34", + "f05c9bd1cdee77ff6be143b0eb4f982c7218908b", "testharness" ], "web-animations/interfaces/KeyframeEffect/iterationComposite.html": [ - "2ed50cdb27335345015d8b13c64ef86c67048757", + "65cd746596a6770d1101b030769712be433bf6f3", "testharness" ], "web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-001.html": [ - "83e58d986208b6cbc51e4124a2b17269a26e0520", + "165b651cea12ab9e0825f4335e7f697ce1fc6247", "testharness" ], "web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-002.html": [ - "38b350320a08cc2a9ae4449944eea427bfbe6f9d", + "e9237e244034845f6f902f8149a0e66e5b6164f2", "testharness" ], "web-animations/interfaces/KeyframeEffect/setKeyframes.html": [ - "477e983fcef02361c305918d10a67f2909cfa561", + "a346e0e004010a6f51e06ffd30d0b6eddd45421d", "testharness" ], - "web-animations/interfaces/KeyframeEffect/setTarget.html": [ - "8c75e6605a134c96e261e5383414b7e15b32d121", + "web-animations/interfaces/KeyframeEffect/target.html": [ + "94bad3b00de7591e9faa7bd479a457b7b76f76b5", "testharness" ], "web-animations/resources/easing-tests.js": [ - "c255d606d00296b4c6957435773a20a9d8d0bd0b", + "77f747cef865fd5eba6ea621881706f801c812c0", "support" ], "web-animations/resources/effect-tests.js": [ - "5cdc52caac1d1db2249155e91591c983a746102e", + "2eb26f4cb0e65282b8e82014ac8ebe87a4209c6a", "support" ], "web-animations/resources/keyframe-tests.js": [ @@ -575293,79 +583017,83 @@ "support" ], "web-animations/testcommon.js": [ - "d057ad66c4561ef32f83770e4948f2019da89d48", + "94130b39fda8e95ca495d297f9d47eefa6430a04", "support" ], "web-animations/timing-model/animation-effects/active-time.html": [ - "42eb1a23e89ae60ccd0a3664a9a583df1eb30d49", + "68ca985984ed6f868cebb539dfde6d7ddba6c824", "testharness" ], "web-animations/timing-model/animation-effects/current-iteration.html": [ - "a83e4dbd359774de7e6dbea4ae0b8d28d16d62e5", + "617bfd8c533d159c4e56ea823917d580fe262bf6", "testharness" ], "web-animations/timing-model/animation-effects/local-time.html": [ - "4b24cf2374a690395398f8caed9d340667dd0a9d", + "cd76b6be13cba0bc7d3b1a0e87b70c6a66222f40", "testharness" ], "web-animations/timing-model/animation-effects/phases-and-states.html": [ - "ce3652c8a6fdd8a6019fd665bca28ed725bacd71", + "3edd2c4bdd8409c2c12f08bc998dd8d532e0fd7d", "testharness" ], "web-animations/timing-model/animation-effects/simple-iteration-progress.html": [ - "521524358dabafea8e78c36829f9cd7d4115400a", + "602fe7e6880e0b18329262699872c696f451d744", "testharness" ], "web-animations/timing-model/animations/canceling-an-animation.html": [ - "079bc0e0f7ea60b94999ed1b4f92c1aa2fc2c7bb", + "d82cbc5caf654b9811c90d5165fb0429891cb149", "testharness" ], "web-animations/timing-model/animations/current-time.html": [ - "b1ea8e490cbfb69fd71b91a90e7e2d9ce99f42d3", + "390e2ba8d6de9bfea5f26cd2e7a42ccdf73f1a35", "testharness" ], "web-animations/timing-model/animations/finishing-an-animation.html": [ - "570ec579c6118866b888b1384e21977c9cfb0ec0", + "8d430adcb97bf3dab9703bc2d31be23e1adaec85", "testharness" ], "web-animations/timing-model/animations/pausing-an-animation.html": [ - "a000d8f86fa62b90ec7a60c289066aaaa1758377", + "c46fbcb8bc40fc3ee26e10802a205926ab97a84f", + "testharness" + ], + "web-animations/timing-model/animations/play-states.html": [ + "3ec76eff991e306699b21fb03bc1f346ffd9cee3", "testharness" ], "web-animations/timing-model/animations/playing-an-animation.html": [ - "2b4f51977d43f9bf90c066bfcc57728ae096b6e9", + "6ee1b850154ce22fffafa686fc2fdfef9dded38b", "testharness" ], "web-animations/timing-model/animations/reversing-an-animation.html": [ - "2b5631893d0d0846e5e57097ce4ae54dfa8a03e3", + "3afdb3cc9a9dafb28ebe46902276c19c24aeb9a8", "testharness" ], "web-animations/timing-model/animations/set-the-animation-start-time.html": [ - "84afa495b1a4c467e27b1394f6449a18c58ed98d", + "10fea7d0b0dbe046d72b4048607816c9ebe37f7f", "testharness" ], "web-animations/timing-model/animations/set-the-target-effect-of-an-animation.html": [ - "840be610db4bce6d6fd1c22710e494a75ee95eba", + "3b7f1f60cd771ff8587daf7ab76ccbecff59f781", "testharness" ], "web-animations/timing-model/animations/set-the-timeline-of-an-animation.html": [ - "6e8e029f813046c3da69b4ff0c9d03d2a56b38a4", + "ef8ce243226296718453e10d89b4cfd68b2d765e", "testharness" ], "web-animations/timing-model/animations/updating-the-finished-state.html": [ - "266f1b793aa74a59486081f3ba8f6cbb482e714b", + "c30161f7d5a20db616ade354133ae6a8989d149f", "testharness" ], "web-animations/timing-model/time-transformations/transformed-progress.html": [ - "66e2277c77e4bd7b2d8981a725fb5083a8f5e0f6", + "2e55f43def584a67eeb313f050154cd146002938", "testharness" ], "web-animations/timing-model/timelines/document-timelines.html": [ - "cfa1e9ab84cb4901068e6305f69d8987cdda69cd", + "d0fcb390c19c9ede7288278dc11ea5b3d33671cb", "testharness" ], "web-animations/timing-model/timelines/timelines.html": [ - "6f0a9efcce6d5438996b650c022d6723dbccf58b", + "29d7fe91c355fc22f563ca17315d2ab493dc0566", "testharness" ], "web-nfc/OWNERS": [ @@ -575545,7 +583273,7 @@ "support" ], "webaudio/resources/audit.js": [ - "20b0d0bc30f4d0f41828f579b4dd4f71a60fcde4", + "1e7c1c4169bc54bd2046ff5b3392f846c6b7b40f", "support" ], "webaudio/resources/sin_440Hz_-6dBFS_1s.wav": [ @@ -575801,17 +583529,13 @@ "testharness" ], "webdriver/OWNERS": [ - "4986cd1bfa1e4c8e5c836581871745b5b2cc440e", + "020bcd036daed8eb8928c2924ea1d04050cf1939", "support" ], "webdriver/README.md": [ "185acb69e9516e0564e16bf7d7f8dc2a4c48d3c7", "support" ], - "webdriver/interface/interface.html": [ - "ff6f1ffa851eed97a5a2ba4e247058bc3982111e", - "testharness" - ], "webdriver/tests/__init__.py": [ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" @@ -575828,16 +583552,24 @@ "d589b53f0096893600e696b43ec19ca84e5ee2ab", "wdspec" ], + "webdriver/tests/actions/key_shortcuts.py": [ + "dbe27dd0b1625169fc8cc2055f8fb49d5a4a78d2", + "wdspec" + ], "webdriver/tests/actions/modifier_click.py": [ - "2ec22f44973e6da3b9506ad7cc9fd0949f3ef8b5", + "88a384182fdd9df1515b9d8cfda8f56aed138ec7", "wdspec" ], "webdriver/tests/actions/mouse.py": [ - "c3cf09eaad1f24b2946c0ef865b10c5ac2e52700", + "0af689cee458ed260b2b9cc6f3231c314a3a6638", + "wdspec" + ], + "webdriver/tests/actions/mouse_dblclick.py": [ + "61bab159bf1ccc7d44e4034a3e67d60b13fc1607", "wdspec" ], "webdriver/tests/actions/sequence.py": [ - "8c948c12cea1e2e8f2de845555817910904f757a", + "d43caf0f8607a76c3baed7806664b686bde21fda", "wdspec" ], "webdriver/tests/actions/special_keys.py": [ @@ -575849,7 +583581,11 @@ "support" ], "webdriver/tests/actions/support/keys.py": [ - "636991372c21e52b623ed4ada9dfb675dd7f7e14", + "528ab8473914c14f9671d89b8a888d30162714ec", + "support" + ], + "webdriver/tests/actions/support/mouse.py": [ + "0a6fca5e3fe20db114dbee1dd9d290ec343f6f9c", "support" ], "webdriver/tests/actions/support/refine.py": [ @@ -575877,7 +583613,7 @@ "wdspec" ], "webdriver/tests/cookies/add_cookie.py": [ - "8da2db1e4d4110fd4bd5705b8e36f35a3dea049a", + "c58e50480aa3189bd4f1c52050cff6fcfcdf8d8b", "wdspec" ], "webdriver/tests/cookies/delete_cookie.py": [ @@ -575885,19 +583621,75 @@ "wdspec" ], "webdriver/tests/cookies/get_named_cookie.py": [ - "9455d1504590154ad2a540f102455baff602aefb", + "12e1f83275fbfe6926380b267689fbfa55d6b93a", + "wdspec" + ], + "webdriver/tests/document_handling/page_source.py": [ + "5dddfce0a5e43f02b8a050afda8c9a07c43cf797", "wdspec" ], "webdriver/tests/element_click/__init__.py": [ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" ], + "webdriver/tests/element_click/bubbling.py": [ + "5437f5ca12b93e9a0087e9b341d63af6bace4ffd", + "wdspec" + ], "webdriver/tests/element_click/select.py": [ "5ba51b660c7203bba3ada597c2f56fe094358e1f", "wdspec" ], + "webdriver/tests/element_click/stale.py": [ + "37af63203540dfe11d36fe05d74694f05c6505f2", + "wdspec" + ], + "webdriver/tests/element_retrieval/__init__.py": [ + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "support" + ], + "webdriver/tests/element_retrieval/find_element.py": [ + "699b97bd31eed625e2f0bed145aaf94c3e646853", + "wdspec" + ], + "webdriver/tests/element_retrieval/find_element_from_element.py": [ + "34f356f2579391289edb31adf5b4d4eb88ffc643", + "wdspec" + ], + "webdriver/tests/element_retrieval/find_elements.py": [ + "284ae53c5c94d02fb46b26dcd70af02d7917e7b4", + "wdspec" + ], + "webdriver/tests/element_retrieval/find_elements_from_element.py": [ + "b062b9f044268f0d9e092def81afae1277a91cd8", + "wdspec" + ], "webdriver/tests/element_retrieval/get_active_element.py": [ - "74bb0beec41ab857f6814d47191f29065a536802", + "7d40a7641dbf04cd78f1dba630afa2e8d80dad13", + "wdspec" + ], + "webdriver/tests/element_send_keys/__init__.py": [ + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "support" + ], + "webdriver/tests/element_send_keys/interactability.py": [ + "bd7cd6c009c86fe93c0e132c30fb9674413962d4", + "wdspec" + ], + "webdriver/tests/element_send_keys/scroll_into_view.py": [ + "fb192d5d1d93aa729b07cadcadfa630587bd0b39", + "wdspec" + ], + "webdriver/tests/execute_async_script/user_prompts.py": [ + "e31edd4537f9b7479a348465154381f5b18f938c", + "wdspec" + ], + "webdriver/tests/execute_script/cyclic.py": [ + "cbebfbd2413ea0b10f547ab66fcc7159898e684a", + "wdspec" + ], + "webdriver/tests/execute_script/user_prompts.py": [ + "901487f8270dcce693867ca090393e093d26f22b", "wdspec" ], "webdriver/tests/fullscreen_window.py": [ @@ -575905,11 +583697,11 @@ "wdspec" ], "webdriver/tests/get_window_rect.py": [ - "5d907b2a16b9ff7dba8e39bba19ea7f85f29f71e", + "c9139c16aa950c734c776887d6a762b867790812", "wdspec" ], "webdriver/tests/interaction/element_clear.py": [ - "c8b700458df1767111f6648b6c1388ecd87555bb", + "9b598e993e404275f1fe4bdb1967d8e1950e25cb", "wdspec" ], "webdriver/tests/interaction/send_keys_content_editable.py": [ @@ -575917,7 +583709,7 @@ "wdspec" ], "webdriver/tests/interface.html": [ - "d783d0dd370f58b264ef238d8da5cd8601dc3c7f", + "6625887cfa7f461dc428c11861fce71c47bef57d", "testharness" ], "webdriver/tests/minimize_window.py": [ @@ -575925,33 +583717,13 @@ "wdspec" ], "webdriver/tests/navigation/current_url.py": [ - "cec2987258d9c807a247da9e0216b3af1f171484", + "828e40301838c99aa2978733bbce3db3acc185a0", "wdspec" ], "webdriver/tests/navigation/get_title.py": [ "2ee18932a8ae3c4190b37e2b28141a6af49cc507", "wdspec" ], - "webdriver/tests/retrieval/__init__.py": [ - "da39a3ee5e6b4b0d3255bfef95601890afd80709", - "support" - ], - "webdriver/tests/retrieval/find_element.py": [ - "2a4cdf4c703493f7c90fc3473daa27660ac61e11", - "wdspec" - ], - "webdriver/tests/retrieval/find_element_from_element.py": [ - "f036ef93adff21a7c83eeb8b131c96b6553b9fcb", - "wdspec" - ], - "webdriver/tests/retrieval/find_element_from_elements.py": [ - "131c25ffbde611f98e29b778d7c861ae9619b2f6", - "wdspec" - ], - "webdriver/tests/retrieval/find_elements.py": [ - "2d5c3c98b00e21a36f91e5797bb97835a8b63f2e", - "wdspec" - ], "webdriver/tests/sessions/get_timeouts.py": [ "eaee354d16aa8c3a0fc960198fa4c5d9365bdee5", "wdspec" @@ -575992,6 +583764,10 @@ "440d88462cc418e4d5e1df6f73074d3a722bd2fd", "support" ], + "webdriver/tests/sessions/status.py": [ + "75edf0e629d9cd494c63585408c76217ff953722", + "wdspec" + ], "webdriver/tests/set_window_rect.py": [ "8a124f80e6e7732a651a80da3f6cdf8e2ed99e3e", "wdspec" @@ -576024,20 +583800,16 @@ "570274d59020c4d8d0b8ecd604660ee7d710a165", "wdspec" ], - "webdriver/tests/status.py": [ - "5d3ae3da2967072dff274f384cceaecc07b6aa4b", - "wdspec" - ], "webdriver/tests/support/__init__.py": [ "5a31a3917a5157516c10951a3b3d5ffb43b992d9", "support" ], "webdriver/tests/support/asserts.py": [ - "fd28bb9531b1644b726b7baba00a09871bd0dd3f", + "68bb420a9d85810c9fd8b6eaa569b855dfb83638", "support" ], "webdriver/tests/support/fixtures.py": [ - "765dd3821da0724024cdd61523f3d2fd79e8be28", + "b9b62366cd60ae7167ad2d0efdf3790ae2e780a4", "support" ], "webdriver/tests/support/http_request.py": [ @@ -576053,7 +583825,7 @@ "support" ], "webdriver/tests/support/wait.py": [ - "a4b0c9c340ea7055139d9fcab3246ee836d6a441", + "511d4ba0ff21325b7503440b4111fac325139edc", "support" ], "webdriver/tests/switch_to_parent_frame.py": [ @@ -576061,19 +583833,19 @@ "wdspec" ], "webdriver/tests/user_prompts/accept_alert.py": [ - "30aa726664c6228dd5901bef862d3d55b3474e41", + "9cd5e82f18455062ec07a5c8a0bef31cfe4ea86f", "wdspec" ], "webdriver/tests/user_prompts/dismiss_alert.py": [ - "bf75a630194dee1d619cb2818d71f9fb06a5dbbc", + "f200db4350a738fc14c9aed853fd3011141e8f3a", "wdspec" ], "webdriver/tests/user_prompts/get_alert_text.py": [ - "2eabe61f38757fd377e9773b7697a9a1ed21ceb6", + "5547f710db1787eb44454988d32a4b52c758e9c2", "wdspec" ], "webdriver/tests/user_prompts/send_alert_text.py": [ - "16d3219eb2404c06e7a6574508a789cb842fc89b", + "e6878e7923b1cdddff2450057020de0bf2e6aa7c", "wdspec" ], "webgl/bufferSubData.html": [ @@ -576213,7 +583985,7 @@ "testharness" ], "webmessaging/event.origin.sub.htm": [ - "68a1bfc42c565f9ec482fbc539f8d3f2ac78e413", + "ef14b99d3eac8c17623f3ba531605fa2abda99d7", "testharness" ], "webmessaging/event.ports.sub.htm": [ @@ -576549,11 +584321,11 @@ "testharness" ], "webrtc/OWNERS": [ - "afb3b4b35f06e38d392fc2ffd57025471a03eec1", + "b9739bfca307233dd72555b30e8492d47680d2af", "support" ], "webrtc/RTCCertificate.html": [ - "95e54d7fb8b37b9f1719137a4245cb25263336e0", + "cc1191d16707c4a5126291850414800cacb76199", "testharness" ], "webrtc/RTCConfiguration-bundlePolicy.html": [ @@ -576573,7 +584345,7 @@ "testharness" ], "webrtc/RTCConfiguration-iceTransportPolicy.html": [ - "f95cceffe7485aac7b53d3f891ad87d50ccc8b1d", + "a3cdf93a5c3da4552c616f43e1fca01b9261dd38", "testharness" ], "webrtc/RTCConfiguration-rtcpMuxPolicy.html": [ @@ -576581,7 +584353,7 @@ "testharness" ], "webrtc/RTCDTMFSender-helper.js": [ - "0c2e8862deffeec71ac925642647bb9ee4ad70ff", + "205469a5d95d35c0cdc091afafa49ecaccac7e2d", "support" ], "webrtc/RTCDTMFSender-insertDTMF.https.html": [ @@ -576613,7 +584385,7 @@ "testharness" ], "webrtc/RTCDtlsTransport-getRemoteCertificates.html": [ - "76eb9e89291ce2aa8fa81dd7216a853193abd6e2", + "7d6ea59253879cac114e2a7b162fa67926a39635", "testharness" ], "webrtc/RTCIceCandidate-constructor.html": [ @@ -576633,7 +584405,7 @@ "testharness" ], "webrtc/RTCPeerConnection-addTransceiver.html": [ - "d4f7108629c221c95fcaafa554ecd820c27a6922", + "c2d5766daa3ea4050ccb2777d7c08af1a1bd176f", "testharness" ], "webrtc/RTCPeerConnection-canTrickleIceCandidates.html": [ @@ -576645,7 +584417,7 @@ "testharness" ], "webrtc/RTCPeerConnection-constructor.html": [ - "2152cb1835b1afe939504e934a7f19d30b17ba3d", + "c229347757f56d239925915ed9e6227086e75b84", "testharness" ], "webrtc/RTCPeerConnection-createAnswer.html": [ @@ -576653,7 +584425,11 @@ "testharness" ], "webrtc/RTCPeerConnection-createDataChannel.html": [ - "0e2c9ab2b4900aa7955d75f867bb5958c7c70ce3", + "102de47ea13e20fe6d196077e47a525911957a00", + "testharness" + ], + "webrtc/RTCPeerConnection-createOffer-offerToReceive.html": [ + "91905d7efc95500ebba085ca4b1fc682a496e228", "testharness" ], "webrtc/RTCPeerConnection-createOffer.html": [ @@ -576673,7 +584449,7 @@ "testharness" ], "webrtc/RTCPeerConnection-getStats.https.html": [ - "1fc0c03ebd989d77c9d721b027a12a0cbbf24d53", + "9446d7bc1aefa7edd28b425415d983d69311e0ca", "testharness" ], "webrtc/RTCPeerConnection-getTransceivers.html": [ @@ -576692,10 +584468,6 @@ "ed3226f9673bc0b69c2a9f9ec6e1ccfa8e83e2e2", "testharness" ], - "webrtc/RTCPeerConnection-idl.html": [ - "9d67664cde55f701e2b15c0e801e79a5bd16110a", - "testharness" - ], "webrtc/RTCPeerConnection-ondatachannel.html": [ "6096ee14d729894e39eb2217828e8b0a5abc7f19", "testharness" @@ -576709,7 +584481,7 @@ "testharness" ], "webrtc/RTCPeerConnection-peerIdentity.html": [ - "2e6808671da699ad3a61f7ebd766b92686ddb17c", + "1cc5702e0aee887d925d2bf3471ac759d7430874", "testharness" ], "webrtc/RTCPeerConnection-removeTrack.https.html": [ @@ -576757,7 +584529,7 @@ "testharness" ], "webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html": [ - "f309fe97cd3954e5f2b337e16f48339d3bb359bd", + "16fe3b155e55d1b66181788c93e570b36e5cc67d", "testharness" ], "webrtc/RTCPeerConnection-setRemoteDescription.html": [ @@ -576769,7 +584541,7 @@ "testharness" ], "webrtc/RTCRtpCapabilities-helper.js": [ - "f66e7842a8b761612e40ef1a825357d9e21d5af5", + "22881ddd3cda1a64ff22474562de1568522e9745", "support" ], "webrtc/RTCRtpParameters-codecs.html": [ @@ -576824,8 +584596,8 @@ "27f083617973770f0d42efb93813f0112fc68ad2", "testharness" ], - "webrtc/RTCRtpSender-getStats.html": [ - "9a95fe0a2bd44fda187b586303a95dd5eb7db0cf", + "webrtc/RTCRtpSender-getStats.https.html": [ + "5c480c0d64de4e3ee041b95e5ccaec6264b878b8", "testharness" ], "webrtc/RTCRtpSender-replaceTrack.html": [ @@ -576848,12 +584620,16 @@ "b92f3acf5113a475b58892f48406aafc9634be07", "testharness" ], + "webrtc/RTCSctpTransport-maxMessageSize.html": [ + "95a1a701ff1ea46c782131dcd2012d3b4d5d57d2", + "testharness" + ], "webrtc/RTCStats-helper.js": [ - "8fa8b228d3b6ee861c843a5f6b7aa2a1c8260763", + "1c18bc44f5694a5a273807c06b7ab8f025dd1530", "support" ], "webrtc/RTCTrackEvent-constructor.html": [ - "a73dde79625035cdd40d5abd8856cd44161dfdf9", + "4e9060c8c67de3a13f9d5727a8140a8ecfb8dfbf", "testharness" ], "webrtc/coverage/RTCDTMFSender.txt": [ @@ -576872,10 +584648,6 @@ "56a37968e489d6ee39a1234ca888dd628f17648e", "testharness" ], - "webrtc/datachannel-idlharness.html": [ - "a1753a9a537a626775194ccc5dfdbf6829c5df35", - "testharness" - ], "webrtc/dictionary-helper.js": [ "9a43fcdfda7da1c281cbb221d1c463d1e280ee3a", "support" @@ -576908,6 +584680,22 @@ "6194af79f137d59334da2193cc6f24b9458344be", "testharness" ], + "webrtc/tools/.eslintrc.js": [ + "ceb052e89c7e9bef32fd37942515b2d38d59d269", + "support" + ], + "webrtc/tools/README.md": [ + "4a7dfd32e2129c362e153a83e4645fcc77b74247", + "support" + ], + "webrtc/tools/package-lock.json": [ + "731c41b82c17db5d5c3e0c636c197fcba01df344", + "support" + ], + "webrtc/tools/package.json": [ + "67474f98b40d247ebac9cdee2146019a8e0b10b1", + "support" + ], "websockets/Close-1000-reason.htm": [ "a3733fc46f0a5358cc8dbfd74d422e1a598bdf64", "testharness" @@ -577245,7 +585033,7 @@ "testharness" ], "websockets/constants.js": [ - "d1aff62046b7ade8beb6bb762adc3a7871b3c71f", + "18bf7dad370e0dbe3cdc3d738448ebae87673b35", "support" ], "websockets/constructor.html": [ @@ -577432,6 +585220,10 @@ "b9faa29fb3d2bff4a373f0baf3b9c1e95b091f26", "support" ], + "websockets/handlers/referrer_wsh.py": [ + "b3eba9c69741d3d542129ba89f49acab76df89dc", + "support" + ], "websockets/handlers/set-cookie-secure_wsh.py": [ "30b03b63d7b12371f6283ed89f967d2ffb66e372", "support" @@ -577481,7 +585273,7 @@ "testharness" ], "websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-defineProperty-getter.html": [ - "466630e990131ebf0b1cd5df8f992a40e52eb6f2", + "bbc86a74509e00ca248826c853d3cf5c9270b06f", "testharness" ], "websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-defineProperty-setter.html": [ @@ -577788,6 +585580,10 @@ "bf330ce240331f39f78a34f638119d5f7b434347", "testharness" ], + "websockets/referrer.any.js": [ + "3d855fd4f80ce7a30e4eb601fb5ba1ca640a114d", + "testharness" + ], "websockets/security/001.html": [ "4de87e1c2660aa70754059971045ca86a6417ae5", "testharness" @@ -577961,7 +585757,7 @@ "support" ], "webstorage/idlharness.html": [ - "9eec3559fc7cfba33bbeb280c392ee0af9d6755b", + "e57413a1868e8d84ba7c500ff13b7e68675cbe66", "testharness" ], "webstorage/missing_arguments.html": [ @@ -578205,7 +586001,7 @@ "support" ], "webvr/idlharness.html": [ - "ef6ad8bff43a6423b9b3e7deb8017a8b3fa0c112", + "3505e27e1b2668010bf61f05f6b8a759cf42cece", "testharness" ], "webvr/webvr-disabled-by-feature-policy.https.sub.html": [ @@ -578260,6 +586056,10 @@ "e88f3e9ddc5a5d4d9597403e8f7ef01d1daa339a", "support" ], + "webvtt/api/VTTCue/constructor-exceptions.html": [ + "0d7efaa2a234a5913412890517fa4722922c08ea", + "testharness" + ], "webvtt/api/VTTCue/constructor.html": [ "c844f513868cbf4053c70f37bbb630b53a763a2a", "testharness" @@ -578652,6 +586452,10 @@ "527b1f144e3af92dddb0746afff4cffc6004a08d", "testharness" ], + "webvtt/parsing/file-parsing/tests/regions-edge-case.html": [ + "dfb3f01d6f6fcb175426446f347fa31f129b42d1", + "testharness" + ], "webvtt/parsing/file-parsing/tests/regions-id.html": [ "b795ab2a5e12895569d24c2828b265d6f9d296fb", "testharness" @@ -578768,6 +586572,10 @@ "f25f0892d6da6d7268a7bbc271c6f1a74924d076", "support" ], + "webvtt/parsing/file-parsing/tests/support/regions-edge-case.vtt": [ + "1c5034a082535379df1ef67978bf97486d53e61e", + "support" + ], "webvtt/parsing/file-parsing/tests/support/regions-id.vtt": [ "8cf754c33225fe4cf905bf5b2198a9e30fa8ec67", "support" @@ -581036,10 +588844,50 @@ "f2372a492268a1b17763a42a808351128128fd89", "reftest" ], + "webvtt/rendering/cues-with-video/processing-model/track-cue-rendering-position-align-rtl-center-ref.html": [ + "1b9fc8a0086673fc5021c873c58b920c718a3d6f", + "support" + ], + "webvtt/rendering/cues-with-video/processing-model/track-cue-rendering-position-align-rtl-center.html": [ + "3ed80bf703c919ce5774208a6bc947bf1f37e6ce", + "reftest" + ], + "webvtt/rendering/cues-with-video/processing-model/track-cue-rendering-position-align-rtl-line-left-ref.html": [ + "79e0c0df8f6262ced630c78206b2115be9e02df0", + "support" + ], + "webvtt/rendering/cues-with-video/processing-model/track-cue-rendering-position-align-rtl-line-left.html": [ + "88864a2cb30622b3566f4f1b402cbd1b6b5fb33f", + "reftest" + ], + "webvtt/rendering/cues-with-video/processing-model/track-cue-rendering-position-align-rtl-line-right-ref.html": [ + "c756d183319554a551482692b0e265165894995d", + "support" + ], + "webvtt/rendering/cues-with-video/processing-model/track-cue-rendering-position-align-rtl-line-right.html": [ + "e0945f78441ab2676e652d6bc2ca13d0bb2b98b3", + "reftest" + ], "webvtt/tools/categorize_results.py": [ "339f3f5f0e968076031f4a7c4361f9dba14d485d", "support" ], + "webxr/OWNERS": [ + "13f9441d368248225df5adc3396a05061ba2924d", + "support" + ], + "webxr/resources/webxr_check.html": [ + "3fa96e39a073bda2e813f0b2c2411c26b73d374e", + "support" + ], + "webxr/resources/webxr_util.js": [ + "2e92835bb77e028fffc597767528a4a3548f27e8", + "support" + ], + "webxr/webxr_availability.http.sub.html": [ + "d8aa0ef8b7b3363fd23af2700dc6d9186201c408", + "testharness" + ], "workers/OWNERS": [ "424c4c3664d3eb0c5123b4a05c55ee78a1dbbba5", "support" @@ -581052,6 +588900,10 @@ "d74620a63e7d911ef60b995cabf6b360c2c46a4f", "testharness" ], + "workers/SharedWorker_dataUrl.html": [ + "285538767c2c79223f12b58da4e347eee8101ccc", + "testharness" + ], "workers/WorkerGlobalScope_ErrorEvent_colno.htm": [ "8ceb41543f928c918010000d638099faeb674980", "testharness" @@ -581464,8 +589316,12 @@ "23ed9eb3cf4b65bdd0301570677a6d89af0e551b", "testharness" ], + "workers/data-url-shared-window.html": [ + "69d590693c5f161176ba2e1f36d89df284a766e4", + "support" + ], "workers/data-url-shared.html": [ - "0fee4678c53e3f30e0f6090b5b9fc51b7bb74806", + "3650dbf419d8bbfe7380a36426793336998975cc", "testharness" ], "workers/data-url.html": [ @@ -582056,6 +589912,10 @@ "b0e679dd7720701364abeaca6870d94db5d7ee74", "support" ], + "workers/support/iframe_sw_dataUrl.html": [ + "2cd66112b612e7b861af00af5ccc26cc7c5a76f8", + "support" + ], "workers/support/name-as-accidental-global.js": [ "530670268fae610b60066773ee475743b8498b53", "support" @@ -582077,7 +589937,7 @@ "support" ], "workers/worker-performance.worker.js": [ - "d1759a707897f66bf013e888ed188023145e2622", + "513fd99e7c523b710386b7e3736d1cbbc6a20e7a", "testharness" ], "worklets/README.md": [ @@ -582129,15 +589989,23 @@ "support" ], "worklets/resources/credentials-tests.js": [ - "3554b8fcf13239de2b89afde1cb0fe97ef5d2124", + "642b8039439a20609788d36a0bc7d116fc8e4f6d", "support" ], "worklets/resources/credentials.py": [ - "6ce932e1cdc3626efc85ba0fe4a517b6308c67bd", + "94a8b7d91f30cf9bc7b7473841dc49b9b7251d7f", "support" ], "worklets/resources/csp-tests.js": [ - "160eff495b94f445098a2764b94841e557b0bc47", + "57332b3e82704f8259e5f748e7195c10bb5ebb2c", + "support" + ], + "worklets/resources/empty-worklet-script-with-cors-header.js": [ + "4b78be9f257ad243eb6ca72f84084081267c46a1", + "support" + ], + "worklets/resources/empty-worklet-script-with-cors-header.js.headers": [ + "90d51a5e46cc58404dd5ec1e9e4e10934a6c0707", "support" ], "worklets/resources/empty-worklet-script.js": [ @@ -582148,8 +590016,16 @@ "f32abb012c93bb69087688f31a0c243d9e6d1060", "support" ], - "worklets/resources/import-empty-worklet-script.js": [ - "4add9359940f440fb2c66d17096a45ffbf77975d", + "worklets/resources/import-empty-worklet-script-with-cors-header.js": [ + "f4c82399ef85e69e24a7a1a3b27448e3f3722b70", + "support" + ], + "worklets/resources/import-empty-worklet-script-with-cors-header.js.headers": [ + "90d51a5e46cc58404dd5ec1e9e4e10934a6c0707", + "support" + ], + "worklets/resources/import-insecure-origin-empty-worklet-script.sub.js": [ + "d38fb85065c1f48864807fd84a87651eecaecd35", "support" ], "worklets/resources/import-nested-internal-worklet-script.js": [ @@ -582164,10 +590040,26 @@ "2d8af6c2e0e7bc3f7feaa5f333824fea94314353", "support" ], + "worklets/resources/import-referrer-checker-worklet-script.sub.js": [ + "8d42d00b53b014c5b0ac6d0702be168b5069d659", + "support" + ], + "worklets/resources/import-referrer-checker-worklet-script.sub.js.headers": [ + "90d51a5e46cc58404dd5ec1e9e4e10934a6c0707", + "support" + ], "worklets/resources/import-remote-origin-empty-worklet-script.sub.js": [ "e048bbd38d7348edd6e487ba2381b57530a5cba6", "support" ], + "worklets/resources/import-remote-origin-referrer-checker-worklet-script.sub.js": [ + "1e60785a8948f090541731edc67b5a2c21419c2c", + "support" + ], + "worklets/resources/import-remote-origin-referrer-checker-worklet-script.sub.js.headers": [ + "90d51a5e46cc58404dd5ec1e9e4e10934a6c0707", + "support" + ], "worklets/resources/import-syntax-error-worklet-script.js": [ "e2f65e87d6d7b885201b4371ce0c4f21af5efe90", "support" @@ -582176,16 +590068,16 @@ "fdc5ee273fa5b4bf3b820f8c0404a5ca9580e2b4", "support" ], + "worklets/resources/referrer-checker.py": [ + "9e4cce637b7402da3b6a17d4cb33dc706f222c41", + "support" + ], "worklets/resources/referrer-tests.js": [ - "47d8ae6d90b88ab8fb856e305b1599a34173852f", + "bfa2e28259a44abf3aac6be528e51976c9ff782d", "support" ], "worklets/resources/referrer-window.html": [ - "0b8b7424014190af51d310b9f843471a3b5fb37f", - "support" - ], - "worklets/resources/referrer.py": [ - "ed296faa934f89efcca9a116f6a2e931cafd831e", + "adfb1c116fedb6396f970ed8072ee73edfc755fc", "support" ], "worklets/resources/service-worker-interception-tests.js": [ @@ -582197,7 +590089,7 @@ "support" ], "worklets/resources/set-cookie.py": [ - "3152f5d79b6f362f5aaf738d7d2454de94a6159d", + "aa55d9ed286809c8d808c102dd409afb75cbe554", "support" ], "worklets/resources/syntax-error-worklet-script.js": [ diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures.worker.js.ini deleted file mode 100644 index 1068757f3a5..00000000000 --- a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures.worker.js.ini +++ /dev/null @@ -1,5 +0,0 @@ -[failures.worker.html] - type: testharness - [Untitled] - expected: FAIL - diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_AES-CBC.https.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_AES-CBC.https.worker.js.ini new file mode 100644 index 00000000000..8ac82d02f13 --- /dev/null +++ b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_AES-CBC.https.worker.js.ini @@ -0,0 +1,4 @@ +[failures_AES-CBC.https.worker.html] + [Untitled] + expected: FAIL + diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_AES-CBC.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_AES-CBC.worker.js.ini deleted file mode 100644 index c59cf0b37b1..00000000000 --- a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_AES-CBC.worker.js.ini +++ /dev/null @@ -1,5 +0,0 @@ -[failures_AES-CBC.worker.html] - type: testharness - [Untitled] - expected: FAIL - diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_AES-CTR.https.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_AES-CTR.https.worker.js.ini new file mode 100644 index 00000000000..965b8f24038 --- /dev/null +++ b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_AES-CTR.https.worker.js.ini @@ -0,0 +1,4 @@ +[failures_AES-CTR.https.worker.html] + [Untitled] + expected: FAIL + diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_AES-CTR.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_AES-CTR.worker.js.ini deleted file mode 100644 index e1d07f1f70b..00000000000 --- a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_AES-CTR.worker.js.ini +++ /dev/null @@ -1,5 +0,0 @@ -[failures_AES-CTR.worker.html] - type: testharness - [Untitled] - expected: FAIL - diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_AES-GCM.https.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_AES-GCM.https.worker.js.ini new file mode 100644 index 00000000000..2dfaeb46c7e --- /dev/null +++ b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_AES-GCM.https.worker.js.ini @@ -0,0 +1,4 @@ +[failures_AES-GCM.https.worker.html] + [Untitled] + expected: FAIL + diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_AES-GCM.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_AES-GCM.worker.js.ini deleted file mode 100644 index b20a0793579..00000000000 --- a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_AES-GCM.worker.js.ini +++ /dev/null @@ -1,5 +0,0 @@ -[failures_AES-GCM.worker.html] - type: testharness - [Untitled] - expected: FAIL - diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_AES-KW.https.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_AES-KW.https.worker.js.ini new file mode 100644 index 00000000000..d1de9f827a0 --- /dev/null +++ b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_AES-KW.https.worker.js.ini @@ -0,0 +1,4 @@ +[failures_AES-KW.https.worker.html] + [Untitled] + expected: FAIL + diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_AES-KW.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_AES-KW.worker.js.ini deleted file mode 100644 index b8aa1b6cae5..00000000000 --- a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_AES-KW.worker.js.ini +++ /dev/null @@ -1,5 +0,0 @@ -[failures_AES-KW.worker.html] - type: testharness - [Untitled] - expected: FAIL - diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_ECDH.https.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_ECDH.https.worker.js.ini new file mode 100644 index 00000000000..b5483769a8a --- /dev/null +++ b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_ECDH.https.worker.js.ini @@ -0,0 +1,4 @@ +[failures_ECDH.https.worker.html] + [Untitled] + expected: FAIL + diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_ECDH.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_ECDH.worker.js.ini deleted file mode 100644 index ae9af4e8a34..00000000000 --- a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_ECDH.worker.js.ini +++ /dev/null @@ -1,5 +0,0 @@ -[failures_ECDH.worker.html] - type: testharness - [Untitled] - expected: FAIL - diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_ECDSA.https.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_ECDSA.https.worker.js.ini new file mode 100644 index 00000000000..41afcd71a30 --- /dev/null +++ b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_ECDSA.https.worker.js.ini @@ -0,0 +1,4 @@ +[failures_ECDSA.https.worker.html] + [Untitled] + expected: FAIL + diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_ECDSA.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_ECDSA.worker.js.ini deleted file mode 100644 index cfba6f7c221..00000000000 --- a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_ECDSA.worker.js.ini +++ /dev/null @@ -1,5 +0,0 @@ -[failures_ECDSA.worker.html] - type: testharness - [Untitled] - expected: FAIL - diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_HMAC.https.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_HMAC.https.worker.js.ini new file mode 100644 index 00000000000..e9b1b81046d --- /dev/null +++ b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_HMAC.https.worker.js.ini @@ -0,0 +1,4 @@ +[failures_HMAC.https.worker.html] + [Untitled] + expected: FAIL + diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_HMAC.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_HMAC.worker.js.ini deleted file mode 100644 index deb887a2321..00000000000 --- a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_HMAC.worker.js.ini +++ /dev/null @@ -1,5 +0,0 @@ -[failures_HMAC.worker.html] - type: testharness - [Untitled] - expected: FAIL - diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_RSA-OAEP.https.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_RSA-OAEP.https.worker.js.ini new file mode 100644 index 00000000000..caa72afe819 --- /dev/null +++ b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_RSA-OAEP.https.worker.js.ini @@ -0,0 +1,4 @@ +[failures_RSA-OAEP.https.worker.html] + [Untitled] + expected: FAIL + diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_RSA-OAEP.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_RSA-OAEP.worker.js.ini deleted file mode 100644 index 1de70f23558..00000000000 --- a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_RSA-OAEP.worker.js.ini +++ /dev/null @@ -1,5 +0,0 @@ -[failures_RSA-OAEP.worker.html] - type: testharness - [Untitled] - expected: FAIL - diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_RSA-PSS.https.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_RSA-PSS.https.worker.js.ini new file mode 100644 index 00000000000..e0caa79ea4f --- /dev/null +++ b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_RSA-PSS.https.worker.js.ini @@ -0,0 +1,4 @@ +[failures_RSA-PSS.https.worker.html] + [Untitled] + expected: FAIL + diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_RSA-PSS.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_RSA-PSS.worker.js.ini deleted file mode 100644 index cc03a108192..00000000000 --- a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_RSA-PSS.worker.js.ini +++ /dev/null @@ -1,5 +0,0 @@ -[failures_RSA-PSS.worker.html] - type: testharness - [Untitled] - expected: FAIL - diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.https.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.https.worker.js.ini new file mode 100644 index 00000000000..18d6ba47d03 --- /dev/null +++ b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.https.worker.js.ini @@ -0,0 +1,4 @@ +[failures_RSASSA-PKCS1-v1_5.https.worker.html] + [Untitled] + expected: FAIL + diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.worker.js.ini deleted file mode 100644 index 8f65dda379d..00000000000 --- a/tests/wpt/metadata/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.worker.js.ini +++ /dev/null @@ -1,5 +0,0 @@ -[failures_RSASSA-PKCS1-v1_5.worker.html] - type: testharness - [Untitled] - expected: FAIL - diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes.worker.js.ini deleted file mode 100644 index ed342a2b9c3..00000000000 --- a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes.worker.js.ini +++ /dev/null @@ -1,5 +0,0 @@ -[successes.worker.html] - type: testharness - [Untitled] - expected: FAIL - diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_AES-CBC.https.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_AES-CBC.https.worker.js.ini new file mode 100644 index 00000000000..1e211bb6f65 --- /dev/null +++ b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_AES-CBC.https.worker.js.ini @@ -0,0 +1,4 @@ +[successes_AES-CBC.https.worker.html] + [Untitled] + expected: FAIL + diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_AES-CBC.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_AES-CBC.worker.js.ini deleted file mode 100644 index 3dc1a08cbb7..00000000000 --- a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_AES-CBC.worker.js.ini +++ /dev/null @@ -1,5 +0,0 @@ -[successes_AES-CBC.worker.html] - type: testharness - [Untitled] - expected: FAIL - diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_AES-CTR.https.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_AES-CTR.https.worker.js.ini new file mode 100644 index 00000000000..a2883df07a6 --- /dev/null +++ b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_AES-CTR.https.worker.js.ini @@ -0,0 +1,4 @@ +[successes_AES-CTR.https.worker.html] + [Untitled] + expected: FAIL + diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_AES-CTR.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_AES-CTR.worker.js.ini deleted file mode 100644 index 16542c965e1..00000000000 --- a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_AES-CTR.worker.js.ini +++ /dev/null @@ -1,5 +0,0 @@ -[successes_AES-CTR.worker.html] - type: testharness - [Untitled] - expected: FAIL - diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_AES-GCM.https.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_AES-GCM.https.worker.js.ini new file mode 100644 index 00000000000..0dd50458c8a --- /dev/null +++ b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_AES-GCM.https.worker.js.ini @@ -0,0 +1,4 @@ +[successes_AES-GCM.https.worker.html] + [Untitled] + expected: FAIL + diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_AES-GCM.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_AES-GCM.worker.js.ini deleted file mode 100644 index 38f1036a947..00000000000 --- a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_AES-GCM.worker.js.ini +++ /dev/null @@ -1,5 +0,0 @@ -[successes_AES-GCM.worker.html] - type: testharness - [Untitled] - expected: FAIL - diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_AES-KW.https.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_AES-KW.https.worker.js.ini new file mode 100644 index 00000000000..6a3dc9d94c2 --- /dev/null +++ b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_AES-KW.https.worker.js.ini @@ -0,0 +1,4 @@ +[successes_AES-KW.https.worker.html] + [Untitled] + expected: FAIL + diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_AES-KW.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_AES-KW.worker.js.ini deleted file mode 100644 index 61332e4ac7d..00000000000 --- a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_AES-KW.worker.js.ini +++ /dev/null @@ -1,5 +0,0 @@ -[successes_AES-KW.worker.html] - type: testharness - [Untitled] - expected: FAIL - diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_ECDH.https.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_ECDH.https.worker.js.ini new file mode 100644 index 00000000000..e4ed8296c89 --- /dev/null +++ b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_ECDH.https.worker.js.ini @@ -0,0 +1,4 @@ +[successes_ECDH.https.worker.html] + [Untitled] + expected: FAIL + diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_ECDH.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_ECDH.worker.js.ini deleted file mode 100644 index c7c0cd21980..00000000000 --- a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_ECDH.worker.js.ini +++ /dev/null @@ -1,5 +0,0 @@ -[successes_ECDH.worker.html] - type: testharness - [Untitled] - expected: FAIL - diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_ECDSA.https.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_ECDSA.https.worker.js.ini new file mode 100644 index 00000000000..605c0e88f46 --- /dev/null +++ b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_ECDSA.https.worker.js.ini @@ -0,0 +1,4 @@ +[successes_ECDSA.https.worker.html] + [Untitled] + expected: FAIL + diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_ECDSA.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_ECDSA.worker.js.ini deleted file mode 100644 index 4c46593c798..00000000000 --- a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_ECDSA.worker.js.ini +++ /dev/null @@ -1,5 +0,0 @@ -[successes_ECDSA.worker.html] - type: testharness - [Untitled] - expected: FAIL - diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_HMAC.https.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_HMAC.https.worker.js.ini new file mode 100644 index 00000000000..10ad8a77ee0 --- /dev/null +++ b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_HMAC.https.worker.js.ini @@ -0,0 +1,4 @@ +[successes_HMAC.https.worker.html] + [Untitled] + expected: FAIL + diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_HMAC.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_HMAC.worker.js.ini deleted file mode 100644 index 2194d88cbd1..00000000000 --- a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_HMAC.worker.js.ini +++ /dev/null @@ -1,5 +0,0 @@ -[successes_HMAC.worker.html] - type: testharness - [Untitled] - expected: FAIL - diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_RSA-OAEP.https.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_RSA-OAEP.https.worker.js.ini new file mode 100644 index 00000000000..ba0c117f6a9 --- /dev/null +++ b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_RSA-OAEP.https.worker.js.ini @@ -0,0 +1,4 @@ +[successes_RSA-OAEP.https.worker.html] + [Untitled] + expected: FAIL + diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_RSA-OAEP.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_RSA-OAEP.worker.js.ini deleted file mode 100644 index b27a732c5ff..00000000000 --- a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_RSA-OAEP.worker.js.ini +++ /dev/null @@ -1,5 +0,0 @@ -[successes_RSA-OAEP.worker.html] - type: testharness - [Untitled] - expected: FAIL - diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_RSA-PSS.https.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_RSA-PSS.https.worker.js.ini new file mode 100644 index 00000000000..e931d698970 --- /dev/null +++ b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_RSA-PSS.https.worker.js.ini @@ -0,0 +1,4 @@ +[successes_RSA-PSS.https.worker.html] + [Untitled] + expected: FAIL + diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_RSA-PSS.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_RSA-PSS.worker.js.ini deleted file mode 100644 index aca82094e98..00000000000 --- a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_RSA-PSS.worker.js.ini +++ /dev/null @@ -1,5 +0,0 @@ -[successes_RSA-PSS.worker.html] - type: testharness - [Untitled] - expected: FAIL - diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.https.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.https.worker.js.ini new file mode 100644 index 00000000000..46f5a9c5953 --- /dev/null +++ b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.https.worker.js.ini @@ -0,0 +1,4 @@ +[successes_RSASSA-PKCS1-v1_5.https.worker.html] + [Untitled] + expected: FAIL + diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.worker.js.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.worker.js.ini deleted file mode 100644 index 4d73a575efa..00000000000 --- a/tests/wpt/metadata/WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.worker.js.ini +++ /dev/null @@ -1,5 +0,0 @@ -[successes_RSASSA-PKCS1-v1_5.worker.html] - type: testharness - [Untitled] - expected: FAIL - diff --git a/tests/wpt/metadata/WebCryptoAPI/generateKey/test_failures.https.html.ini b/tests/wpt/metadata/WebCryptoAPI/generateKey/test_failures.https.html.ini deleted file mode 100644 index 584ab56284e..00000000000 --- a/tests/wpt/metadata/WebCryptoAPI/generateKey/test_failures.https.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[test_failures.https.html] - type: testharness - [WebCryptoAPI: generateKey() for Failures] - expected: FAIL - diff --git a/tests/wpt/metadata/WebIDL/ecmascript-binding/no-regexp-special-casing.any.js.ini b/tests/wpt/metadata/WebIDL/ecmascript-binding/no-regexp-special-casing.any.js.ini new file mode 100644 index 00000000000..e44c35b2e8a --- /dev/null +++ b/tests/wpt/metadata/WebIDL/ecmascript-binding/no-regexp-special-casing.any.js.ini @@ -0,0 +1,9 @@ +[no-regexp-special-casing.any.worker.html] + [Untitled] + expected: FAIL + + +[no-regexp-special-casing.any.html] + [Untitled] + expected: FAIL + diff --git a/tests/wpt/metadata/XMLHttpRequest/send-redirect-post-upload.htm.ini b/tests/wpt/metadata/XMLHttpRequest/send-redirect-post-upload.htm.ini index c3b3c67c601..343465b443c 100644 --- a/tests/wpt/metadata/XMLHttpRequest/send-redirect-post-upload.htm.ini +++ b/tests/wpt/metadata/XMLHttpRequest/send-redirect-post-upload.htm.ini @@ -12,3 +12,9 @@ [XMLHttpRequest: The send() method: POSTing to URL that redirects (307)] expected: FAIL + [XMLHttpRequest: The send() method: POSTing to URL that redirects (307 (string))] + expected: FAIL + + [XMLHttpRequest: The send() method: POSTing to URL that redirects (307 (blob))] + expected: FAIL + diff --git a/tests/wpt/metadata/css/CSS2/backgrounds/background-color-030.xht.ini b/tests/wpt/metadata/css/CSS2/backgrounds/background-color-030.xht.ini deleted file mode 100644 index 0b1da424bb7..00000000000 --- a/tests/wpt/metadata/css/CSS2/backgrounds/background-color-030.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[background-color-030.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/backgrounds/background-color-174.xht.ini b/tests/wpt/metadata/css/CSS2/backgrounds/background-color-174.xht.ini deleted file mode 100644 index 586e9e4fa6d..00000000000 --- a/tests/wpt/metadata/css/CSS2/backgrounds/background-color-174.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[background-color-174.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/backgrounds/background-image-002.xht.ini b/tests/wpt/metadata/css/CSS2/backgrounds/background-image-002.xht.ini deleted file mode 100644 index d672e211cd6..00000000000 --- a/tests/wpt/metadata/css/CSS2/backgrounds/background-image-002.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[background-image-002.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/colors/color-083.xht.ini b/tests/wpt/metadata/css/CSS2/colors/color-083.xht.ini deleted file mode 100644 index 9fa48494a27..00000000000 --- a/tests/wpt/metadata/css/CSS2/colors/color-083.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[color-083.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/colors/color-084.xht.ini b/tests/wpt/metadata/css/CSS2/colors/color-084.xht.ini deleted file mode 100644 index ccff2657d29..00000000000 --- a/tests/wpt/metadata/css/CSS2/colors/color-084.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[color-084.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/after-inheritable-001.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/after-inheritable-001.xht.ini new file mode 100644 index 00000000000..262bcf9ca31 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/after-inheritable-001.xht.ini @@ -0,0 +1,2 @@ +[after-inheritable-001.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/after-inheritable-002.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/after-inheritable-002.xht.ini new file mode 100644 index 00000000000..da9f319fb18 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/after-inheritable-002.xht.ini @@ -0,0 +1,2 @@ +[after-inheritable-002.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/before-inheritable-002.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/before-inheritable-002.xht.ini new file mode 100644 index 00000000000..819aada9757 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/before-inheritable-002.xht.ini @@ -0,0 +1,2 @@ +[before-inheritable-002.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-004.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-004.xht.ini new file mode 100644 index 00000000000..b8c378c2311 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-004.xht.ini @@ -0,0 +1,2 @@ +[content-004.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-010.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-010.xht.ini new file mode 100644 index 00000000000..53d86009692 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-010.xht.ini @@ -0,0 +1,2 @@ +[content-010.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-011.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-011.xht.ini new file mode 100644 index 00000000000..88b04433aab --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-011.xht.ini @@ -0,0 +1,2 @@ +[content-011.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-012.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-012.xht.ini new file mode 100644 index 00000000000..13962b4f1b2 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-012.xht.ini @@ -0,0 +1,2 @@ +[content-012.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-014.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-014.xht.ini new file mode 100644 index 00000000000..882942b7e4b --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-014.xht.ini @@ -0,0 +1,2 @@ +[content-014.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-015.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-015.xht.ini new file mode 100644 index 00000000000..13b5ff2c3d0 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-015.xht.ini @@ -0,0 +1,2 @@ +[content-015.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-016.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-016.xht.ini new file mode 100644 index 00000000000..b0fff3c6e74 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-016.xht.ini @@ -0,0 +1,2 @@ +[content-016.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-017.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-017.xht.ini new file mode 100644 index 00000000000..5e77a7c159d --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-017.xht.ini @@ -0,0 +1,2 @@ +[content-017.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-026.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-026.xht.ini new file mode 100644 index 00000000000..79b39dcaf91 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-026.xht.ini @@ -0,0 +1,2 @@ +[content-026.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-027.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-027.xht.ini new file mode 100644 index 00000000000..12a23e99a95 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-027.xht.ini @@ -0,0 +1,2 @@ +[content-027.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-028.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-028.xht.ini new file mode 100644 index 00000000000..c3440a23a36 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-028.xht.ini @@ -0,0 +1,2 @@ +[content-028.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-030.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-030.xht.ini new file mode 100644 index 00000000000..0ad1d84145d --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-030.xht.ini @@ -0,0 +1,2 @@ +[content-030.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-031.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-031.xht.ini new file mode 100644 index 00000000000..3186dd6b061 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-031.xht.ini @@ -0,0 +1,2 @@ +[content-031.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-032.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-032.xht.ini new file mode 100644 index 00000000000..19bd40696b7 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-032.xht.ini @@ -0,0 +1,2 @@ +[content-032.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-033.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-033.xht.ini new file mode 100644 index 00000000000..bec98d50d89 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-033.xht.ini @@ -0,0 +1,2 @@ +[content-033.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-037.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-037.xht.ini new file mode 100644 index 00000000000..8d581a62d55 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-037.xht.ini @@ -0,0 +1,2 @@ +[content-037.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-038.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-038.xht.ini new file mode 100644 index 00000000000..55dbc005478 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-038.xht.ini @@ -0,0 +1,2 @@ +[content-038.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-039.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-039.xht.ini new file mode 100644 index 00000000000..914b3392422 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-039.xht.ini @@ -0,0 +1,2 @@ +[content-039.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-040.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-040.xht.ini new file mode 100644 index 00000000000..1574f541d85 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-040.xht.ini @@ -0,0 +1,2 @@ +[content-040.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-041.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-041.xht.ini new file mode 100644 index 00000000000..6c4ed008895 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-041.xht.ini @@ -0,0 +1,2 @@ +[content-041.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-042.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-042.xht.ini new file mode 100644 index 00000000000..be86618b552 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-042.xht.ini @@ -0,0 +1,2 @@ +[content-042.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-043.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-043.xht.ini new file mode 100644 index 00000000000..0548440f58a --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-043.xht.ini @@ -0,0 +1,2 @@ +[content-043.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-046.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-046.xht.ini new file mode 100644 index 00000000000..77b3181f52f --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-046.xht.ini @@ -0,0 +1,2 @@ +[content-046.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-047.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-047.xht.ini new file mode 100644 index 00000000000..b2e2661878e --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-047.xht.ini @@ -0,0 +1,2 @@ +[content-047.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-048.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-048.xht.ini new file mode 100644 index 00000000000..f59c49831af --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-048.xht.ini @@ -0,0 +1,2 @@ +[content-048.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-050.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-050.xht.ini new file mode 100644 index 00000000000..d56f7c171ca --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-050.xht.ini @@ -0,0 +1,2 @@ +[content-050.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-052.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-052.xht.ini new file mode 100644 index 00000000000..d97829257fd --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-052.xht.ini @@ -0,0 +1,2 @@ +[content-052.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-053.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-053.xht.ini new file mode 100644 index 00000000000..f563db1b2ed --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-053.xht.ini @@ -0,0 +1,2 @@ +[content-053.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-054.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-054.xht.ini new file mode 100644 index 00000000000..4f9cbcc7586 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-054.xht.ini @@ -0,0 +1,2 @@ +[content-054.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-056.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-056.xht.ini new file mode 100644 index 00000000000..02a73baf31e --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-056.xht.ini @@ -0,0 +1,2 @@ +[content-056.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-057.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-057.xht.ini new file mode 100644 index 00000000000..3cd26ca3bc8 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-057.xht.ini @@ -0,0 +1,2 @@ +[content-057.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-063.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-063.xht.ini new file mode 100644 index 00000000000..72352e9b5a8 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-063.xht.ini @@ -0,0 +1,2 @@ +[content-063.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-065.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-065.xht.ini new file mode 100644 index 00000000000..2b7544e293c --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-065.xht.ini @@ -0,0 +1,2 @@ +[content-065.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-067.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-067.xht.ini new file mode 100644 index 00000000000..69df6c0eee6 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-067.xht.ini @@ -0,0 +1,2 @@ +[content-067.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-068.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-068.xht.ini new file mode 100644 index 00000000000..fac5b5d46f4 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-068.xht.ini @@ -0,0 +1,2 @@ +[content-068.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-070.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-070.xht.ini new file mode 100644 index 00000000000..397ef880c7e --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-070.xht.ini @@ -0,0 +1,2 @@ +[content-070.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-072.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-072.xht.ini new file mode 100644 index 00000000000..1a48e77c1ca --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-072.xht.ini @@ -0,0 +1,2 @@ +[content-072.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-073.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-073.xht.ini new file mode 100644 index 00000000000..64f361a4929 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-073.xht.ini @@ -0,0 +1,2 @@ +[content-073.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-075.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-075.xht.ini new file mode 100644 index 00000000000..8d777f9e0cc --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-075.xht.ini @@ -0,0 +1,2 @@ +[content-075.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-076.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-076.xht.ini new file mode 100644 index 00000000000..5c7f2cdc4d8 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-076.xht.ini @@ -0,0 +1,2 @@ +[content-076.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-077.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-077.xht.ini new file mode 100644 index 00000000000..bb0c2878460 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-077.xht.ini @@ -0,0 +1,2 @@ +[content-077.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-080.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-080.xht.ini new file mode 100644 index 00000000000..24fca12d0dd --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-080.xht.ini @@ -0,0 +1,2 @@ +[content-080.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-081.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-081.xht.ini new file mode 100644 index 00000000000..b7e84a0ae3d --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-081.xht.ini @@ -0,0 +1,2 @@ +[content-081.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-082.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-082.xht.ini new file mode 100644 index 00000000000..b7fe80a3612 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-082.xht.ini @@ -0,0 +1,2 @@ +[content-082.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-083.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-083.xht.ini new file mode 100644 index 00000000000..98d9750ca56 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-083.xht.ini @@ -0,0 +1,2 @@ +[content-083.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-085.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-085.xht.ini new file mode 100644 index 00000000000..c36c5f28065 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-085.xht.ini @@ -0,0 +1,2 @@ +[content-085.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-086.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-086.xht.ini new file mode 100644 index 00000000000..4bcc74b9e98 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-086.xht.ini @@ -0,0 +1,2 @@ +[content-086.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-089.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-089.xht.ini new file mode 100644 index 00000000000..9be53ac8af7 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-089.xht.ini @@ -0,0 +1,2 @@ +[content-089.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-090.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-090.xht.ini new file mode 100644 index 00000000000..8f692e0192e --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-090.xht.ini @@ -0,0 +1,2 @@ +[content-090.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-091.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-091.xht.ini new file mode 100644 index 00000000000..8c44f8a727e --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-091.xht.ini @@ -0,0 +1,2 @@ +[content-091.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-096.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-096.xht.ini new file mode 100644 index 00000000000..e290d19a5d7 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-096.xht.ini @@ -0,0 +1,2 @@ +[content-096.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-097.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-097.xht.ini new file mode 100644 index 00000000000..17fe2fa1b34 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-097.xht.ini @@ -0,0 +1,2 @@ +[content-097.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-099.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-099.xht.ini new file mode 100644 index 00000000000..eee1288f410 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-099.xht.ini @@ -0,0 +1,2 @@ +[content-099.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-100.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-100.xht.ini new file mode 100644 index 00000000000..639d5fcdc8d --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-100.xht.ini @@ -0,0 +1,2 @@ +[content-100.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-103.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-103.xht.ini new file mode 100644 index 00000000000..7df6c41cff5 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-103.xht.ini @@ -0,0 +1,2 @@ +[content-103.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-105.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-105.xht.ini new file mode 100644 index 00000000000..29fae9eec9e --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-105.xht.ini @@ -0,0 +1,2 @@ +[content-105.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-109.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-109.xht.ini new file mode 100644 index 00000000000..3fed7d41624 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-109.xht.ini @@ -0,0 +1,2 @@ +[content-109.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-113.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-113.xht.ini new file mode 100644 index 00000000000..13bd3922dbb --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-113.xht.ini @@ -0,0 +1,2 @@ +[content-113.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-122.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-122.xht.ini new file mode 100644 index 00000000000..82275f32b5f --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-122.xht.ini @@ -0,0 +1,2 @@ +[content-122.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-123.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-123.xht.ini new file mode 100644 index 00000000000..87d67c7ed86 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-123.xht.ini @@ -0,0 +1,2 @@ +[content-123.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-126.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-126.xht.ini new file mode 100644 index 00000000000..309532c3473 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-126.xht.ini @@ -0,0 +1,2 @@ +[content-126.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-127.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-127.xht.ini new file mode 100644 index 00000000000..e91e9bc86ed --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-127.xht.ini @@ -0,0 +1,2 @@ +[content-127.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-129.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-129.xht.ini new file mode 100644 index 00000000000..176fb737186 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-129.xht.ini @@ -0,0 +1,2 @@ +[content-129.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-131.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-131.xht.ini new file mode 100644 index 00000000000..d8fafac4a1f --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-131.xht.ini @@ -0,0 +1,2 @@ +[content-131.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-132.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-132.xht.ini new file mode 100644 index 00000000000..018ba9b20de --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-132.xht.ini @@ -0,0 +1,2 @@ +[content-132.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-135.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-135.xht.ini new file mode 100644 index 00000000000..7afbb752485 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-135.xht.ini @@ -0,0 +1,2 @@ +[content-135.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-136.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-136.xht.ini new file mode 100644 index 00000000000..1c9ecc23cd1 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-136.xht.ini @@ -0,0 +1,2 @@ +[content-136.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-138.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-138.xht.ini new file mode 100644 index 00000000000..f27ea134f5a --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-138.xht.ini @@ -0,0 +1,2 @@ +[content-138.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-141.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-141.xht.ini new file mode 100644 index 00000000000..3ceb8673e6a --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-141.xht.ini @@ -0,0 +1,2 @@ +[content-141.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-143.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-143.xht.ini new file mode 100644 index 00000000000..3bbf03acd0f --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-143.xht.ini @@ -0,0 +1,2 @@ +[content-143.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-144.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-144.xht.ini new file mode 100644 index 00000000000..d13329af770 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-144.xht.ini @@ -0,0 +1,2 @@ +[content-144.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-145.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-145.xht.ini new file mode 100644 index 00000000000..fd45b0a544a --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-145.xht.ini @@ -0,0 +1,2 @@ +[content-145.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-146.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-146.xht.ini new file mode 100644 index 00000000000..dbf1acbb8bf --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-146.xht.ini @@ -0,0 +1,2 @@ +[content-146.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-147.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-147.xht.ini new file mode 100644 index 00000000000..1d1b252a89c --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-147.xht.ini @@ -0,0 +1,2 @@ +[content-147.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-149.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-149.xht.ini new file mode 100644 index 00000000000..1f2bcb42bb9 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-149.xht.ini @@ -0,0 +1,2 @@ +[content-149.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-150.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-150.xht.ini new file mode 100644 index 00000000000..0c2f70e8202 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-150.xht.ini @@ -0,0 +1,2 @@ +[content-150.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-152.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-152.xht.ini new file mode 100644 index 00000000000..5c40b2c07ab --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-152.xht.ini @@ -0,0 +1,2 @@ +[content-152.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-153.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-153.xht.ini new file mode 100644 index 00000000000..42275aa9af4 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-153.xht.ini @@ -0,0 +1,2 @@ +[content-153.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-155.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-155.xht.ini new file mode 100644 index 00000000000..bdfb2ac2935 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-155.xht.ini @@ -0,0 +1,2 @@ +[content-155.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-158.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-158.xht.ini new file mode 100644 index 00000000000..27b90b85080 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-158.xht.ini @@ -0,0 +1,2 @@ +[content-158.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-attr-case-001.html.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-attr-case-001.html.ini new file mode 100644 index 00000000000..1cb6c0fdb8a --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-attr-case-001.html.ini @@ -0,0 +1,2 @@ +[content-attr-case-001.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/content-white-space-002.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/content-white-space-002.xht.ini new file mode 100644 index 00000000000..d9895725434 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/content-white-space-002.xht.ini @@ -0,0 +1,2 @@ +[content-white-space-002.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/counters-hidden-002.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/counters-hidden-002.xht.ini new file mode 100644 index 00000000000..d78930678da --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/counters-hidden-002.xht.ini @@ -0,0 +1,2 @@ +[counters-hidden-002.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/counters-multi-000.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/counters-multi-000.xht.ini new file mode 100644 index 00000000000..e7d4eb1814f --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/counters-multi-000.xht.ini @@ -0,0 +1,2 @@ +[counters-multi-000.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/counters-multi-001.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/counters-multi-001.xht.ini new file mode 100644 index 00000000000..3d3bb16b81c --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/counters-multi-001.xht.ini @@ -0,0 +1,2 @@ +[counters-multi-001.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/generated-content/counters-order-000.xht.ini b/tests/wpt/metadata/css/CSS2/generated-content/counters-order-000.xht.ini new file mode 100644 index 00000000000..f3def3f9f20 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/generated-content/counters-order-000.xht.ini @@ -0,0 +1,2 @@ +[counters-order-000.xht] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/visudet/line-height-204.html.ini b/tests/wpt/metadata/css/CSS2/visudet/line-height-204.html.ini new file mode 100644 index 00000000000..3d28990c283 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/visudet/line-height-204.html.ini @@ -0,0 +1,2 @@ +[line-height-204.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/CSS2/visudet/line-height-205.html.ini b/tests/wpt/metadata/css/CSS2/visudet/line-height-205.html.ini new file mode 100644 index 00000000000..540feb5e7ee --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/visudet/line-height-205.html.ini @@ -0,0 +1,2 @@ +[line-height-205.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/css-animations/animation-delay-011.html.ini b/tests/wpt/metadata/css/css-animations/animation-delay-011.html.ini new file mode 100644 index 00000000000..78b88159561 --- /dev/null +++ b/tests/wpt/metadata/css/css-animations/animation-delay-011.html.ini @@ -0,0 +1,2 @@ +[animation-delay-011.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/css-backgrounds/background-color-body-propagation-003.html.ini b/tests/wpt/metadata/css/css-backgrounds/background-color-body-propagation-003.html.ini new file mode 100644 index 00000000000..1a916e0c7d8 --- /dev/null +++ b/tests/wpt/metadata/css/css-backgrounds/background-color-body-propagation-003.html.ini @@ -0,0 +1,2 @@ +[background-color-body-propagation-003.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/css-backgrounds/background-image-none-gradient-repaint.html.ini b/tests/wpt/metadata/css/css-backgrounds/background-image-none-gradient-repaint.html.ini new file mode 100644 index 00000000000..edbd34d5956 --- /dev/null +++ b/tests/wpt/metadata/css/css-backgrounds/background-image-none-gradient-repaint.html.ini @@ -0,0 +1,2 @@ +[background-image-none-gradient-repaint.html] + expected: TIMEOUT diff --git a/tests/wpt/metadata/css/css-backgrounds/border-radius-011.xht.ini b/tests/wpt/metadata/css/css-backgrounds/border-radius-011.xht.ini deleted file mode 100644 index 092cc2c9a25..00000000000 --- a/tests/wpt/metadata/css/css-backgrounds/border-radius-011.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[border-radius-011.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-backgrounds/box-shadow-syntax-001.xht.ini b/tests/wpt/metadata/css/css-backgrounds/box-shadow-syntax-001.xht.ini index bb9b1b76687..47a52ac2420 100644 --- a/tests/wpt/metadata/css/css-backgrounds/box-shadow-syntax-001.xht.ini +++ b/tests/wpt/metadata/css/css-backgrounds/box-shadow-syntax-001.xht.ini @@ -1,3 +1,3 @@ [box-shadow-syntax-001.xht] type: reftest - expected: FAIL + expected: TIMEOUT diff --git a/tests/wpt/metadata/css/css-block/quotes-applies-to-011.xht.ini b/tests/wpt/metadata/css/css-block/quotes-applies-to-011.xht.ini deleted file mode 100644 index ed5af0a4bf5..00000000000 --- a/tests/wpt/metadata/css/css-block/quotes-applies-to-011.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[quotes-applies-to-011.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-abspos-between-001.xht.ini b/tests/wpt/metadata/css/css-block/run-in-abspos-between-001.xht.ini deleted file mode 100644 index c63f10d6610..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-abspos-between-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-abspos-between-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-abspos-between-002.xht.ini b/tests/wpt/metadata/css/css-block/run-in-abspos-between-002.xht.ini deleted file mode 100644 index 532fd4a6c64..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-abspos-between-002.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-abspos-between-002.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-basic-001.xht.ini b/tests/wpt/metadata/css/css-block/run-in-basic-001.xht.ini deleted file mode 100644 index d1facc3ff9d..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-basic-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-basic-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-basic-002.xht.ini b/tests/wpt/metadata/css/css-block/run-in-basic-002.xht.ini deleted file mode 100644 index 5e0f7cab79d..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-basic-002.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-basic-002.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-basic-003.xht.ini b/tests/wpt/metadata/css/css-block/run-in-basic-003.xht.ini deleted file mode 100644 index d842dfe24fa..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-basic-003.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-basic-003.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-basic-004.xht.ini b/tests/wpt/metadata/css/css-block/run-in-basic-004.xht.ini deleted file mode 100644 index 89d86cda3ba..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-basic-004.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-basic-004.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-basic-005.xht.ini b/tests/wpt/metadata/css/css-block/run-in-basic-005.xht.ini deleted file mode 100644 index 9f3549d7d72..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-basic-005.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-basic-005.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-basic-006.xht.ini b/tests/wpt/metadata/css/css-block/run-in-basic-006.xht.ini deleted file mode 100644 index e013afeb14a..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-basic-006.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-basic-006.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-basic-007.xht.ini b/tests/wpt/metadata/css/css-block/run-in-basic-007.xht.ini deleted file mode 100644 index 8b7061b2d6d..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-basic-007.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-basic-007.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-basic-008.xht.ini b/tests/wpt/metadata/css/css-block/run-in-basic-008.xht.ini deleted file mode 100644 index a6aa69fbbb2..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-basic-008.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-basic-008.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-basic-009.xht.ini b/tests/wpt/metadata/css/css-block/run-in-basic-009.xht.ini deleted file mode 100644 index 317f92249b8..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-basic-009.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-basic-009.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-basic-010.xht.ini b/tests/wpt/metadata/css/css-block/run-in-basic-010.xht.ini deleted file mode 100644 index d5e21f21a5e..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-basic-010.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-basic-010.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-basic-011.xht.ini b/tests/wpt/metadata/css/css-block/run-in-basic-011.xht.ini deleted file mode 100644 index a7bf9a8cda3..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-basic-011.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-basic-011.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-basic-012.xht.ini b/tests/wpt/metadata/css/css-block/run-in-basic-012.xht.ini deleted file mode 100644 index 46f20410883..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-basic-012.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-basic-012.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-basic-013.xht.ini b/tests/wpt/metadata/css/css-block/run-in-basic-013.xht.ini deleted file mode 100644 index c3c3fc25883..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-basic-013.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-basic-013.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-basic-018.xht.ini b/tests/wpt/metadata/css/css-block/run-in-basic-018.xht.ini deleted file mode 100644 index 4123f0e8e4c..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-basic-018.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-basic-018.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-block-between-003.xht.ini b/tests/wpt/metadata/css/css-block/run-in-block-between-003.xht.ini deleted file mode 100644 index afb953280aa..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-block-between-003.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-block-between-003.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-breaking-001.xht.ini b/tests/wpt/metadata/css/css-block/run-in-breaking-001.xht.ini deleted file mode 100644 index 047bc8a9530..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-breaking-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-breaking-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-breaking-002.xht.ini b/tests/wpt/metadata/css/css-block/run-in-breaking-002.xht.ini deleted file mode 100644 index 0a4a610bd8e..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-breaking-002.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-breaking-002.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-clear-001.xht.ini b/tests/wpt/metadata/css/css-block/run-in-clear-001.xht.ini deleted file mode 100644 index d78f8082fa1..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-clear-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-clear-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-clear-002.xht.ini b/tests/wpt/metadata/css/css-block/run-in-clear-002.xht.ini deleted file mode 100644 index 25dc6f9c838..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-clear-002.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-clear-002.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-contains-abspos-001.xht.ini b/tests/wpt/metadata/css/css-block/run-in-contains-abspos-001.xht.ini deleted file mode 100644 index 7b81ce1acbb..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-contains-abspos-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-contains-abspos-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-contains-block-003.xht.ini b/tests/wpt/metadata/css/css-block/run-in-contains-block-003.xht.ini deleted file mode 100644 index cc3d96209b9..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-contains-block-003.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-contains-block-003.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-contains-block-005.xht.ini b/tests/wpt/metadata/css/css-block/run-in-contains-block-005.xht.ini deleted file mode 100644 index 837636b3ae2..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-contains-block-005.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-contains-block-005.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-contains-block-inside-inline-003.xht.ini b/tests/wpt/metadata/css/css-block/run-in-contains-block-inside-inline-003.xht.ini deleted file mode 100644 index 06ca32d3539..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-contains-block-inside-inline-003.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-contains-block-inside-inline-003.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-contains-float-001.xht.ini b/tests/wpt/metadata/css/css-block/run-in-contains-float-001.xht.ini deleted file mode 100644 index a23d51a45be..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-contains-float-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-contains-float-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-contains-inline-001.xht.ini b/tests/wpt/metadata/css/css-block/run-in-contains-inline-001.xht.ini deleted file mode 100644 index 0b7c5a95abf..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-contains-inline-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-contains-inline-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-contains-inline-002.xht.ini b/tests/wpt/metadata/css/css-block/run-in-contains-inline-002.xht.ini deleted file mode 100644 index 5080238f437..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-contains-inline-002.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-contains-inline-002.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-contains-inline-003.xht.ini b/tests/wpt/metadata/css/css-block/run-in-contains-inline-003.xht.ini deleted file mode 100644 index 8509249a633..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-contains-inline-003.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-contains-inline-003.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-contains-inline-004.xht.ini b/tests/wpt/metadata/css/css-block/run-in-contains-inline-004.xht.ini deleted file mode 100644 index c754f9757a5..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-contains-inline-004.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-contains-inline-004.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-contains-inline-005.xht.ini b/tests/wpt/metadata/css/css-block/run-in-contains-inline-005.xht.ini deleted file mode 100644 index aefb8f516ce..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-contains-inline-005.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-contains-inline-005.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-contains-inline-006.xht.ini b/tests/wpt/metadata/css/css-block/run-in-contains-inline-006.xht.ini deleted file mode 100644 index 94b62103c4b..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-contains-inline-006.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-contains-inline-006.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-contains-inline-007.xht.ini b/tests/wpt/metadata/css/css-block/run-in-contains-inline-007.xht.ini deleted file mode 100644 index e89498c8345..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-contains-inline-007.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-contains-inline-007.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-contains-inline-block-001.xht.ini b/tests/wpt/metadata/css/css-block/run-in-contains-inline-block-001.xht.ini deleted file mode 100644 index 82dd3400196..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-contains-inline-block-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-contains-inline-block-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-contains-inline-table-001.xht.ini b/tests/wpt/metadata/css/css-block/run-in-contains-inline-table-001.xht.ini deleted file mode 100644 index c4fe591657c..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-contains-inline-table-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-contains-inline-table-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-contains-relpos-block-003.xht.ini b/tests/wpt/metadata/css/css-block/run-in-contains-relpos-block-003.xht.ini deleted file mode 100644 index 1bcdcc4bf6a..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-contains-relpos-block-003.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-contains-relpos-block-003.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-contains-run-in-003.xht.ini b/tests/wpt/metadata/css/css-block/run-in-contains-run-in-003.xht.ini deleted file mode 100644 index 4f151c9ee33..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-contains-run-in-003.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-contains-run-in-003.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-contains-table-003.xht.ini b/tests/wpt/metadata/css/css-block/run-in-contains-table-003.xht.ini deleted file mode 100644 index 14445ee94b8..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-contains-table-003.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-contains-table-003.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-contains-table-caption-001.xht.ini b/tests/wpt/metadata/css/css-block/run-in-contains-table-caption-001.xht.ini deleted file mode 100644 index 894f7801570..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-contains-table-caption-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-contains-table-caption-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-contains-table-cell-001.xht.ini b/tests/wpt/metadata/css/css-block/run-in-contains-table-cell-001.xht.ini deleted file mode 100644 index 65009b73029..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-contains-table-cell-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-contains-table-cell-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-contains-table-column-001.xht.ini b/tests/wpt/metadata/css/css-block/run-in-contains-table-column-001.xht.ini deleted file mode 100644 index 28ccae4a7d4..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-contains-table-column-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-contains-table-column-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-contains-table-column-group-001.xht.ini b/tests/wpt/metadata/css/css-block/run-in-contains-table-column-group-001.xht.ini deleted file mode 100644 index eea7c6b24e4..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-contains-table-column-group-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-contains-table-column-group-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-contains-table-inside-inline-003.xht.ini b/tests/wpt/metadata/css/css-block/run-in-contains-table-inside-inline-003.xht.ini deleted file mode 100644 index 8ba292cc3bb..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-contains-table-inside-inline-003.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-contains-table-inside-inline-003.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-contains-table-row-001.xht.ini b/tests/wpt/metadata/css/css-block/run-in-contains-table-row-001.xht.ini deleted file mode 100644 index 025135439a9..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-contains-table-row-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-contains-table-row-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-contains-table-row-group-001.xht.ini b/tests/wpt/metadata/css/css-block/run-in-contains-table-row-group-001.xht.ini deleted file mode 100644 index bd77b3d2fed..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-contains-table-row-group-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-contains-table-row-group-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-display-none-between-001.xht.ini b/tests/wpt/metadata/css/css-block/run-in-display-none-between-001.xht.ini deleted file mode 100644 index 4d330f1bbfc..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-display-none-between-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-display-none-between-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-display-none-between-002.xht.ini b/tests/wpt/metadata/css/css-block/run-in-display-none-between-002.xht.ini deleted file mode 100644 index b82c5fec663..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-display-none-between-002.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-display-none-between-002.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-fixedpos-between-001.xht.ini b/tests/wpt/metadata/css/css-block/run-in-fixedpos-between-001.xht.ini deleted file mode 100644 index 23a614fa29b..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-fixedpos-between-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-fixedpos-between-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-fixedpos-between-002.xht.ini b/tests/wpt/metadata/css/css-block/run-in-fixedpos-between-002.xht.ini deleted file mode 100644 index 84fb7c576b6..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-fixedpos-between-002.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-fixedpos-between-002.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-float-between-001.xht.ini b/tests/wpt/metadata/css/css-block/run-in-float-between-001.xht.ini deleted file mode 100644 index 16c2e40fcb8..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-float-between-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-float-between-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-float-between-002.xht.ini b/tests/wpt/metadata/css/css-block/run-in-float-between-002.xht.ini deleted file mode 100644 index 5d1ae86d452..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-float-between-002.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-float-between-002.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-inherit-001.xht.ini b/tests/wpt/metadata/css/css-block/run-in-inherit-001.xht.ini deleted file mode 100644 index e4d5c3718ff..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-inherit-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-inherit-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-inline-between-003.xht.ini b/tests/wpt/metadata/css/css-block/run-in-inline-between-003.xht.ini deleted file mode 100644 index 4cbb1927126..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-inline-between-003.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-inline-between-003.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-inline-block-between-003.xht.ini b/tests/wpt/metadata/css/css-block/run-in-inline-block-between-003.xht.ini deleted file mode 100644 index 94e42aacc1a..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-inline-block-between-003.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-inline-block-between-003.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-inline-table-between-003.xht.ini b/tests/wpt/metadata/css/css-block/run-in-inline-table-between-003.xht.ini deleted file mode 100644 index 5e58af7fd2b..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-inline-table-between-003.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-inline-table-between-003.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-listitem-between-001.xht.ini b/tests/wpt/metadata/css/css-block/run-in-listitem-between-001.xht.ini deleted file mode 100644 index c8cf3528516..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-listitem-between-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-listitem-between-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-listitem-between-002.xht.ini b/tests/wpt/metadata/css/css-block/run-in-listitem-between-002.xht.ini deleted file mode 100644 index b1cf7538d12..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-listitem-between-002.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-listitem-between-002.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-listitem-between-003.xht.ini b/tests/wpt/metadata/css/css-block/run-in-listitem-between-003.xht.ini deleted file mode 100644 index 7fa6fa57f86..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-listitem-between-003.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-listitem-between-003.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-relpos-between-003.xht.ini b/tests/wpt/metadata/css/css-block/run-in-relpos-between-003.xht.ini deleted file mode 100644 index ee18b60783a..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-relpos-between-003.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-relpos-between-003.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-replaced-001.xht.ini b/tests/wpt/metadata/css/css-block/run-in-replaced-001.xht.ini deleted file mode 100644 index 8e2460e8a0a..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-replaced-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-replaced-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-restyle-003.xht.ini b/tests/wpt/metadata/css/css-block/run-in-restyle-003.xht.ini deleted file mode 100644 index 99060956c70..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-restyle-003.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-restyle-003.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-run-in-between-003.xht.ini b/tests/wpt/metadata/css/css-block/run-in-run-in-between-003.xht.ini deleted file mode 100644 index 913bd257979..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-run-in-between-003.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-run-in-between-003.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-run-in-between-004.xht.ini b/tests/wpt/metadata/css/css-block/run-in-run-in-between-004.xht.ini deleted file mode 100644 index 27b01f4dfab..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-run-in-between-004.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-run-in-between-004.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-run-in-between-005.xht.ini b/tests/wpt/metadata/css/css-block/run-in-run-in-between-005.xht.ini deleted file mode 100644 index a27522207f3..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-run-in-between-005.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-run-in-between-005.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-run-in-between-006.xht.ini b/tests/wpt/metadata/css/css-block/run-in-run-in-between-006.xht.ini deleted file mode 100644 index a89e0e18cfe..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-run-in-between-006.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-run-in-between-006.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-run-in-between-007.xht.ini b/tests/wpt/metadata/css/css-block/run-in-run-in-between-007.xht.ini deleted file mode 100644 index e9740569069..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-run-in-between-007.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-run-in-between-007.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-table-between-003.xht.ini b/tests/wpt/metadata/css/css-block/run-in-table-between-003.xht.ini deleted file mode 100644 index 764fe74a9ea..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-table-between-003.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-table-between-003.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-table-cell-between-003.xht.ini b/tests/wpt/metadata/css/css-block/run-in-table-cell-between-003.xht.ini deleted file mode 100644 index 46da2ca4125..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-table-cell-between-003.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-table-cell-between-003.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-table-row-between-003.xht.ini b/tests/wpt/metadata/css/css-block/run-in-table-row-between-003.xht.ini deleted file mode 100644 index e2bf1c42371..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-table-row-between-003.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-table-row-between-003.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-text-between-004.xht.ini b/tests/wpt/metadata/css/css-block/run-in-text-between-004.xht.ini deleted file mode 100644 index fac83125988..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-text-between-004.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-text-between-004.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-block/run-in-text-between-005.xht.ini b/tests/wpt/metadata/css/css-block/run-in-text-between-005.xht.ini deleted file mode 100644 index 2e94491740e..00000000000 --- a/tests/wpt/metadata/css/css-block/run-in-text-between-005.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[run-in-text-between-005.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-color/color-001.html.ini b/tests/wpt/metadata/css/css-color/color-001.html.ini deleted file mode 100644 index ffaf684f384..00000000000 --- a/tests/wpt/metadata/css/css-color/color-001.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[color-001.html] - expected: FAIL diff --git a/tests/wpt/metadata/css/css-color/color-003.html.ini b/tests/wpt/metadata/css/css-color/color-003.html.ini deleted file mode 100644 index 0e638df7b46..00000000000 --- a/tests/wpt/metadata/css/css-color/color-003.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[color-003.html] - expected: FAIL diff --git a/tests/wpt/metadata/css/css-color/currentcolor-001.html.ini b/tests/wpt/metadata/css/css-color/currentcolor-001.html.ini deleted file mode 100644 index c9861c726c5..00000000000 --- a/tests/wpt/metadata/css/css-color/currentcolor-001.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[currentcolor-001.html] - expected: FAIL diff --git a/tests/wpt/metadata/css/css-color/currentcolor-002.html.ini b/tests/wpt/metadata/css/css-color/currentcolor-002.html.ini deleted file mode 100644 index 6eb6550c070..00000000000 --- a/tests/wpt/metadata/css/css-color/currentcolor-002.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[currentcolor-002.html] - expected: FAIL diff --git a/tests/wpt/metadata/css/css-flexbox/anonymous-flex-item-001.html.ini b/tests/wpt/metadata/css/css-flexbox/anonymous-flex-item-001.html.ini new file mode 100644 index 00000000000..b22638a8537 --- /dev/null +++ b/tests/wpt/metadata/css/css-flexbox/anonymous-flex-item-001.html.ini @@ -0,0 +1,2 @@ +[anonymous-flex-item-001.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/css-flexbox/anonymous-flex-item-003.html.ini b/tests/wpt/metadata/css/css-flexbox/anonymous-flex-item-003.html.ini new file mode 100644 index 00000000000..331eec32683 --- /dev/null +++ b/tests/wpt/metadata/css/css-flexbox/anonymous-flex-item-003.html.ini @@ -0,0 +1,2 @@ +[anonymous-flex-item-003.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/css-flexbox/anonymous-flex-item-005.html.ini b/tests/wpt/metadata/css/css-flexbox/anonymous-flex-item-005.html.ini new file mode 100644 index 00000000000..f5db1aa1610 --- /dev/null +++ b/tests/wpt/metadata/css/css-flexbox/anonymous-flex-item-005.html.ini @@ -0,0 +1,2 @@ +[anonymous-flex-item-005.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/css-flexbox/anonymous-flex-item-006.html.ini b/tests/wpt/metadata/css/css-flexbox/anonymous-flex-item-006.html.ini new file mode 100644 index 00000000000..5865ea15bc8 --- /dev/null +++ b/tests/wpt/metadata/css/css-flexbox/anonymous-flex-item-006.html.ini @@ -0,0 +1,2 @@ +[anonymous-flex-item-006.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/css-flexbox/percentage-heights-004.html.ini b/tests/wpt/metadata/css/css-flexbox/percentage-heights-004.html.ini new file mode 100644 index 00000000000..988af23e1f6 --- /dev/null +++ b/tests/wpt/metadata/css/css-flexbox/percentage-heights-004.html.ini @@ -0,0 +1,2 @@ +[percentage-heights-004.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/css-flexbox/table-as-item-narrow-content.html.ini b/tests/wpt/metadata/css/css-flexbox/table-as-item-narrow-content.html.ini new file mode 100644 index 00000000000..194e30876c1 --- /dev/null +++ b/tests/wpt/metadata/css/css-flexbox/table-as-item-narrow-content.html.ini @@ -0,0 +1,2 @@ +[table-as-item-narrow-content.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/css-flexbox/table-as-item-wide-content.html.ini b/tests/wpt/metadata/css/css-flexbox/table-as-item-wide-content.html.ini new file mode 100644 index 00000000000..f6def90a63b --- /dev/null +++ b/tests/wpt/metadata/css/css-flexbox/table-as-item-wide-content.html.ini @@ -0,0 +1,2 @@ +[table-as-item-wide-content.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/css-multicol/multicol-count-computed-001.xht.ini b/tests/wpt/metadata/css/css-multicol/multicol-count-computed-001.xht.ini deleted file mode 100644 index 0ec74934be1..00000000000 --- a/tests/wpt/metadata/css/css-multicol/multicol-count-computed-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[multicol-count-computed-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-multicol/multicol-count-computed-002.xht.ini b/tests/wpt/metadata/css/css-multicol/multicol-count-computed-002.xht.ini deleted file mode 100644 index 08c18e5950c..00000000000 --- a/tests/wpt/metadata/css/css-multicol/multicol-count-computed-002.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[multicol-count-computed-002.xht] - expected: FAIL diff --git a/tests/wpt/metadata/css/css-multicol/multicol-count-large-001.xht.ini b/tests/wpt/metadata/css/css-multicol/multicol-count-large-001.xht.ini deleted file mode 100644 index ab7602c8729..00000000000 --- a/tests/wpt/metadata/css/css-multicol/multicol-count-large-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[multicol-count-large-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-multicol/multicol-count-large-002.xht.ini b/tests/wpt/metadata/css/css-multicol/multicol-count-large-002.xht.ini deleted file mode 100644 index e5ea24727e4..00000000000 --- a/tests/wpt/metadata/css/css-multicol/multicol-count-large-002.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[multicol-count-large-002.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-multicol/multicol-fill-auto.xht.ini b/tests/wpt/metadata/css/css-multicol/multicol-fill-auto.xht.ini deleted file mode 100644 index 2444eb2c3d9..00000000000 --- a/tests/wpt/metadata/css/css-multicol/multicol-fill-auto.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[multicol-fill-auto.xht] - type: reftest - expected: TIMEOUT diff --git a/tests/wpt/metadata/css/css-multicol/multicol-inherit-004.xht.ini b/tests/wpt/metadata/css/css-multicol/multicol-inherit-004.xht.ini deleted file mode 100644 index 7091b9d314d..00000000000 --- a/tests/wpt/metadata/css/css-multicol/multicol-inherit-004.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[multicol-inherit-004.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-multicol/multicol-rule-style-groove-001.xht.ini b/tests/wpt/metadata/css/css-multicol/multicol-rule-style-groove-001.xht.ini deleted file mode 100644 index 86b889128e3..00000000000 --- a/tests/wpt/metadata/css/css-multicol/multicol-rule-style-groove-001.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[multicol-rule-style-groove-001.xht] - expected: FAIL diff --git a/tests/wpt/metadata/css/css-multicol/multicol-rule-style-inset-001.xht.ini b/tests/wpt/metadata/css/css-multicol/multicol-rule-style-inset-001.xht.ini deleted file mode 100644 index da85daf7e38..00000000000 --- a/tests/wpt/metadata/css/css-multicol/multicol-rule-style-inset-001.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[multicol-rule-style-inset-001.xht] - expected: FAIL diff --git a/tests/wpt/metadata/css/css-multicol/multicol-rule-style-outset-001.xht.ini b/tests/wpt/metadata/css/css-multicol/multicol-rule-style-outset-001.xht.ini deleted file mode 100644 index 9755d370914..00000000000 --- a/tests/wpt/metadata/css/css-multicol/multicol-rule-style-outset-001.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[multicol-rule-style-outset-001.xht] - expected: FAIL diff --git a/tests/wpt/metadata/css/css-multicol/multicol-rule-style-ridge-001.xht.ini b/tests/wpt/metadata/css/css-multicol/multicol-rule-style-ridge-001.xht.ini deleted file mode 100644 index 3163cb42b9d..00000000000 --- a/tests/wpt/metadata/css/css-multicol/multicol-rule-style-ridge-001.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[multicol-rule-style-ridge-001.xht] - expected: FAIL diff --git a/tests/wpt/metadata/css/css-multicol/multicol-span-all-child-001.xht.ini b/tests/wpt/metadata/css/css-multicol/multicol-span-all-child-001.xht.ini deleted file mode 100644 index 3c4d7203d21..00000000000 --- a/tests/wpt/metadata/css/css-multicol/multicol-span-all-child-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[multicol-span-all-child-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-multicol/multicol-span-all-child-002.xht.ini b/tests/wpt/metadata/css/css-multicol/multicol-span-all-child-002.xht.ini deleted file mode 100644 index 867a42a30ea..00000000000 --- a/tests/wpt/metadata/css/css-multicol/multicol-span-all-child-002.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[multicol-span-all-child-002.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-multicol/multicol-span-all-margin-nested-003.xht.ini b/tests/wpt/metadata/css/css-multicol/multicol-span-all-margin-nested-003.xht.ini deleted file mode 100644 index 190b2195d7e..00000000000 --- a/tests/wpt/metadata/css/css-multicol/multicol-span-all-margin-nested-003.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[multicol-span-all-margin-nested-003.xht] - type: reftest - expected: TIMEOUT diff --git a/tests/wpt/metadata/css/css-multicol/multicol-width-ems-001.xht.ini b/tests/wpt/metadata/css/css-multicol/multicol-width-ems-001.xht.ini deleted file mode 100644 index 9aa34c830da..00000000000 --- a/tests/wpt/metadata/css/css-multicol/multicol-width-ems-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[multicol-width-ems-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/css/css-style-attr/style-attr-urls-003.xht.ini b/tests/wpt/metadata/css/css-style-attr/style-attr-urls-003.xht.ini deleted file mode 100644 index d656c060555..00000000000 --- a/tests/wpt/metadata/css/css-style-attr/style-attr-urls-003.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[style-attr-urls-003.xht] - expected: FAIL diff --git a/tests/wpt/metadata/css/css-text-decor/text-decoration-color.html.ini b/tests/wpt/metadata/css/css-text-decor/text-decoration-color.html.ini new file mode 100644 index 00000000000..81c110041f6 --- /dev/null +++ b/tests/wpt/metadata/css/css-text-decor/text-decoration-color.html.ini @@ -0,0 +1,2 @@ +[text-decoration-color.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/css-text-decor/text-decoration-line-012.xht.ini b/tests/wpt/metadata/css/css-text-decor/text-decoration-line-012.xht.ini deleted file mode 100644 index 1eacec34566..00000000000 --- a/tests/wpt/metadata/css/css-text-decor/text-decoration-line-012.xht.ini +++ /dev/null @@ -1,4 +0,0 @@ -[text-decoration-line-012.xht] - type: reftest - expected: - if os == "mac": FAIL diff --git a/tests/wpt/metadata/css/css-text-decor/text-decoration-serialization.tentative.html.ini b/tests/wpt/metadata/css/css-text-decor/text-decoration-serialization.tentative.html.ini new file mode 100644 index 00000000000..501b9848c78 --- /dev/null +++ b/tests/wpt/metadata/css/css-text-decor/text-decoration-serialization.tentative.html.ini @@ -0,0 +1,4 @@ +[text-decoration-serialization.tentative.html] + [text-decoration shorthand serialization] + expected: FAIL + diff --git a/tests/wpt/metadata/css/css-transforms/transform-box/fill-box-mutation.html.ini b/tests/wpt/metadata/css/css-transforms/transform-box/fill-box-mutation.html.ini new file mode 100644 index 00000000000..2a8fe8adfe7 --- /dev/null +++ b/tests/wpt/metadata/css/css-transforms/transform-box/fill-box-mutation.html.ini @@ -0,0 +1,2 @@ +[fill-box-mutation.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/css-color/hex-001.html.ini b/tests/wpt/metadata/css/css-transforms/transform-box/fill-box.html.ini similarity index 51% rename from tests/wpt/metadata/css/css-color/hex-001.html.ini rename to tests/wpt/metadata/css/css-transforms/transform-box/fill-box.html.ini index 5b223d8822f..536029e626b 100644 --- a/tests/wpt/metadata/css/css-color/hex-001.html.ini +++ b/tests/wpt/metadata/css/css-transforms/transform-box/fill-box.html.ini @@ -1,2 +1,2 @@ -[hex-001.html] +[fill-box.html] expected: FAIL diff --git a/tests/wpt/metadata/css/css-transforms/transform-box/value-changed.html.ini b/tests/wpt/metadata/css/css-transforms/transform-box/value-changed.html.ini new file mode 100644 index 00000000000..0067c94bc23 --- /dev/null +++ b/tests/wpt/metadata/css/css-transforms/transform-box/value-changed.html.ini @@ -0,0 +1,2 @@ +[value-changed.html] + expected: TIMEOUT diff --git a/tests/wpt/metadata/css/css-transforms/transform-box/view-box-nested.html.ini b/tests/wpt/metadata/css/css-transforms/transform-box/view-box-nested.html.ini new file mode 100644 index 00000000000..d7b29996b28 --- /dev/null +++ b/tests/wpt/metadata/css/css-transforms/transform-box/view-box-nested.html.ini @@ -0,0 +1,2 @@ +[view-box-nested.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/css-transforms/transform-box/view-box-viewbox-nested.html.ini b/tests/wpt/metadata/css/css-transforms/transform-box/view-box-viewbox-nested.html.ini new file mode 100644 index 00000000000..74ff4a1dfe9 --- /dev/null +++ b/tests/wpt/metadata/css/css-transforms/transform-box/view-box-viewbox-nested.html.ini @@ -0,0 +1,2 @@ +[view-box-viewbox-nested.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/css-transforms/transform-box/view-box-viewbox.html.ini b/tests/wpt/metadata/css/css-transforms/transform-box/view-box-viewbox.html.ini new file mode 100644 index 00000000000..d628df64758 --- /dev/null +++ b/tests/wpt/metadata/css/css-transforms/transform-box/view-box-viewbox.html.ini @@ -0,0 +1,2 @@ +[view-box-viewbox.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/css-color/hex-002.html.ini b/tests/wpt/metadata/css/css-transforms/transform-box/view-box.html.ini similarity index 51% rename from tests/wpt/metadata/css/css-color/hex-002.html.ini rename to tests/wpt/metadata/css/css-transforms/transform-box/view-box.html.ini index 7d7e587c206..53b0567e12d 100644 --- a/tests/wpt/metadata/css/css-color/hex-002.html.ini +++ b/tests/wpt/metadata/css/css-transforms/transform-box/view-box.html.ini @@ -1,2 +1,2 @@ -[hex-002.html] +[view-box.html] expected: FAIL diff --git a/tests/wpt/metadata/css/css-ui/outline-014.html.ini b/tests/wpt/metadata/css/css-ui/outline-014.html.ini index c07eb92e12b..89f88d32926 100644 --- a/tests/wpt/metadata/css/css-ui/outline-014.html.ini +++ b/tests/wpt/metadata/css/css-ui/outline-014.html.ini @@ -2,4 +2,3 @@ type: reftest expected: FAIL bug: https://github.com/servo/servo/issues/19508 - diff --git a/tests/wpt/metadata/css/css-values/vh_not_refreshing_on_chrome.html.ini b/tests/wpt/metadata/css/css-values/vh_not_refreshing_on_chrome.html.ini new file mode 100644 index 00000000000..26435e28b09 --- /dev/null +++ b/tests/wpt/metadata/css/css-values/vh_not_refreshing_on_chrome.html.ini @@ -0,0 +1,2 @@ +[vh_not_refreshing_on_chrome.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/cssom-view/scroll-behavior-smooth.html.ini b/tests/wpt/metadata/css/cssom-view/scroll-behavior-smooth.html.ini new file mode 100644 index 00000000000..e1a609649d6 --- /dev/null +++ b/tests/wpt/metadata/css/cssom-view/scroll-behavior-smooth.html.ini @@ -0,0 +1,5 @@ +[scroll-behavior-smooth.html] + expected: ERROR + [scroll-behavior: smooth on DIV element] + expected: FAIL + diff --git a/tests/wpt/metadata/css/cssom/getComputedStyle-pseudo.html.ini b/tests/wpt/metadata/css/cssom/getComputedStyle-pseudo.html.ini index f0d704bf616..114f59a0286 100644 --- a/tests/wpt/metadata/css/cssom/getComputedStyle-pseudo.html.ini +++ b/tests/wpt/metadata/css/cssom/getComputedStyle-pseudo.html.ini @@ -8,3 +8,6 @@ [Item-based blockification of nonexistent pseudo-elements] expected: FAIL + [display: contents on pseudo-elements] + expected: FAIL + diff --git a/tests/wpt/metadata/css/cssom/medialist-dynamic-001.html.ini b/tests/wpt/metadata/css/cssom/medialist-dynamic-001.html.ini new file mode 100644 index 00000000000..0d28942060d --- /dev/null +++ b/tests/wpt/metadata/css/cssom/medialist-dynamic-001.html.ini @@ -0,0 +1,2 @@ +[medialist-dynamic-001.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/mediaqueries/test_media_queries.html.ini b/tests/wpt/metadata/css/mediaqueries/test_media_queries.html.ini index 8210ee452cd..63f757ce648 100644 --- a/tests/wpt/metadata/css/mediaqueries/test_media_queries.html.ini +++ b/tests/wpt/metadata/css/mediaqueries/test_media_queries.html.ini @@ -227,108 +227,6 @@ [subtest_78] expected: FAIL - [subtest_79] - expected: FAIL - - [subtest_82] - expected: FAIL - - [subtest_84] - expected: FAIL - - [subtest_85] - expected: FAIL - - [subtest_86] - expected: FAIL - - [subtest_89] - expected: FAIL - - [subtest_90] - expected: FAIL - - [subtest_92] - expected: FAIL - - [subtest_95] - expected: FAIL - - [subtest_97] - expected: FAIL - - [subtest_98] - expected: FAIL - - [subtest_99] - expected: FAIL - - [subtest_102] - expected: FAIL - - [subtest_103] - expected: FAIL - - [subtest_105] - expected: FAIL - - [subtest_108] - expected: FAIL - - [subtest_110] - expected: FAIL - - [subtest_111] - expected: FAIL - - [subtest_112] - expected: FAIL - - [subtest_115] - expected: FAIL - - [subtest_116] - expected: FAIL - - [subtest_118] - expected: FAIL - - [subtest_121] - expected: FAIL - - [subtest_123] - expected: FAIL - - [subtest_124] - expected: FAIL - - [subtest_125] - expected: FAIL - - [subtest_128] - expected: FAIL - - [subtest_129] - expected: FAIL - - [subtest_131] - expected: FAIL - - [subtest_135] - expected: FAIL - - [subtest_136] - expected: FAIL - - [subtest_138] - expected: FAIL - - [subtest_139] - expected: FAIL - - [subtest_140] - expected: FAIL - [subtest_141] expected: FAIL @@ -356,99 +254,15 @@ [subtest_149] expected: FAIL - [subtest_150] - expected: FAIL - - [subtest_151] - expected: FAIL - - [subtest_153] - expected: FAIL - - [subtest_154] - expected: FAIL - - [subtest_156] - expected: FAIL - - [subtest_157] - expected: FAIL - - [subtest_158] - expected: FAIL - - [subtest_163] - expected: FAIL - - [subtest_164] - expected: FAIL - - [subtest_165] - expected: FAIL - - [subtest_170] - expected: FAIL - - [subtest_171] - expected: FAIL - - [subtest_172] - expected: FAIL - - [subtest_173] - expected: FAIL - [subtest_176] expected: FAIL - [subtest_177] - expected: FAIL - - [subtest_180] - expected: FAIL - - [subtest_181] - expected: FAIL - [subtest_182] expected: FAIL - [subtest_183] - expected: FAIL - - [subtest_184] - expected: FAIL - - [subtest_187] - expected: FAIL - - [subtest_188] - expected: FAIL - - [subtest_189] - expected: FAIL - - [subtest_191] - expected: FAIL - - [subtest_193] - expected: FAIL - [subtest_194] expected: FAIL - [subtest_195] - expected: FAIL - - [subtest_196] - expected: FAIL - - [subtest_197] - expected: FAIL - - [subtest_199] - expected: FAIL - [subtest_200] expected: FAIL @@ -545,15 +359,6 @@ [monochrome_and_color] expected: FAIL - [subtest_231] - expected: FAIL - - [subtest_234] - expected: FAIL - - [subtest_236] - expected: FAIL - [subtest_238] expected: FAIL @@ -629,21 +434,6 @@ [subtest_264] expected: FAIL - [subtest_265] - expected: FAIL - - [subtest_267] - expected: FAIL - - [subtest_269] - expected: FAIL - - [subtest_270] - expected: FAIL - - [subtest_271] - expected: FAIL - [subtest_272] expected: FAIL @@ -707,9 +497,6 @@ [subtest_292] expected: FAIL - [find_resolution] - expected: FAIL - [subtest_295] expected: FAIL @@ -719,15 +506,9 @@ [subtest_299] expected: FAIL - [subtest_300] - expected: FAIL - [subtest_302] expected: FAIL - [subtest_303] - expected: FAIL - [subtest_304] expected: FAIL @@ -749,15 +530,6 @@ [subtest_313] expected: FAIL - [subtest_314] - expected: FAIL - - [subtest_315] - expected: FAIL - - [subtest_316] - expected: FAIL - [subtest_317] expected: FAIL @@ -800,27 +572,216 @@ [subtest_340] expected: FAIL - [subtest_341] - expected: FAIL - - [subtest_342] - expected: FAIL - - [subtest_343] - expected: FAIL - - [subtest_344] - expected: FAIL - [subtest_346] expected: FAIL - [subtest_347] - expected: FAIL - [subtest_350] expected: FAIL - [subtest_351] + [subtest_80] + expected: FAIL + + [subtest_81] + expected: FAIL + + [subtest_83] + expected: FAIL + + [subtest_87] + expected: FAIL + + [subtest_88] + expected: FAIL + + [subtest_91] + expected: FAIL + + [subtest_93] + expected: FAIL + + [subtest_94] + expected: FAIL + + [subtest_96] + expected: FAIL + + [subtest_100] + expected: FAIL + + [subtest_101] + expected: FAIL + + [subtest_104] + expected: FAIL + + [subtest_106] + expected: FAIL + + [subtest_107] + expected: FAIL + + [subtest_109] + expected: FAIL + + [subtest_113] + expected: FAIL + + [subtest_114] + expected: FAIL + + [subtest_117] + expected: FAIL + + [subtest_119] + expected: FAIL + + [subtest_120] + expected: FAIL + + [subtest_122] + expected: FAIL + + [subtest_126] + expected: FAIL + + [subtest_127] + expected: FAIL + + [subtest_130] + expected: FAIL + + [subtest_132] + expected: FAIL + + [subtest_133] + expected: FAIL + + [subtest_134] + expected: FAIL + + [subtest_137] + expected: FAIL + + [subtest_152] + expected: FAIL + + [subtest_155] + expected: FAIL + + [subtest_159] + expected: FAIL + + [subtest_160] + expected: FAIL + + [subtest_161] + expected: FAIL + + [subtest_162] + expected: FAIL + + [subtest_166] + expected: FAIL + + [subtest_167] + expected: FAIL + + [subtest_168] + expected: FAIL + + [subtest_169] + expected: FAIL + + [subtest_174] + expected: FAIL + + [subtest_175] + expected: FAIL + + [subtest_178] + expected: FAIL + + [subtest_179] + expected: FAIL + + [subtest_185] + expected: FAIL + + [subtest_186] + expected: FAIL + + [subtest_190] + expected: FAIL + + [subtest_192] + expected: FAIL + + [subtest_198] + expected: FAIL + + [find_depth] + expected: FAIL + + [subtest_232] + expected: FAIL + + [subtest_233] + expected: FAIL + + [subtest_235] + expected: FAIL + + [subtest_266] + expected: FAIL + + [subtest_268] + expected: FAIL + + [subtest_294] + expected: FAIL + + [subtest_310] + expected: FAIL + + [subtest_311] + expected: FAIL + + [subtest_312] + expected: FAIL + + [subtest_325] + expected: FAIL + + [subtest_328] + expected: FAIL + + [subtest_329] + expected: FAIL + + [subtest_332] + expected: FAIL + + [subtest_337] + expected: FAIL + + [subtest_349] + expected: FAIL + + [subtest_353] + expected: FAIL + + [subtest_354] + expected: FAIL + + [subtest_357] + expected: FAIL + + [subtest_358] + expected: FAIL + + [subtest_359] + expected: FAIL + + [subtest_360] expected: FAIL diff --git a/tests/wpt/metadata/css/selectors/any-link-dynamic-001.html.ini b/tests/wpt/metadata/css/selectors/any-link-dynamic-001.html.ini new file mode 100644 index 00000000000..586972d310f --- /dev/null +++ b/tests/wpt/metadata/css/selectors/any-link-dynamic-001.html.ini @@ -0,0 +1,2 @@ +[any-link-dynamic-001.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/selectors/invalidation/any-link-pseudo.html.ini b/tests/wpt/metadata/css/selectors/invalidation/any-link-pseudo.html.ini new file mode 100644 index 00000000000..7cf5d1b77a2 --- /dev/null +++ b/tests/wpt/metadata/css/selectors/invalidation/any-link-pseudo.html.ini @@ -0,0 +1,4 @@ +[any-link-pseudo.html] + [Style was recalculated for the :any-link pseudo class.] + expected: FAIL + diff --git a/tests/wpt/metadata/custom-elements/microtasks-and-constructors.html.ini b/tests/wpt/metadata/custom-elements/microtasks-and-constructors.html.ini index 00638b8a8c2..22111c6cb3d 100644 --- a/tests/wpt/metadata/custom-elements/microtasks-and-constructors.html.ini +++ b/tests/wpt/metadata/custom-elements/microtasks-and-constructors.html.ini @@ -1,4 +1,3 @@ [microtasks-and-constructors.html] expected: CRASH bug: https://github.com/servo/servo/issues/19392 - diff --git a/tests/wpt/metadata/custom-elements/parser/parser-fallsback-to-unknown-element.html.ini b/tests/wpt/metadata/custom-elements/parser/parser-fallsback-to-unknown-element.html.ini index b8c0c4d4172..9f8fb480445 100644 --- a/tests/wpt/metadata/custom-elements/parser/parser-fallsback-to-unknown-element.html.ini +++ b/tests/wpt/metadata/custom-elements/parser/parser-fallsback-to-unknown-element.html.ini @@ -1,4 +1,3 @@ [parser-fallsback-to-unknown-element.html] expected: CRASH bug: https://github.com/servo/servo/issues/19392 - diff --git a/tests/wpt/metadata/custom-elements/parser/parser-uses-registry-of-owner-document.html.ini b/tests/wpt/metadata/custom-elements/parser/parser-uses-registry-of-owner-document.html.ini index aea72a43f87..f682fd43fb6 100644 --- a/tests/wpt/metadata/custom-elements/parser/parser-uses-registry-of-owner-document.html.ini +++ b/tests/wpt/metadata/custom-elements/parser/parser-uses-registry-of-owner-document.html.ini @@ -6,3 +6,9 @@ [HTML parser must use the registry of window.document in a document created by document.implementation.createHTMLDocument()] expected: FAIL + [document.write() must not instantiate a custom element without a defined insertion point] + expected: FAIL + + [document.writeln() must not instantiate a custom element without a defined insertion point] + expected: FAIL + diff --git a/tests/wpt/metadata/dom/events/Event-subclasses-constructors.html.ini b/tests/wpt/metadata/dom/events/Event-subclasses-constructors.html.ini index f25d6555b66..c8c3c5ec618 100644 --- a/tests/wpt/metadata/dom/events/Event-subclasses-constructors.html.ini +++ b/tests/wpt/metadata/dom/events/Event-subclasses-constructors.html.ini @@ -57,3 +57,21 @@ [CompositionEvent constructor (argument with non-default values)] expected: FAIL + [SubclassedEvent constructor (no argument)] + expected: FAIL + + [SubclassedEvent constructor (undefined argument)] + expected: FAIL + + [SubclassedEvent constructor (null argument)] + expected: FAIL + + [SubclassedEvent constructor (empty argument)] + expected: FAIL + + [SubclassedEvent constructor (argument with default values)] + expected: FAIL + + [SubclassedEvent constructor (argument with non-default values)] + expected: FAIL + diff --git a/tests/wpt/metadata/dom/events/EventListener-invoke-legacy.html.ini b/tests/wpt/metadata/dom/events/EventListener-invoke-legacy.html.ini index ff1b7c039c6..c7ff398c924 100644 --- a/tests/wpt/metadata/dom/events/EventListener-invoke-legacy.html.ini +++ b/tests/wpt/metadata/dom/events/EventListener-invoke-legacy.html.ini @@ -1,9 +1,6 @@ [EventListener-invoke-legacy.html] type: testharness expected: TIMEOUT - [Listener of transitionend] - expected: FAIL - [Legacy listener of transitionend] expected: TIMEOUT diff --git a/tests/wpt/metadata/fetch/api/redirect/redirect-method-worker.html.ini b/tests/wpt/metadata/fetch/api/redirect/redirect-method-worker.html.ini index 672f5a8635a..37435990814 100644 --- a/tests/wpt/metadata/fetch/api/redirect/redirect-method-worker.html.ini +++ b/tests/wpt/metadata/fetch/api/redirect/redirect-method-worker.html.ini @@ -36,3 +36,9 @@ [Redirect 307 with HEAD] expected: FAIL + [Redirect 307 with POST (string body)] + expected: FAIL + + [Redirect 307 with POST (blob body)] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/api/redirect/redirect-method.html.ini b/tests/wpt/metadata/fetch/api/redirect/redirect-method.html.ini index de315047f46..3f92aa3540c 100644 --- a/tests/wpt/metadata/fetch/api/redirect/redirect-method.html.ini +++ b/tests/wpt/metadata/fetch/api/redirect/redirect-method.html.ini @@ -36,3 +36,9 @@ [Redirect 307 with HEAD] expected: FAIL + [Redirect 307 with POST (string body)] + expected: FAIL + + [Redirect 307 with POST (blob body)] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/api/request/destination/fetch-destination.https.html.ini b/tests/wpt/metadata/fetch/api/request/destination/fetch-destination.https.html.ini new file mode 100644 index 00000000000..c61b4930e0c --- /dev/null +++ b/tests/wpt/metadata/fetch/api/request/destination/fetch-destination.https.html.ini @@ -0,0 +1,4 @@ +[fetch-destination.https.html] + [Service Worker: the body of FetchEvent using XMLHttpRequest] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/api/request/request-keepalive-quota.html.ini b/tests/wpt/metadata/fetch/api/request/request-keepalive-quota.html.ini index 53ccea0d402..e4d7c3be226 100644 --- a/tests/wpt/metadata/fetch/api/request/request-keepalive-quota.html.ini +++ b/tests/wpt/metadata/fetch/api/request/request-keepalive-quota.html.ini @@ -6,3 +6,6 @@ [A Keep-Alive fetch() should not be allowed if the Quota is used up.] expected: FAIL + [A Keep-Alive fetch() should return only its allocated Quota upon promise resolution.] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/http-cache/partial.html.ini b/tests/wpt/metadata/fetch/http-cache/partial.html.ini index 65c7f3ebc0c..d3f8a45038e 100644 --- a/tests/wpt/metadata/fetch/http-cache/partial.html.ini +++ b/tests/wpt/metadata/fetch/http-cache/partial.html.ini @@ -1,6 +1,5 @@ [partial.html] type: testharness - [HTTP cache stores partial content and completes it.] expected: FAIL diff --git a/tests/wpt/metadata/hr-time/idlharness.html.ini b/tests/wpt/metadata/hr-time/idlharness.html.ini index 028cee6abc5..1b082bfa85f 100644 --- a/tests/wpt/metadata/hr-time/idlharness.html.ini +++ b/tests/wpt/metadata/hr-time/idlharness.html.ini @@ -21,3 +21,9 @@ [Test default toJSON operation of Performance] expected: FAIL + [Performance interface: window.performance must inherit property "timeOrigin" with the proper type] + expected: FAIL + + [Performance interface: window.performance must inherit property "toJSON()" with the proper type] + expected: FAIL + diff --git a/tests/wpt/metadata/hr-time/performance-tojson.html.ini b/tests/wpt/metadata/hr-time/performance-tojson.html.ini new file mode 100644 index 00000000000..f04c6c49fa6 --- /dev/null +++ b/tests/wpt/metadata/hr-time/performance-tojson.html.ini @@ -0,0 +1,4 @@ +[performance-tojson.html] + [Untitled] + expected: FAIL + diff --git a/tests/wpt/metadata/html/browsers/history/the-session-history-of-browsing-contexts/navigation-in-onload.tentative.html.ini b/tests/wpt/metadata/html/browsers/history/the-session-history-of-browsing-contexts/navigation-in-onload.tentative.html.ini index 37a316d60be..2d6b8fa2546 100644 --- a/tests/wpt/metadata/html/browsers/history/the-session-history-of-browsing-contexts/navigation-in-onload.tentative.html.ini +++ b/tests/wpt/metadata/html/browsers/history/the-session-history-of-browsing-contexts/navigation-in-onload.tentative.html.ini @@ -1,4 +1,5 @@ [navigation-in-onload.tentative.html] + expected: ERROR [Navigation in onload handler] - expected: FAIL + expected: NOTRUN diff --git a/tests/wpt/metadata/html/browsers/the-window-object/window-properties.html.ini b/tests/wpt/metadata/html/browsers/the-window-object/window-properties.html.ini index 905abfcd492..a8a3946b8e7 100644 --- a/tests/wpt/metadata/html/browsers/the-window-object/window-properties.html.ini +++ b/tests/wpt/metadata/html/browsers/the-window-object/window-properties.html.ini @@ -1,5 +1,6 @@ [window-properties.html] type: testharness + expected: TIMEOUT [Window method: stop] expected: FAIL diff --git a/tests/wpt/metadata/html/dom/interfaces.html.ini b/tests/wpt/metadata/html/dom/interfaces.html.ini index 30512680019..d58a1b90b02 100644 --- a/tests/wpt/metadata/html/dom/interfaces.html.ini +++ b/tests/wpt/metadata/html/dom/interfaces.html.ini @@ -14316,3 +14316,18 @@ [History interface: window.history must inherit property "index" with the proper type] expected: FAIL + [HTMLElement interface: attribute inputMode] + expected: FAIL + + [HTMLElement interface: document.createElement("noscript") must inherit property "inputMode" with the proper type] + expected: FAIL + + [HTMLSlotElement interface: operation assignedElements(AssignedNodesOptions)] + expected: FAIL + + [HTMLSlotElement interface: document.createElement("slot") must inherit property "assignedElements(AssignedNodesOptions)" with the proper type] + expected: FAIL + + [HTMLSlotElement interface: calling assignedElements(AssignedNodesOptions) on document.createElement("slot") with too few arguments must throw TypeError] + expected: FAIL + diff --git a/tests/wpt/metadata/html/dom/reflection-misc.html.ini b/tests/wpt/metadata/html/dom/reflection-misc.html.ini index 91808fec6d2..eb6cf13e977 100644 --- a/tests/wpt/metadata/html/dom/reflection-misc.html.ini +++ b/tests/wpt/metadata/html/dom/reflection-misc.html.ini @@ -18540,3 +18540,339 @@ [slot.name: IDL set to object "test-valueOf"] expected: FAIL + [undefinedelement.inputMode: typeof IDL attribute] + expected: FAIL + + [undefinedelement.inputMode: IDL get with DOM attribute unset] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to ""] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to " \\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07 \\b\\t\\n\\v\\f\\r\\x0e\\x0f \\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17 \\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f foo "] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to undefined] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to 7] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to 1.5] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to true] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to false] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to object "[object Object\]"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to NaN] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to Infinity] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to -Infinity] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "\\0"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to null] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to object "test-toString"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to object "test-valueOf"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "none"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "xnone"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "none\\0"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "one"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "NONE"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "text"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "xtext"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "text\\0"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "ext"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "TEXT"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "tel"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "xtel"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "tel\\0"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "el"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "TEL"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "url"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "xurl"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "url\\0"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "rl"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "URL"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "email"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "xemail"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "email\\0"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "mail"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "EMAIL"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "numeric"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "xnumeric"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "numeric\\0"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "umeric"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "NUMERIC"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "decimal"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "xdecimal"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "decimal\\0"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "ecimal"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "DECIMAL"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "search"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "xsearch"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "search\\0"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "earch"] + expected: FAIL + + [undefinedelement.inputMode: setAttribute() to "SEARCH"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to ""] + expected: FAIL + + [undefinedelement.inputMode: IDL set to " \\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07 \\b\\t\\n\\v\\f\\r\\x0e\\x0f \\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17 \\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f foo "] + expected: FAIL + + [undefinedelement.inputMode: IDL set to undefined] + expected: FAIL + + [undefinedelement.inputMode: IDL set to 7] + expected: FAIL + + [undefinedelement.inputMode: IDL set to 1.5] + expected: FAIL + + [undefinedelement.inputMode: IDL set to true] + expected: FAIL + + [undefinedelement.inputMode: IDL set to false] + expected: FAIL + + [undefinedelement.inputMode: IDL set to object "[object Object\]"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to NaN] + expected: FAIL + + [undefinedelement.inputMode: IDL set to Infinity] + expected: FAIL + + [undefinedelement.inputMode: IDL set to -Infinity] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "\\0"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to null] + expected: FAIL + + [undefinedelement.inputMode: IDL set to object "test-toString"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to object "test-valueOf"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "none"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "xnone"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "none\\0"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "one"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "NONE"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "text"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "xtext"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "text\\0"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "ext"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "TEXT"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "tel"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "xtel"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "tel\\0"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "el"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "TEL"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "url"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "xurl"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "url\\0"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "rl"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "URL"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "email"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "xemail"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "email\\0"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "mail"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "EMAIL"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "numeric"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "xnumeric"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "numeric\\0"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "umeric"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "NUMERIC"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "decimal"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "xdecimal"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "decimal\\0"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "ecimal"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "DECIMAL"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "search"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "xsearch"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "search\\0"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "earch"] + expected: FAIL + + [undefinedelement.inputMode: IDL set to "SEARCH"] + expected: FAIL + diff --git a/tests/wpt/metadata/html/dom/usvstring-reflection.html.ini b/tests/wpt/metadata/html/dom/usvstring-reflection.html.ini new file mode 100644 index 00000000000..fabbe8f8ca0 --- /dev/null +++ b/tests/wpt/metadata/html/dom/usvstring-reflection.html.ini @@ -0,0 +1,19 @@ +[usvstring-reflection.html] + [window.open : unpaired surrogate codepoint should be replaced with U+FFFD] + expected: FAIL + + [anchor : unpaired surrogate codepoint should be replaced with U+FFFD] + expected: FAIL + + [area : unpaired surrogate codepoint should be replaced with U+FFFD] + expected: FAIL + + [frame : unpaired surrogate codepoint should be replaced with U+FFFD] + expected: FAIL + + [iframe : unpaired surrogate codepoint should be replaced with U+FFFD] + expected: FAIL + + [source : unpaired surrogate codepoint should be replaced with U+FFFD] + expected: FAIL + diff --git a/tests/wpt/metadata/html/form-elements/the-textarea-element/multiline-placeholder-cr.html.ini b/tests/wpt/metadata/html/form-elements/the-textarea-element/multiline-placeholder-cr.html.ini new file mode 100644 index 00000000000..341c31c230c --- /dev/null +++ b/tests/wpt/metadata/html/form-elements/the-textarea-element/multiline-placeholder-cr.html.ini @@ -0,0 +1,2 @@ +[multiline-placeholder-cr.html] + expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLMediaElement/crossOrigin.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLMediaElement/crossOrigin.html.ini new file mode 100644 index 00000000000..684d8638fcc --- /dev/null +++ b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLMediaElement/crossOrigin.html.ini @@ -0,0 +1,31 @@ +[crossOrigin.html] + [HTMLMediaElement.crossOrigin] + expected: FAIL + + [HTMLMediaElement.crossOrigin, content attribute missing] + expected: FAIL + + [HTMLMediaElement.crossOrigin, content attribute invalid value] + expected: FAIL + + [HTMLMediaElement.crossOrigin, content attribute empty string] + expected: FAIL + + [HTMLMediaElement.crossOrigin, content attribute uppercase ANONYMOUS] + expected: FAIL + + [HTMLMediaElement.crossOrigin, content attribute use-credentials] + expected: FAIL + + [HTMLMediaElement.crossOrigin, setting to empty string] + expected: FAIL + + [HTMLMediaElement.crossOrigin, setting to invalid value] + expected: FAIL + + [HTMLMediaElement.crossOrigin, setting to uppercase ANONYMOUS] + expected: FAIL + + [HTMLMediaElement.crossOrigin, setting to use-credentials] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLTrackElement/readyState.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLTrackElement/readyState.html.ini index 27cb06d6489..db492bf4d80 100644 --- a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLTrackElement/readyState.html.ini +++ b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLTrackElement/readyState.html.ini @@ -3,3 +3,6 @@ [HTMLTrackElement.readyState default value] expected: FAIL + [HTMLTrackElement.readyState values] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/interfaces/TextTrackCue/constructor.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/interfaces/TextTrackCue/constructor.html.ini new file mode 100644 index 00000000000..9bef795b52a --- /dev/null +++ b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/interfaces/TextTrackCue/constructor.html.ini @@ -0,0 +1,7 @@ +[constructor.html] + [TextTrackCue and VTTCue are separate interfaces] + expected: FAIL + + [TextTrackCue constructor should not be supported] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/forms/the-input-element/date.html.ini b/tests/wpt/metadata/html/semantics/forms/the-input-element/date.html.ini index 99eb0c7bba3..1354ae61137 100644 --- a/tests/wpt/metadata/html/semantics/forms/the-input-element/date.html.ini +++ b/tests/wpt/metadata/html/semantics/forms/the-input-element/date.html.ini @@ -5,3 +5,4 @@ [The max attribute, if specified, must have a value that is a valid date string.] expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/forms/the-input-element/datetime-local.html.ini b/tests/wpt/metadata/html/semantics/forms/the-input-element/datetime-local.html.ini index ed93cfbd3d9..10d425b9e86 100644 --- a/tests/wpt/metadata/html/semantics/forms/the-input-element/datetime-local.html.ini +++ b/tests/wpt/metadata/html/semantics/forms/the-input-element/datetime-local.html.ini @@ -1,6 +1,5 @@ [datetime-local.html] type: testharness - [Value < min attribute] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/forms/the-input-element/month.html.ini b/tests/wpt/metadata/html/semantics/forms/the-input-element/month.html.ini index dd41c559298..b688bb4eb9c 100644 --- a/tests/wpt/metadata/html/semantics/forms/the-input-element/month.html.ini +++ b/tests/wpt/metadata/html/semantics/forms/the-input-element/month.html.ini @@ -2,3 +2,4 @@ type: testharness [When step attribute is given invalid value, it must ignore the invalid value and use defaul value instead.] expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/forms/the-input-element/type-change-state.html.ini b/tests/wpt/metadata/html/semantics/forms/the-input-element/type-change-state.html.ini index da29acb8975..887b455d261 100644 --- a/tests/wpt/metadata/html/semantics/forms/the-input-element/type-change-state.html.ini +++ b/tests/wpt/metadata/html/semantics/forms/the-input-element/type-change-state.html.ini @@ -329,3 +329,4 @@ [change state from color to range] expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/forms/the-select-element/select-add.html.ini b/tests/wpt/metadata/html/semantics/forms/the-select-element/select-add.html.ini new file mode 100644 index 00000000000..510c23a07de --- /dev/null +++ b/tests/wpt/metadata/html/semantics/forms/the-select-element/select-add.html.ini @@ -0,0 +1,7 @@ +[select-add.html] + [test that HTMLSelectElement.add method can add option element] + expected: FAIL + + [test that HierarchyRequestError exception must be thrown when element is an ancestor of the element into which it is to be inserted] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/interactive-elements/the-dialog-element/abspos-dialog-layout.html.ini b/tests/wpt/metadata/html/semantics/interactive-elements/the-dialog-element/abspos-dialog-layout.html.ini new file mode 100644 index 00000000000..6cfa67fcebc --- /dev/null +++ b/tests/wpt/metadata/html/semantics/interactive-elements/the-dialog-element/abspos-dialog-layout.html.ini @@ -0,0 +1,43 @@ +[abspos-dialog-layout.html] + [showModal() should center in the viewport] + expected: FAIL + + [The dialog is a positioned element, so the top and bottom should not have style auto.] + expected: FAIL + + [Dialog should be recentered if showModal() is called after close()] + expected: FAIL + + [Dialog should not recenter on relayout.] + expected: FAIL + + [A tall dialog should be positioned at the top of the viewport.] + expected: FAIL + + [The dialog should be centered regardless of the presence of a horizontal scrollbar.] + expected: FAIL + + [Centering should work when dialog is inside positioned containers.] + expected: FAIL + + [A centered dialog's position should survive becoming display:none temporarily.] + expected: FAIL + + [Dialog should lose centering when removed from the document.] + expected: FAIL + + [Dialog's specified position should survive after close() and showModal().] + expected: FAIL + + [Dialog should be recentered if showModal() is called after removing 'open'.] + expected: FAIL + + [Dialog should not be centered if showModal() was called when an ancestor had display 'none'.] + expected: FAIL + + [A dialog with specified 'top' should be positioned as usual] + expected: FAIL + + [A dialog with specified 'bottom' should be positioned as usual] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/interactive-elements/the-dialog-element/dialog-scrolled-viewport.html.ini b/tests/wpt/metadata/html/semantics/interactive-elements/the-dialog-element/dialog-scrolled-viewport.html.ini new file mode 100644 index 00000000000..998744525b3 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/interactive-elements/the-dialog-element/dialog-scrolled-viewport.html.ini @@ -0,0 +1,4 @@ +[dialog-scrolled-viewport.html] + [Tests modal dialog's containing block is the initial containing block] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/interactive-elements/the-dialog-element/inert-does-not-match-disabled-selector.html.ini b/tests/wpt/metadata/html/semantics/interactive-elements/the-dialog-element/inert-does-not-match-disabled-selector.html.ini new file mode 100644 index 00000000000..43c91c1a01e --- /dev/null +++ b/tests/wpt/metadata/html/semantics/interactive-elements/the-dialog-element/inert-does-not-match-disabled-selector.html.ini @@ -0,0 +1,4 @@ +[inert-does-not-match-disabled-selector.html] + [Tests inert elements do not match the :disabled selector.] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/interactive-elements/the-dialog-element/inert-node-is-unfocusable.html.ini b/tests/wpt/metadata/html/semantics/interactive-elements/the-dialog-element/inert-node-is-unfocusable.html.ini new file mode 100644 index 00000000000..92fe79a8971 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/interactive-elements/the-dialog-element/inert-node-is-unfocusable.html.ini @@ -0,0 +1,4 @@ +[inert-node-is-unfocusable.html] + [Test that inert nodes are not focusable.] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/choice-of-error-1.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/choice-of-error-1.html.ini new file mode 100644 index 00000000000..2046faa6ed8 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/choice-of-error-1.html.ini @@ -0,0 +1,4 @@ +[choice-of-error-1.html] + [Parse errors in different files should be reported depending on different roots] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/choice-of-error-2.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/choice-of-error-2.html.ini new file mode 100644 index 00000000000..9d55b00ff31 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/choice-of-error-2.html.ini @@ -0,0 +1,4 @@ +[choice-of-error-2.html] + [Instantiation errors in different files should be reported depending on different roots] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/choice-of-error-3.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/choice-of-error-3.html.ini new file mode 100644 index 00000000000..19e185bb343 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/choice-of-error-3.html.ini @@ -0,0 +1,4 @@ +[choice-of-error-3.html] + [Evaluation errors are cached in intermediate module scripts] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-classic.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-classic.html.ini deleted file mode 100644 index 01ce266ac9e..00000000000 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-classic.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[string-compilation-base-url-classic.html] - type: testharness - [import() inside compiled strings uses the document base URL inside a classic script] - expected: FAIL - diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-classic.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-classic.html.ini new file mode 100644 index 00000000000..01f5651e9e1 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-classic.html.ini @@ -0,0 +1,4 @@ +[string-compilation-base-url-external-classic.html] + [import() inside compiled strings uses the script base URL inside a classic script that is loaded from a file] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-module.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-module.html.ini new file mode 100644 index 00000000000..2dbf1ad6e29 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-module.html.ini @@ -0,0 +1,2 @@ +[string-compilation-base-url-external-module.html] + expected: TIMEOUT diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-classic.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-classic.html.ini new file mode 100644 index 00000000000..e27c6b06a0c --- /dev/null +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-classic.html.ini @@ -0,0 +1,4 @@ +[string-compilation-base-url-inline-classic.html] + [import() inside compiled strings uses the script base URL (= document base URL) inside an inline classic script] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-module.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-module.html.ini new file mode 100644 index 00000000000..238b8a863f4 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-module.html.ini @@ -0,0 +1,2 @@ +[string-compilation-base-url-inline-module.html] + expected: TIMEOUT diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-module.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-module.html.ini deleted file mode 100644 index d5cadc8673b..00000000000 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-module.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[string-compilation-base-url-module.html] - type: testharness - expected: TIMEOUT diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-classic.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-classic.html.ini new file mode 100644 index 00000000000..bb7e3e4779f --- /dev/null +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-classic.html.ini @@ -0,0 +1,2 @@ +[string-compilation-integrity-classic.html] + expected: TIMEOUT diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-module.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-module.html.ini new file mode 100644 index 00000000000..da1840b68fb --- /dev/null +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-module.html.ini @@ -0,0 +1,2 @@ +[string-compilation-integrity-module.html] + expected: TIMEOUT diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-classic.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-classic.html.ini new file mode 100644 index 00000000000..2432b79d461 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-classic.html.ini @@ -0,0 +1,20 @@ +[string-compilation-nonce-classic.html] + expected: ERROR + [setTimeout must inherit the nonce from the triggering script, thus execute] + expected: TIMEOUT + + [direct eval must inherit the nonce from the triggering script, thus execute] + expected: NOTRUN + + [indirect eval must inherit the nonce from the triggering script, thus execute] + expected: NOTRUN + + [the Function constructor must inherit the nonce from the triggering script, thus execute] + expected: NOTRUN + + [reflected inline event handlers must inherit the nonce from the triggering script, thus execute] + expected: NOTRUN + + [inline event handlers triggered via UA code must inherit the nonce from the triggering script, thus execute] + expected: NOTRUN + diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-module.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-module.html.ini new file mode 100644 index 00000000000..d87f8ba32d7 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-module.html.ini @@ -0,0 +1,2 @@ +[string-compilation-nonce-module.html] + expected: TIMEOUT diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/error-type-1.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/error-type-1.html.ini new file mode 100644 index 00000000000..c756960b09d --- /dev/null +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/error-type-1.html.ini @@ -0,0 +1,4 @@ +[error-type-1.html] + [network error has higher priority than parse error] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/error-type-2.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/error-type-2.html.ini new file mode 100644 index 00000000000..e24139fb1a2 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/error-type-2.html.ini @@ -0,0 +1,4 @@ +[error-type-2.html] + [parse error has higher priority than instantiation error] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/error-type-3.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/error-type-3.html.ini new file mode 100644 index 00000000000..58cc436ec05 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/error-type-3.html.ini @@ -0,0 +1,4 @@ +[error-type-3.html] + [instantiation error has higher priority than evaluation error] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html.ini index c9c35bb3976..b3fdd6f764e 100644 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html.ini +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html.ini @@ -3,3 +3,6 @@ [Test that missing exports lead to SyntaxError events on window and load events on script, and that exceptions are remembered] expected: FAIL + [Test that missing exports lead to SyntaxError events on window and load events on script] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/instantiation-error-2.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/instantiation-error-2.html.ini index b00561ef5eb..c5e6fec931a 100644 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/instantiation-error-2.html.ini +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/instantiation-error-2.html.ini @@ -3,3 +3,6 @@ [Test that missing exports lead to SyntaxError events on window and load events on script, and that exceptions are remembered] expected: FAIL + [Test that missing exports lead to SyntaxError events on window and load events on script] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html.ini index 38c8188c8b2..25019f2ce0f 100644 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html.ini +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html.ini @@ -3,3 +3,6 @@ [Test that unresolvable cycles lead to SyntaxError events on window and load events on script, and that exceptions are remembered] expected: FAIL + [Test that unresolvable cycles lead to SyntaxError events on window and load events on script] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/instantiation-error-4.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/instantiation-error-4.html.ini index 3e63cc081c9..8acedfbc746 100644 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/instantiation-error-4.html.ini +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/instantiation-error-4.html.ini @@ -3,3 +3,6 @@ [Test that loading a graph in which a module is already errored results in that module's error.] expected: FAIL + [Test that loading a graph in which a module is already errored results in an error.] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/instantiation-error-5.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/instantiation-error-5.html.ini index d9bb17db2ce..44be8de5091 100644 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/instantiation-error-5.html.ini +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/instantiation-error-5.html.ini @@ -3,3 +3,6 @@ [Test that loading a graph in which a module is already errored results in that module's error.] expected: FAIL + [Test that loading a graph in which a module is already errored results an error.] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/referrer-no-referrer.sub.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/referrer-no-referrer.sub.html.ini new file mode 100644 index 00000000000..634cf356318 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/referrer-no-referrer.sub.html.ini @@ -0,0 +1,2 @@ +[referrer-no-referrer.sub.html] + expected: TIMEOUT diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub.html.ini new file mode 100644 index 00000000000..92d04781a2e --- /dev/null +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub.html.ini @@ -0,0 +1,2 @@ +[referrer-origin-when-cross-origin.sub.html] + expected: TIMEOUT diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/referrer-origin.sub.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/referrer-origin.sub.html.ini new file mode 100644 index 00000000000..9a2db3d8993 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/referrer-origin.sub.html.ini @@ -0,0 +1,2 @@ +[referrer-origin.sub.html] + expected: TIMEOUT diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/referrer-same-origin.sub.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/referrer-same-origin.sub.html.ini new file mode 100644 index 00000000000..d499edb6fc8 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/referrer-same-origin.sub.html.ini @@ -0,0 +1,2 @@ +[referrer-same-origin.sub.html] + expected: TIMEOUT diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/referrer-unsafe-url.sub.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/referrer-unsafe-url.sub.html.ini new file mode 100644 index 00000000000..2b700b1c9b4 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/referrer-unsafe-url.sub.html.ini @@ -0,0 +1,2 @@ +[referrer-unsafe-url.sub.html] + expected: TIMEOUT diff --git a/tests/wpt/metadata/html/semantics/text-level-semantics/the-a-element/a-download-click-404.html.ini b/tests/wpt/metadata/html/semantics/text-level-semantics/the-a-element/a-download-click-404.html.ini index f69644f7477..d173f7601cd 100644 --- a/tests/wpt/metadata/html/semantics/text-level-semantics/the-a-element/a-download-click-404.html.ini +++ b/tests/wpt/metadata/html/semantics/text-level-semantics/the-a-element/a-download-click-404.html.ini @@ -1,3 +1,5 @@ [a-download-click-404.html] type: testharness - expected: ERROR + [Do not navigate to 404 for anchor with download] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/text-level-semantics/the-a-element/a-download-click.html.ini b/tests/wpt/metadata/html/semantics/text-level-semantics/the-a-element/a-download-click.html.ini new file mode 100644 index 00000000000..b4d12d613ab --- /dev/null +++ b/tests/wpt/metadata/html/semantics/text-level-semantics/the-a-element/a-download-click.html.ini @@ -0,0 +1,4 @@ +[a-download-click.html] + [Clicking on an element with a download attribute must not throw an exception] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/text-level-semantics/the-ruby-element/ruby-usage.html.ini b/tests/wpt/metadata/html/semantics/text-level-semantics/the-ruby-element/ruby-usage.html.ini new file mode 100644 index 00000000000..1dac9f70200 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/text-level-semantics/the-ruby-element/ruby-usage.html.ini @@ -0,0 +1,2 @@ +[ruby-usage.html] + expected: FAIL diff --git a/tests/wpt/metadata/mozilla-sync b/tests/wpt/metadata/mozilla-sync index 530ceee0029..48dce5e5051 100644 --- a/tests/wpt/metadata/mozilla-sync +++ b/tests/wpt/metadata/mozilla-sync @@ -1,2 +1,2 @@ -local: 85fa6409bb699647b4f5e22952538365e87418d7 -upstream: 40ee9a4553dca805163766c5970979a23e357292 +local: 9187c9a093860d9f3c31b5a5f402458aa4a607cb +upstream: 1b93a7d98bc4849fa8f365d9bd13fb2a0448c6e1 diff --git a/tests/wpt/metadata/navigation-timing/idlharness.html.ini b/tests/wpt/metadata/navigation-timing/idlharness.html.ini index 3abacf64d64..30f14482254 100644 --- a/tests/wpt/metadata/navigation-timing/idlharness.html.ini +++ b/tests/wpt/metadata/navigation-timing/idlharness.html.ini @@ -342,3 +342,6 @@ [Test default toJSON operation of PerformanceNavigation] expected: FAIL + [Performance interface: window.performance must inherit property "navigation" with the proper type] + expected: FAIL + diff --git a/tests/wpt/metadata/performance-timeline/performanceentry-tojson.html.ini b/tests/wpt/metadata/performance-timeline/performanceentry-tojson.html.ini new file mode 100644 index 00000000000..c212efca8e8 --- /dev/null +++ b/tests/wpt/metadata/performance-timeline/performanceentry-tojson.html.ini @@ -0,0 +1,4 @@ +[performanceentry-tojson.html] + [Untitled] + expected: FAIL + diff --git a/tests/wpt/metadata/quirks-mode/hashless-hex-color.html.ini b/tests/wpt/metadata/quirks-mode/hashless-hex-color.html.ini deleted file mode 100644 index 78f1bc1f4c9..00000000000 --- a/tests/wpt/metadata/quirks-mode/hashless-hex-color.html.ini +++ /dev/null @@ -1,47 +0,0 @@ -[hashless-hex-color.html] - type: testharness - [rgb(calc(100 + 155), 255, 255) (quirks)] - expected: FAIL - - [rgb(calc(100 + 155), 255, 255) (almost standards)] - expected: FAIL - - [rgb(calc(100 + 155), 255, 255) (standards)] - expected: FAIL - - [rgba(calc(100 + 155), 255, 255, 001) (quirks)] - expected: FAIL - - [rgba(calc(100 + 155), 255, 255, 001) (almost standards)] - expected: FAIL - - [rgba(calc(100 + 155), 255, 255, 001) (standards)] - expected: FAIL - - [hsl(calc(050 + 050), 100%, 100%) (quirks)] - expected: FAIL - - [hsl(calc(050 + 050), 100%, 100%) (almost standards)] - expected: FAIL - - [hsl(calc(050 + 050), 100%, 100%) (standards)] - expected: FAIL - - [hsla(calc(050 + 050), 100%, 100%, 001) (quirks)] - expected: FAIL - - [hsla(calc(050 + 050), 100%, 100%, 001) (almost standards)] - expected: FAIL - - [hsla(calc(050 + 050), 100%, 100%, 001) (standards)] - expected: FAIL - - [rgb(calc(/**/100/**/ + /**/155/**/), 255, 255) (quirks)] - expected: FAIL - - [rgb(calc(/**/100/**/ + /**/155/**/), 255, 255) (almost standards)] - expected: FAIL - - [rgb(calc(/**/100/**/ + /**/155/**/), 255, 255) (standards)] - expected: FAIL - diff --git a/tests/wpt/metadata/quirks-mode/blocks-ignore-line-height.html.ini b/tests/wpt/metadata/quirks/blocks-ignore-line-height.html.ini similarity index 100% rename from tests/wpt/metadata/quirks-mode/blocks-ignore-line-height.html.ini rename to tests/wpt/metadata/quirks/blocks-ignore-line-height.html.ini diff --git a/tests/wpt/metadata/quirks-mode/line-height-calculation.html.ini b/tests/wpt/metadata/quirks/line-height-calculation.html.ini similarity index 100% rename from tests/wpt/metadata/quirks-mode/line-height-calculation.html.ini rename to tests/wpt/metadata/quirks/line-height-calculation.html.ini diff --git a/tests/wpt/metadata/quirks-mode/percentage-height-calculation.html.ini b/tests/wpt/metadata/quirks/percentage-height-calculation.html.ini similarity index 100% rename from tests/wpt/metadata/quirks-mode/percentage-height-calculation.html.ini rename to tests/wpt/metadata/quirks/percentage-height-calculation.html.ini diff --git a/tests/wpt/metadata/quirks-mode/supports.html.ini b/tests/wpt/metadata/quirks/supports.html.ini similarity index 100% rename from tests/wpt/metadata/quirks-mode/supports.html.ini rename to tests/wpt/metadata/quirks/supports.html.ini diff --git a/tests/wpt/metadata/quirks-mode/table-cell-nowrap-minimum-width-calculation.html.ini b/tests/wpt/metadata/quirks/table-cell-nowrap-minimum-width-calculation.html.ini similarity index 100% rename from tests/wpt/metadata/quirks-mode/table-cell-nowrap-minimum-width-calculation.html.ini rename to tests/wpt/metadata/quirks/table-cell-nowrap-minimum-width-calculation.html.ini diff --git a/tests/wpt/metadata/quirks-mode/table-cell-width-calculation.html.ini b/tests/wpt/metadata/quirks/table-cell-width-calculation.html.ini similarity index 100% rename from tests/wpt/metadata/quirks-mode/table-cell-width-calculation.html.ini rename to tests/wpt/metadata/quirks/table-cell-width-calculation.html.ini diff --git a/tests/wpt/metadata/quirks-mode/unitless-length.html.ini b/tests/wpt/metadata/quirks/unitless-length.html.ini similarity index 100% rename from tests/wpt/metadata/quirks-mode/unitless-length.html.ini rename to tests/wpt/metadata/quirks/unitless-length.html.ini diff --git a/tests/wpt/metadata/url/a-element-xhtml.xhtml.ini b/tests/wpt/metadata/url/a-element-xhtml.xhtml.ini index 55bf5603369..939b2644d3e 100644 --- a/tests/wpt/metadata/url/a-element-xhtml.xhtml.ini +++ b/tests/wpt/metadata/url/a-element-xhtml.xhtml.ini @@ -186,3 +186,27 @@ [Parsing: against ] expected: FAIL + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: bar> against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + diff --git a/tests/wpt/metadata/url/a-element.html.ini b/tests/wpt/metadata/url/a-element.html.ini index c3fe798ea76..aa7e1be63e1 100644 --- a/tests/wpt/metadata/url/a-element.html.ini +++ b/tests/wpt/metadata/url/a-element.html.ini @@ -186,3 +186,27 @@ [Parsing: against ] expected: FAIL + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: bar> against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + diff --git a/tests/wpt/metadata/url/url-constructor.html.ini b/tests/wpt/metadata/url/url-constructor.html.ini index fcd43bcda1a..c3b9ceadc63 100644 --- a/tests/wpt/metadata/url/url-constructor.html.ini +++ b/tests/wpt/metadata/url/url-constructor.html.ini @@ -177,3 +177,27 @@ [Parsing: against ] expected: FAIL + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: bar> against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + diff --git a/tests/wpt/metadata/url/url-setters.html.ini b/tests/wpt/metadata/url/url-setters.html.ini index 138d36a1f2c..dcb7cf62196 100644 --- a/tests/wpt/metadata/url/url-setters.html.ini +++ b/tests/wpt/metadata/url/url-setters.html.ini @@ -933,3 +933,48 @@ [: Setting .protocol = 'https' Port is set to null if it is the default for new scheme.] expected: FAIL + [URL: Setting .hash = '#foo bar'] + expected: FAIL + + [: Setting .hash = '#foo bar'] + expected: FAIL + + [: Setting .hash = '#foo bar'] + expected: FAIL + + [URL: Setting .hash = '#foo"bar'] + expected: FAIL + + [: Setting .hash = '#foo"bar'] + expected: FAIL + + [: Setting .hash = '#foo"bar'] + expected: FAIL + + [URL: Setting .hash = '#foo: Setting .hash = '#foo: Setting .hash = '#foo.hash = '#foo>bar'] + expected: FAIL + + [: Setting .hash = '#foo>bar'] + expected: FAIL + + [: Setting .hash = '#foo>bar'] + expected: FAIL + + [URL: Setting .hash = '#foo`bar'] + expected: FAIL + + [: Setting .hash = '#foo`bar'] + expected: FAIL + + [: Setting .hash = '#foo`bar'] + expected: FAIL + diff --git a/tests/wpt/metadata/workers/SharedWorker_dataUrl.html.ini b/tests/wpt/metadata/workers/SharedWorker_dataUrl.html.ini new file mode 100644 index 00000000000..b3bd1e4649f --- /dev/null +++ b/tests/wpt/metadata/workers/SharedWorker_dataUrl.html.ini @@ -0,0 +1,8 @@ +[SharedWorker_dataUrl.html] + expected: TIMEOUT + [Data URL not shared by cross-origin SharedWorkers] + expected: TIMEOUT + + [Data URLs shared by same-origin SharedWorkers] + expected: NOTRUN + diff --git a/tests/wpt/metadata/workers/data-url-shared.html.ini b/tests/wpt/metadata/workers/data-url-shared.html.ini index 35294e6609f..036709be081 100644 --- a/tests/wpt/metadata/workers/data-url-shared.html.ini +++ b/tests/wpt/metadata/workers/data-url-shared.html.ini @@ -27,3 +27,6 @@ [worker has opaque origin] expected: FAIL + [A data: URL shared worker should not be shared among origins.] + expected: FAIL + diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index 72d9560b7b2..9f3589df210 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -59973,7 +59973,7 @@ }, "paths": { "./lint.whitelist": [ - "28c20b33fcbd818a46005dcbf53473f8b8346c89", + "3e30a95c5b79cc3752c21739da62f47b37c025e5", "support" ], "bluetooth/advertisingEvent/watchAdvertisements-succeeds.html": [ diff --git a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/glsl/bugs/long-expressions-should-not-crash.html.ini b/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/glsl/bugs/long-expressions-should-not-crash.html.ini index fafbedda0a6..17dcfea137f 100644 --- a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/glsl/bugs/long-expressions-should-not-crash.html.ini +++ b/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/glsl/bugs/long-expressions-should-not-crash.html.ini @@ -2,3 +2,4 @@ expected: TIMEOUT [Overall test] expected: NOTRUN + diff --git a/tests/wpt/mozilla/tests/lint.whitelist b/tests/wpt/mozilla/tests/lint.whitelist index 1bd7f2d23df..4e9dcc5ddf8 100644 --- a/tests/wpt/mozilla/tests/lint.whitelist +++ b/tests/wpt/mozilla/tests/lint.whitelist @@ -29,3 +29,7 @@ LAYOUTTESTS APIS:* ## CSSWG-only checks ## SUPPORT-WRONG-DIR:* + +## Unnecessary checks ## + +WEB-PLATFORM.TEST:* \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/.travis.yml b/tests/wpt/web-platform-tests/.travis.yml index 933183f9a4b..dfad9bb136c 100644 --- a/tests/wpt/web-platform-tests/.travis.yml +++ b/tests/wpt/web-platform-tests/.travis.yml @@ -63,7 +63,7 @@ matrix: - fonts-liberation env: - secure: "YTSXPwI0DyCA1GhYrLT9KMEV6b7QQKuEeaQgeFDP38OTzJ1+cIj3CC4SRNqbnJ/6SJwPGcdqSxLuV8m4e5HFFnyCcQnJe6h8EMsTehZ7W3j/fP9UYrJqYqvGpe3Vj3xblO5pwBYmq7sg3jAmmuCgAgOW6VGf7cRMucrsmFeo7VM=" - - JOB=stability SCRIPT=tools/ci/ci_stability.sh PRODUCT=chrome:unstable + - JOB=stability SCRIPT=tools/ci/ci_stability.sh PRODUCT=chrome:dev - os: linux python: "2.7" env: @@ -94,7 +94,7 @@ matrix: - env: JOB=build_css SCRIPT=css/build-css-testsuites.sh - env: - secure: "YTSXPwI0DyCA1GhYrLT9KMEV6b7QQKuEeaQgeFDP38OTzJ1+cIj3CC4SRNqbnJ/6SJwPGcdqSxLuV8m4e5HFFnyCcQnJe6h8EMsTehZ7W3j/fP9UYrJqYqvGpe3Vj3xblO5pwBYmq7sg3jAmmuCgAgOW6VGf7cRMucrsmFeo7VM=" - - JOB=stability SCRIPT=tools/ci/ci_stability.sh PRODUCT=chrome:unstable + - JOB=stability SCRIPT=tools/ci/ci_stability.sh PRODUCT=chrome:dev - env: - secure: "YTSXPwI0DyCA1GhYrLT9KMEV6b7QQKuEeaQgeFDP38OTzJ1+cIj3CC4SRNqbnJ/6SJwPGcdqSxLuV8m4e5HFFnyCcQnJe6h8EMsTehZ7W3j/fP9UYrJqYqvGpe3Vj3xblO5pwBYmq7sg3jAmmuCgAgOW6VGf7cRMucrsmFeo7VM=" - JOB=stability SCRIPT=tools/ci/ci_stability.sh PRODUCT=sauce:MicrosoftEdge:14.14393 PLATFORM='Windows 10' diff --git a/tests/wpt/web-platform-tests/2dcontext/fill-and-stroke-styles/2d.gradient.object.invalidcolour.html b/tests/wpt/web-platform-tests/2dcontext/fill-and-stroke-styles/2d.gradient.object.invalidcolour.html index 7687d0b94ea..7ea349e74bc 100644 --- a/tests/wpt/web-platform-tests/2dcontext/fill-and-stroke-styles/2d.gradient.object.invalidcolour.html +++ b/tests/wpt/web-platform-tests/2dcontext/fill-and-stroke-styles/2d.gradient.object.invalidcolour.html @@ -21,6 +21,15 @@ _addTest(function(canvas, ctx) { var g = ctx.createLinearGradient(0, 0, 100, 0); assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, ""); }); +assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, 'rgb(NaN%, NaN%, NaN%)'); }); +assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, 'null'); }); +assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, 'undefined'); }); +assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, null); }); +assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, undefined); }); + +var g = ctx.createRadialGradient(0, 0, 0, 100, 0, 0); +assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, ""); }); +assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, 'rgb(NaN%, NaN%, NaN%)'); }); assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, 'null'); }); assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, 'undefined'); }); assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, null); }); diff --git a/tests/wpt/web-platform-tests/2dcontext/imagebitmap/createImageBitmap-invalid-args.html b/tests/wpt/web-platform-tests/2dcontext/imagebitmap/createImageBitmap-invalid-args.html index a0bcf48fb6c..ad8618a5ce0 100644 --- a/tests/wpt/web-platform-tests/2dcontext/imagebitmap/createImageBitmap-invalid-args.html +++ b/tests/wpt/web-platform-tests/2dcontext/imagebitmap/createImageBitmap-invalid-args.html @@ -1,10 +1,6 @@ - - - + - - - - diff --git a/tests/wpt/web-platform-tests/2dcontext/tools/tests2d.yaml b/tests/wpt/web-platform-tests/2dcontext/tools/tests2d.yaml index 63ffe9d5db8..7da08f96c1b 100644 --- a/tests/wpt/web-platform-tests/2dcontext/tools/tests2d.yaml +++ b/tests/wpt/web-platform-tests/2dcontext/tools/tests2d.yaml @@ -2092,6 +2092,15 @@ code: | var g = ctx.createLinearGradient(0, 0, 100, 0); @assert throws SYNTAX_ERR g.addColorStop(0, ""); + @assert throws SYNTAX_ERR g.addColorStop(0, 'rgb(NaN%, NaN%, NaN%)'); + @assert throws SYNTAX_ERR g.addColorStop(0, 'null'); + @assert throws SYNTAX_ERR g.addColorStop(0, 'undefined'); + @assert throws SYNTAX_ERR g.addColorStop(0, null); + @assert throws SYNTAX_ERR g.addColorStop(0, undefined); + + var g = ctx.createRadialGradient(0, 0, 0, 100, 0, 0); + @assert throws SYNTAX_ERR g.addColorStop(0, ""); + @assert throws SYNTAX_ERR g.addColorStop(0, 'rgb(NaN%, NaN%, NaN%)'); @assert throws SYNTAX_ERR g.addColorStop(0, 'null'); @assert throws SYNTAX_ERR g.addColorStop(0, 'undefined'); @assert throws SYNTAX_ERR g.addColorStop(0, null); diff --git a/tests/wpt/web-platform-tests/FileAPI/blob/Blob-Request-revoke-fetch.html b/tests/wpt/web-platform-tests/FileAPI/blob/Blob-Request-revoke-fetch.html new file mode 100644 index 00000000000..2cac5343cd8 --- /dev/null +++ b/tests/wpt/web-platform-tests/FileAPI/blob/Blob-Request-revoke-fetch.html @@ -0,0 +1,41 @@ + +Revoking blob URL used with Request/fetch + + + + diff --git a/tests/wpt/web-platform-tests/FileAPI/blob/Blob-constructor-endings.html b/tests/wpt/web-platform-tests/FileAPI/blob/Blob-constructor-endings.html new file mode 100644 index 00000000000..1dee99ff775 --- /dev/null +++ b/tests/wpt/web-platform-tests/FileAPI/blob/Blob-constructor-endings.html @@ -0,0 +1,104 @@ + + +Blob constructor: endings option + + + + diff --git a/tests/wpt/web-platform-tests/FileAPI/blob/Blob-constructor.html b/tests/wpt/web-platform-tests/FileAPI/blob/Blob-constructor.html index d8375c2a6e8..4d39ed78e0e 100644 --- a/tests/wpt/web-platform-tests/FileAPI/blob/Blob-constructor.html +++ b/tests/wpt/web-platform-tests/FileAPI/blob/Blob-constructor.html @@ -74,6 +74,20 @@ test_blob(function() { type: "", desc: "A plain object with @@iterator should be treated as a sequence for the blobParts argument." }); +test(t => { + const blob = new Blob({ + [Symbol.iterator]() { + var i = 0; + return {next: () => [ + {done:false, value:'ab'}, + {done:false, value:'cde'}, + {done:true} + ][i++] + }; + } + }); + assert_equals(blob.size, 5, 'Custom @@iterator should be treated as a sequence'); +}, "A plain object with custom @@iterator should be treated as a sequence for the blobParts argument."); test_blob(function() { return new Blob({ [Symbol.iterator]: Array.prototype[Symbol.iterator], @@ -392,26 +406,20 @@ test_blob(function() { desc: "Array with mixed types" }); -// options argument test(function() { - new Blob([], { endings: "invalidEnumValue" }); - new Blob([], { endings: null }); - new Blob([], { endings: undefined }); - new Blob([], { endings: 0 }); - new Blob([], { get endings() { assert_unreached("Should not call getter"); } }); -}, "The 'endings' property should be ignored."); + const accessed = []; + const stringified = []; -test(function() { - assert_throws(test_error, function() { - new Blob([], { - get type() { throw test_error; } - }); + new Blob([], { + get type() { accessed.push('type'); }, + get endings() { accessed.push('endings'); } }); - assert_throws(test_error, function() { - new Blob([], { - type: { toString: function() { throw test_error; } } - }); + new Blob([], { + type: { toString: () => { stringified.push('type'); return ''; } }, + endings: { toString: () => { stringified.push('endings'); return 'transparent'; } } }); + assert_array_equals(accessed, ['endings', 'type']); + assert_array_equals(stringified, ['endings', 'type']); }, "options properties should be accessed in lexicographic order."); test(function() { @@ -449,19 +457,16 @@ test(function() { }); }); -test_blob(function() { - return new Blob(["\na\r\nb\n\rc\r"], { endings: "transparent" }); -}, { - expected: "\na\r\nb\n\rc\r", - type: "", - desc: "Newlines should not change when endings is 'transparent'." -}); -test_blob(function() { - return new Blob(["\na\r\nb\n\rc\r"], { endings: "native" }); -}, { - expected: "\na\r\nb\n\rc\r", - type: "", - desc: "Newlines should not change when endings is 'native'." +[ + 123, + 123.4, + true, + 'abc' +].forEach(arg => { + test(t => { + assert_throws(new TypeError(), () => new Blob([], arg), + 'Blob constructor should throw with invalid property bag'); + }, `Passing ${JSON.stringify(arg)} for options should throw`); }); var type_tests = [ @@ -471,6 +476,7 @@ var type_tests = [ [[], 'A', 'a'], [[], 'text/html', 'text/html'], [[], 'TEXT/HTML', 'text/html'], + [[], 'text/plain;charset=utf-8', 'text/plain;charset=utf-8'], [[], '\u00E5', ''], [[], '\uD801\uDC7E', ''], // U+1047E [[], ' image/gif ', ' image/gif '], diff --git a/tests/wpt/web-platform-tests/FileAPI/file/File-constructor-endings.html b/tests/wpt/web-platform-tests/FileAPI/file/File-constructor-endings.html new file mode 100644 index 00000000000..f0f9090768f --- /dev/null +++ b/tests/wpt/web-platform-tests/FileAPI/file/File-constructor-endings.html @@ -0,0 +1,104 @@ + + +File constructor: endings option + + + + diff --git a/tests/wpt/web-platform-tests/FileAPI/file/File-constructor.html b/tests/wpt/web-platform-tests/FileAPI/file/File-constructor.html index 97c08b6546e..9c1a940662a 100644 --- a/tests/wpt/web-platform-tests/FileAPI/file/File-constructor.html +++ b/tests/wpt/web-platform-tests/FileAPI/file/File-constructor.html @@ -6,10 +6,20 @@
diff --git a/tests/wpt/web-platform-tests/FileAPI/file/send-file-form-iso-2022-jp.tentative.html b/tests/wpt/web-platform-tests/FileAPI/file/send-file-form-iso-2022-jp.tentative.html new file mode 100644 index 00000000000..421de301298 --- /dev/null +++ b/tests/wpt/web-platform-tests/FileAPI/file/send-file-form-iso-2022-jp.tentative.html @@ -0,0 +1,71 @@ + + +Upload files in ISO-2022-JP form (tentative) + + + + + + + + + + diff --git a/tests/wpt/web-platform-tests/FileAPI/file/send-file-form-utf-8.html b/tests/wpt/web-platform-tests/FileAPI/file/send-file-form-utf-8.html new file mode 100644 index 00000000000..03417ba72e4 --- /dev/null +++ b/tests/wpt/web-platform-tests/FileAPI/file/send-file-form-utf-8.html @@ -0,0 +1,61 @@ + + +Upload files in UTF-8 form + + + + + + + + diff --git a/tests/wpt/web-platform-tests/FileAPI/file/send-file-form-windows-1252.tentative.html b/tests/wpt/web-platform-tests/FileAPI/file/send-file-form-windows-1252.tentative.html new file mode 100644 index 00000000000..8e9463f83ae --- /dev/null +++ b/tests/wpt/web-platform-tests/FileAPI/file/send-file-form-windows-1252.tentative.html @@ -0,0 +1,70 @@ + + +Upload files in Windows-1252 form (tentative) + + + + + + + + + + diff --git a/tests/wpt/web-platform-tests/FileAPI/file/send-file-form-x-user-defined.tentative.html b/tests/wpt/web-platform-tests/FileAPI/file/send-file-form-x-user-defined.tentative.html new file mode 100644 index 00000000000..072e3bb1e02 --- /dev/null +++ b/tests/wpt/web-platform-tests/FileAPI/file/send-file-form-x-user-defined.tentative.html @@ -0,0 +1,70 @@ + + +Upload files in x-user-defined form (tentative) + + + + + + + + + + diff --git a/tests/wpt/web-platform-tests/FileAPI/file/send-file-form.html b/tests/wpt/web-platform-tests/FileAPI/file/send-file-form.html new file mode 100644 index 00000000000..baa8d4286c5 --- /dev/null +++ b/tests/wpt/web-platform-tests/FileAPI/file/send-file-form.html @@ -0,0 +1,25 @@ + + +Upload ASCII-named file in UTF-8 form + + + + + + + + diff --git a/tests/wpt/web-platform-tests/FileAPI/idlharness.html b/tests/wpt/web-platform-tests/FileAPI/idlharness.html index b88a7521688..7b706ad0dd8 100644 --- a/tests/wpt/web-platform-tests/FileAPI/idlharness.html +++ b/tests/wpt/web-platform-tests/FileAPI/idlharness.html @@ -30,8 +30,6 @@ setup(function() { request.onload = function() { var idls = request.responseText; - idl_array.add_untested_idls("[PrimaryGlobal] interface Window { };"); - idl_array.add_untested_idls("[Exposed=(Window,Worker)] interface ArrayBuffer {};"); idl_array.add_untested_idls("interface URL {};"); idl_array.add_untested_idls("[Exposed=(Window,Worker)] interface EventTarget {};"); diff --git a/tests/wpt/web-platform-tests/FileAPI/support/send-file-form-helper.js b/tests/wpt/web-platform-tests/FileAPI/support/send-file-form-helper.js new file mode 100644 index 00000000000..a7522c7b08e --- /dev/null +++ b/tests/wpt/web-platform-tests/FileAPI/support/send-file-form-helper.js @@ -0,0 +1,249 @@ +'use strict'; + +// Rationale for this particular test character sequence, which is +// used in filenames and also in file contents: +// +// - ABC~ ensures the string starts with something we can read to +// ensure it is from the correct source; ~ is used because even +// some 1-byte otherwise-ASCII-like parts of ISO-2022-JP +// interpret it differently. +// - ‾¥ are inside a single-byte range of ISO-2022-JP and help +// diagnose problems due to filesystem encoding or locale +// - ≈ is inside IBM437 and helps diagnose problems due to filesystem +// encoding or locale +// - ¤ is inside Latin-1 and helps diagnose problems due to +// filesystem encoding or locale; it is also the "simplest" case +// needing substitution in ISO-2022-JP +// - ・ is inside a single-byte range of ISO-2022-JP in some variants +// and helps diagnose problems due to filesystem encoding or locale; +// on the web it is distinct when decoding but unified when encoding +// - ・ is inside a double-byte range of ISO-2022-JP and helps +// diagnose problems due to filesystem encoding or locale +// - • is inside Windows-1252 and helps diagnose problems due to +// filesystem encoding or locale and also ensures these aren't +// accidentally turned into e.g. control codes +// - ∙ is inside IBM437 and helps diagnose problems due to filesystem +// encoding or locale +// - · is inside Latin-1 and helps diagnose problems due to +// filesystem encoding or locale and also ensures HTML named +// character references (e.g. ·) are not used +// - ☼ is inside IBM437 shadowing C0 and helps diagnose problems due to +// filesystem encoding or locale and also ensures these aren't +// accidentally turned into e.g. control codes +// - ★ is inside ISO-2022-JP on a non-Kanji page and makes correct +// output easier to spot +// - 星 is inside ISO-2022-JP on a Kanji page and makes correct +// output easier to spot +// - 🌟 is outside the BMP and makes incorrect surrogate pair +// substitution detectable and ensures substitutions work +// correctly immediately after Kanji 2-byte ISO-2022-JP +// - 星 repeated here ensures the correct codec state is used +// after a non-BMP substitution +// - ★ repeated here also makes correct output easier to spot +// - ☼ is inside IBM437 shadowing C0 and helps diagnose problems due to +// filesystem encoding or locale and also ensures these aren't +// accidentally turned into e.g. control codes and also ensures +// substitutions work correctly immediately after non-Kanji +// 2-byte ISO-2022-JP +// - · is inside Latin-1 and helps diagnose problems due to +// filesystem encoding or locale and also ensures HTML named +// character references (e.g. ·) are not used +// - ∙ is inside IBM437 and helps diagnose problems due to filesystem +// encoding or locale +// - • is inside Windows-1252 and again helps diagnose problems +// due to filesystem encoding or locale +// - ・ is inside a double-byte range of ISO-2022-JP and helps +// diagnose problems due to filesystem encoding or locale +// - ・ is inside a single-byte range of ISO-2022-JP in some variants +// and helps diagnose problems due to filesystem encoding or locale; +// on the web it is distinct when decoding but unified when encoding +// - ¤ is inside Latin-1 and helps diagnose problems due to +// filesystem encoding or locale; again it is a "simple" +// substitution case +// - ≈ is inside IBM437 and helps diagnose problems due to filesystem +// encoding or locale +// - ¥‾ are inside a single-byte range of ISO-2022-JP and help +// diagnose problems due to filesystem encoding or locale +// - ~XYZ ensures earlier errors don't lead to misencoding of +// simple ASCII +// +// Overall the near-symmetry makes common I18N mistakes like +// off-by-1-after-non-BMP easier to spot. All the characters +// are also allowed in Windows Unicode filenames. +const kTestChars = 'ABC~‾¥≈¤・・•∙·☼★星🌟星★☼·∙•・・¤≈¥‾~XYZ'; + +// NOTE: The expected interpretation of ISO-2022-JP according to +// https://encoding.spec.whatwg.org/#iso-2022-jp-encoder unifies +// single-byte and double-byte katakana. +const kTestFallbackIso2022jp = + ('ABC~\x1B(J~\\≈¤\x1B$B!&!&\x1B(B•∙·☼\x1B$B!z@1\x1B(B🌟' + + '\x1B$B@1!z\x1B(B☼·∙•\x1B$B!&!&\x1B(B¤≈\x1B(J\\~\x1B(B~XYZ').replace( + /[^\0-\x7F]/gu, + x => `&#${x.codePointAt(0)};`); + +// NOTE: \uFFFD is used here to replace Windows-1252 bytes to match +// how we will see them in the reflected POST bytes in a frame using +// UTF-8 byte interpretation. The bytes will actually be intact, but +// this code cannot tell and does not really care. +const kTestFallbackWindows1252 = + 'ABC~‾\xA5≈\xA4・・\x95∙\xB7☼★星🌟星★☼\xB7∙\x95・・\xA4≈\xA5‾~XYZ'.replace( + /[^\0-\xFF]/gu, + x => `&#${x.codePointAt(0)};`).replace(/[\x80-\xFF]/g, '\uFFFD'); + +const kTestFallbackXUserDefined = + kTestChars.replace(/[^\0-\x7F]/gu, x => `&#${x.codePointAt(0)};`); + +// formPostFileUploadTest - verifies multipart upload structure and +// numeric character reference replacement for filenames, field names, +// and field values. +// +// Uses /fetch/api/resources/echo-content.py to echo the upload +// POST with UTF-8 byte interpretation, leading to the "UTF-8 goggles" +// behavior documented below for expectedEncodedBaseName when non- +// UTF-8-compatible byte sequences appear in the formEncoding-encoded +// uploaded data. +// +// Fields in the parameter object: +// +// - fileNameSource: purely explanatory and gives a clue about which +// character encoding is the source for the non-7-bit-ASCII parts of +// the fileBaseName, or Unicode if no smaller-than-Unicode source +// contains all the characters. Used in the test name. +// - fileBaseName: the not-necessarily-just-7-bit-ASCII file basename +// used for the constructed test file. Used in the test name. +// - formEncoding: the acceptCharset of the form used to submit the +// test file. Used in the test name. +// - expectedEncodedBaseName: the expected formEncoding-encoded +// version of fileBaseName with unencodable characters replaced by +// numeric character references and non-7-bit-ASCII bytes seen +// through UTF-8 goggles; subsequences not interpretable as UTF-8 +// have each byte represented here by \uFFFD REPLACEMENT CHARACTER. +const formPostFileUploadTest = ({ + fileNameSource, + fileBaseName, + formEncoding, + expectedEncodedBaseName, +}) => { + promise_test(async testCase => { + + if (document.readyState !== 'complete') { + await new Promise(resolve => addEventListener('load', resolve)); + } + + const formTargetFrame = Object.assign(document.createElement('iframe'), { + name: 'formtargetframe', + }); + document.body.append(formTargetFrame); + testCase.add_cleanup(() => { + document.body.removeChild(formTargetFrame); + }); + + const form = Object.assign(document.createElement('form'), { + acceptCharset: formEncoding, + action: '/fetch/api/resources/echo-content.py', + method: 'POST', + enctype: 'multipart/form-data', + target: formTargetFrame.name, + }); + document.body.append(form); + testCase.add_cleanup(() => { + document.body.removeChild(form); + }); + + // Used to verify that the browser agrees with the test about + // which form charset is used. + form.append(Object.assign(document.createElement('input'), { + type: 'hidden', + name: '_charset_', + })); + + // Used to verify that the browser agrees with the test about + // field value replacement and encoding independently of file system + // idiosyncracies. + form.append(Object.assign(document.createElement('input'), { + type: 'hidden', + name: 'filename', + value: fileBaseName, + })); + + // Same, but with name and value reversed to ensure field names + // get the same treatment. + form.append(Object.assign(document.createElement('input'), { + type: 'hidden', + name: fileBaseName, + value: 'filename', + })); + + const fileInput = Object.assign(document.createElement('input'), { + type: 'file', + name: 'file', + }); + form.append(fileInput); + + // Removes c:\fakepath\ or other pseudofolder and returns just the + // final component of filePath; allows both / and \ as segment + // delimiters. + const baseNameOfFilePath = filePath => filePath.split(/[\/\\]/).pop(); + await new Promise(resolve => { + const dataTransfer = new DataTransfer; + dataTransfer.items.add( + new File([kTestChars], fileBaseName, {type: 'text/plain'})); + fileInput.files = dataTransfer.files; + // For historical reasons .value will be prefixed with + // c:\fakepath\, but the basename should match the file name + // exposed through the newer .files[0].name API. This check + // verifies that assumption. + assert_equals( + fileInput.files[0].name, + baseNameOfFilePath(fileInput.value), + `The basename of the field's value should match its files[0].name`); + form.submit(); + formTargetFrame.onload = resolve; + }); + + const formDataText = formTargetFrame.contentDocument.body.textContent; + const formDataLines = formDataText.split('\n'); + if (formDataLines.length && !formDataLines[formDataLines.length - 1]) { + --formDataLines.length; + } + assert_greater_than( + formDataLines.length, + 2, + `${fileBaseName}: multipart form data must have at least 3 lines: ${ + JSON.stringify(formDataText) + }`); + const boundary = formDataLines[0]; + assert_equals( + formDataLines[formDataLines.length - 1], + boundary + '--', + `${fileBaseName}: multipart form data must end with ${boundary}--: ${ + JSON.stringify(formDataText) + }`); + const expectedText = [ + boundary, + 'Content-Disposition: form-data; name="_charset_"', + '', + formEncoding, + boundary, + 'Content-Disposition: form-data; name="filename"', + '', + expectedEncodedBaseName, + boundary, + `Content-Disposition: form-data; name="${expectedEncodedBaseName}"`, + '', + 'filename', + boundary, + `Content-Disposition: form-data; name="file"; ` + + `filename="${expectedEncodedBaseName}"`, + 'Content-Type: text/plain', + '', + kTestChars, + boundary + '--', + ].join('\n'); + assert_true( + formDataText.startsWith(expectedText), + `Unexpected multipart-shaped form data received:\n${ + formDataText + }\nExpected:\n${expectedText}`); + }, `Upload ${fileBaseName} (${fileNameSource}) in ${formEncoding} form`); +}; diff --git a/tests/wpt/web-platform-tests/FileAPI/unicode.html b/tests/wpt/web-platform-tests/FileAPI/unicode.html new file mode 100644 index 00000000000..ce3e3579d7c --- /dev/null +++ b/tests/wpt/web-platform-tests/FileAPI/unicode.html @@ -0,0 +1,46 @@ + + +Blob/Unicode interaction: normalization and encoding + + + diff --git a/tests/wpt/web-platform-tests/FileAPI/url/url_xmlhttprequest_img.html b/tests/wpt/web-platform-tests/FileAPI/url/url_xmlhttprequest_img.html index 7f26633d81e..468dcb086d7 100644 --- a/tests/wpt/web-platform-tests/FileAPI/url/url_xmlhttprequest_img.html +++ b/tests/wpt/web-platform-tests/FileAPI/url/url_xmlhttprequest_img.html @@ -20,9 +20,8 @@ http.onloadend = function() { var fileDisplay = document.querySelector("#fileDisplay"); fileDisplay.src = window.URL.createObjectURL(http.response); - takeScreenshot(); + fileDisplay.onload = takeScreenshot; }; http.send(); - diff --git a/tests/wpt/web-platform-tests/IndexedDB/interfaces.html b/tests/wpt/web-platform-tests/IndexedDB/interfaces.html index 6fb37f88e51..30372b6d60b 100644 --- a/tests/wpt/web-platform-tests/IndexedDB/interfaces.html +++ b/tests/wpt/web-platform-tests/IndexedDB/interfaces.html @@ -20,7 +20,7 @@ async_test(function(t) { var idls = request.responseText; // https://html.spec.whatwg.org/multipage/browsers.html#window - idlArray.add_untested_idls("[PrimaryGlobal] interface Window { };"); + idlArray.add_untested_idls("[Global=Window, Exposed=Window] interface Window { };"); // https://html.spec.whatwg.org/multipage/webappapis.html#windoworworkerglobalscope-mixin idlArray.add_untested_idls(`[NoInterfaceObject, Exposed=(Window,Worker)] diff --git a/tests/wpt/web-platform-tests/README.md b/tests/wpt/web-platform-tests/README.md index b67e2082ab7..0247e8c69ce 100644 --- a/tests/wpt/web-platform-tests/README.md +++ b/tests/wpt/web-platform-tests/README.md @@ -53,8 +53,15 @@ Running Tests Manually ====================== The test server can be started using +``` +./wpt serve +``` - ./wpt serve +**On Windows**: You will need to preceed the prior command with +`python` or the path to the python binary. +```bash +python wpt serve +``` This will start HTTP servers on two ports and a websockets server on one port. By default one web server starts on port 8000 and the other @@ -82,12 +89,15 @@ file setup documented above, but you must *not* have the test server already running when calling `wpt run`. The basic command line syntax is: -``` +```bash ./wpt run product [tests] ``` **On Windows**: You will need to preceed the prior command with `python` or the path to the python binary. +```bash +python wpt product [tests] +``` where `product` is currently `firefox` or `chrome` and `[tests]` is a list of paths to tests. This will attempt to automatically locate a @@ -114,7 +124,7 @@ brew install nss On other platforms, download the firefox archive and common.tests.zip archive for your platform from -[https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central/](Mozilla CI) +[Mozilla CI](https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central/). Then extract `certutil[.exe]` from the tests.zip package and `libnss3[.so|.dll|.dynlib]` and put the former on your path and the latter on @@ -187,9 +197,13 @@ then remove the `tools` and `resources` directories, as above. Windows Notes ============================================= -On Windows `wpt` commands mut bre prefixed with `python` or the path +On Windows `wpt` commands must be prefixed with `python` or the path to the python binary (if `python` is not in your `%PATH%`). +```bash +python wpt [command] +``` + Alternatively, you may also use [Bash on Ubuntu on Windows](https://msdn.microsoft.com/en-us/commandline/wsl/about) in the Windows 10 Anniversary Update build, then access your windows diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures.worker.js b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures.worker.js deleted file mode 100644 index 705664c2d92..00000000000 --- a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures.worker.js +++ /dev/null @@ -1,5 +0,0 @@ -importScripts("/resources/testharness.js"); -importScripts("../util/helpers.js"); -importScripts("failures.js"); -run_test(); -done(); diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_AES-CBC.worker.js b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_AES-CBC.https.worker.js similarity index 100% rename from tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_AES-CBC.worker.js rename to tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_AES-CBC.https.worker.js diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_AES-CTR.worker.js b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_AES-CTR.https.worker.js similarity index 100% rename from tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_AES-CTR.worker.js rename to tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_AES-CTR.https.worker.js diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_AES-GCM.worker.js b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_AES-GCM.https.worker.js similarity index 100% rename from tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_AES-GCM.worker.js rename to tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_AES-GCM.https.worker.js diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_AES-KW.worker.js b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_AES-KW.https.worker.js similarity index 100% rename from tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_AES-KW.worker.js rename to tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_AES-KW.https.worker.js diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_ECDH.worker.js b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_ECDH.https.worker.js similarity index 100% rename from tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_ECDH.worker.js rename to tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_ECDH.https.worker.js diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_ECDSA.worker.js b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_ECDSA.https.worker.js similarity index 100% rename from tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_ECDSA.worker.js rename to tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_ECDSA.https.worker.js diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_HMAC.worker.js b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_HMAC.https.worker.js similarity index 100% rename from tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_HMAC.worker.js rename to tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_HMAC.https.worker.js diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_RSA-OAEP.worker.js b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_RSA-OAEP.https.worker.js similarity index 100% rename from tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_RSA-OAEP.worker.js rename to tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_RSA-OAEP.https.worker.js diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_RSA-PSS.worker.js b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_RSA-PSS.https.worker.js similarity index 100% rename from tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_RSA-PSS.worker.js rename to tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_RSA-PSS.https.worker.js diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.worker.js b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.https.worker.js similarity index 100% rename from tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.worker.js rename to tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.https.worker.js diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes.worker.js b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes.worker.js deleted file mode 100644 index 52e34946ef0..00000000000 --- a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes.worker.js +++ /dev/null @@ -1,6 +0,0 @@ -importScripts("/resources/testharness.js"); -importScripts("../util/helpers.js"); -importScripts("successes.js"); - -run_test(); -done(); diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_AES-CBC.worker.js b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_AES-CBC.https.worker.js similarity index 100% rename from tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_AES-CBC.worker.js rename to tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_AES-CBC.https.worker.js diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_AES-CTR.worker.js b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_AES-CTR.https.worker.js similarity index 100% rename from tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_AES-CTR.worker.js rename to tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_AES-CTR.https.worker.js diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_AES-GCM.worker.js b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_AES-GCM.https.worker.js similarity index 100% rename from tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_AES-GCM.worker.js rename to tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_AES-GCM.https.worker.js diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_AES-KW.worker.js b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_AES-KW.https.worker.js similarity index 100% rename from tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_AES-KW.worker.js rename to tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_AES-KW.https.worker.js diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_ECDH.worker.js b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_ECDH.https.worker.js similarity index 100% rename from tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_ECDH.worker.js rename to tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_ECDH.https.worker.js diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_ECDSA.worker.js b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_ECDSA.https.worker.js similarity index 100% rename from tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_ECDSA.worker.js rename to tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_ECDSA.https.worker.js diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_HMAC.worker.js b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_HMAC.https.worker.js similarity index 100% rename from tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_HMAC.worker.js rename to tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_HMAC.https.worker.js diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_RSA-OAEP.worker.js b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_RSA-OAEP.https.worker.js similarity index 100% rename from tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_RSA-OAEP.worker.js rename to tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_RSA-OAEP.https.worker.js diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_RSA-PSS.worker.js b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_RSA-PSS.https.worker.js similarity index 100% rename from tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_RSA-PSS.worker.js rename to tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_RSA-PSS.https.worker.js diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.worker.js b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.https.worker.js similarity index 100% rename from tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.worker.js rename to tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.https.worker.js diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/test_failures.https.html b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/test_failures.https.html deleted file mode 100644 index 14e57b25cf2..00000000000 --- a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/test_failures.https.html +++ /dev/null @@ -1,18 +0,0 @@ - - - -WebCryptoAPI: generateKey() for Failures - - - - - - - - -

generateKey Tests for Bad Parameters

- -
- diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/test_successes_RSA-OAEP.https.html b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/test_successes_RSA-OAEP.https.html index 48136260390..db58fd6690a 100644 --- a/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/test_successes_RSA-OAEP.https.html +++ b/tests/wpt/web-platform-tests/WebCryptoAPI/generateKey/test_successes_RSA-OAEP.https.html @@ -19,5 +19,5 @@
+run_test(["RSA-OAEP"]); + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/idlharness.html b/tests/wpt/web-platform-tests/WebCryptoAPI/idlharness.html index 81e1e04f9c1..53faef26d4d 100644 --- a/tests/wpt/web-platform-tests/WebCryptoAPI/idlharness.html +++ b/tests/wpt/web-platform-tests/WebCryptoAPI/idlharness.html @@ -29,11 +29,6 @@ setup(function() { request.onload = function() { var idls = request.responseText; - idl_array.add_untested_idls("[PrimaryGlobal] interface Window { };"); - - idl_array.add_untested_idls("interface ArrayBuffer {};"); - idl_array.add_untested_idls("interface ArrayBufferView {};"); - idl_array.add_idls(idls); idl_array.add_objects({"Crypto":["crypto"], "SubtleCrypto":["crypto.subtle"]}); diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/idlharness.https.html b/tests/wpt/web-platform-tests/WebCryptoAPI/idlharness.https.html index 81e1e04f9c1..53faef26d4d 100644 --- a/tests/wpt/web-platform-tests/WebCryptoAPI/idlharness.https.html +++ b/tests/wpt/web-platform-tests/WebCryptoAPI/idlharness.https.html @@ -29,11 +29,6 @@ setup(function() { request.onload = function() { var idls = request.responseText; - idl_array.add_untested_idls("[PrimaryGlobal] interface Window { };"); - - idl_array.add_untested_idls("interface ArrayBuffer {};"); - idl_array.add_untested_idls("interface ArrayBufferView {};"); - idl_array.add_idls(idls); idl_array.add_objects({"Crypto":["crypto"], "SubtleCrypto":["crypto.subtle"]}); diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/tools/generate.py b/tests/wpt/web-platform-tests/WebCryptoAPI/tools/generate.py index 8e06f00054d..728f914bdb2 100644 --- a/tests/wpt/web-platform-tests/WebCryptoAPI/tools/generate.py +++ b/tests/wpt/web-platform-tests/WebCryptoAPI/tools/generate.py @@ -66,10 +66,10 @@ done();""" names = ["AES-CTR", "AES-CBC", "AES-GCM", "AES-KW", "HMAC", "RSASSA-PKCS1-v1_5", "RSA-PSS", "RSA-OAEP", "ECDSA", "ECDH"] -for filename_pattern, template in [("test_successes_%s.html", successes_html), - ("test_failures_%s.html", failures_html), - ("successes_%s.worker.js", successes_worker), - ("failures_%s.worker.js", failures_worker)]: +for filename_pattern, template in [("test_successes_%s.https.html", successes_html), + ("test_failures_%s.https.html", failures_html), + ("successes_%s.https.worker.js", successes_worker), + ("failures_%s.https.worker.js", failures_worker)]: for name in names: path = os.path.join(here, os.pardir, "generateKey", filename_pattern % name) with open(path, "w") as f: diff --git a/tests/wpt/web-platform-tests/WebIDL/ecmascript-binding/no-regexp-special-casing.any.js b/tests/wpt/web-platform-tests/WebIDL/ecmascript-binding/no-regexp-special-casing.any.js new file mode 100644 index 00000000000..4446dbf69c0 --- /dev/null +++ b/tests/wpt/web-platform-tests/WebIDL/ecmascript-binding/no-regexp-special-casing.any.js @@ -0,0 +1,47 @@ +"use strict"; +// RegExps used to be special-cased in Web IDL, but that was removed in +// https://github.com/heycam/webidl/commit/bbb2bde. These tests check that implementations no longer +// do any such special-casing. + +test(() => { + const regExp = new RegExp(); + regExp.message = "some message"; + + const errorEvent = new ErrorEvent("type", regExp); + + assert_equals(errorEvent.message, "some message"); +}, "Conversion to a dictionary works"); + +test(() => { + const messageChannel = new MessageChannel(); + const regExp = new RegExp(); + regExp[Symbol.iterator] = function* () { + yield messageChannel.port1; + }; + + const messageEvent = new MessageEvent("type", { ports: regExp }); + + assert_array_equals(messageEvent.ports, [messageChannel.port1]); +}, "Conversion to a sequence works"); + +promise_test(async () => { + const regExp = new RegExp(); + + const response = new Response(regExp); + + assert_equals(await response.text(), "/(?:)/"); +}, "Can convert a RegExp to a USVString"); + +test(() => { + let functionCalled = false; + + const regExp = new RegExp(); + regExp.handleEvent = () => { + functionCalled = true; + }; + + self.addEventListener("testevent", regExp); + self.dispatchEvent(new Event("testevent")); + + assert_true(functionCalled); +}, "Can be used as an object implementing a callback interface"); diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/send-network-error-sync-events.sub.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/send-network-error-sync-events.sub.htm index 0ae94069858..b89958060f3 100644 --- a/tests/wpt/web-platform-tests/XMLHttpRequest/send-network-error-sync-events.sub.htm +++ b/tests/wpt/web-platform-tests/XMLHttpRequest/send-network-error-sync-events.sub.htm @@ -17,7 +17,7 @@ { var xhr = new XMLHttpRequest(); - xhr.open("POST", "http://nonexistent-origin.{{host}}}:{{ports[http][0]}}", false); + xhr.open("POST", "http://nonexistent-origin.{{host}}:{{ports[http][0]}}", false); assert_throws("NetworkError", function() { @@ -25,6 +25,12 @@ }); assert_equals(xhr.readyState, 4) + }, "http URL"); + + test(function() + { + var xhr = new XMLHttpRequest(); + xhr.open("GET", "data:text/html;charset=utf-8;base64,PT0NUWVBFIGh0bWw%2BDQo8", false); assert_throws("NetworkError", function() @@ -33,7 +39,7 @@ }); assert_equals(xhr.readyState, 4) - }); + }, "data URL"); diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/send-redirect-post-upload.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/send-redirect-post-upload.htm index 37a90d42cbd..5c1c6387adb 100644 --- a/tests/wpt/web-platform-tests/XMLHttpRequest/send-redirect-post-upload.htm +++ b/tests/wpt/web-platform-tests/XMLHttpRequest/send-redirect-post-upload.htm @@ -15,8 +15,8 @@
diff --git a/tests/wpt/web-platform-tests/accelerometer/Accelerometer-disabled-by-feature-policy.https.html b/tests/wpt/web-platform-tests/accelerometer/Accelerometer-disabled-by-feature-policy.https.html new file mode 100644 index 00000000000..d849db13359 --- /dev/null +++ b/tests/wpt/web-platform-tests/accelerometer/Accelerometer-disabled-by-feature-policy.https.html @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/tests/wpt/web-platform-tests/accelerometer/Accelerometer-disabled-by-feature-policy.https.html.headers b/tests/wpt/web-platform-tests/accelerometer/Accelerometer-disabled-by-feature-policy.https.html.headers new file mode 100644 index 00000000000..beea0422d92 --- /dev/null +++ b/tests/wpt/web-platform-tests/accelerometer/Accelerometer-disabled-by-feature-policy.https.html.headers @@ -0,0 +1 @@ +Feature-Policy: accelerometer 'none' diff --git a/tests/wpt/web-platform-tests/accelerometer/Accelerometer-enabled-by-feature-policy-attribute-redirect-on-load.https.html b/tests/wpt/web-platform-tests/accelerometer/Accelerometer-enabled-by-feature-policy-attribute-redirect-on-load.https.html new file mode 100644 index 00000000000..7306ed58ce6 --- /dev/null +++ b/tests/wpt/web-platform-tests/accelerometer/Accelerometer-enabled-by-feature-policy-attribute-redirect-on-load.https.html @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/tests/wpt/web-platform-tests/accelerometer/Accelerometer-enabled-by-feature-policy-attribute.https.html b/tests/wpt/web-platform-tests/accelerometer/Accelerometer-enabled-by-feature-policy-attribute.https.html new file mode 100644 index 00000000000..1ee0f42a510 --- /dev/null +++ b/tests/wpt/web-platform-tests/accelerometer/Accelerometer-enabled-by-feature-policy-attribute.https.html @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/tests/wpt/web-platform-tests/accelerometer/Accelerometer-enabled-by-feature-policy.https.html b/tests/wpt/web-platform-tests/accelerometer/Accelerometer-enabled-by-feature-policy.https.html new file mode 100644 index 00000000000..6dc33c829ca --- /dev/null +++ b/tests/wpt/web-platform-tests/accelerometer/Accelerometer-enabled-by-feature-policy.https.html @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/tests/wpt/web-platform-tests/accelerometer/Accelerometer-enabled-by-feature-policy.https.html.headers b/tests/wpt/web-platform-tests/accelerometer/Accelerometer-enabled-by-feature-policy.https.html.headers new file mode 100644 index 00000000000..5df2754abf5 --- /dev/null +++ b/tests/wpt/web-platform-tests/accelerometer/Accelerometer-enabled-by-feature-policy.https.html.headers @@ -0,0 +1 @@ +Feature-Policy: accelerometer * diff --git a/tests/wpt/web-platform-tests/accelerometer/Accelerometer-enabled-on-self-origin-by-feature-policy.https.html b/tests/wpt/web-platform-tests/accelerometer/Accelerometer-enabled-on-self-origin-by-feature-policy.https.html new file mode 100644 index 00000000000..fddbca0f5bb --- /dev/null +++ b/tests/wpt/web-platform-tests/accelerometer/Accelerometer-enabled-on-self-origin-by-feature-policy.https.html @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/tests/wpt/web-platform-tests/accelerometer/Accelerometer-enabled-on-self-origin-by-feature-policy.https.html.headers b/tests/wpt/web-platform-tests/accelerometer/Accelerometer-enabled-on-self-origin-by-feature-policy.https.html.headers new file mode 100644 index 00000000000..cdefed843e3 --- /dev/null +++ b/tests/wpt/web-platform-tests/accelerometer/Accelerometer-enabled-on-self-origin-by-feature-policy.https.html.headers @@ -0,0 +1 @@ +Feature-Policy: accelerometer 'self' diff --git a/tests/wpt/web-platform-tests/accelerometer/Accelerometer.https.html b/tests/wpt/web-platform-tests/accelerometer/Accelerometer.https.html index 58355571797..2a9bc543cdf 100644 --- a/tests/wpt/web-platform-tests/accelerometer/Accelerometer.https.html +++ b/tests/wpt/web-platform-tests/accelerometer/Accelerometer.https.html @@ -10,5 +10,6 @@ diff --git a/tests/wpt/web-platform-tests/accelerometer/Accelerometer_insecure_context.html b/tests/wpt/web-platform-tests/accelerometer/Accelerometer_insecure_context.html index d55a62f18e7..96eeef2daf7 100644 --- a/tests/wpt/web-platform-tests/accelerometer/Accelerometer_insecure_context.html +++ b/tests/wpt/web-platform-tests/accelerometer/Accelerometer_insecure_context.html @@ -16,5 +16,6 @@ diff --git a/tests/wpt/web-platform-tests/accelerometer/Accelerometer_onerror-manual.https.html b/tests/wpt/web-platform-tests/accelerometer/Accelerometer_onerror-manual.https.html index a3e81500122..8778693ccb2 100644 --- a/tests/wpt/web-platform-tests/accelerometer/Accelerometer_onerror-manual.https.html +++ b/tests/wpt/web-platform-tests/accelerometer/Accelerometer_onerror-manual.https.html @@ -16,5 +16,6 @@ diff --git a/tests/wpt/web-platform-tests/acid/acid3/test.html b/tests/wpt/web-platform-tests/acid/acid3/test.html index d2f08405af5..1ac8da6838e 100644 --- a/tests/wpt/web-platform-tests/acid/acid3/test.html +++ b/tests/wpt/web-platform-tests/acid/acid3/test.html @@ -956,8 +956,8 @@ test('di + + + + + + + diff --git a/tests/wpt/web-platform-tests/ambient-light/AmbientLightSensor-disabled-by-feature-policy.https.html.headers b/tests/wpt/web-platform-tests/ambient-light/AmbientLightSensor-disabled-by-feature-policy.https.html.headers new file mode 100644 index 00000000000..b8073a87be0 --- /dev/null +++ b/tests/wpt/web-platform-tests/ambient-light/AmbientLightSensor-disabled-by-feature-policy.https.html.headers @@ -0,0 +1 @@ +Feature-Policy: ambient-light-sensor 'none' diff --git a/tests/wpt/web-platform-tests/ambient-light/AmbientLightSensor-enabled-by-feature-policy-attribute-redirect-on-load.https.html b/tests/wpt/web-platform-tests/ambient-light/AmbientLightSensor-enabled-by-feature-policy-attribute-redirect-on-load.https.html new file mode 100644 index 00000000000..f5d4b0fdde8 --- /dev/null +++ b/tests/wpt/web-platform-tests/ambient-light/AmbientLightSensor-enabled-by-feature-policy-attribute-redirect-on-load.https.html @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/tests/wpt/web-platform-tests/ambient-light/AmbientLightSensor-enabled-by-feature-policy-attribute.https.html b/tests/wpt/web-platform-tests/ambient-light/AmbientLightSensor-enabled-by-feature-policy-attribute.https.html new file mode 100644 index 00000000000..13de3f8b4ee --- /dev/null +++ b/tests/wpt/web-platform-tests/ambient-light/AmbientLightSensor-enabled-by-feature-policy-attribute.https.html @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/tests/wpt/web-platform-tests/ambient-light/AmbientLightSensor-enabled-by-feature-policy.https.html b/tests/wpt/web-platform-tests/ambient-light/AmbientLightSensor-enabled-by-feature-policy.https.html new file mode 100644 index 00000000000..f2c2c3bbae1 --- /dev/null +++ b/tests/wpt/web-platform-tests/ambient-light/AmbientLightSensor-enabled-by-feature-policy.https.html @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/tests/wpt/web-platform-tests/ambient-light/AmbientLightSensor-enabled-by-feature-policy.https.html.headers b/tests/wpt/web-platform-tests/ambient-light/AmbientLightSensor-enabled-by-feature-policy.https.html.headers new file mode 100644 index 00000000000..f037f3ff579 --- /dev/null +++ b/tests/wpt/web-platform-tests/ambient-light/AmbientLightSensor-enabled-by-feature-policy.https.html.headers @@ -0,0 +1 @@ +Feature-Policy: ambient-light-sensor * diff --git a/tests/wpt/web-platform-tests/ambient-light/AmbientLightSensor-enabled-on-self-origin-by-feature-policy.https.html b/tests/wpt/web-platform-tests/ambient-light/AmbientLightSensor-enabled-on-self-origin-by-feature-policy.https.html new file mode 100644 index 00000000000..33d36cb44e7 --- /dev/null +++ b/tests/wpt/web-platform-tests/ambient-light/AmbientLightSensor-enabled-on-self-origin-by-feature-policy.https.html @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/tests/wpt/web-platform-tests/ambient-light/AmbientLightSensor-enabled-on-self-origin-by-feature-policy.https.html.headers b/tests/wpt/web-platform-tests/ambient-light/AmbientLightSensor-enabled-on-self-origin-by-feature-policy.https.html.headers new file mode 100644 index 00000000000..1d22667050e --- /dev/null +++ b/tests/wpt/web-platform-tests/ambient-light/AmbientLightSensor-enabled-on-self-origin-by-feature-policy.https.html.headers @@ -0,0 +1 @@ +Feature-Policy: ambient-light-sensor 'self' diff --git a/tests/wpt/web-platform-tests/beacon/OWNERS b/tests/wpt/web-platform-tests/beacon/OWNERS new file mode 100644 index 00000000000..719eb69cf52 --- /dev/null +++ b/tests/wpt/web-platform-tests/beacon/OWNERS @@ -0,0 +1,2 @@ +@toddreifsteck +@igrigorik diff --git a/tests/wpt/web-platform-tests/bluetooth/README.md b/tests/wpt/web-platform-tests/bluetooth/README.md new file mode 100644 index 00000000000..593967ee089 --- /dev/null +++ b/tests/wpt/web-platform-tests/bluetooth/README.md @@ -0,0 +1,12 @@ +# Web Bluetooth Testing + +Web Bluetooth testing relies on the [Web Bluetooth Testing API] which must be +provided by browsers under test. + +In this test suite `resources/bluetooth-helpers.js` detects and triggers +the API to be loaded as needed. + +The Chromium implementation is provided by +`../resources/chromium/web-bluetooth-test.js`. + +[Web Bluetooth Testing API]: https://docs.google.com/document/d/1Nhv_oVDCodd1pEH_jj9k8gF4rPGb_84VYaZ9IG8M_WY/ diff --git a/tests/wpt/web-platform-tests/bluetooth/idl-Bluetooth.html b/tests/wpt/web-platform-tests/bluetooth/idl/idl-Bluetooth.html similarity index 100% rename from tests/wpt/web-platform-tests/bluetooth/idl-Bluetooth.html rename to tests/wpt/web-platform-tests/bluetooth/idl/idl-Bluetooth.html diff --git a/tests/wpt/web-platform-tests/bluetooth/idl/idl-BluetoothUUID.html b/tests/wpt/web-platform-tests/bluetooth/idl/idl-BluetoothUUID.html new file mode 100644 index 00000000000..efebb15cb25 --- /dev/null +++ b/tests/wpt/web-platform-tests/bluetooth/idl/idl-BluetoothUUID.html @@ -0,0 +1,166 @@ + + + + diff --git a/tests/wpt/web-platform-tests/bluetooth/idl/idl-NavigatorBluetooth.html b/tests/wpt/web-platform-tests/bluetooth/idl/idl-NavigatorBluetooth.html new file mode 100644 index 00000000000..9449cf1ec88 --- /dev/null +++ b/tests/wpt/web-platform-tests/bluetooth/idl/idl-NavigatorBluetooth.html @@ -0,0 +1,15 @@ + + + + diff --git a/tests/wpt/web-platform-tests/bluetooth/resources/bluetooth-helpers.js b/tests/wpt/web-platform-tests/bluetooth/resources/bluetooth-helpers.js new file mode 100644 index 00000000000..3f3ff52189f --- /dev/null +++ b/tests/wpt/web-platform-tests/bluetooth/resources/bluetooth-helpers.js @@ -0,0 +1,800 @@ +'use strict'; + +function loadScript(path) { + let script = document.createElement('script'); + let promise = new Promise(resolve => script.onload = resolve); + script.src = path; + script.async = false; + document.head.appendChild(script); + return promise; +} + +function loadScripts(paths) { + let chain = Promise.resolve(); + for (let path of paths) { + chain = chain.then(() => loadScript(path)); + } + return chain; +} + +function performChromiumSetup() { + // Make sure we are actually on Chromium. + if (!Mojo) { + return; + } + + // Load the Chromium-specific resources. + let prefix = '/resources/chromium'; + let extra = []; + if (window.location.pathname.includes('/LayoutTests/')) { + let root = window.location.pathname.match(/.*LayoutTests/); + prefix = `${root}/external/wpt/resources/chromium`; + extra = [ + `${root}/resources/bluetooth/bluetooth-fake-adapter.js`, + ]; + } else if (window.location.pathname.startsWith('/bluetooth/https/')) { + extra = [ + '/js-test-resources/bluetooth/bluetooth-fake-adapter.js', + ]; + } + return loadScripts([ + `${prefix}/mojo_bindings.js`, + `${prefix}/mojo_layouttest_test.mojom.js`, + `${prefix}/uuid.mojom.js`, + `${prefix}/fake_bluetooth.mojom.js`, + `${prefix}/web-bluetooth-test.js`, + ].concat(extra)) + // Call setBluetoothFakeAdapter() to clean up any fake adapters left over + // by legacy tests. + // Legacy tests that use setBluetoothFakeAdapter() sometimes fail to clean + // their fake adapter. This is not a problem for these tests because the + // next setBluetoothFakeAdapter() will clean it up anyway but it is a + // problem for the new tests that do not use setBluetoothFakeAdapter(). + // TODO(crbug.com/569709): Remove once setBluetoothFakeAdapter is no + // longer used. + .then(() => setBluetoothFakeAdapter ? setBluetoothFakeAdapter('') + : undefined); +} + + +// These tests rely on the User Agent providing an implementation of the +// Web Bluetooth Testing API. +// https://docs.google.com/document/d/1Nhv_oVDCodd1pEH_jj9k8gF4rPGb_84VYaZ9IG8M_WY/edit?ts=59b6d823#heading=h.7nki9mck5t64 +function bluetooth_test(func, name, properties) { + Promise.resolve() + .then(() => promise_test(t => Promise.resolve() + // Trigger Chromium-specific setup. + .then(performChromiumSetup) + .then(() => func(t)), name, properties)); +} + +// HCI Error Codes. Used for simulateGATT[Dis]ConnectionResponse. +// For a complete list of possible error codes see +// BT 4.2 Vol 2 Part D 1.3 List Of Error Codes. +const HCI_SUCCESS = 0x0000; +const HCI_CONNECTION_TIMEOUT = 0x0008; + +// GATT Error codes. Used for GATT operations responses. +// BT 4.2 Vol 3 Part F 3.4.1.1 Error Response +const GATT_SUCCESS = 0x0000; +const GATT_INVALID_HANDLE = 0x0001; + +// Bluetooth UUID constants: +// Services: +var blocklist_test_service_uuid = "611c954a-263b-4f4a-aab6-01ddb953f985"; +var request_disconnection_service_uuid = "01d7d889-7451-419f-aeb8-d65e7b9277af"; +// Characteristics: +var blocklist_exclude_reads_characteristic_uuid = + "bad1c9a2-9a5b-4015-8b60-1579bbbf2135"; +var request_disconnection_characteristic_uuid = + "01d7d88a-7451-419f-aeb8-d65e7b9277af"; +// Descriptors: +var blocklist_test_descriptor_uuid = "bad2ddcf-60db-45cd-bef9-fd72b153cf7c"; + +// Sometimes we need to test that using either the name, alias, or UUID +// produces the same result. The following objects help us do that. +var generic_access = { + alias: 0x1800, + name: 'generic_access', + uuid: '00001800-0000-1000-8000-00805f9b34fb' +}; +var device_name = { + alias: 0x2a00, + name: 'gap.device_name', + uuid: '00002a00-0000-1000-8000-00805f9b34fb' +}; +var reconnection_address = { + alias: 0x2a03, + name: 'gap.reconnection_address', + uuid: '00002a03-0000-1000-8000-00805f9b34fb' +}; +var heart_rate = { + alias: 0x180d, + name: 'heart_rate', + uuid: '0000180d-0000-1000-8000-00805f9b34fb' +}; +var health_thermometer = { + alias: 0x1809, + name: 'health_thermometer', + uuid: '00001809-0000-1000-8000-00805f9b34fb' +}; +var body_sensor_location = { + alias: 0x2a38, + name: 'body_sensor_location', + uuid: '00002a38-0000-1000-8000-00805f9b34fb' +}; +var glucose = { + alias: 0x1808, + name: 'glucose', + uuid: '00001808-0000-1000-8000-00805f9b34fb' +}; +var battery_service = { + alias: 0x180f, + name: 'battery_service', + uuid: '0000180f-0000-1000-8000-00805f9b34fb' +}; +var battery_level = { + alias: 0x2A19, + name: 'battery_level', + uuid: '00002a19-0000-1000-8000-00805f9b34fb' +}; +var user_description = { + alias: 0x2901, + name: 'gatt.characteristic_user_description', + uuid: '00002901-0000-1000-8000-00805f9b34fb' +}; +var client_characteristic_configuration = { + alias: 0x2902, + name: 'gatt.client_characteristic_configuration', + uuid: '00002902-0000-1000-8000-00805f9b34fb' +}; +var measurement_interval = { + alias: 0x2a21, + name: 'measurement_interval', + uuid: '00002a21-0000-1000-8000-00805f9b34fb' +}; + +// The following tests make sure the Web Bluetooth implementation +// responds correctly to the different types of errors the +// underlying platform might return for GATT operations. + +// Each browser should map these characteristics to specific code paths +// that result in different errors thus increasing code coverage +// when testing. Therefore some of these characteristics might not be useful +// for all browsers. +// +// TODO(ortuno): According to the testing spec errorUUID(0x101) to +// errorUUID(0x1ff) should be use for the uuids of the characteristics. +var gatt_errors_tests = [{ + testName: 'GATT Error: Unknown.', + uuid: errorUUID(0xA1), + error: new DOMException( + 'GATT Error Unknown.', + 'NotSupportedError') +}, { + testName: 'GATT Error: Failed.', + uuid: errorUUID(0xA2), + error: new DOMException( + 'GATT operation failed for unknown reason.', + 'NotSupportedError') +}, { + testName: 'GATT Error: In Progress.', + uuid: errorUUID(0xA3), + error: new DOMException( + 'GATT operation already in progress.', + 'NetworkError') +}, { + testName: 'GATT Error: Invalid Length.', + uuid: errorUUID(0xA4), + error: new DOMException( + 'GATT Error: invalid attribute length.', + 'InvalidModificationError') +}, { + testName: 'GATT Error: Not Permitted.', + uuid: errorUUID(0xA5), + error: new DOMException( + 'GATT operation not permitted.', + 'NotSupportedError') +}, { + testName: 'GATT Error: Not Authorized.', + uuid: errorUUID(0xA6), + error: new DOMException( + 'GATT operation not authorized.', + 'SecurityError') +}, { + testName: 'GATT Error: Not Paired.', + uuid: errorUUID(0xA7), + // TODO(ortuno): Change to InsufficientAuthenticationError or similiar + // once https://github.com/WebBluetoothCG/web-bluetooth/issues/137 is + // resolved. + error: new DOMException( + 'GATT Error: Not paired.', + 'NetworkError') +}, { + testName: 'GATT Error: Not Supported.', + uuid: errorUUID(0xA8), + error: new DOMException( + 'GATT Error: Not supported.', + 'NotSupportedError') +}]; + +function callWithTrustedClick(callback) { + return new Promise(resolve => { + let button = document.createElement('button'); + button.textContent = 'click to continue test'; + button.style.display = 'block'; + button.style.fontSize = '20px'; + button.style.padding = '10px'; + button.onclick = () => { + document.body.removeChild(button); + resolve(callback()); + }; + document.body.appendChild(button); + test_driver.click(button); + }); +} + +// Calls requestDevice() in a context that's 'allowed to show a popup'. +function requestDeviceWithTrustedClick() { + let args = arguments; + return callWithTrustedClick( + () => navigator.bluetooth.requestDevice.apply(navigator.bluetooth, args)); +} + +// errorUUID(alias) returns a UUID with the top 32 bits of +// '00000000-97e5-4cd7-b9f1-f5a427670c59' replaced with the bits of |alias|. +// For example, errorUUID(0xDEADBEEF) returns +// 'deadbeef-97e5-4cd7-b9f1-f5a427670c59'. The bottom 96 bits of error UUIDs +// were generated as a type 4 (random) UUID. +function errorUUID(uuidAlias) { + // Make the number positive. + uuidAlias >>>= 0; + // Append the alias as a hex number. + var strAlias = '0000000' + uuidAlias.toString(16); + // Get last 8 digits of strAlias. + strAlias = strAlias.substr(-8); + // Append Base Error UUID + return strAlias + '-97e5-4cd7-b9f1-f5a427670c59'; +} + +// Function to test that a promise rejects with the expected error type and +// message. +function assert_promise_rejects_with_message(promise, expected, description) { + return promise.then(() => { + assert_unreached('Promise should have rejected: ' + description); + }, error => { + assert_equals(error.name, expected.name, 'Unexpected Error Name:'); + if (expected.message) { + assert_equals(error.message, expected.message, 'Unexpected Error Message:'); + } + }); +} + +function runGarbageCollection() +{ + // Run gc() as a promise. + return new Promise( + function(resolve, reject) { + GCController.collect(); + step_timeout(resolve, 0); + }); +} + +function eventPromise(target, type, options) { + return new Promise(resolve => { + let wrapper = function(event) { + target.removeEventListener(type, wrapper); + resolve(event); + }; + target.addEventListener(type, wrapper, options); + }); +} + +// Helper function to assert that events are fired and a promise resolved +// in the correct order. +// 'event' should be passed as |should_be_first| to indicate that the events +// should be fired first, otherwise 'promiseresolved' should be passed. +// Attaches |num_listeners| |event| listeners to |object|. If all events have +// been fired and the promise resolved in the correct order, returns a promise +// that fulfills with the result of |object|.|func()| and |event.target.value| +// of each of event listeners. Otherwise throws an error. +function assert_promise_event_order_(should_be_first, object, func, event, num_listeners) { + let order = []; + let event_promises = []; + for (let i = 0; i < num_listeners; i++) { + event_promises.push(new Promise(resolve => { + let event_listener = (e) => { + object.removeEventListener(event, event_listener); + order.push('event'); + resolve(e.target.value); + }; + object.addEventListener(event, event_listener); + })); + } + + let func_promise = object[func]().then(result => { + order.push('promiseresolved'); + return result; + }); + + return Promise.all([func_promise, ...event_promises]) + .then((result) => { + if (should_be_first !== order[0]) { + throw should_be_first === 'promiseresolved' ? + `'${event}' was fired before promise resolved.` : + `Promise resolved before '${event}' was fired.`; + } + + if (order[0] !== 'promiseresolved' && + order[order.length - 1] !== 'promiseresolved') { + throw 'Promise resolved in between event listeners.'; + } + + return result; + }); +} + +// See assert_promise_event_order_ above. +function assert_promise_resolves_before_event( + object, func, event, num_listeners=1) { + return assert_promise_event_order_( + 'promiseresolved', object, func, event, num_listeners); +} + +// See assert_promise_event_order_ above. +function assert_promise_resolves_after_event( + object, func, event, num_listeners=1) { + return assert_promise_event_order_( + 'event', object, func, event, num_listeners); +} + +// Returns a promise that resolves after 100ms unless +// the the event is fired on the object in which case +// the promise rejects. +function assert_no_events(object, event_name) { + return new Promise((resolve, reject) => { + let event_listener = (e) => { + object.removeEventListener(event_name, event_listener); + assert_unreached('Object should not fire an event.'); + }; + object.addEventListener(event_name, event_listener); + // TODO: Remove timeout. + // http://crbug.com/543884 + step_timeout(() => { + object.removeEventListener(event_name, event_listener); + resolve(); + }, 100); + }); +} + +class TestCharacteristicProperties { + // |properties| is an array of strings for property bits to be set + // as true. + constructor(properties) { + this.broadcast = false; + this.read = false; + this.writeWithoutResponse = false; + this.write = false; + this.notify = false; + this.indicate = false; + this.authenticatedSignedWrites = false; + this.reliableWrite = false; + this.writableAuxiliaries = false; + + properties.forEach(val => { + if (this.hasOwnProperty(val)) + this[val] = true; + else + throw `Invalid member '${val}'`; + }); + } +} + +function assert_properties_equal(properties, expected_properties) { + for (let key in expected_properties) { + assert_equals(properties[key], expected_properties[key]); + } +} + +class EventCatcher { + constructor(object, event) { + this.eventFired = false; + let event_listener = () => { + object.removeEventListener(event, event_listener); + this.eventFired = true; + }; + object.addEventListener(event, event_listener); + } +} + +// Returns a function that when called returns a promise that resolves when +// the device has disconnected. Example: +// device.gatt.connect() +// .then(gatt => get_request_disconnection(gatt)) +// .then(requestDisconnection => requestDisconnection()) +// .then(() => // device is now disconnected) +function get_request_disconnection(gattServer) { + return gattServer.getPrimaryService(request_disconnection_service_uuid) + .then(service => service.getCharacteristic(request_disconnection_characteristic_uuid)) + .then(characteristic => { + return () => assert_promise_rejects_with_message( + characteristic.writeValue(new Uint8Array([0])), + new DOMException( + 'GATT Server is disconnected. Cannot perform GATT operations. ' + + '(Re)connect first with `device.gatt.connect`.', + 'NetworkError')); + }); +} + +function generateRequestDeviceArgsWithServices(services = ['heart_rate']) { + return [{ + filters: [{ services: services }] + }, { + filters: [{ services: services, name: 'Name' }] + }, { + filters: [{ services: services, namePrefix: 'Pre' }] + }, { + filters: [{ services: services, name: 'Name', namePrefix: 'Pre' }] + }, { + filters: [{ services: services }], + optionalServices: ['heart_rate'] + }, { + filters: [{ services: services, name: 'Name' }], + optionalServices: ['heart_rate'] + }, { + filters: [{ services: services, namePrefix: 'Pre' }], + optionalServices: ['heart_rate'] + }, { + filters: [{ services: services, name: 'Name', namePrefix: 'Pre' }], + optionalServices: ['heart_rate'] + }]; +} + +// Simulates a pre-connected device with |address|, |name| and +// |knownServiceUUIDs|. +function setUpPreconnectedDevice({ + address = '00:00:00:00:00:00', name = 'LE Device', knownServiceUUIDs = []}) { + return navigator.bluetooth.test.simulateCentral({state: 'powered-on'}) + .then(fake_central => fake_central.simulatePreconnectedPeripheral({ + address: address, + name: name, + knownServiceUUIDs: knownServiceUUIDs, + })); +} + +// Returns a FakePeripheral that corresponds to a simulated pre-connected device +// called 'Health Thermometer'. The device has two known serviceUUIDs: +// 'generic_access' and 'health_thermometer'. +function setUpHealthThermometerDevice() { + return setUpPreconnectedDevice({ + address: '09:09:09:09:09:09', + name: 'Health Thermometer', + knownServiceUUIDs: ['generic_access', 'health_thermometer'], + }); +} + +// Returns an array containing two FakePeripherals corresponding +// to the simulated devices. +function setUpHealthThermometerAndHeartRateDevices() { + return navigator.bluetooth.test.simulateCentral({state: 'powered-on'}) + .then(fake_central => Promise.all([ + fake_central.simulatePreconnectedPeripheral({ + address: '09:09:09:09:09:09', + name: 'Health Thermometer', + knownServiceUUIDs: ['generic_access', 'health_thermometer'], + }), + fake_central.simulatePreconnectedPeripheral({ + address: '08:08:08:08:08:08', + name: 'Heart Rate', + knownServiceUUIDs: ['generic_access', 'heart_rate'], + })])); +} + +// Returns the same fake peripheral as setUpHealthThermometerDevice() except +// that connecting to the peripheral will succeed. +function setUpConnectableHealthThermometerDevice() { + let fake_peripheral; + return setUpHealthThermometerDevice() + .then(_ => fake_peripheral = _) + .then(() => fake_peripheral.setNextGATTConnectionResponse({ + code: HCI_SUCCESS, + })) + .then(() => fake_peripheral); +} + +// Returns an object containing a BluetoothDevice discovered using |options|, +// its corresponding FakePeripheral and FakeRemoteGATTServices. +// The simulated device is called 'Health Thermometer' it has two known service +// UUIDs: 'generic_access' and 'health_thermometer' which correspond to two +// services with the same UUIDs. The 'health thermometer' service contains three +// characteristics: +// - 'temperature_measurement' (indicate), +// - 'temperature_type' (read), +// - 'measurement_interval' (read, write, indicate) +// The 'measurement_interval' characteristic contains a +// 'gatt.client_characteristic_configuration' descriptor and a +// 'characteristic_user_description' descriptor. +// The device has been connected to and its attributes are ready to be +// discovered. +function getHealthThermometerDevice(options) { + let result; + return getConnectedHealthThermometerDevice(options) + .then(_ => result = _) + .then(() => result.fake_peripheral.setNextGATTDiscoveryResponse({ + code: HCI_SUCCESS, + })) + .then(() => result); +} + +// Similar to getHealthThermometerDevice except that the peripheral has +// two 'health_thermometer' services. +function getTwoHealthThermometerServicesDevice(options) { + let device; + let fake_peripheral; + let fake_generic_access; + let fake_health_thermometer1; + let fake_health_thermometer2; + + return getConnectedHealthThermometerDevice(options) + .then(result => { + ({ + device, + fake_peripheral, + fake_generic_access, + fake_health_thermometer: fake_health_thermometer1, + } = result); + }) + .then(() => fake_peripheral.addFakeService({uuid: 'health_thermometer'})) + .then(s => fake_health_thermometer2 = s) + .then(() => fake_peripheral.setNextGATTDiscoveryResponse({ + code: HCI_SUCCESS})) + .then(() => ({ + device: device, + fake_peripheral: fake_peripheral, + fake_generic_access: fake_generic_access, + fake_health_thermometer1: fake_health_thermometer1, + fake_health_thermometer2: fake_health_thermometer2 + })); +} + +// Returns an object containing a Health Thermometer BluetoothRemoteGattService +// and its corresponding FakeRemoteGATTService. +function getHealthThermometerService() { + let result; + return getHealthThermometerDevice() + .then(r => result = r) + .then(() => result.device.gatt.getPrimaryService('health_thermometer')) + .then(service => Object.assign(result, { + service, + fake_service: result.fake_health_thermometer, + })); +} + +// Returns an object containing a Measurement Interval +// BluetoothRemoteGATTCharacteristic and its corresponding +// FakeRemoteGATTCharacteristic. +function getMeasurementIntervalCharacteristic() { + let result; + return getHealthThermometerService() + .then(r => result = r) + .then(() => result.service.getCharacteristic('measurement_interval')) + .then(characteristic => Object.assign(result, { + characteristic, + fake_characteristic: result.fake_measurement_interval, + })); +} + +function getUserDescriptionDescriptor() { + let result; + return getMeasurementIntervalCharacteristic() + .then(r => result = r) + .then(() => result.characteristic.getDescriptor( + 'gatt.characteristic_user_description')) + .then(descriptor => Object.assign(result, { + descriptor, + fake_descriptor: result.fake_user_description, + })); +} + +// Populates a fake_peripheral with various fakes appropriate for a health +// thermometer. This resolves to an associative array composed of the fakes, +// including the |fake_peripheral|. +function populateHealthThermometerFakes(fake_peripheral) { + let fake_generic_access, fake_health_thermometer, fake_measurement_interval, + fake_user_description, fake_cccd, fake_temperature_measurement, + fake_temperature_type; + return fake_peripheral.addFakeService({uuid: 'generic_access'}) + .then(_ => fake_generic_access = _) + .then(() => fake_peripheral.addFakeService({ + uuid: 'health_thermometer', + })) + .then(_ => fake_health_thermometer = _) + .then(() => fake_health_thermometer.addFakeCharacteristic({ + uuid: 'measurement_interval', + properties: ['read', 'write', 'indicate'], + })) + .then(_ => fake_measurement_interval = _) + .then(() => fake_measurement_interval.addFakeDescriptor({ + uuid: 'gatt.characteristic_user_description', + })) + .then(_ => fake_user_description = _) + .then(() => fake_measurement_interval.addFakeDescriptor({ + uuid: 'gatt.client_characteristic_configuration', + })) + .then(_ => fake_cccd = _) + .then(() => fake_health_thermometer.addFakeCharacteristic({ + uuid: 'temperature_measurement', + properties: ['indicate'], + })) + .then(_ => fake_temperature_measurement = _) + .then(() => fake_health_thermometer.addFakeCharacteristic({ + uuid: 'temperature_type', + properties: ['read'], + })) + .then(_ => fake_temperature_type = _) + .then(() => ({ + fake_peripheral, + fake_generic_access, + fake_health_thermometer, + fake_measurement_interval, + fake_cccd, + fake_user_description, + fake_temperature_measurement, + fake_temperature_type, + })); +} + +// Similar to getHealthThermometerDevice except the GATT discovery +// response has not been set yet so more attributes can still be added. +function getConnectedHealthThermometerDevice(options) { + let device, fake_peripheral, fakes; + return getDiscoveredHealthThermometerDevice(options) + .then(_ => ({device, fake_peripheral} = _)) + .then(() => fake_peripheral.setNextGATTConnectionResponse({ + code: HCI_SUCCESS, + })) + .then(() => populateHealthThermometerFakes(fake_peripheral)) + .then(_ => fakes = _) + .then(() => device.gatt.connect()) + .then(() => Object.assign({device}, fakes)); +} + +// Returns the same device and fake peripheral as getHealthThermometerDevice() +// after another frame (an iframe we insert) discovered the device, +// connected to it and discovered its services. +function getHealthThermometerDeviceWithServicesDiscovered(options) { + let device, fake_peripheral, fakes; + let iframe = document.createElement('iframe'); + return setUpConnectableHealthThermometerDevice() + .then(_ => fake_peripheral = _) + .then(() => populateHealthThermometerFakes(fake_peripheral)) + .then(_ => fakes = _) + .then(() => fake_peripheral.setNextGATTDiscoveryResponse({ + code: HCI_SUCCESS, + })) + .then(() => new Promise(resolve => { + iframe.src = '../../../resources/bluetooth/health-thermometer-iframe.html'; + document.body.appendChild(iframe); + iframe.addEventListener('load', resolve); + })) + .then(() => new Promise((resolve, reject) => { + callWithTrustedClick(() => { + iframe.contentWindow.postMessage({ + type: 'DiscoverServices', + options: options + }, '*'); + }); + + function messageHandler(messageEvent) { + if (messageEvent.data == 'DiscoveryComplete') { + window.removeEventListener('message', messageHandler); + resolve(); + } else { + reject(new Error(`Unexpected message: ${messageEvent.data}`)); + } + } + window.addEventListener('message', messageHandler); + })) + .then(() => requestDeviceWithTrustedClick(options)) + .then(_ => device = _) + .then(device => device.gatt.connect()) + .then(_ => Object.assign({device}, fakes)); +} + +// Similar to getHealthThermometerDevice() except the device has no services, +// characteristics, or descriptors. +function getEmptyHealthThermometerDevice(options) { + return getDiscoveredHealthThermometerDevice(options) + .then(({device, fake_peripheral}) => { + return fake_peripheral.setNextGATTConnectionResponse({code: HCI_SUCCESS}) + .then(() => device.gatt.connect()) + .then(() => fake_peripheral.setNextGATTDiscoveryResponse({ + code: HCI_SUCCESS})) + .then(() => ({ + device: device, + fake_peripheral: fake_peripheral + })); + }); +} + +// Similar to getHealthThermometerService() except the service has no +// characteristics or included services. +function getEmptyHealthThermometerService(options) { + let device; + let fake_peripheral; + let fake_health_thermometer; + return getDiscoveredHealthThermometerDevice(options) + .then(result => ({device, fake_peripheral} = result)) + .then(() => fake_peripheral.setNextGATTConnectionResponse({ + code: HCI_SUCCESS})) + .then(() => device.gatt.connect()) + .then(() => fake_peripheral.addFakeService({uuid: 'health_thermometer'})) + .then(s => fake_health_thermometer = s) + .then(() => fake_peripheral.setNextGATTDiscoveryResponse({ + code: HCI_SUCCESS})) + .then(() => device.gatt.getPrimaryService('health_thermometer')) + .then(service => ({ + service: service, + fake_health_thermometer: fake_health_thermometer, + })); +} + +// Returns a BluetoothDevice discovered using |options| and its +// corresponding FakePeripheral. +// The simulated device is called 'HID Device' it has three known service +// UUIDs: 'generic_access', 'device_information', 'human_interface_device'. +// The primary service with 'device_information' UUID has a characteristics +// with UUID 'serial_number_string'. The device has been connected to and its +// attributes are ready to be discovered. +// TODO(crbug.com/719816): Add descriptors. +function getHIDDevice(options) { + return setUpPreconnectedDevice({ + address: '10:10:10:10:10:10', + name: 'HID Device', + knownServiceUUIDs: [ + 'generic_access', + 'device_information', + 'human_interface_device' + ], + }) + .then(fake_peripheral => { + return requestDeviceWithTrustedClick(options) + .then(device => { + return fake_peripheral + .setNextGATTConnectionResponse({ + code: HCI_SUCCESS}) + .then(() => device.gatt.connect()) + .then(() => fake_peripheral.addFakeService({ + uuid: 'generic_access'})) + .then(() => fake_peripheral.addFakeService({ + uuid: 'device_information'})) + // Blocklisted Characteristic: + // https://github.com/WebBluetoothCG/registries/blob/master/gatt_blocklist.txt + .then(dev_info => dev_info.addFakeCharacteristic({ + uuid: 'serial_number_string', properties: ['read']})) + .then(() => fake_peripheral.addFakeService({ + uuid: 'human_interface_device'})) + .then(() => fake_peripheral.setNextGATTDiscoveryResponse({ + code: HCI_SUCCESS})) + .then(() => ({ + device: device, + fake_peripheral: fake_peripheral + })); + }); + }); +} + +// Similar to getHealthThermometerDevice() except the device +// is not connected and thus its services have not been +// discovered. +function getDiscoveredHealthThermometerDevice( + options = {filters: [{services: ['health_thermometer']}]}) { + return setUpHealthThermometerDevice() + .then(fake_peripheral => { + return requestDeviceWithTrustedClick(options) + .then(device => ({ + device: device, + fake_peripheral: fake_peripheral + })); + }); +} diff --git a/tests/wpt/web-platform-tests/common/media.js b/tests/wpt/web-platform-tests/common/media.js index 6bddea5fd92..7cea1ac9b3c 100644 --- a/tests/wpt/web-platform-tests/common/media.js +++ b/tests/wpt/web-platform-tests/common/media.js @@ -33,3 +33,14 @@ function getAudioURI(base) return base + extension; } + +function getMediaContentType(url) { + var extension = new URL(url, location).pathname.split(".").pop(); + var map = { + "mp4": "video/mp4", + "ogv": "video/ogg", + "mp3": "audio/mp3", + "oga": "audio/ogg", + }; + return map[extension]; +} diff --git a/tests/wpt/web-platform-tests/common/performance-timeline-utils.js b/tests/wpt/web-platform-tests/common/performance-timeline-utils.js index 3beb28e9bf7..6845d6cbc68 100644 --- a/tests/wpt/web-platform-tests/common/performance-timeline-utils.js +++ b/tests/wpt/web-platform-tests/common/performance-timeline-utils.js @@ -36,7 +36,9 @@ function test_entries(actualEntries, expectedEntries) { return actualEntry[key] !== expectedEntry[key] }) === 'undefined' }) - test_true(!!foundEntry) - assert_object_equals(foundEntry.toJSON(), expectedEntry) + test_true(!!foundEntry, `Entry ${JSON.stringify(expectedEntry)} could not be found.`) + if (foundEntry) { + assert_object_equals(foundEntry.toJSON(), expectedEntry) + } }) } diff --git a/tests/wpt/web-platform-tests/conformance-checkers/html-aria/_functional/tree/ariatree.html b/tests/wpt/web-platform-tests/conformance-checkers/html-aria/_functional/tree/ariatree.html index d2d57e5082e..d915c55d786 100644 --- a/tests/wpt/web-platform-tests/conformance-checkers/html-aria/_functional/tree/ariatree.html +++ b/tests/wpt/web-platform-tests/conformance-checkers/html-aria/_functional/tree/ariatree.html @@ -4,9 +4,9 @@ ARIA Tree Example - - - + + + diff --git a/tests/wpt/web-platform-tests/conformance-checkers/html-aria/_functional/tree/ariatree2.html b/tests/wpt/web-platform-tests/conformance-checkers/html-aria/_functional/tree/ariatree2.html index b6d809ce61f..3efe2464881 100644 --- a/tests/wpt/web-platform-tests/conformance-checkers/html-aria/_functional/tree/ariatree2.html +++ b/tests/wpt/web-platform-tests/conformance-checkers/html-aria/_functional/tree/ariatree2.html @@ -4,9 +4,9 @@ ARIA Tree Example - - - + + + diff --git a/tests/wpt/web-platform-tests/conformance-checkers/html-aria/accessible-name-updates/673.html b/tests/wpt/web-platform-tests/conformance-checkers/html-aria/accessible-name-updates/673.html index d24cd6b01e3..38100513da4 100644 --- a/tests/wpt/web-platform-tests/conformance-checkers/html-aria/accessible-name-updates/673.html +++ b/tests/wpt/web-platform-tests/conformance-checkers/html-aria/accessible-name-updates/673.html @@ -15,7 +15,7 @@ After the onload event completes a child DOM text node is added to the element with the aria-live attribute.

- - +

diff --git a/tests/wpt/web-platform-tests/conformance-checkers/html-svg/animate-elem-33-t-isvalid.html b/tests/wpt/web-platform-tests/conformance-checkers/html-svg/animate-elem-33-t-isvalid.html index b9a460041cd..f8b1d078546 100644 --- a/tests/wpt/web-platform-tests/conformance-checkers/html-svg/animate-elem-33-t-isvalid.html +++ b/tests/wpt/web-platform-tests/conformance-checkers/html-svg/animate-elem-33-t-isvalid.html @@ -66,7 +66,7 @@ - - + class diff --git a/tests/wpt/web-platform-tests/conformance-checkers/html-svg/filters-turb-02-f-isvalid.html b/tests/wpt/web-platform-tests/conformance-checkers/html-svg/filters-turb-02-f-isvalid.html index 203f6a79e99..42306736a9f 100644 --- a/tests/wpt/web-platform-tests/conformance-checkers/html-svg/filters-turb-02-f-isvalid.html +++ b/tests/wpt/web-platform-tests/conformance-checkers/html-svg/filters-turb-02-f-isvalid.html @@ -72,7 +72,7 @@ - diff --git a/tests/wpt/web-platform-tests/conformance-checkers/html-svg/fonts-elem-03-b-isvalid.html b/tests/wpt/web-platform-tests/conformance-checkers/html-svg/fonts-elem-03-b-isvalid.html index e8e47d4d238..3fc08bcb411 100644 --- a/tests/wpt/web-platform-tests/conformance-checkers/html-svg/fonts-elem-03-b-isvalid.html +++ b/tests/wpt/web-platform-tests/conformance-checkers/html-svg/fonts-elem-03-b-isvalid.html @@ -29,7 +29,7 @@ - - HTML Standard + + + +

+ + + + + + + + + + + +
  1. 9 Communication
    1. 9.1 The MessageEvent interface

9 Communication

+ +

9.1 The MessageEvent interface

+ +

Messages in server-sent events, Web sockets, cross-document + messaging, channel messaging, and broadcast channels use the + MessageEvent interface for their message + events:

+ +
[Constructor(DOMString type, optional MessageEventInit eventInitDict), Exposed=(Window,Worker,AudioWorklet)]
+interface MessageEvent : Event {
+  readonly attribute any data;
+  readonly attribute USVString origin;
+  readonly attribute DOMString lastEventId;
+  readonly attribute MessageEventSource? source;
+  readonly attribute FrozenArray<MessagePort> ports;
+
+  void initMessageEvent(DOMString type, optional boolean bubbles = false, optional boolean cancelable = false, optional any data = null, optional USVString origin = "", optional DOMString lastEventId = "", optional MessageEventSource? source = null, optional sequence<MessagePort> ports = []);
+};
+
+dictionary MessageEventInit : EventInit {
+  any data = null;
+  USVString origin = "";
+  DOMString lastEventId = "";
+  MessageEventSource? source = null;
+  sequence<MessagePort> ports = [];
+};
+
+typedef (WindowProxy or MessagePort or ServiceWorker) MessageEventSource;
+ +
event . data
+ +

Returns the data of the message.

+ +
event . origin
+ +

Returns the origin of the message, for server-sent events and + cross-document messaging.

+ +
event . lastEventId
+ +

Returns the last event ID string, for + server-sent events.

+ +
event . source
+ +

Returns the WindowProxy of the source window, for cross-document + messaging, and the MessagePort being attached, in the connect event fired at + SharedWorkerGlobalScope objects.

+ +
event . ports
+ +

Returns the MessagePort array sent with the message, for cross-document + messaging and channel messaging.

+ +
+ + + +

The data attribute must return the value + it was initialized to. It represents the message being sent.

+ +

The origin attribute must return the + value it was initialized to. It represents, in server-sent events and + cross-document messaging, the origin of the document that sent the + message (typically the scheme, hostname, and port of the document, but not its path or fragment).

+ +

The lastEventId attribute must + return the value it was initialized to. It represents, in server-sent events, the + last event ID string of the event + source.

+ +

The source attribute must return the + value it was initialized to. It represents, in cross-document messaging, the + WindowProxy of the browsing context of the Window object + from which the message came; and in the connect events used by shared workers, the newly connecting + MessagePort.

+ +

The ports attribute must return the + value it was initialized to. It represents, in cross-document messaging and + channel messaging, the MessagePort array being sent.

+ + +

The initMessageEvent() + method must initialize the event in a manner analogous to the similarly-named initEvent() method. [DOM]

+ + + +

Various APIs (e.g., WebSocket, EventSource) use the + MessageEvent interface for their message event + without using the MessagePort API.

+ + + diff --git a/tests/wpt/web-platform-tests/conformance-checkers/html/elements/style/model-isvalid.html b/tests/wpt/web-platform-tests/conformance-checkers/html/elements/style/model-isvalid.html index f0dd1c23fd1..e55c3e94ec0 100644 --- a/tests/wpt/web-platform-tests/conformance-checkers/html/elements/style/model-isvalid.html +++ b/tests/wpt/web-platform-tests/conformance-checkers/html/elements/style/model-isvalid.html @@ -4,15 +4,12 @@ <STYLE>s - diff --git a/tests/wpt/web-platform-tests/conformance-checkers/html/elements/style/type-novalid.html b/tests/wpt/web-platform-tests/conformance-checkers/html/elements/style/type-novalid.html new file mode 100644 index 00000000000..f977b1790ef --- /dev/null +++ b/tests/wpt/web-platform-tests/conformance-checkers/html/elements/style/type-novalid.html @@ -0,0 +1,13 @@ + + + + + <STYLE>s + + + + + + diff --git a/tests/wpt/web-platform-tests/conformance-checkers/index.html b/tests/wpt/web-platform-tests/conformance-checkers/index.html index 2dadc40cf1f..fbf944a3cdf 100644 --- a/tests/wpt/web-platform-tests/conformance-checkers/index.html +++ b/tests/wpt/web-platform-tests/conformance-checkers/index.html @@ -14,7 +14,7 @@

Curious committers should see the makefile. - diff --git a/tests/wpt/web-platform-tests/css/CSS2/colors/color-083-ref.xht b/tests/wpt/web-platform-tests/css/CSS2/colors/color-083-ref.xht index 65f5c6f76e3..5417ef07e8f 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/colors/color-083-ref.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/colors/color-083-ref.xht @@ -30,7 +30,6 @@

-
Image download support must be enabled
diff --git a/tests/wpt/web-platform-tests/css/CSS2/fonts/font-148-ref.xht b/tests/wpt/web-platform-tests/css/CSS2/fonts/font-148-ref.xht new file mode 100644 index 00000000000..22a8e1a263b --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/fonts/font-148-ref.xht @@ -0,0 +1,25 @@ + + + + + + + CSS Reftest Reference + + + + + + + +

Test passes if letters "def" below are larger than "abc" and "ghi".

+
abcdefghi
+ + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/CSS2/fonts/font-148.xht b/tests/wpt/web-platform-tests/css/CSS2/fonts/font-148.xht new file mode 100644 index 00000000000..972aa1a7350 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/fonts/font-148.xht @@ -0,0 +1,24 @@ + + + + CSS Test: Font shorthand using calc() value for font-size + + + + + + + + + +

Test passes if letters "def" below are larger than "abc" and "ghi".

+
abcdefghi
+ + diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/after-inheritable-001-ref.html b/tests/wpt/web-platform-tests/css/CSS2/generated-content/after-inheritable-001-ref.html new file mode 100644 index 00000000000..77aa2dbd512 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/after-inheritable-001-ref.html @@ -0,0 +1,14 @@ + + +CSS Reference + + +

Test passes if the words "PASS PASS" below are green and the words are centered within the box below.

+
PASS PASS
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/after-inheritable-001.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/after-inheritable-001.xht index 273defe20b3..aa1b4906249 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/after-inheritable-001.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/after-inheritable-001.xht @@ -4,6 +4,7 @@ CSS Test: Pseudo-element ':after' inherits inheritable values + + +

Test passes if the words "PASS PASS" are green, they are contained within an orange box with thinner lines than the blue box.

+
PASS PASS
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/after-inheritable-002.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/after-inheritable-002.xht index 827329382ec..dd56d042fdf 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/after-inheritable-002.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/after-inheritable-002.xht @@ -4,6 +4,7 @@ CSS Test: Pseudo-element ':after' does not inherit non-inheritable values + -

Test passes if the words "PASS PASS" appear in green inside the box.

+

Test passes if the words "PASS PASS" appear in the box below.

\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/before-inheritable-001.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/before-inheritable-001.xht index 82153e2f5ff..f2407113029 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/before-inheritable-001.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/before-inheritable-001.xht @@ -4,6 +4,7 @@ CSS Test: Pseudo-element ':before' inherits inheritable values + + +

Test passes if there is no red visible on the page.

+
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-001.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-001.xht index efd40d220c0..447d8dabe7c 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-001.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-001.xht @@ -5,7 +5,7 @@ - + + +

Test passes if the words "PASS PASS" appear in the box below.

+
PASS PASS
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-003.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-003.xht index 9394d90c3e5..93f016a8269 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-003.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-003.xht @@ -5,6 +5,7 @@ + -

Test passes if the words "PASS PASS" are in the box below.

+

Test passes if the words "PASS PASS" appear in the box below.

\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-004.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-004.xht index 7a2f183fc1c..1388f76d475 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-004.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-004.xht @@ -5,17 +5,18 @@ + -

Test passes if there is a green box below.

+

Test passes if there is a filled green square.

\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-005-ref.html b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-005-ref.html new file mode 100644 index 00000000000..9947695209b --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-005-ref.html @@ -0,0 +1,13 @@ + + +CSS Reference + + +

Test passes if there is a zero "0" in the box below.

+
0
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-005.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-005.xht index 7accf9253aa..3036214c3d2 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-005.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-005.xht @@ -5,6 +5,7 @@ + + +

Test passes if there is a bullet (•) in the box below.

+
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-006.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-006.xht index bd4584e9037..297e27586af 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-006.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-006.xht @@ -5,6 +5,7 @@ + + +

Test passes if there is a bullet (◦) in the box below.

+
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-007.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-007.xht index 9573188a593..c4449d12115 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-007.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-007.xht @@ -5,6 +5,7 @@ + + +

Test passes if there are double zeros "00" in the box below.

+
00
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-010.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-010.xht index ac8550c6bb7..f0db8df1dfd 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-010.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-010.xht @@ -5,6 +5,7 @@ + -

Test passes if there is are double zeros "00" in the box below.

+

Test passes if there are double zeros "00" in the box below.

\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-011-ref.html b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-011-ref.html new file mode 100644 index 00000000000..8bc5f313b3f --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-011-ref.html @@ -0,0 +1,13 @@ + + +CSS Reference + + +

Test passes if there is a letter "i" in the box below.

+
i
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-011.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-011.xht index b5f8932b311..8bd626a695a 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-011.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-011.xht @@ -5,6 +5,7 @@ + + +

Test passes if there is a letter "I" in the box below.

+
I
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-012.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-012.xht index 6ba353f3efb..1b57d03357b 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-012.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-012.xht @@ -5,6 +5,7 @@ + + +

Test passes if there is a greek letter "α" in the box below.

+
α
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-013.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-013.xht index 753dcc240e1..9ac30e504c7 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-013.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-013.xht @@ -5,6 +5,7 @@ + + +

Test passes if there is a letter "a" in the box below.

+
a
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-014.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-014.xht index f7fe2d3a612..879b4dd5941 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-014.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-014.xht @@ -5,6 +5,7 @@ + + +

Test passes if there is a letter "A" in the box below.

+
A
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-015.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-015.xht index 843350bfc46..089496d16f1 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-015.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-015.xht @@ -5,6 +5,7 @@ + + +

Test passes if there is an Armenian character "Ա" below.

+
Ա
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-016.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-016.xht index 2ff6f8368a7..75d8bb7c426 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-016.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-016.xht @@ -5,6 +5,7 @@ + -

Test passes if there is an Armenian character "ա" or "Ա" below.

+

Test passes if there is an Armenian character "Ա" below.

\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-017-ref.html b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-017-ref.html new file mode 100644 index 00000000000..25d69f22bea --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-017-ref.html @@ -0,0 +1,13 @@ + + +CSS Reference + + +

Test passes if there is a Georgian character "ა" in the box below.

+
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-017.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-017.xht index f887d2c5a5f..adf5b8953f0 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-017.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-017.xht @@ -5,6 +5,7 @@ + + +

Test passes if the numbers "0" and "0.0" are in the box below.

+
0
0.0
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-021.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-021.xht index b003a29c84e..cbe53ed8313 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-021.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-021.xht @@ -5,6 +5,7 @@ + -

Test passes if there are the numbers "0" and "0.0" in the box below.

+

Test passes if the numbers "0" and "0.0" are in the box below.

diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-022-ref.html b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-022-ref.html new file mode 100644 index 00000000000..a7087f7bc6e --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-022-ref.html @@ -0,0 +1,12 @@ + + +CSS Reference + + +

Test passes if there are bullets "•" and "•.•" in the box below.

+

•.•
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-022.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-022.xht index 11ac0edd9b1..c5adb66e1f0 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-022.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-022.xht @@ -5,6 +5,7 @@ + + +

Test passes if there are circles "◦" and "◦.◦" in the box below.

+

◦.◦
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-023.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-023.xht index 6168a5e14d4..319f04cf12a 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-023.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-023.xht @@ -5,6 +5,7 @@ + -

Test passes if there are numbers "0" and "0.0" in the box below.

+

Test passes if the numbers "0" and "0.0" are in the box below.

diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-026-ref.html b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-026-ref.html new file mode 100644 index 00000000000..c884052e448 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-026-ref.html @@ -0,0 +1,12 @@ + + +CSS Reference + + +

Test passes if there are numbers "00" and "00.00" in the box below.

+
00
00.00
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-026.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-026.xht index a8222921d0a..54642cd2305 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-026.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-026.xht @@ -5,6 +5,7 @@ + + +

Test passes if there are letters "i" and "i.i" in the box below.

+
i
i.i
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-027.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-027.xht index b2bc7c010ab..8ee1644af82 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-027.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-027.xht @@ -5,6 +5,7 @@ + + +

Test passes if there are letters "I" and "I.I" in the box below.

+
I
I.I
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-028.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-028.xht index 1086c5e09c8..fb36942cbb9 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-028.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-028.xht @@ -5,6 +5,7 @@ + + +

Test passes if there are greek letters "α" and "α.α" in the box below.

+
α
α.α
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-029.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-029.xht index eb8b86273d6..d49a216cf49 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-029.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-029.xht @@ -5,6 +5,7 @@ + + +

Test passes if there are letters "a" and "a.a" in the box below.

+
a
a.a
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-030.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-030.xht index 30fdae91591..619ae0c9585 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-030.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-030.xht @@ -5,6 +5,7 @@ + + +

Test passes if there are letters "A" and "A.A" in the box below.

+
A
A.A
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-031.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-031.xht index 2771e04c633..305c724c30c 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-031.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-031.xht @@ -5,6 +5,7 @@ + + +

Test passes if there are Armenian characters "Ա" and "Ա.Ա" in the box below.

+
Ա
Ա.Ա
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-032.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-032.xht index 998223dfbf8..4e74b311fb4 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-032.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-032.xht @@ -5,6 +5,7 @@ + -

Test passes if there are Armenian characters "ա" and "ա.ա" or "Ա" and "Ա.Ա" in the box below.

+

Test passes if there are Armenian characters "Ա" and "Ա.Ա" in the box below.

diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-033-ref.html b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-033-ref.html new file mode 100644 index 00000000000..fc0aa9eb5fb --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-033-ref.html @@ -0,0 +1,12 @@ + + +CSS Reference + + +

Test passes if there are Georgian characters "ა" and "ა.ა" in the box below.

+

ა.ა
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-033.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-033.xht index f915c6081a9..2d41a9fea9d 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-033.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-033.xht @@ -5,6 +5,7 @@ + diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-037-ref.html b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-037-ref.html new file mode 100644 index 00000000000..39b5ba9284f --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-037-ref.html @@ -0,0 +1,17 @@ + + +CSS Reference + + +

Test passes if the words "PASS PASS" appear in the box below.

+ + + + +
PASS PASS
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-037.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-037.xht index d76522579e0..f0f45e1c58e 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-037.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-037.xht @@ -5,6 +5,7 @@ + + +

Test passes if the letter "P" appears in the box below.

+
P
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-040.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-040.xht index ec011ec902e..79791c98176 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-040.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-040.xht @@ -5,6 +5,7 @@ + + +

Test passes if the word "PASS" appears in the box below.

+
PASS
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-041.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-041.xht index 8bdf075ebdd..9f7745026e2 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-041.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-041.xht @@ -5,6 +5,7 @@ + + +

Test passes if the words "center" appear in the box below.

+
center
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-042.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-042.xht index 2b8d00637b7..0f927cc112f 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-042.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-042.xht @@ -5,6 +5,7 @@ + + +
#ffff00
+

Test passes if there is the text "#ffff00" above.

+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-043.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-043.xht index 5d93f31072b..3ecf8477bf1 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-043.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-043.xht @@ -5,6 +5,7 @@ + + +
PASS PASS
+

Test passes if the words "PASS PASS" appear above this text.

+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-047.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-047.xht index 3c8ef21c326..2b575f8e549 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-047.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-047.xht @@ -5,17 +5,23 @@ + -

Test passes if only the words "PASS PASS" appear above.

+

Test passes if the words "PASS PASS" appear above this text.

\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-048-ref.html b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-048-ref.html new file mode 100644 index 00000000000..e871e3be62a --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-048-ref.html @@ -0,0 +1,15 @@ + + +CSS Reference + + +
#ffff00
+

Test passes if there is the text "#ffff00" above.

+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-048.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-048.xht index fb906d6f102..9a1e66f1d07 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-048.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-048.xht @@ -5,6 +5,7 @@ + + +

Test passes if the number "1" appears in the box below.

+ + + + +
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-050.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-050.xht index 89d28417990..623ce5aea64 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-050.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-050.xht @@ -5,6 +5,7 @@ + + +

Test passes if the letter "A" appears in the box below.

+ + + + +
A
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-052.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-052.xht index 4b1ed885ebb..e155c2323ba 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-052.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-052.xht @@ -5,6 +5,7 @@ + + +

Test passes if the number "1" appears in the box below.

+ + + + +
1
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-053.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-053.xht index 0cc6b7cd8b6..0c85ab6e375 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-053.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-053.xht @@ -5,6 +5,7 @@ + -

Test passes if the words "PASS PASS" appears in the box below.

+

Test passes if the words "PASS PASS" appear in the box below.

\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-063-ref.html b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-063-ref.html new file mode 100644 index 00000000000..84a732bb1d6 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-063-ref.html @@ -0,0 +1,13 @@ + + +CSS Reference + + +

Test passes if the word "green" appears in the box below.

+
green
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-063.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-063.xht index 5ce5a7a453c..a5fdada076d 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-063.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-063.xht @@ -5,6 +5,7 @@ + + +

Test passes if the number "10" appears in the box below.

+
10
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-068.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-068.xht index c9eb1143556..de2a9dc92b2 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-068.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-068.xht @@ -5,6 +5,7 @@ + + +

Test passes if the text "2000-01-01T00:00:00-08:00" appears in the box below.

+ 2000-01-01T00:00:00-08:00 + diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-070.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-070.xht index 9b162fbaf28..97aa0a27e1d 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-070.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-070.xht @@ -5,6 +5,7 @@ + + +

Test passes if the word "defer" appears in the box below.

+
defer
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-072.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-072.xht index 8fd060ec477..755a6d52b18 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-072.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-072.xht @@ -5,6 +5,7 @@ + + +

Test passes if the letters "ltr" appear in the box below.

+
ltr
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-073.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-073.xht index d8e0b88f019..8a3c396699a 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-073.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-073.xht @@ -5,6 +5,7 @@ + + +

Test passes if the text "multipart/form-data" appear in the box below.

+
multipart/form-data
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-075.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-075.xht index 222528c3985..4f7a6856689 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-075.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-075.xht @@ -5,6 +5,7 @@ + + +

Test passes if the word "PASS" appears in the box below.

+ + + + +
PASS
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-080.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-080.xht index 3936e7d5aa3..7dbe2e42310 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-080.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-080.xht @@ -5,6 +5,7 @@ + + +

Test passes if the number "10" appears in the box below.

+ + + + +
10
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-081.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-081.xht index 21cd3041974..937a691eb1b 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-081.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-081.xht @@ -5,6 +5,7 @@ + + +

Test passes if the character "#" appears in the box below.

+
#
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-082.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-082.xht index 3713792ccd6..9c51a98070f 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-082.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-082.xht @@ -5,6 +5,7 @@ + + +

Test passes if the letters "aa" appear in the box below.

+
aa
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-083.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-083.xht index 63f73880b50..833a4b6a194 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-083.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-083.xht @@ -5,6 +5,7 @@ + -

Test passes if the word "PASS" appear in the box below.

+

Test passes if the word "PASS" appears in the box below.

\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-089-ref.html b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-089-ref.html new file mode 100644 index 00000000000..375572bac55 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-089-ref.html @@ -0,0 +1,13 @@ + + +CSS Reference + + +

Test passes if the letters "aa" appear in the box below.

+
aa
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-089.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-089.xht index 51ad578abbd..cd9d500ecbf 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-089.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-089.xht @@ -5,6 +5,7 @@ + + +

Test passes if the word "ecmascript" appears in the box below.

+
ecmascript
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-090.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-090.xht index d4f15c508c3..982023deaad 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-090.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-090.xht @@ -5,6 +5,7 @@ + + +
green
+

Test passes if the word "green" appears above.

+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-091.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-091.xht index cb6a8decb23..1c1b35239ee 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-091.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-091.xht @@ -5,6 +5,7 @@ + + +
all
+

Test passes if the word "all" appears above this text.

+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-096.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-096.xht index 24dbcdd0cf8..a968386f10e 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-096.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-096.xht @@ -5,6 +5,7 @@ + diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-097-ref.html b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-097-ref.html new file mode 100644 index 00000000000..d68b7955f5f --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-097-ref.html @@ -0,0 +1,13 @@ + + +CSS Reference + + +

Test passes if the word "get" appears in the box below.

+
get
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-097.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-097.xht index f6de01047d3..a95a303e94c 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-097.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-097.xht @@ -5,6 +5,7 @@ + + +

Test passes if the word "nohref" appears in the box below.

+
nohref
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-100.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-100.xht index e928b353dcc..f067992204d 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-100.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-100.xht @@ -5,6 +5,7 @@ + -

Test passes if the word "nohref" appear in the box below.

+

Test passes if the word "nohref" appears in the box below.

diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-103-ref.html b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-103-ref.html new file mode 100644 index 00000000000..d538ab4b479 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-103-ref.html @@ -0,0 +1,17 @@ + + +CSS Reference + + +

Test passes if the word "nowrap" appears in the box below.

+ + + + +
nowrap
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-103.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-103.xht index 9b22daaf663..b8380e4500a 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-103.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-103.xht @@ -5,6 +5,7 @@ + + +
PASS();
+

Test passes if only the word "PASS();" appears above. Fail if there is any other additional text.

+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-113.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-113.xht index 7de819efea3..559b7953d23 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-113.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-113.xht @@ -5,6 +5,7 @@ + diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-122.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-122.xht index 3cf97e3e1f1..a32ce892c37 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-122.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-122.xht @@ -5,6 +5,7 @@ + diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-123.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-123.xht index 76d726d9907..94399d109a7 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-123.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-123.xht @@ -5,6 +5,7 @@ + -

Test passes if only the words "PASS PASS" appear above.

+

Test passes if the words "PASS PASS" appear above this text.

\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-126-ref.html b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-126-ref.html new file mode 100644 index 00000000000..74f46da24c0 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-126-ref.html @@ -0,0 +1,13 @@ + + +CSS Reference + + +

Test passes if only the word "Alternate" appears in the box below.

+
Alternate
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-126.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-126.xht index a4273a8ebfe..6157e818869 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-126.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-126.xht @@ -5,6 +5,7 @@ + -

Test passes if only the number "1" appears in the box below.

+

Test passes if the number "1" appears in the box below.

diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-131.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-131.xht index 3e7c5307759..ad6d62830a9 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-131.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-131.xht @@ -5,6 +5,7 @@ + @@ -21,6 +22,6 @@ -

Test passes if only the words "PASS PASS" appear above this text.

+

Test passes if the words "PASS PASS" appear above this text.

\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-132-ref.html b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-132-ref.html new file mode 100644 index 00000000000..6c1736b5c65 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-132-ref.html @@ -0,0 +1,17 @@ + + +CSS Reference + + +

Test passes if only the word "col" appears in the box below.

+
+ + + +
col
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-132.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-132.xht index da7701eebce..389966d079e 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-132.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-132.xht @@ -5,6 +5,7 @@ + + +

Test passes if only the word "circle" appears in the box below.

+
circle
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-135.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-135.xht index 9fdce200d5f..3acddbdf2e9 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-135.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-135.xht @@ -5,6 +5,7 @@ + + +

Test passes if the number "5" appears in the box below.

+
5
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-136.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-136.xht index c4d9531f39e..97b36915460 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-136.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-136.xht @@ -5,6 +5,7 @@ + -

Test passes if only the words "PASS PASS" appear in the box below.

+

Test passes if the words "PASS PASS" appear in the box below.

\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-141-ref.html b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-141-ref.html new file mode 100644 index 00000000000..9a5d248bc69 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-141-ref.html @@ -0,0 +1,13 @@ + + +CSS Reference + + +

Test passes if the words "color: green;" appear in the box below.

+
color: green;
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-141.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-141.xht index 9f0b2074d5b..1a384c02264 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-141.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-141.xht @@ -5,6 +5,7 @@ + diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-143-ref.html b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-143-ref.html new file mode 100644 index 00000000000..6a4e3dcf9cd --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-143-ref.html @@ -0,0 +1,13 @@ + + +CSS Reference + + +

Test passes if the number "5" appears in the box below.

+
5
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-143.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-143.xht index 001b572df3d..ff6b23552af 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-143.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-143.xht @@ -5,6 +5,7 @@ + + +

Test passes if the word "_blank" appears in the box below.

+
_blank
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-144.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-144.xht index 71be8cd4b8b..3ca997ae596 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-144.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-144.xht @@ -5,6 +5,7 @@ + -

Test passes if there is only the word "green" above.

+

Test passes if the word "green" appears above.

\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-146.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-146.xht index 3c2d4fc7474..fdc5166b50d 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-146.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-146.xht @@ -5,6 +5,7 @@ + + +

Test passes if the words "text/plain" appear in the box below.

+
text/plain
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-147.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-147.xht index a1dc049baa6..12db407512e 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-147.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-147.xht @@ -5,6 +5,7 @@ + -

Test passes if the words "text/plain"" appear in the box below.

+

Test passes if the words "text/plain" appear in the box below.

diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-149-ref.html b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-149-ref.html new file mode 100644 index 00000000000..55641ccda07 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-149-ref.html @@ -0,0 +1,17 @@ + + +CSS Reference + + +

Test passes if only the word "baseline" appears in the box below.

+ + + + +
baseline
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-149.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-149.xht index 2685e6cd35c..ab98d48e1c8 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-149.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-149.xht @@ -5,6 +5,7 @@ + + +

Test passes if only the number "1" appears in the box below.

+
    +
  1. 1
  2. +
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-150.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-150.xht index a82d07dd2fc..258fb9934e8 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-150.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-150.xht @@ -5,6 +5,7 @@ + -

Test passes if only the number "1" appear in the box below.

+

Test passes if only the number "1" appears in the box below.

diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-152.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-152.xht index 7da46d4e1dd..78965fb7db6 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-152.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-152.xht @@ -5,6 +5,7 @@ + -

Test passes if the words "PASS PASS" appear above.

+

Test passes if the words "PASS PASS" appear above this text.

\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-153.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-153.xht index 27e18dee899..36c0344763a 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-153.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-153.xht @@ -5,6 +5,7 @@ + + +

Test passes if the number "10" appears in the box below.

+
10
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-155.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-155.xht index 8bf60b1b863..7821cadcf41 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-155.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-155.xht @@ -5,6 +5,7 @@ + + +

Test passes if there is a quote (") in the blue box below.

+
"
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-156.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-156.xht index c190e1b29a2..6dcdee90730 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-156.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-156.xht @@ -5,6 +5,7 @@ + + +

Test passes if there is a single quote (') in the blue box below.

+
'
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-158.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-158.xht index 84cf084568d..d52e18b3d19 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-158.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-158.xht @@ -5,6 +5,7 @@ + + +

Test passes if there are 3 quotes (" ' ") in the blue box.

+
" ' "
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-159.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-159.xht index e0e65a47b39..de8ec378618 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-159.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-159.xht @@ -5,6 +5,7 @@ + -

Test passes if there is nothing displayed below.

+

Test passes if there is nothing below.

\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-attr-case-001.html b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-attr-case-001.html index 21361c3f3e7..2ba49f95584 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-attr-case-001.html +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-attr-case-001.html @@ -4,12 +4,12 @@ CSS Test: Content property attr(x) case sensitivity + diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-attr-case-002.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-attr-case-002.xht index 46632f15d08..d3126bafcda 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-attr-case-002.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-attr-case-002.xht @@ -4,6 +4,7 @@ CSS Test: content attr(x) case sensitivity + -
Test Passes if there is no red visible on the page.
+

Test passes if there is no red visible on the page.

\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-auto-reset-001-ref.html b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-auto-reset-001-ref.html new file mode 100644 index 00000000000..3a2e1d7e2e5 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-auto-reset-001-ref.html @@ -0,0 +1,7 @@ + + +CSS Reference + +

Test passes if there is the number '0' below.

+
0
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-auto-reset-001.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-auto-reset-001.xht index c6476035343..6fc8adbb8f2 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-auto-reset-001.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-auto-reset-001.xht @@ -4,6 +4,7 @@ CSS Test: Content property on out of scope counter + + +

Test passes if there are exactly two lines of text below.

+
This text
should be on two lines.
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-newline-001.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-newline-001.xht index 5823940f2d8..2e1a3bda0f0 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-newline-001.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-newline-001.xht @@ -4,6 +4,7 @@ CSS Test: Content property \A creates newline + + +

Test passes if the text in the green box and the blue box have the same spacing between words and the lines wrap at the same point.

+
This text
should be on two lines.
+
This text
should be on two lines.
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-white-space-001.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-white-space-001.xht index 2fe179f43fe..92698714036 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-white-space-001.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-white-space-001.xht @@ -4,6 +4,7 @@ CSS Test: Content property and white-space: pre-line + + +

Test passes if the contents of the two silver boxes are identical.

+
This text + should be on + four + lines.
+
This text + should be on + four + lines.
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-white-space-002.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-white-space-002.xht index 131489e4013..52294d27f47 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-white-space-002.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-white-space-002.xht @@ -5,6 +5,7 @@ + + +

Test passes if the contents of the two silver boxes are identical.

+
This text should be on one line.
+
This text should be on one line.
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-white-space-003.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-white-space-003.xht index dc72283a4b4..83fd21d574f 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-white-space-003.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-white-space-003.xht @@ -5,6 +5,7 @@ + + +

Test passes if the contents of the two silver boxes are identical.

+
This text should wrap normally.
+
This text should wrap normally.
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-white-space-004.xht b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-white-space-004.xht index 83561849c28..34c186295a4 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-white-space-004.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/generated-content/content-white-space-004.xht @@ -5,6 +5,7 @@ + +

Some paragraph

+

Some paragraph

+

Some paragraph

+

Some other paragraph

diff --git a/tests/wpt/web-platform-tests/css/CSS2/linebox/line-height-oof-descendants-001.html b/tests/wpt/web-platform-tests/css/CSS2/linebox/line-height-oof-descendants-001.html new file mode 100644 index 00000000000..6663b1949a7 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/linebox/line-height-oof-descendants-001.html @@ -0,0 +1,17 @@ + + +CSS Test: line-height is not affected by out-of-flow descendants + + + + + +

Some paragraph

+

Some paragraph

+

Some paragraph

+

Some other paragraph

diff --git a/tests/wpt/web-platform-tests/css/CSS2/values/numbers-units-011.xht b/tests/wpt/web-platform-tests/css/CSS2/values/numbers-units-011.xht index ae5737b5e19..eb52c980f84 100644 --- a/tests/wpt/web-platform-tests/css/CSS2/values/numbers-units-011.xht +++ b/tests/wpt/web-platform-tests/css/CSS2/values/numbers-units-011.xht @@ -22,6 +22,7 @@ { font-family: Ahem; margin-top: 10px; + line-height: 1; } diff --git a/tests/wpt/web-platform-tests/css/CSS2/visudet/content-height-001.html b/tests/wpt/web-platform-tests/css/CSS2/visudet/content-height-001.html new file mode 100644 index 00000000000..54fc8da4bea --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/visudet/content-height-001.html @@ -0,0 +1,22 @@ + + +CSS2 inline level box content height test + + + + + + + +

Test passes if the blue shape below is a rectangle, but not some other polygon. + +

aa
aa
aa
diff --git a/tests/wpt/web-platform-tests/css/CSS2/visudet/content-height-002.html b/tests/wpt/web-platform-tests/css/CSS2/visudet/content-height-002.html new file mode 100644 index 00000000000..af1ed946c70 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/visudet/content-height-002.html @@ -0,0 +1,42 @@ + + +CSS2 inline level box content height test + + + + + + + +

Test passes if the blue shape below is a rectangle, but not some other polygon. + +

ab
ab
ab
diff --git a/tests/wpt/web-platform-tests/css/CSS2/visudet/content-height-003.html b/tests/wpt/web-platform-tests/css/CSS2/visudet/content-height-003.html new file mode 100644 index 00000000000..c0247991928 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/visudet/content-height-003.html @@ -0,0 +1,42 @@ + + +CSS2 inline level box content height test + + + + + + + +

Test passes if the blue shape below is a rectangle, but not some other polygon. + +

bb
bb
bb
diff --git a/tests/wpt/web-platform-tests/css/CSS2/visudet/content-height-004.html b/tests/wpt/web-platform-tests/css/CSS2/visudet/content-height-004.html new file mode 100644 index 00000000000..b5823b9f56a --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/visudet/content-height-004.html @@ -0,0 +1,50 @@ + + +CSS2 inline level box content height test + + + + + + + +

Test passes if the blue shape below is a rectangle, but not some other polygon. + +

diff --git a/tests/wpt/web-platform-tests/css/CSS2/visudet/content-height-005.html b/tests/wpt/web-platform-tests/css/CSS2/visudet/content-height-005.html new file mode 100644 index 00000000000..6780f814349 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/visudet/content-height-005.html @@ -0,0 +1,41 @@ + + +CSS2 inline level box content height test + + + + + + + +

Test passes if there are more than 2 lines below. + +

diff --git a/tests/wpt/web-platform-tests/css/CSS2/visudet/line-height-201.html b/tests/wpt/web-platform-tests/css/CSS2/visudet/line-height-201.html new file mode 100644 index 00000000000..10b8ae0d9fb --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/visudet/line-height-201.html @@ -0,0 +1,55 @@ + + +CSS2 Line height test: explicit sizing + + + + + + + +

Test passes if there is a green square and no red below. + +

+ +
ab
+
ab
diff --git a/tests/wpt/web-platform-tests/css/CSS2/visudet/line-height-202.html b/tests/wpt/web-platform-tests/css/CSS2/visudet/line-height-202.html new file mode 100644 index 00000000000..719cf84aa48 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/visudet/line-height-202.html @@ -0,0 +1,56 @@ + + +CSS2 Line height test: baseline position when explicit sizing + + + + + + + +

Test passes if there is no red below. + +

ab
+
aa
diff --git a/tests/wpt/web-platform-tests/css/CSS2/visudet/line-height-203.html b/tests/wpt/web-platform-tests/css/CSS2/visudet/line-height-203.html new file mode 100644 index 00000000000..4c72aa0000a --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/visudet/line-height-203.html @@ -0,0 +1,52 @@ + + +CSS2 Line height test: baseline position with explicit sizing + + + + + + + +

Test passes if there is a small green rectangle or square below. + +

aa
+
aa
diff --git a/tests/wpt/web-platform-tests/css/CSS2/visudet/line-height-204.html b/tests/wpt/web-platform-tests/css/CSS2/visudet/line-height-204.html new file mode 100644 index 00000000000..9f16e624526 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/visudet/line-height-204.html @@ -0,0 +1,60 @@ + + + +CSS2 Line height test: baseline position, normal sizing vs explicit sizing + + + + + + + + +

Test passes if there is no red below. + +

a
+
a
+ + diff --git a/tests/wpt/web-platform-tests/css/CSS2/visudet/line-height-205.html b/tests/wpt/web-platform-tests/css/CSS2/visudet/line-height-205.html new file mode 100644 index 00000000000..506a044d566 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/visudet/line-height-205.html @@ -0,0 +1,53 @@ + + +CSS2 Line height test: normal sizing + + + + + + + +

Test passes if there is no red below. + + + +

ab
+
ab
+ + + +
ab
+
ab
+ diff --git a/tests/wpt/web-platform-tests/css/CSS2/visudet/line-height-206.html b/tests/wpt/web-platform-tests/css/CSS2/visudet/line-height-206.html new file mode 100644 index 00000000000..25f0ab933f7 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/visudet/line-height-206.html @@ -0,0 +1,46 @@ + + +CSS2 Line height test: normal sizing with fallback fonts + + + + + + + +

There should be two stacked rectangles below: a tall one above a short one, both the same width, sharing the edge at which they touch. + + +

a
+
a
diff --git a/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/content-height-001-ref.html b/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/content-height-001-ref.html new file mode 100644 index 00000000000..d6ca716b0cb --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/content-height-001-ref.html @@ -0,0 +1,16 @@ + + +CSS Test Reference file + + + +

Test passes if the blue shape below is a rectangle, but not some other polygon. + +

aa
aa
aa
diff --git a/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/content-height-002-ref.html b/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/content-height-002-ref.html new file mode 100644 index 00000000000..511eef0549a --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/content-height-002-ref.html @@ -0,0 +1,35 @@ + + +CSS Test Reference file + + + +

Test passes if the blue shape below is a rectangle, but not some other polygon. + +

ab
ab
ab
diff --git a/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/content-height-003-ref.html b/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/content-height-003-ref.html new file mode 100644 index 00000000000..60a805de4e9 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/content-height-003-ref.html @@ -0,0 +1,35 @@ + + +CSS Test Reference file + + + +

Test passes if the blue shape below is a rectangle, but not some other polygon. + +

bb
bb
bb
diff --git a/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/content-height-004-ref.html b/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/content-height-004-ref.html new file mode 100644 index 00000000000..10460f018fc --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/content-height-004-ref.html @@ -0,0 +1,34 @@ + + +CSS2 Line height test: explicit sizing + + + +

Test passes if the blue shape below is a rectangle, but not some other polygon. + +

diff --git a/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/content-height-005-ref.html b/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/content-height-005-ref.html new file mode 100644 index 00000000000..70a3ee07840 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/content-height-005-ref.html @@ -0,0 +1,22 @@ + + +CSS Test Reference file + + +div { + font-size: 50px; + display: inline-block; +} + +span { + padding-left: 1em; + color: black; + border-top: solid 1px; + border-bottom: solid 1px; +} + + + +

Test passes if there are more than 2 lines below. + +

diff --git a/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/line-height-201-ref.html b/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/line-height-201-ref.html new file mode 100644 index 00000000000..3564bf77858 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/line-height-201-ref.html @@ -0,0 +1,16 @@ + + +CSS Test Reference file + + + +

Test passes if there is a green square and no red below. + +

diff --git a/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/line-height-202-ref.html b/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/line-height-202-ref.html new file mode 100644 index 00000000000..2b77a6b3dd3 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/line-height-202-ref.html @@ -0,0 +1,6 @@ + + +CSS Test Reference file + + +

Test passes if there is no red below. diff --git a/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/line-height-203-ref.html b/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/line-height-203-ref.html new file mode 100644 index 00000000000..ec605c76a91 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/line-height-203-ref.html @@ -0,0 +1,6 @@ + + +CSS Test Reference file + + +

Test passes if there is a small green rectangle or square below. diff --git a/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/line-height-206-ref.html b/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/line-height-206-ref.html new file mode 100644 index 00000000000..31ce1a98dc3 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/CSS2/visudet/reference/line-height-206-ref.html @@ -0,0 +1,26 @@ + + +CSS Test Reference file + + + +

There should be two stacked rectangles below: a tall one above a short one, both the same width, sharing the edge at which they touch. + +

a
diff --git a/tests/wpt/web-platform-tests/css/CSS2/visudet/support/1x1-green.png b/tests/wpt/web-platform-tests/css/CSS2/visudet/support/1x1-green.png new file mode 100644 index 00000000000..b98ca0ba0a0 Binary files /dev/null and b/tests/wpt/web-platform-tests/css/CSS2/visudet/support/1x1-green.png differ diff --git a/tests/wpt/web-platform-tests/css/CSS2/visudet/support/AD.woff b/tests/wpt/web-platform-tests/css/CSS2/visudet/support/AD.woff new file mode 100644 index 00000000000..3df8ea8efda Binary files /dev/null and b/tests/wpt/web-platform-tests/css/CSS2/visudet/support/AD.woff differ diff --git a/tests/wpt/web-platform-tests/css/CSS2/visudet/support/Revalia.woff b/tests/wpt/web-platform-tests/css/CSS2/visudet/support/Revalia.woff new file mode 100644 index 00000000000..631bee6de90 Binary files /dev/null and b/tests/wpt/web-platform-tests/css/CSS2/visudet/support/Revalia.woff differ diff --git a/tests/wpt/web-platform-tests/css/OWNERS b/tests/wpt/web-platform-tests/css/OWNERS deleted file mode 100644 index 7282743f680..00000000000 --- a/tests/wpt/web-platform-tests/css/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -@gsnedders - diff --git a/tests/wpt/web-platform-tests/css/README.md b/tests/wpt/web-platform-tests/css/README.md index 668ba28f4ac..4967f8cf479 100644 --- a/tests/wpt/web-platform-tests/css/README.md +++ b/tests/wpt/web-platform-tests/css/README.md @@ -1,12 +1,14 @@ Introduction ------------ -This directory contains all testsuites for all CSS specifications still using -the [CSS test harness][harness]. These should primarily be considered legacy; -new testsuites should almost always be put at the top level without any level -suffix. +This directory contains testsuites for CSS WG specifications, including ones +that do not strictly speaking define CSS features, e.g., +[Geometry Interfaces](https://drafts.fxtf.org/geometry/). -As the test harness relies on the largely undocumented(!) old CSS build system, +The directories should be named like the specification's shortname, but without +any level suffix. + +As the test harness relies on the largely undocumented old CSS build system, this directory has a number of test requirements specific to it: * support files for a given test must live in an adjacent `support` directory; @@ -20,21 +22,14 @@ this directory has a number of test requirements specific to it: `css` directory. -Odd Directories ---------------- - -There are a few special directories that do not map to specifications: +vendor-imports/ Directory +------------------------- vendor-imports/ is a legacy directory where third parties historically imported their tests that originate and are maintained in an external repo. Files in this directory should never be modified in this repo, but should go through the vendor's process to be imported here. -work-in-progress/ is a legacy directory that contains all the work that was -once submitted to the repo, but was not yet ready for review. As pull requests -are now used, no new files should be added here. The subdirectories here are -named by test author or contributing organization. - Importing Old Branches ---------------------- diff --git a/tests/wpt/web-platform-tests/css/compositing/mix-blend-mode/mix-blend-mode-transition.html b/tests/wpt/web-platform-tests/css/compositing/mix-blend-mode/mix-blend-mode-transition.html deleted file mode 100644 index e3d3501eb5d..00000000000 --- a/tests/wpt/web-platform-tests/css/compositing/mix-blend-mode/mix-blend-mode-transition.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - CSS Test: Blended element with transition - - - - - - - - - - -

Test passes if you can see a fading green rectangle.

-
- - - diff --git a/tests/wpt/web-platform-tests/css/compositing/mix-blend-mode/reference/mix-blend-mode-transition-ref.html b/tests/wpt/web-platform-tests/css/compositing/mix-blend-mode/reference/mix-blend-mode-transition-ref.html deleted file mode 100644 index bb7d02039c1..00000000000 --- a/tests/wpt/web-platform-tests/css/compositing/mix-blend-mode/reference/mix-blend-mode-transition-ref.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - CSS Test: Blended element with transition - - - - - -

Test passes if you can see a fading green rectangle.

-
- - - diff --git a/tests/wpt/web-platform-tests/css/css-animations/animation-delay-011.html b/tests/wpt/web-platform-tests/css/css-animations/animation-delay-011.html new file mode 100644 index 00000000000..415a5747553 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-animations/animation-delay-011.html @@ -0,0 +1,24 @@ + + +CSS Animations Test: inherited animation-delay with mismatched animation-name length + + + + +
diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/background-color-body-propagation-001.html b/tests/wpt/web-platform-tests/css/css-backgrounds/background-color-body-propagation-001.html new file mode 100644 index 00000000000..4cfc36033d4 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/background-color-body-propagation-001.html @@ -0,0 +1,16 @@ + +CSS Backgrounds and Borders Test: propagate body background to viewport + + + + +

The viewport should have a green background.

diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/background-color-body-propagation-002.html b/tests/wpt/web-platform-tests/css/css-backgrounds/background-color-body-propagation-002.html new file mode 100644 index 00000000000..1c42637e505 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/background-color-body-propagation-002.html @@ -0,0 +1,19 @@ + +CSS Backgrounds and Borders Test: body background not propagating when html does + + + + +

The viewport should have a green background.

diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/background-color-body-propagation-003.html b/tests/wpt/web-platform-tests/css/css-backgrounds/background-color-body-propagation-003.html new file mode 100644 index 00000000000..8106822a4e8 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/background-color-body-propagation-003.html @@ -0,0 +1,11 @@ + +CSS Backgrounds and Borders Test: propagate body background while display changes + + + + +

The viewport should have a green background.

+ diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/background-color-body-propagation-ref.html b/tests/wpt/web-platform-tests/css/css-backgrounds/background-color-body-propagation-ref.html new file mode 100644 index 00000000000..1a138740de9 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/background-color-body-propagation-ref.html @@ -0,0 +1,6 @@ + + +CSS Reftest Reference + + +

The viewport should have a green background.

diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/background-image-none-gradient-repaint.html b/tests/wpt/web-platform-tests/css/css-backgrounds/background-image-none-gradient-repaint.html new file mode 100644 index 00000000000..3f39fb8d850 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/background-image-none-gradient-repaint.html @@ -0,0 +1,29 @@ + + + +CSS Backgrounds and Borders: Repaint gradient change in second layer + + + + +

There should be a green square below.

+
+ diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-001-ref.xht b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-001-ref.xht index 9c7bc4bd5f3..0d6f4d703e6 100644 --- a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-001-ref.xht +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-001-ref.xht @@ -3,29 +3,25 @@ CSS Test: Border radius reference - -

- There should be two boxes with no rounded corners.

+

There should be two boxes with no rounded corners.

-
-


-
+
+


+
diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-001.xht b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-001.xht index 7536df1dc51..5029dd0f151 100644 --- a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-001.xht +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-001.xht @@ -3,65 +3,33 @@ CSS Test: Borders. border–radius set to zero - - - - - -

- There should be two boxes with no rounded corners. -

- - +

There should be two boxes with no rounded corners.

+ -
-


-
- +
+


+
diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-002-ref.xht b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-002-ref.xht index 104c1e15128..b9282343ebb 100644 --- a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-002-ref.xht +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-002-ref.xht @@ -3,34 +3,28 @@ CSS Test: Border radius reference - -

- There should be two identical boxes, each with 4 rounded corners. -

+

There should be two identical boxes, each with 4 rounded corners.

-
-


-
+
+


+
- diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-002.xht b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-002.xht index 1877e082fba..9f53fc37587 100644 --- a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-002.xht +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-002.xht @@ -3,68 +3,36 @@ CSS Test: Borders. border–radius using one length value 25px - - - - - -

- There should be two identical boxes, each with 4 rounded corners. -

+

There should be two identical boxes, each with 4 rounded corners.

-
-


-
- +
+


+
- diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-003-ref.xht b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-003-ref.xht index be824c20732..d7017f024f9 100644 --- a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-003-ref.xht +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-003-ref.xht @@ -3,34 +3,28 @@ CSS Test: Border radius reference - -

- There should be two identical boxes, each with rounded corners at the top left and bottom right only. -

+

There should be two identical boxes, each with rounded corners at the top left and bottom right only.

-
-


-
+
+


+
- diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-003.xht b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-003.xht index cfe4d742688..398358f1f1d 100644 --- a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-003.xht +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-003.xht @@ -3,68 +3,36 @@ CSS Test: Borders. border–radius set to value: 50px 0 - - - - - -

- There should be two identical boxes, each with rounded corners at the top left and bottom right only. -

+

There should be two identical boxes, each with rounded corners at the top left and bottom right only.

-
-


-
- +
+


+
- diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-004-ref.xht b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-004-ref.xht index 74e70ab4917..3062d7832fc 100644 --- a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-004-ref.xht +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-004-ref.xht @@ -3,34 +3,29 @@ CSS Test: Border radius reference - -

- There should be two identical boxes, each with 4 rounded corners. -

+

There should be two identical boxes, each with 4 rounded corners.

-
-


-
+
+


+
diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-004.xht b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-004.xht index cfd57e29d9f..8a000d909c5 100644 --- a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-004.xht +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-004.xht @@ -3,68 +3,37 @@ CSS Test: Borders. border–radius using slash: 50px / 25px - - - - - -

- There should be two identical boxes, each with 4 rounded corners. -

+

There should be two identical boxes, each with 4 rounded corners.

-
-


-
- +
+


+
diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-005-ref.xht b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-005-ref.xht index 378b40ec20b..57605a76f5f 100644 --- a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-005-ref.xht +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-005-ref.xht @@ -3,34 +3,29 @@ CSS Test: Border radius reference - -

- There should be two identical boxes, each with 4 rounded corners. -

+

There should be two identical boxes, each with 4 rounded corners.

-
-


-
+
+


+
diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-005.xht b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-005.xht index 839d48f91e1..7be93af636d 100644 --- a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-005.xht +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-005.xht @@ -3,66 +3,36 @@ CSS Test: Borders. border–radius using slash: 50px 15px 40px / 20px 25px - - - - - -

- There should be two identical boxes, each with 4 rounded corners. -

+

There should be two identical boxes, each with 4 rounded corners.

-
-


-
- +
+


+
- diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-006-ref.xht b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-006-ref.xht index 730a19bf121..93c19491eae 100644 --- a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-006-ref.xht +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-006-ref.xht @@ -3,34 +3,28 @@ CSS Test: Border radius reference - -

- There should be two identical boxes, each with 4 rounded corners. -

+

There should be two identical boxes, each with 4 rounded corners.

-
-


-
+
+


+
- diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-006.xht b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-006.xht index e2426d02bbf..89da74c4827 100644 --- a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-006.xht +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-006.xht @@ -3,68 +3,36 @@ CSS Test: Borders. border–radius using slash: 50px 15px / 20px 25px 10% - - - - - -

- There should be two identical boxes, each with 4 rounded corners. -

+

There should be two identical boxes, each with 4 rounded corners.

-
-


-
- +
+


+
- diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-007-ref.xht b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-007-ref.xht index 3d3ab1bfc65..c10c0ee848c 100644 --- a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-007-ref.xht +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-007-ref.xht @@ -3,34 +3,28 @@ CSS Test: Border radius reference - -

- There should be two identical boxes, each with 4 rounded corners. -

+

There should be two identical boxes, each with 4 rounded corners.

-
-


-
+
+


+
- diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-007.xht b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-007.xht index ab0bdf2ee9a..df442e00852 100644 --- a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-007.xht +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-007.xht @@ -3,68 +3,36 @@ CSS Test: Borders. border–radius using slash: 50px 10mm 3pc 15% / 0.5in 25px 10% 70pt - - - - - -

- There should be two identical boxes, each with 4 rounded corners. -

+

There should be two identical boxes, each with 4 rounded corners.

-
-


-
- +
+


+
- diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-008.xht b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-008.xht index 8c5a7a961e1..a4b1408dd30 100644 --- a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-008.xht +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-008.xht @@ -3,65 +3,33 @@ CSS Test: Borders. border–radius using slash: 50px 15px 40px 30em 25em / 20px 25px - - - - - -

- There should be two boxes with no rounded corners. -

- - +

There should be two boxes with no rounded corners.

+ + -
-


-
- +
+


+
- diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-009-ref.xht b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-009-ref.xht index 99064998e9c..c86e22d3871 100644 --- a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-009-ref.xht +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-009-ref.xht @@ -3,34 +3,29 @@ CSS Test: Border radius reference - -

- There should be two identical boxes, each with 4 rounded corners. -

+

There should be two identical boxes, each with 4 rounded corners.

-
-


-
+
+


+
diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-009.xht b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-009.xht index 70169c31854..822f1668596 100644 --- a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-009.xht +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-009.xht @@ -3,70 +3,39 @@ CSS Test: Borders. border–radius using "inherit" - - - - - -

- There should be two identical boxes, each with 4 rounded corners. -

+

There should be two identical boxes, each with 4 rounded corners.

-
-


-
- +
+


+
- diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-010-ref.xht b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-010-ref.xht index 7cb553e7edd..882032bfbc7 100644 --- a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-010-ref.xht +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-010-ref.xht @@ -3,34 +3,29 @@ CSS Test: Border radius reference - -

- There should be two identical boxes, each with rounded corners at the top left and bottom right only. -

+

There should be two identical boxes, each with rounded corners at the top left and bottom right only.

-
-


-
+
+


+
diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-010.xht b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-010.xht index 99791d10a52..32d464673a7 100644 --- a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-010.xht +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-010.xht @@ -3,73 +3,40 @@ CSS Test: Borders. border–radius using "inherit" - - - - - -

- There should be two identical boxes, each with rounded corners at the top left and bottom right only. -

+

There should be two identical boxes, each with rounded corners at the top left and bottom right only.

-
-


-
- +
+


+
- diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-011-ref.xht b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-011-ref.xht index 32120f12ea7..cdeaf1c8e81 100644 --- a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-011-ref.xht +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-011-ref.xht @@ -3,29 +3,22 @@ CSS Test: Border radius reference - -

- There should be two boxes, each with corners that have no rounding. -

- +

A white rectangle with no border-radius property sits exactly on top of an exact same size red rectangle with border-radius set to zero.

+ -
-


-
+
diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-011.xht b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-011.xht index 6a5ceab204e..8439302d6bd 100644 --- a/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-011.xht +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/border-radius-011.xht @@ -5,44 +5,36 @@ - - -

- A white rectangle with no border-radius property sits exactly on top of an exact same size red rectangle with border-radius set to zero. -

- - +

A white rectangle with no border-radius property sits exactly on top of an exact same size red rectangle with border-radius set to zero.

+ + -
-
+
+
diff --git a/tests/wpt/web-platform-tests/css/css-break/OWNERS b/tests/wpt/web-platform-tests/css/css-break/OWNERS new file mode 100644 index 00000000000..f4d064aef21 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-break/OWNERS @@ -0,0 +1 @@ +@mstensho diff --git a/tests/wpt/web-platform-tests/css/css-break/break-before-always-001.xht b/tests/wpt/web-platform-tests/css/css-break/break-before-always-001.xht index d97a8c25696..e2e7297d153 100644 --- a/tests/wpt/web-platform-tests/css/css-break/break-before-always-001.xht +++ b/tests/wpt/web-platform-tests/css/css-break/break-before-always-001.xht @@ -3,7 +3,7 @@ CSS Test: 'break-before: always' and paginated multi-column elements - + -

Test passess if this text is black

+

Test passes if this text is black

diff --git a/tests/wpt/web-platform-tests/css/css-color/color-001.html b/tests/wpt/web-platform-tests/css/css-color/color-001.html index 5d93d5e2667..580307ba073 100644 --- a/tests/wpt/web-platform-tests/css/css-color/color-001.html +++ b/tests/wpt/web-platform-tests/css/css-color/color-001.html @@ -9,5 +9,5 @@ .test {color: green} -

Test passess if this text is green

+

Test passes if this text is green

diff --git a/tests/wpt/web-platform-tests/css/css-color/color-002.html b/tests/wpt/web-platform-tests/css/css-color/color-002.html index 8b53b6862b6..7d2f5b318e6 100644 --- a/tests/wpt/web-platform-tests/css/css-color/color-002.html +++ b/tests/wpt/web-platform-tests/css/css-color/color-002.html @@ -9,5 +9,5 @@ .test {color: initial} -

Test passess if this text is black

+

Test passes if this text is black

diff --git a/tests/wpt/web-platform-tests/css/css-color/color-003.html b/tests/wpt/web-platform-tests/css/css-color/color-003.html index df01b0a1e92..c9ed7c773ba 100644 --- a/tests/wpt/web-platform-tests/css/css-color/color-003.html +++ b/tests/wpt/web-platform-tests/css/css-color/color-003.html @@ -7,8 +7,8 @@ -

Test passess if this text is green

+

Test passes if this text is green

diff --git a/tests/wpt/web-platform-tests/css/css-color/color-resolving-hsl.html b/tests/wpt/web-platform-tests/css/css-color/color-resolving-hsl.html new file mode 100644 index 00000000000..d33701759d6 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color/color-resolving-hsl.html @@ -0,0 +1,80 @@ + + +CSS Color 4: Resolving HSL color values + + + + + + + +
+
+
+ + diff --git a/tests/wpt/web-platform-tests/css/css-color/color-resolving-keywords.html b/tests/wpt/web-platform-tests/css/css-color/color-resolving-keywords.html new file mode 100644 index 00000000000..5cbdcbe4b07 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color/color-resolving-keywords.html @@ -0,0 +1,205 @@ + + +CSS Color 4: Resolving keyword color values + + + + + + +
+
+
+ + diff --git a/tests/wpt/web-platform-tests/css/css-color/color-resolving.html b/tests/wpt/web-platform-tests/css/css-color/color-resolving.html new file mode 100644 index 00000000000..b3d1c740c57 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color/color-resolving.html @@ -0,0 +1,180 @@ + + +CSS Color 4: Resolving color values + + + + + + +
+
+
+ + diff --git a/tests/wpt/web-platform-tests/css/css-color/currentcolor-001.html b/tests/wpt/web-platform-tests/css/css-color/currentcolor-001.html index 355b00fbf2c..e08129ee522 100644 --- a/tests/wpt/web-platform-tests/css/css-color/currentcolor-001.html +++ b/tests/wpt/web-platform-tests/css/css-color/currentcolor-001.html @@ -3,13 +3,13 @@ CSS Color 4: currentcolor - +

Test passes if you see a green square, and no red.

-
FAIL
+
FAIL
diff --git a/tests/wpt/web-platform-tests/css/css-color/currentcolor-002.html b/tests/wpt/web-platform-tests/css/css-color/currentcolor-002.html index 014794b11b8..aa5d736c688 100644 --- a/tests/wpt/web-platform-tests/css/css-color/currentcolor-002.html +++ b/tests/wpt/web-platform-tests/css/css-color/currentcolor-002.html @@ -3,14 +3,14 @@ CSS Color 4: currentcolor - +

Test passes if you see a green square, and no red.

-
FAIL
+
FAIL
diff --git a/tests/wpt/web-platform-tests/css/css-color/greensquare-ref.html b/tests/wpt/web-platform-tests/css/css-color/greensquare-ref.html new file mode 100644 index 00000000000..35a31f8f564 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color/greensquare-ref.html @@ -0,0 +1,10 @@ + + +Green square reference + + +

Test passes if you see a green square, and no red.

+
+ diff --git a/tests/wpt/web-platform-tests/css/css-color/hex-001.html b/tests/wpt/web-platform-tests/css/css-color/hex-001.html index b3c10931633..4ff5cdbd9ce 100644 --- a/tests/wpt/web-platform-tests/css/css-color/hex-001.html +++ b/tests/wpt/web-platform-tests/css/css-color/hex-001.html @@ -9,5 +9,5 @@ .test {color: #008000} -

Test passess if this text is green

+

Test passes if this text is green

diff --git a/tests/wpt/web-platform-tests/css/css-color/hex-002.html b/tests/wpt/web-platform-tests/css/css-color/hex-002.html index 53480981707..5e0d48a23d3 100644 --- a/tests/wpt/web-platform-tests/css/css-color/hex-002.html +++ b/tests/wpt/web-platform-tests/css/css-color/hex-002.html @@ -9,5 +9,5 @@ .test {color: #008000FF} -

Test passess if this text is green

+

Test passes if this text is green

diff --git a/tests/wpt/web-platform-tests/css/css-color/hex-003-ref.html b/tests/wpt/web-platform-tests/css/css-color/hex-003-ref.html new file mode 100644 index 00000000000..613528e9260 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color/hex-003-ref.html @@ -0,0 +1,9 @@ + + +Green text reference for hex shorthand tests + + +

Test passes if this text is green

+ diff --git a/tests/wpt/web-platform-tests/css/css-color/hex-003.html b/tests/wpt/web-platform-tests/css/css-color/hex-003.html index 13889e32528..a6a19ad6191 100644 --- a/tests/wpt/web-platform-tests/css/css-color/hex-003.html +++ b/tests/wpt/web-platform-tests/css/css-color/hex-003.html @@ -3,11 +3,11 @@ CSS Color 4: The RGB hexadecimal notations: #RRGGBB + -

Test passess if this text is green

- +

Test passes if this text is green

diff --git a/tests/wpt/web-platform-tests/css/css-color/hex-004.html b/tests/wpt/web-platform-tests/css/css-color/hex-004.html index e51a8d96b3c..074fb1d4760 100644 --- a/tests/wpt/web-platform-tests/css/css-color/hex-004.html +++ b/tests/wpt/web-platform-tests/css/css-color/hex-004.html @@ -4,10 +4,10 @@ + -

Test passess if this text is green

- +

Test passes if this text is green

diff --git a/tests/wpt/web-platform-tests/css/css-color/hsl-001.html b/tests/wpt/web-platform-tests/css/css-color/hsl-001.html new file mode 100644 index 00000000000..842dbb9e713 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color/hsl-001.html @@ -0,0 +1,13 @@ + + +CSS Color 4: HSL functions hsl() and hsla() + + + + + + +

Test passes if this text is green

+ diff --git a/tests/wpt/web-platform-tests/css/css-color/hsl-002.html b/tests/wpt/web-platform-tests/css/css-color/hsl-002.html new file mode 100644 index 00000000000..91750d426aa --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color/hsl-002.html @@ -0,0 +1,13 @@ + + +CSS Color 4: HSL functions hsl() and hsla() + + + + + + +

Test passes if this text is green

+ diff --git a/tests/wpt/web-platform-tests/css/css-color/hsl-003.html b/tests/wpt/web-platform-tests/css/css-color/hsl-003.html new file mode 100644 index 00000000000..5b6bb4b1c9a --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color/hsl-003.html @@ -0,0 +1,13 @@ + + +CSS Color 4: HSL functions hsl() and hsla() + + + + + + +

Test passes if this text is green

+ diff --git a/tests/wpt/web-platform-tests/css/css-color/hsl-004.html b/tests/wpt/web-platform-tests/css/css-color/hsl-004.html new file mode 100644 index 00000000000..483c821aeca --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color/hsl-004.html @@ -0,0 +1,13 @@ + + +CSS Color 4: HSL functions hsl() and hsla() + + + + + + +

Test passes if this text is green

+ diff --git a/tests/wpt/web-platform-tests/css/css-color/hsl-005.html b/tests/wpt/web-platform-tests/css/css-color/hsl-005.html new file mode 100644 index 00000000000..b0970c316f3 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color/hsl-005.html @@ -0,0 +1,13 @@ + + +CSS Color 4: HSL functions hsl() and hsla() + + + + + + +

Test passes if this text is green

+ diff --git a/tests/wpt/web-platform-tests/css/css-color/hsl-006.html b/tests/wpt/web-platform-tests/css/css-color/hsl-006.html new file mode 100644 index 00000000000..389c5a49d4f --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color/hsl-006.html @@ -0,0 +1,13 @@ + + +CSS Color 4: HSL functions hsl() and hsla() + + + + + + +

Test passes if this text is green

+ diff --git a/tests/wpt/web-platform-tests/css/css-color/hsl-007.html b/tests/wpt/web-platform-tests/css/css-color/hsl-007.html new file mode 100644 index 00000000000..18bbe405922 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color/hsl-007.html @@ -0,0 +1,13 @@ + + +CSS Color 4: HSL functions hsl() and hsla() + + + + + + +

Test passes if this text is green

+ diff --git a/tests/wpt/web-platform-tests/css/css-color/hsl-008.html b/tests/wpt/web-platform-tests/css/css-color/hsl-008.html new file mode 100644 index 00000000000..89b962171a3 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color/hsl-008.html @@ -0,0 +1,13 @@ + + +CSS Color 4: HSL functions hsl() and hsla() + + + + + + +

Test passes if this text is green

+ diff --git a/tests/wpt/web-platform-tests/css/css-color/hsla-001.html b/tests/wpt/web-platform-tests/css/css-color/hsla-001.html new file mode 100644 index 00000000000..9e5bbfa4772 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color/hsla-001.html @@ -0,0 +1,13 @@ + + +CSS Color 4: HSL functions hsl() and hsla() + + + + + + +

Test passes if this text is green

+ diff --git a/tests/wpt/web-platform-tests/css/css-color/hsla-002.html b/tests/wpt/web-platform-tests/css/css-color/hsla-002.html new file mode 100644 index 00000000000..8b9cff818f2 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color/hsla-002.html @@ -0,0 +1,13 @@ + + +CSS Color 4: HSL functions hsl() and hsla() + + + + + + +

Test passes if this text is green

+ diff --git a/tests/wpt/web-platform-tests/css/css-color/hsla-003.html b/tests/wpt/web-platform-tests/css/css-color/hsla-003.html new file mode 100644 index 00000000000..3aadd8e5b0a --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color/hsla-003.html @@ -0,0 +1,13 @@ + + +CSS Color 4: HSL functions hsl() and hsla() + + + + + + +

Test passes if this text is green

+ diff --git a/tests/wpt/web-platform-tests/css/css-color/hsla-004.html b/tests/wpt/web-platform-tests/css/css-color/hsla-004.html new file mode 100644 index 00000000000..e68669fdeac --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color/hsla-004.html @@ -0,0 +1,13 @@ + + +CSS Color 4: HSL functions hsl() and hsla() + + + + + + +

Test passes if this text is green

+ diff --git a/tests/wpt/web-platform-tests/css/css-color/hsla-005.html b/tests/wpt/web-platform-tests/css/css-color/hsla-005.html new file mode 100644 index 00000000000..4efeb1912c0 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color/hsla-005.html @@ -0,0 +1,13 @@ + + +CSS Color 4: HSL functions hsl() and hsla() + + + + + + +

Test passes if this text is green

+ diff --git a/tests/wpt/web-platform-tests/css/css-color/hsla-006.html b/tests/wpt/web-platform-tests/css/css-color/hsla-006.html new file mode 100644 index 00000000000..e440ebe5bdb --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color/hsla-006.html @@ -0,0 +1,13 @@ + + +CSS Color 4: HSL functions hsl() and hsla() + + + + + + +

Test passes if this text is green

+ diff --git a/tests/wpt/web-platform-tests/css/css-color/hsla-007.html b/tests/wpt/web-platform-tests/css/css-color/hsla-007.html new file mode 100644 index 00000000000..ba647ae7514 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color/hsla-007.html @@ -0,0 +1,13 @@ + + +CSS Color 4: HSL functions hsl() and hsla() + + + + + + +

Test passes if this text is green

+ diff --git a/tests/wpt/web-platform-tests/css/css-color/hsla-008.html b/tests/wpt/web-platform-tests/css/css-color/hsla-008.html new file mode 100644 index 00000000000..8f78f88656e --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color/hsla-008.html @@ -0,0 +1,13 @@ + + +CSS Color 4: HSL functions hsl() and hsla() + + + + + + +

Test passes if this text is green

+ diff --git a/tests/wpt/web-platform-tests/css/css-color/lab-001.html b/tests/wpt/web-platform-tests/css/css-color/lab-001.html index b8b2a23b53d..70dbd9123c5 100644 --- a/tests/wpt/web-platform-tests/css/css-color/lab-001.html +++ b/tests/wpt/web-platform-tests/css/css-color/lab-001.html @@ -6,8 +6,8 @@ -

Test passess if this text is green

+

Test passes if this text is green

diff --git a/tests/wpt/web-platform-tests/css/css-color/lab-002.html b/tests/wpt/web-platform-tests/css/css-color/lab-002.html index 592740873b6..1f1b4476814 100644 --- a/tests/wpt/web-platform-tests/css/css-color/lab-002.html +++ b/tests/wpt/web-platform-tests/css/css-color/lab-002.html @@ -7,8 +7,8 @@ -

Test passess if this text is black

+

Test passes if this text is black

diff --git a/tests/wpt/web-platform-tests/css/css-color/lab-003.html b/tests/wpt/web-platform-tests/css/css-color/lab-003.html index 672c5da799c..072dafa211b 100644 --- a/tests/wpt/web-platform-tests/css/css-color/lab-003.html +++ b/tests/wpt/web-platform-tests/css/css-color/lab-003.html @@ -6,9 +6,9 @@ -

Test passess if this text is white

+

Test passes if this text is white

diff --git a/tests/wpt/web-platform-tests/css/css-color/lab-004.html b/tests/wpt/web-platform-tests/css/css-color/lab-004.html index 4155f1072b8..0037a1e7653 100644 --- a/tests/wpt/web-platform-tests/css/css-color/lab-004.html +++ b/tests/wpt/web-platform-tests/css/css-color/lab-004.html @@ -7,11 +7,11 @@ -

Test passes if the two lines of filler text are the same color.

+

Test passes if the two lines of filler text are the same color.

Filler text. Filler text. Filler text.

-

Filler text. Filler text. Filler text.

+

Filler text. Filler text. Filler text.

diff --git a/tests/wpt/web-platform-tests/css/css-color/lab-005.html b/tests/wpt/web-platform-tests/css/css-color/lab-005.html index 990dcb59a95..366cd1bc304 100644 --- a/tests/wpt/web-platform-tests/css/css-color/lab-005.html +++ b/tests/wpt/web-platform-tests/css/css-color/lab-005.html @@ -7,11 +7,11 @@ -

Test passes if the two lines of filler text are the same color.

+

Test passes if the two lines of filler text are the same color.

Filler text. Filler text. Filler text.

-

Filler text. Filler text. Filler text.

+

Filler text. Filler text. Filler text.

diff --git a/tests/wpt/web-platform-tests/css/css-color/lab-006.html b/tests/wpt/web-platform-tests/css/css-color/lab-006.html index 972c3448a25..079c37978f4 100644 --- a/tests/wpt/web-platform-tests/css/css-color/lab-006.html +++ b/tests/wpt/web-platform-tests/css/css-color/lab-006.html @@ -7,11 +7,11 @@ -

Test passes if the two lines of filler text are the same color.

+

Test passes if the two lines of filler text are the same color.

Filler text. Filler text. Filler text.

-

Filler text. Filler text. Filler text.

+

Filler text. Filler text. Filler text.

diff --git a/tests/wpt/web-platform-tests/css/css-color/lab-007.html b/tests/wpt/web-platform-tests/css/css-color/lab-007.html index 79a257c1f99..4cdb35788d4 100644 --- a/tests/wpt/web-platform-tests/css/css-color/lab-007.html +++ b/tests/wpt/web-platform-tests/css/css-color/lab-007.html @@ -7,11 +7,11 @@ -

Test passes if the two lines of filler text are the same color.

+

Test passes if the two lines of filler text are the same color.

Filler text. Filler text. Filler text.

-

Filler text. Filler text. Filler text.

+

Filler text. Filler text. Filler text.

diff --git a/tests/wpt/web-platform-tests/css/css-color/lch-001.html b/tests/wpt/web-platform-tests/css/css-color/lch-001.html index 9d824048028..966e1fd4055 100644 --- a/tests/wpt/web-platform-tests/css/css-color/lch-001.html +++ b/tests/wpt/web-platform-tests/css/css-color/lch-001.html @@ -6,8 +6,8 @@ -

Test passess if this text is green

+

Test passes if this text is green

diff --git a/tests/wpt/web-platform-tests/css/css-color/lch-002.html b/tests/wpt/web-platform-tests/css/css-color/lch-002.html index ae845ace96b..d87d0421a0d 100644 --- a/tests/wpt/web-platform-tests/css/css-color/lch-002.html +++ b/tests/wpt/web-platform-tests/css/css-color/lch-002.html @@ -7,8 +7,8 @@ -

Test passess if this text is black

+

Test passes if this text is black

diff --git a/tests/wpt/web-platform-tests/css/css-color/lch-003.html b/tests/wpt/web-platform-tests/css/css-color/lch-003.html index 55a35cf2592..eb8f8a25b4a 100644 --- a/tests/wpt/web-platform-tests/css/css-color/lch-003.html +++ b/tests/wpt/web-platform-tests/css/css-color/lch-003.html @@ -6,9 +6,9 @@ -

Test passess if this text is white

+

Test passes if this text is white

diff --git a/tests/wpt/web-platform-tests/css/css-color/lch-004.html b/tests/wpt/web-platform-tests/css/css-color/lch-004.html index 68c634ee2fa..46ac7d3988e 100644 --- a/tests/wpt/web-platform-tests/css/css-color/lch-004.html +++ b/tests/wpt/web-platform-tests/css/css-color/lch-004.html @@ -7,11 +7,11 @@ -

Test passes if the two lines of filler text are the same color.

+

Test passes if the two lines of filler text are the same color.

Filler text. Filler text. Filler text.

-

Filler text. Filler text. Filler text.

+

Filler text. Filler text. Filler text.

diff --git a/tests/wpt/web-platform-tests/css/css-color/lch-005.html b/tests/wpt/web-platform-tests/css/css-color/lch-005.html index 93d51163d93..789d4b23fef 100644 --- a/tests/wpt/web-platform-tests/css/css-color/lch-005.html +++ b/tests/wpt/web-platform-tests/css/css-color/lch-005.html @@ -7,11 +7,11 @@ -

Test passes if the two lines of filler text are the same color.

+

Test passes if the two lines of filler text are the same color.

Filler text. Filler text. Filler text.

-

Filler text. Filler text. Filler text.

+

Filler text. Filler text. Filler text.

diff --git a/tests/wpt/web-platform-tests/css/css-color/lch-006.html b/tests/wpt/web-platform-tests/css/css-color/lch-006.html index ab96f011585..760362cbf93 100644 --- a/tests/wpt/web-platform-tests/css/css-color/lch-006.html +++ b/tests/wpt/web-platform-tests/css/css-color/lch-006.html @@ -7,11 +7,11 @@ -

Test passes if the two lines of filler text are the same color.

+

Test passes if the two lines of filler text are the same color.

Filler text. Filler text. Filler text.

-

Filler text. Filler text. Filler text.

+

Filler text. Filler text. Filler text.

diff --git a/tests/wpt/web-platform-tests/css/css-color/lch-007.html b/tests/wpt/web-platform-tests/css/css-color/lch-007.html index a5ad333185c..7b8c41fa9c7 100644 --- a/tests/wpt/web-platform-tests/css/css-color/lch-007.html +++ b/tests/wpt/web-platform-tests/css/css-color/lch-007.html @@ -7,11 +7,11 @@ -

Test passes if the two lines of filler text are the same color.

+

Test passes if the two lines of filler text are the same color.

Filler text. Filler text. Filler text.

-

Filler text. Filler text. Filler text.

+

Filler text. Filler text. Filler text.

diff --git a/tests/wpt/web-platform-tests/css/css-color/named-001.html b/tests/wpt/web-platform-tests/css/css-color/named-001.html index b6c66a7c260..61a98dcb7bb 100644 --- a/tests/wpt/web-platform-tests/css/css-color/named-001.html +++ b/tests/wpt/web-platform-tests/css/css-color/named-001.html @@ -7,9 +7,9 @@

Test passes if you see a purple square and no red.

-
+
diff --git a/tests/wpt/web-platform-tests/css/css-color/rebeccapurple-ref.html b/tests/wpt/web-platform-tests/css/css-color/rebeccapurple-ref.html index 71074541575..8c15364f38e 100644 --- a/tests/wpt/web-platform-tests/css/css-color/rebeccapurple-ref.html +++ b/tests/wpt/web-platform-tests/css/css-color/rebeccapurple-ref.html @@ -6,5 +6,5 @@

Test passes if you see a purple square and no red.

-
+
diff --git a/tests/wpt/web-platform-tests/css/css-color/t32-opacity-basic-0.0-a-ref.html b/tests/wpt/web-platform-tests/css/css-color/t32-opacity-basic-0.0-a-ref.html new file mode 100644 index 00000000000..298c4890dff --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color/t32-opacity-basic-0.0-a-ref.html @@ -0,0 +1,6 @@ + + +CSS Reference + +

This should be the only text visible on this page.

+ diff --git a/tests/wpt/web-platform-tests/css/css-color/t32-opacity-basic-0.0-a.xht b/tests/wpt/web-platform-tests/css/css-color/t32-opacity-basic-0.0-a.xht index 20a2dd325b6..637638d96a4 100644 --- a/tests/wpt/web-platform-tests/css/css-color/t32-opacity-basic-0.0-a.xht +++ b/tests/wpt/web-platform-tests/css/css-color/t32-opacity-basic-0.0-a.xht @@ -5,6 +5,7 @@ + + +

The following five boxes should be the same color:

+ +
+
+
+
+
+ diff --git a/tests/wpt/web-platform-tests/css/css-color/t32-opacity-offscreen-b.xht b/tests/wpt/web-platform-tests/css/css-color/t32-opacity-offscreen-b.xht index 2303facab8a..a373f98980e 100644 --- a/tests/wpt/web-platform-tests/css/css-color/t32-opacity-offscreen-b.xht +++ b/tests/wpt/web-platform-tests/css/css-color/t32-opacity-offscreen-b.xht @@ -5,6 +5,7 @@ + + +

The following four boxes should be the same color:

+ +
+
+
+
+ diff --git a/tests/wpt/web-platform-tests/css/css-color/t32-opacity-offscreen-with-alpha-c.xht b/tests/wpt/web-platform-tests/css/css-color/t32-opacity-offscreen-with-alpha-c.xht index 5fa074c57b5..fdd9ae27793 100644 --- a/tests/wpt/web-platform-tests/css/css-color/t32-opacity-offscreen-with-alpha-c.xht +++ b/tests/wpt/web-platform-tests/css/css-color/t32-opacity-offscreen-with-alpha-c.xht @@ -5,6 +5,7 @@ + + +

Each row in the following table (except the first and last, to show where the columns are) should have two cells with the same background color. None of them should match the background of the page.

+ + + + + + + + + + + + + + + + + + + + +
      
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
      
+ diff --git a/tests/wpt/web-platform-tests/css/css-color/t41-html4-keywords-a.xht b/tests/wpt/web-platform-tests/css/css-color/t41-html4-keywords-a.xht index 1862f827d30..3a3e332ed56 100644 --- a/tests/wpt/web-platform-tests/css/css-color/t41-html4-keywords-a.xht +++ b/tests/wpt/web-platform-tests/css/css-color/t41-html4-keywords-a.xht @@ -5,6 +5,7 @@ + + +

WARNING: This test assumes that the device gamut is sRGB + (as it will be for many CRT monitors).

+

Every row in this table should have both columns the same color:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Column 1Column 2
 
 
 
 
 
 
 
 
+ diff --git a/tests/wpt/web-platform-tests/css/css-color/t421-rgb-clip-outside-gamut-b.xht b/tests/wpt/web-platform-tests/css/css-color/t421-rgb-clip-outside-gamut-b.xht index 5e00ea63379..1fd50ff3493 100644 --- a/tests/wpt/web-platform-tests/css/css-color/t421-rgb-clip-outside-gamut-b.xht +++ b/tests/wpt/web-platform-tests/css/css-color/t421-rgb-clip-outside-gamut-b.xht @@ -5,6 +5,7 @@ + + +

The left and right cells in each row of the following table should be the same color.

+ + + + + +
  
  
  
+ +

The left and right cells in each row of the following table should be slightly different colors. The right side should be slightly darker than the left.

+ + + + + +
  
  
  
+ diff --git a/tests/wpt/web-platform-tests/css/css-color/t421-rgb-values-meaning-b-ref.html b/tests/wpt/web-platform-tests/css/css-color/t421-rgb-values-meaning-b-ref.html new file mode 100644 index 00000000000..b468f0eb988 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color/t421-rgb-values-meaning-b-ref.html @@ -0,0 +1,1539 @@ + + +CSS Reference + + +

The following table should have four matching rows gradually changing from red at the left to black at the right (plus a checkerboard at both ends to show where the rows are):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                  
                  
                  
                  
+ +

The following table should have four matching rows gradually changing from white at the left to red at the right (plus a checkerboard at both ends to show where the rows are):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                  
                  
                  
                  
+ +

The following table should have four matching rows gradually changing from green at the left to black at the right (plus a checkerboard at both ends to show where the rows are):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                  
                  
                  
                  
+ +

The following table should have four matching rows gradually changing from white at the left to green at the right (plus a checkerboard at both ends to show where the rows are):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                  
                  
                  
                  
+ +

The following table should have four matching rows gradually changing from blue at the left to black at the right (plus a checkerboard at both ends to show where the rows are):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                  
                  
                  
                  
+ +

The following table should have four matching rows gradually changing from white at the left to blue at the right (plus a checkerboard at both ends to show where the rows are):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                  
                  
                  
                  
+ +

The following table should have four matching rows gradually changing from yellow at the left to black at the right (plus a checkerboard at both ends to show where the rows are):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                  
                  
                  
                  
+ +

The following table should have four matching rows gradually changing from white at the left to yellow at the right (plus a checkerboard at both ends to show where the rows are):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                  
                  
                  
                  
+ +

The following table should have four matching rows gradually changing from fuchsia at the left to black at the right (plus a checkerboard at both ends to show where the rows are):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                  
                  
                  
                  
+ +

The following table should have four matching rows gradually changing from white at the left to fuchsia at the right (plus a checkerboard at both ends to show where the rows are):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                  
                  
                  
                  
+ +

The following table should have four matching rows gradually changing from aqua at the left to black at the right (plus a checkerboard at both ends to show where the rows are):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                  
                  
                  
                  
+ +

The following table should have four matching rows gradually changing from white at the left to aqua at the right (plus a checkerboard at both ends to show where the rows are):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                  
                  
                  
                  
+ +

The following table should have four matching rows gradually changing from red at the left to green at the right (plus a checkerboard at both ends to show where the rows are):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                  
                  
                  
                  
+ +

The following table should have four matching rows gradually changing from green at the left to blue at the right (plus a checkerboard at both ends to show where the rows are):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                  
                  
                  
                  
+ +

The following table should have four matching rows gradually changing from blue at the left to red at the right (plus a checkerboard at both ends to show where the rows are):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                  
                  
                  
                  
+ +

The following table should have four matching rows gradually changing from fuchsia at the left to aqua at the right (plus a checkerboard at both ends to show where the rows are):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                  
                  
                  
                  
+ +

The following table should have four matching rows gradually changing from yellow at the left to fuchsia at the right (plus a checkerboard at both ends to show where the rows are):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                  
                  
                  
                  
+ +

The following table should have four matching rows gradually changing from aqua at the left to yellow at the right (plus a checkerboard at both ends to show where the rows are):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                  
                  
                  
                  
+ diff --git a/tests/wpt/web-platform-tests/css/css-color/t421-rgb-values-meaning-b.xht b/tests/wpt/web-platform-tests/css/css-color/t421-rgb-values-meaning-b.xht index 760a4416ac0..b628d3e859c 100644 --- a/tests/wpt/web-platform-tests/css/css-color/t421-rgb-values-meaning-b.xht +++ b/tests/wpt/web-platform-tests/css/css-color/t421-rgb-values-meaning-b.xht @@ -5,6 +5,7 @@ + + +

The following table should have four matching rows changing (in 5 steps) from red at the left to black at the right: (plus a checkerboard at both ends to show where the rows are):

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        
        
        
        
+
+ +

The following table should have four matching rows changing (in 5 steps) from red at the left to white at the right: (plus a checkerboard at both ends to show where the rows are):

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        
        
        
        
+
+ +

The following table should have four matching rows changing (in 5 steps) from green at the left to black at the right: (plus a checkerboard at both ends to show where the rows are):

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        
        
        
        
+
+ +

The following table should have four matching rows changing (in 5 steps) from green at the left to white at the right: (plus a checkerboard at both ends to show where the rows are):

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        
        
        
        
+
+ +

The following table should have four matching rows changing (in 5 steps) from blue at the left to black at the right: (plus a checkerboard at both ends to show where the rows are):

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        
        
        
        
+
+ +

The following table should have four matching rows changing (in 5 steps) from blue at the left to white at the right: (plus a checkerboard at both ends to show where the rows are):

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        
        
        
        
+
+ +

The following table should have four matching rows changing (in 5 steps) from red at the left to green at the right: (plus a checkerboard at both ends to show where the rows are):

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        
        
        
        
+
+ +

The following table should have four matching rows changing (in 5 steps) from green at the left to blue at the right: (plus a checkerboard at both ends to show where the rows are):

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        
        
        
        
+
+ +

The following table should have four matching rows changing (in 5 steps) from blue at the left to red at the right (plus a checkerboard at both ends to show where the rows are):

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        
        
        
        
+
+ diff --git a/tests/wpt/web-platform-tests/css/css-color/t422-rgba-values-meaning-b.xht b/tests/wpt/web-platform-tests/css/css-color/t422-rgba-values-meaning-b.xht index 27e21cfa48f..daea66c47b8 100644 --- a/tests/wpt/web-platform-tests/css/css-color/t422-rgba-values-meaning-b.xht +++ b/tests/wpt/web-platform-tests/css/css-color/t422-rgba-values-meaning-b.xht @@ -5,6 +5,7 @@ + + +

Each column in the following table should have every cell the + same color, except for the checkerboard pattern at the right and + left used to indicate the row positions.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        
        
        
        
+ diff --git a/tests/wpt/web-platform-tests/css/css-color/t424-hsl-h-rotating-b.xht b/tests/wpt/web-platform-tests/css/css-color/t424-hsl-h-rotating-b.xht index 08196e48ab9..4d2d4cf527b 100644 --- a/tests/wpt/web-platform-tests/css/css-color/t424-hsl-h-rotating-b.xht +++ b/tests/wpt/web-platform-tests/css/css-color/t424-hsl-h-rotating-b.xht @@ -5,6 +5,7 @@ + + +

Each column in the following table should have every cell the + same color, except for the checkerboard pattern at the right and + left used to indicate the row positions.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        
        
        
        
+ + diff --git a/tests/wpt/web-platform-tests/css/css-color/t425-hsla-h-rotating-b.xht b/tests/wpt/web-platform-tests/css/css-color/t425-hsla-h-rotating-b.xht index b9339ad9835..09747330d55 100644 --- a/tests/wpt/web-platform-tests/css/css-color/t425-hsla-h-rotating-b.xht +++ b/tests/wpt/web-platform-tests/css/css-color/t425-hsla-h-rotating-b.xht @@ -6,6 +6,7 @@ + + +

Each row in the following table (except the first and last, to show where the columns are) should have two cells with the same background color. None of them should match the background of the page.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
      
+ diff --git a/tests/wpt/web-platform-tests/css/css-color/t43-svg-keywords-a.xht b/tests/wpt/web-platform-tests/css/css-color/t43-svg-keywords-a.xht index 69b6aef6c10..75bbf4f70f1 100644 --- a/tests/wpt/web-platform-tests/css/css-color/t43-svg-keywords-a.xht +++ b/tests/wpt/web-platform-tests/css/css-color/t43-svg-keywords-a.xht @@ -5,6 +5,7 @@ + -

Test passess if this text is white

+

Test passes if this text is white

diff --git a/tests/wpt/web-platform-tests/css/css-conditional/test_group_insertRule.html b/tests/wpt/web-platform-tests/css/css-conditional/test_group_insertRule.html index 85edc2a1a0b..f34245ec472 100644 --- a/tests/wpt/web-platform-tests/css/css-conditional/test_group_insertRule.html +++ b/tests/wpt/web-platform-tests/css/css-conditional/test_group_insertRule.html @@ -11,26 +11,6 @@ -
@@ -240,4 +220,3 @@ - diff --git a/tests/wpt/web-platform-tests/css/css-contain/contain-style-counters-ref.html b/tests/wpt/web-platform-tests/css/css-contain/contain-style-counters-ref.html new file mode 100644 index 00000000000..feef9209f5c --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-contain/contain-style-counters-ref.html @@ -0,0 +1,4 @@ + +CSS Containment Reference File +
You should see the number 1 here: 1
+
You should see the number 4 here: 4
diff --git a/tests/wpt/web-platform-tests/css/css-contain/contain-style-counters.html b/tests/wpt/web-platform-tests/css/css-contain/contain-style-counters.html new file mode 100644 index 00000000000..73de6dc9604 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-contain/contain-style-counters.html @@ -0,0 +1,22 @@ + +CSS Containment Test: contain:style for counters + + + +
+
You should see the number 1 here:
+
+
You should see the number 4 here:
diff --git a/tests/wpt/web-platform-tests/css/css-display/display-contents-before-after-003.html b/tests/wpt/web-platform-tests/css/css-display/display-contents-before-after-003.html new file mode 100644 index 00000000000..772ad440c26 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-display/display-contents-before-after-003.html @@ -0,0 +1,17 @@ + + +CSS Display: Generated ::before and ::after with display:contents inside flex + + + + + +

You should see the word PASS below.

+P
S diff --git a/tests/wpt/web-platform-tests/css/css-display/display-contents-button.html b/tests/wpt/web-platform-tests/css/css-display/display-contents-button.html new file mode 100644 index 00000000000..c166583ff6c --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-display/display-contents-button.html @@ -0,0 +1,15 @@ + + +CSS Display: display:contents and HTML button element + + + + +

You should see the word PASS below.

+ diff --git a/tests/wpt/web-platform-tests/css/css-display/display-contents-details.html b/tests/wpt/web-platform-tests/css/css-display/display-contents-details.html new file mode 100644 index 00000000000..b6a6540f013 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-display/display-contents-details.html @@ -0,0 +1,15 @@ + + +CSS Display: display:contents and HTML details and summary elements + + + + +

You should see the word PASS below.

+P
AS
S diff --git a/tests/wpt/web-platform-tests/css/css-display/display-contents-dynamic-pseudo-insertion-001-ref.html b/tests/wpt/web-platform-tests/css/css-display/display-contents-dynamic-pseudo-insertion-001-ref.html new file mode 100644 index 00000000000..38dd74a744d --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-display/display-contents-dynamic-pseudo-insertion-001-ref.html @@ -0,0 +1,5 @@ + + +CSS Test Reference + +PASS diff --git a/tests/wpt/web-platform-tests/css/css-display/display-contents-dynamic-pseudo-insertion-001.html b/tests/wpt/web-platform-tests/css/css-display/display-contents-dynamic-pseudo-insertion-001.html new file mode 100644 index 00000000000..f35c3cc47b4 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-display/display-contents-dynamic-pseudo-insertion-001.html @@ -0,0 +1,26 @@ + + +CSS Test: Dynamic insertion on empty display: contents element with pseudo-elements + + + + +
+ diff --git a/tests/wpt/web-platform-tests/css/css-display/display-contents-fieldset.html b/tests/wpt/web-platform-tests/css/css-display/display-contents-fieldset.html new file mode 100644 index 00000000000..5dcd343143f --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-display/display-contents-fieldset.html @@ -0,0 +1,15 @@ + + +CSS Display: display:contents and HTML fieldset and legend elements + + + + +

You should see the word PASS below.

+P
ASS
diff --git a/tests/wpt/web-platform-tests/css/css-display/display-contents-first-letter-002.html b/tests/wpt/web-platform-tests/css/css-display/display-contents-first-letter-002.html new file mode 100644 index 00000000000..8d1d8572ac1 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-display/display-contents-first-letter-002.html @@ -0,0 +1,14 @@ + + +CSS Display: display:contents and ::first-letter inheritance + + + + + +

You should see the word PASS in green and no red below.

+
PASS
diff --git a/tests/wpt/web-platform-tests/css/css-display/display-contents-first-line-002.html b/tests/wpt/web-platform-tests/css/css-display/display-contents-first-line-002.html new file mode 100644 index 00000000000..ae900235a5e --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-display/display-contents-first-line-002.html @@ -0,0 +1,16 @@ + + +CSS Display: display:contents and ::first-line inheritance + + + + + +

You should see the word PASS in green and no red below.

+
+ PASS +
diff --git a/tests/wpt/web-platform-tests/css/css-display/display-contents-line-height-ref.html b/tests/wpt/web-platform-tests/css/css-display/display-contents-line-height-ref.html new file mode 100644 index 00000000000..d06c63f09f4 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-display/display-contents-line-height-ref.html @@ -0,0 +1,9 @@ + + +CSS Reftest Reference + + +

The two lines below should not overlap.

+Line 1
Line 2 diff --git a/tests/wpt/web-platform-tests/css/css-display/display-contents-line-height.html b/tests/wpt/web-platform-tests/css/css-display/display-contents-line-height.html new file mode 100644 index 00000000000..31fd5a6d479 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-display/display-contents-line-height.html @@ -0,0 +1,14 @@ + + +CSS Display: display:contents font-size should affect line-height + + + + +

The two lines below should not overlap.

+Line 1
Line 2 diff --git a/tests/wpt/web-platform-tests/css/css-display/display-contents-replaced-001-ref.html b/tests/wpt/web-platform-tests/css/css-display/display-contents-replaced-001-ref.html deleted file mode 100644 index ff807c7575d..00000000000 --- a/tests/wpt/web-platform-tests/css/css-display/display-contents-replaced-001-ref.html +++ /dev/null @@ -1,17 +0,0 @@ - - -CSS Reftest Reference - - -

You should see five form inputs, and an orange image, with green border below.

- - - - - - diff --git a/tests/wpt/web-platform-tests/css/css-display/display-contents-replaced-001.html b/tests/wpt/web-platform-tests/css/css-display/display-contents-replaced-001.html deleted file mode 100644 index 22d3995feb1..00000000000 --- a/tests/wpt/web-platform-tests/css/css-display/display-contents-replaced-001.html +++ /dev/null @@ -1,19 +0,0 @@ - - -CSS Display: display:contents and replaced elements - - - - -

You should see five form inputs, and an orange image, with green border below.

- - - - - - diff --git a/tests/wpt/web-platform-tests/css/css-display/display-contents-svg-elements-ref.html b/tests/wpt/web-platform-tests/css/css-display/display-contents-svg-elements-ref.html new file mode 100644 index 00000000000..b691e0e80ed --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-display/display-contents-svg-elements-ref.html @@ -0,0 +1,13 @@ + + +CSS Reftest Reference + +

You should see the word PASS below.

+
+ + P + A + S + S + +
diff --git a/tests/wpt/web-platform-tests/css/css-display/display-contents-svg-elements.html b/tests/wpt/web-platform-tests/css/css-display/display-contents-svg-elements.html new file mode 100644 index 00000000000..7ccc92f7207 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-display/display-contents-svg-elements.html @@ -0,0 +1,22 @@ + + +CSS Display: display:contents and SVG elements + + + +

You should see the word PASS below.

+
+ + S + FAIL + + P + + + A + + + S + + FAIL +
diff --git a/tests/wpt/web-platform-tests/css/css-display/display-contents-text-inherit-ref.html b/tests/wpt/web-platform-tests/css/css-display/display-contents-text-inherit-ref.html new file mode 100644 index 00000000000..163efd401c4 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-display/display-contents-text-inherit-ref.html @@ -0,0 +1,7 @@ + + +CSS Reftest Reference + +

The words "Two" and "lines" should not be on the same line.

+Two
+lines diff --git a/tests/wpt/web-platform-tests/css/css-display/display-contents-text-inherit.html b/tests/wpt/web-platform-tests/css/css-display/display-contents-text-inherit.html new file mode 100644 index 00000000000..b7e769cd69f --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-display/display-contents-text-inherit.html @@ -0,0 +1,15 @@ + + +CSS Display: Apply display:contents text properties to text children + + + + +

The words "Two" and "lines" should not be on the same line.

+
Two +lines
diff --git a/tests/wpt/web-platform-tests/css/css-display/display-contents-unusual-html-elements-none.html b/tests/wpt/web-platform-tests/css/css-display/display-contents-unusual-html-elements-none.html new file mode 100644 index 00000000000..403ff5ce299 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-display/display-contents-unusual-html-elements-none.html @@ -0,0 +1,31 @@ + + +CSS Display: display:contents and unusual HTML elements as display:none + + + + +

You should see the word PASS below.

+
+ + + + + FAIL + + + + + + + +
+P
AS
S diff --git a/tests/wpt/web-platform-tests/css/css-block/OWNERS b/tests/wpt/web-platform-tests/css/css-display/run-in/OWNERS similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/OWNERS rename to tests/wpt/web-platform-tests/css/css-display/run-in/OWNERS diff --git a/tests/wpt/web-platform-tests/css/css-block/after-content-display-004.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/after-content-display-004.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/after-content-display-004.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/after-content-display-004.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/anonymous-box-generation-002.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/anonymous-box-generation-002.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/anonymous-box-generation-002.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/anonymous-box-generation-002.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/background-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/background-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/background-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/background-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/background-attachment-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/background-attachment-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/background-attachment-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/background-attachment-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/background-color-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/background-color-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/background-color-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/background-color-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/background-image-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/background-image-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/background-image-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/background-image-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/background-position-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/background-position-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/background-position-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/background-position-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/background-repeat-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/background-repeat-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/background-repeat-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/background-repeat-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/before-content-display-004.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/before-content-display-004.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/before-content-display-004.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/before-content-display-004.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/border-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/border-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/border-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/border-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/border-bottom-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/border-bottom-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/border-bottom-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/border-bottom-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/border-bottom-color-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/border-bottom-color-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/border-bottom-color-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/border-bottom-color-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/border-bottom-style-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/border-bottom-style-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/border-bottom-style-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/border-bottom-style-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/border-bottom-width-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/border-bottom-width-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/border-bottom-width-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/border-bottom-width-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/border-collapse-applies-to-004.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/border-collapse-applies-to-004.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/border-collapse-applies-to-004.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/border-collapse-applies-to-004.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/border-color-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/border-color-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/border-color-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/border-color-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/border-left-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/border-left-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/border-left-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/border-left-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/border-left-color-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/border-left-color-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/border-left-color-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/border-left-color-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/border-left-style-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/border-left-style-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/border-left-style-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/border-left-style-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/border-left-width-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/border-left-width-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/border-left-width-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/border-left-width-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/border-right-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/border-right-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/border-right-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/border-right-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/border-right-color-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/border-right-color-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/border-right-color-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/border-right-color-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/border-right-style-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/border-right-style-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/border-right-style-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/border-right-style-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/border-right-width-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/border-right-width-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/border-right-width-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/border-right-width-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/border-spacing-applies-to-004.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/border-spacing-applies-to-004.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/border-spacing-applies-to-004.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/border-spacing-applies-to-004.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/border-style-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/border-style-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/border-style-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/border-style-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/border-top-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/border-top-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/border-top-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/border-top-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/border-top-color-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/border-top-color-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/border-top-color-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/border-top-color-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/border-top-style-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/border-top-style-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/border-top-style-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/border-top-style-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/border-top-width-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/border-top-width-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/border-top-width-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/border-top-width-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/border-width-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/border-width-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/border-width-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/border-width-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/bottom-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/bottom-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/bottom-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/bottom-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/caption-side-applies-to-004.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/caption-side-applies-to-004.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/caption-side-applies-to-004.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/caption-side-applies-to-004.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/clear-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/clear-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/clear-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/clear-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/clear-runin-001.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/clear-runin-001.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/clear-runin-001.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/clear-runin-001.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/color-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/color-applies-to-011.xht similarity index 100% rename from tests/wpt/web-platform-tests/css/css-block/color-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/color-applies-to-011.xht diff --git a/tests/wpt/web-platform-tests/css/css-block/counter-increment-applies-to-011.xht b/tests/wpt/web-platform-tests/css/css-display/run-in/counter-increment-applies-to-011.xht similarity index 93% rename from tests/wpt/web-platform-tests/css/css-block/counter-increment-applies-to-011.xht rename to tests/wpt/web-platform-tests/css/css-display/run-in/counter-increment-applies-to-011.xht index 9c491951568..4bf9e1233fa 100644 --- a/tests/wpt/web-platform-tests/css/css-block/counter-increment-applies-to-011.xht +++ b/tests/wpt/web-platform-tests/css/css-display/run-in/counter-increment-applies-to-011.xht @@ -5,7 +5,7 @@ - + +

There should be a space between "two" and "words" below.

+
two words
+ diff --git a/tests/wpt/web-platform-tests/css/css-flexbox/anonymous-flex-item-ref.html b/tests/wpt/web-platform-tests/css/css-flexbox/anonymous-flex-item-ref.html new file mode 100644 index 00000000000..4a2285400c9 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-flexbox/anonymous-flex-item-ref.html @@ -0,0 +1,6 @@ + + +CSS Reftest Reference + +

There should be a space between "two" and "words" below.

+two words diff --git a/tests/wpt/web-platform-tests/css/css-flexbox/percentage-heights-004-ref.html b/tests/wpt/web-platform-tests/css/css-flexbox/percentage-heights-004-ref.html new file mode 100644 index 00000000000..ffb44a82b53 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-flexbox/percentage-heights-004-ref.html @@ -0,0 +1,57 @@ + + +CSS Flexbox: Percentages in stretched container + + + + +

You should not see red nor a vertical scrollbar

+ +
+
+
+ hello +
+
+
+ +
+
+
+ hello +
+
+
+ diff --git a/tests/wpt/web-platform-tests/css/css-flexbox/percentage-heights-004.html b/tests/wpt/web-platform-tests/css/css-flexbox/percentage-heights-004.html new file mode 100644 index 00000000000..4f162487a71 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-flexbox/percentage-heights-004.html @@ -0,0 +1,61 @@ + + +CSS Flexbox: Percentages in stretched container + + + + + + +

You should not see red nor a vertical scrollbar

+ +
+
+
+ hello +
+
+
+ +
+
+
+ hello +
+
+
+ diff --git a/tests/wpt/web-platform-tests/css/css-flexbox/table-as-item-narrow-content.html b/tests/wpt/web-platform-tests/css/css-flexbox/table-as-item-narrow-content.html new file mode 100644 index 00000000000..31cf1125181 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-flexbox/table-as-item-narrow-content.html @@ -0,0 +1,13 @@ + +CSS Flexbox Test: Flex item as table with narrow content + + + + +

Test passes if there is a filled green square.

+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/css/css-flexbox/table-as-item-wide-content.html b/tests/wpt/web-platform-tests/css/css-flexbox/table-as-item-wide-content.html new file mode 100644 index 00000000000..475adf548fd --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-flexbox/table-as-item-wide-content.html @@ -0,0 +1,12 @@ + +CSS Flexbox Test: Flex item as table with wide content + + + + +

Test passes if there is a filled green square.

+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-001-ref.html b/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-001-ref.html new file mode 100644 index 00000000000..f5cc3bd65bd --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-001-ref.html @@ -0,0 +1,25 @@ + + +CSS-fonts: reference file + + + +

Test passes if there is a blue square below. + +

diff --git a/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-001.html b/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-001.html new file mode 100644 index 00000000000..065be3a48f2 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-001.html @@ -0,0 +1,44 @@ + + +CSS-fonts: first available font and the ex unit + + + + + + + + +

Test passes if there is a blue square below. + +

+
diff --git a/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-002-ref.html b/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-002-ref.html new file mode 100644 index 00000000000..cbfcd3112e5 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-002-ref.html @@ -0,0 +1,25 @@ + + +CSS-fonts: reference file + + + +

Test passes if there is a blue square below. + +

diff --git a/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-002.html b/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-002.html new file mode 100644 index 00000000000..cfd580927cf --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-002.html @@ -0,0 +1,44 @@ + + +CSS-fonts: first available font and the ch unit + + + + + + + + +

Test passes if there is a blue square below. + +

+
diff --git a/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-003-ref.html b/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-003-ref.html new file mode 100644 index 00000000000..afcbe3b4b34 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-003-ref.html @@ -0,0 +1,28 @@ + + +CSS-fonts: reference file + + + +

There should be two identically sized rectangles below. + +

a
+
a
diff --git a/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-003.html b/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-003.html new file mode 100644 index 00000000000..948171df258 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-003.html @@ -0,0 +1,50 @@ + + +CSS-fonts: first available font and the strut + + + + + + + + +

There should be two identically sized rectangles below. + + +

a
+
a
diff --git a/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-004.html b/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-004.html new file mode 100644 index 00000000000..d2fb1616842 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-004.html @@ -0,0 +1,55 @@ + + +CSS-fonts: first available font and the strut + + + + + + + + +

There should be two identically sized rectangles below. + +

b
+ + +
a
+
a
+ diff --git a/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-005-ref.html b/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-005-ref.html new file mode 100644 index 00000000000..9f27c19670c --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-005-ref.html @@ -0,0 +1,5 @@ + + +CSS fonts test: baseline position with explicit sizing, no space in first font + +

Test passes if there is no red below. diff --git a/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-005.html b/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-005.html new file mode 100644 index 00000000000..bf46a9f12f4 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-005.html @@ -0,0 +1,64 @@ + + +CSS fonts test: baseline position with explicit sizing, no space in first font + + + + + + + + +

Test passes if there is no red below. + +

bb
+
bb
diff --git a/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-006.html b/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-006.html new file mode 100644 index 00000000000..6f543840a50 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-006.html @@ -0,0 +1,66 @@ + + +CSS fonts test: baseline position with explicit sizing, no space in first font + + + + + + + + +

Test passes if there is no red below. + +

aa
+
aa
diff --git a/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-007.html b/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-007.html new file mode 100644 index 00000000000..a05b029a0ab --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-fonts/first-available-font-007.html @@ -0,0 +1,52 @@ + + +CSS-fonts: inline level box content height and first available font, missing U+0020 + + + + + + + + +

Test passes if there is no red below. + +

aaaaa
aaaaa
diff --git a/tests/wpt/web-platform-tests/css/css-fonts/font-default-01-ref.html b/tests/wpt/web-platform-tests/css/css-fonts/font-default-01-ref.html new file mode 100644 index 00000000000..bbe0251f243 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-fonts/font-default-01-ref.html @@ -0,0 +1,24 @@ + + + +CSS Test: font default features + + + + + +

Test passes if the two lines below are identical, with six check marks (✓).

+
+

AAAAAA

+

AAAAAA

+
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-fonts/font-default-01.html b/tests/wpt/web-platform-tests/css/css-fonts/font-default-01.html new file mode 100644 index 00000000000..99fc58b7e18 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-fonts/font-default-01.html @@ -0,0 +1,27 @@ + + + +CSS Test: font default features + + + + + + + + +

Test passes if the two lines below are identical, with six check marks (✓).

+
+

CDGÂÂÄ

+

AAAAAA

+
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-fonts/font-default-02-ref.html b/tests/wpt/web-platform-tests/css/css-fonts/font-default-02-ref.html new file mode 100644 index 00000000000..6d45ace67e9 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-fonts/font-default-02-ref.html @@ -0,0 +1,28 @@ + + + +CSS Test: font default features + + + + + +

Test passes if the three lines below are identical, with six check marks (✓).

+
+

AAAAAA

+

AAAAAA

+

AAAAAA

+
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-fonts/font-default-02.html b/tests/wpt/web-platform-tests/css/css-fonts/font-default-02.html new file mode 100644 index 00000000000..24f61942140 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-fonts/font-default-02.html @@ -0,0 +1,32 @@ + + + +CSS Test: font default features + + + + + + + + + +

Test passes if the three lines below are identical, with six check marks (✓).

+
+

CDGÂÂÄ

+

CDGÂÂÄ

+

AAAAAA

+
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-fonts/font-default-03-ref.html b/tests/wpt/web-platform-tests/css/css-fonts/font-default-03-ref.html new file mode 100644 index 00000000000..2f1d160c123 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-fonts/font-default-03-ref.html @@ -0,0 +1,28 @@ + + + +CSS Test: font default features + + + + + +

Test passes if the three lines below are identical, with six check marks (✓).

+
+

CDGÂÂÄ

+

CDGÂÂÄ

+

AAAAAA

+
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-fonts/font-default-03.html b/tests/wpt/web-platform-tests/css/css-fonts/font-default-03.html new file mode 100644 index 00000000000..a72a4bc00d4 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-fonts/font-default-03.html @@ -0,0 +1,32 @@ + + + +CSS Test: font default features + + + + + + + + + +

Test passes if the three lines below are identical, with six check marks (✓).

+
+

CDGÂÂÄ

+

CDGÂÂÄ

+

AAAAAA

+
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-fonts/font-default-04-a-ref.html b/tests/wpt/web-platform-tests/css/css-fonts/font-default-04-a-ref.html new file mode 100644 index 00000000000..cf428d2cf15 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-fonts/font-default-04-a-ref.html @@ -0,0 +1,32 @@ + + + +CSS Test: font default features + + + + + +

Test passes if the first vertical line (in purple) has at least one check mark +and the next two lines (in green) are identical, with two check marks (✓).

+
+

AB

+

AA

+

AA

+
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-fonts/font-default-04-b-ref.html b/tests/wpt/web-platform-tests/css/css-fonts/font-default-04-b-ref.html new file mode 100644 index 00000000000..3051b27365b --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-fonts/font-default-04-b-ref.html @@ -0,0 +1,32 @@ + + + +CSS Test: font default features + + + + + +

Test passes if the first vertical line (in purple) has at least one check mark +and the next two lines (in green) are identical, with two check marks (✓).

+
+

BA

+

AA

+

AA

+
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-fonts/font-default-04-c-ref.html b/tests/wpt/web-platform-tests/css/css-fonts/font-default-04-c-ref.html new file mode 100644 index 00000000000..773acfc592e --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-fonts/font-default-04-c-ref.html @@ -0,0 +1,32 @@ + + + +CSS Test: font default features + + + + + +

Test passes if the first vertical line (in purple) has at least one check mark +and the next two lines (in green) are identical, with two check marks (✓).

+
+

AA

+

AA

+

AA

+
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-fonts/font-default-04.html b/tests/wpt/web-platform-tests/css/css-fonts/font-default-04.html new file mode 100644 index 00000000000..5493d7205fb --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-fonts/font-default-04.html @@ -0,0 +1,45 @@ + + + +CSS Test: font default features + + + + + + + + + + + + +

Test passes if the first vertical line (in purple) has at least one check mark +and the next two lines (in green) are identical, with two check marks (✓).

+
+

Å人

+

Å

+

AA

+
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-fonts/font-display/font-display-change-ref.html b/tests/wpt/web-platform-tests/css/css-fonts/font-display/font-display-change-ref.html new file mode 100644 index 00000000000..e06a5593999 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-fonts/font-display/font-display-change-ref.html @@ -0,0 +1,72 @@ + + +Updating font-display value while loading + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
autoblockswapfallbackoptional
from autoaaaaa
from blockaaaaa
from swapaaaaa
from fallbackaaaaa
from optionalaaaaa
+ diff --git a/tests/wpt/web-platform-tests/css/css-fonts/font-display/font-display-change.html b/tests/wpt/web-platform-tests/css/css-fonts/font-display/font-display-change.html new file mode 100644 index 00000000000..64130ca52af --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-fonts/font-display/font-display-change.html @@ -0,0 +1,84 @@ + + +Updating font-display value while loading + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
autoblockswapfallbackoptional
from autoaaaaa
from blockaaaaa
from swapaaaaa
from fallbackaaaaa
from optionalaaaaa
+ diff --git a/tests/wpt/web-platform-tests/css/css-fonts/font-variant-01.html b/tests/wpt/web-platform-tests/css/css-fonts/font-variant-01.html index e73b1d517da..ed69967d3b0 100644 --- a/tests/wpt/web-platform-tests/css/css-fonts/font-variant-01.html +++ b/tests/wpt/web-platform-tests/css/css-fonts/font-variant-01.html @@ -23,9 +23,9 @@ } .outer { font-variant-ligatures: common-ligatures discretionary-ligatures historical-ligatures contextual; - font-variant-position: sub; + font-variant-numeric: oldstyle-nums; font-variant-caps: small-caps; - font-variant-east-asian: jis04; + font-variant-east-asian: jis90; } .child { color: green; @@ -36,6 +36,6 @@

Test passes if the two lines below are identical, with (in purple) eight check marks (✓), and then (in green) three check marks (✓) followed by five crosses (✗).

-

CDGFEJHaCDGFEJHa

+

CDGFEJQaCDGFEJQa

AAAAAAAAAAABBBBB

\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-fonts/font-variant-02.html b/tests/wpt/web-platform-tests/css/css-fonts/font-variant-02.html index 6e1aecc61a7..acda863b7d1 100644 --- a/tests/wpt/web-platform-tests/css/css-fonts/font-variant-02.html +++ b/tests/wpt/web-platform-tests/css/css-fonts/font-variant-02.html @@ -23,9 +23,9 @@ } .outer { font-variant-ligatures: common-ligatures discretionary-ligatures historical-ligatures contextual; - font-variant-position: sub; + font-variant-numeric: oldstyle-nums; font-variant-caps: small-caps; - font-variant-east-asian: jis04; + font-variant-east-asian: jis90; } .child { color: green; @@ -36,6 +36,6 @@

Test passes if the two lines below are identical, with (in purple) eight check marks (✓), and then (in green) eight crosses (✗).

-

CDGFEJHaCDGFEJHa

+

CDGFEJQaCDGFEJQa

AAAAAAAABBBBBBBB

\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-fonts/font-variant-03.html b/tests/wpt/web-platform-tests/css/css-fonts/font-variant-03.html index 3da212a542b..7e130cc8317 100644 --- a/tests/wpt/web-platform-tests/css/css-fonts/font-variant-03.html +++ b/tests/wpt/web-platform-tests/css/css-fonts/font-variant-03.html @@ -22,7 +22,7 @@ font-variant: normal; } .outer { - font-feature-settings: "liga" on, "clig" on, "calt" on, "hlig" on, "dlig" on, "subs" on, "smcp" on, "jp04" on; + font-feature-settings: "liga" on, "clig" on, "calt" on, "hlig" on, "dlig" on, "onum" on, "smcp" on, "jp90" on; } .child { color: green; @@ -33,6 +33,6 @@

Test passes if the two lines below are identical, with (in purple) eight check marks (✓), and then (in green) eight check marks (✓).

-

CDGFEJHaCDGFEJHa

+

CDGFEJQaCDGFEJQa

AAAAAAAAAAAAAAAA

\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-fonts/font-variant-04.html b/tests/wpt/web-platform-tests/css/css-fonts/font-variant-04.html index 12aeaf56c45..be426398eee 100644 --- a/tests/wpt/web-platform-tests/css/css-fonts/font-variant-04.html +++ b/tests/wpt/web-platform-tests/css/css-fonts/font-variant-04.html @@ -22,7 +22,7 @@ font-variant: none; } .outer { - font-feature-settings: "liga" on, "clig" on, "calt" on, "hlig" on, "dlig" on, "subs" on, "smcp" on, "jp04" on; + font-feature-settings: "liga" on, "clig" on, "calt" on, "hlig" on, "dlig" on, "onum" on, "smcp" on, "jp90" on; } .child { color: green; @@ -33,6 +33,6 @@

Test passes if the two lines below are identical, with (in purple) eight check marks (✓), and then (in green) eight check marks (✓).

-

CDGFEJHaCDGFEJHa

+

CDGFEJQaCDGFEJQa

AAAAAAAAAAAAAAAA

\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-fonts/font-variant-alternates-parsing.html b/tests/wpt/web-platform-tests/css/css-fonts/font-variant-alternates-parsing.html new file mode 100644 index 00000000000..a02bcedfb6b --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-fonts/font-variant-alternates-parsing.html @@ -0,0 +1,18 @@ + + +CSS Test: font-variant-alternates: historical-forms; parses case-insensitively + + + + + diff --git a/tests/wpt/web-platform-tests/css/css-fonts/support/AD.woff b/tests/wpt/web-platform-tests/css/css-fonts/support/AD.woff new file mode 100644 index 00000000000..3df8ea8efda Binary files /dev/null and b/tests/wpt/web-platform-tests/css/css-fonts/support/AD.woff differ diff --git a/tests/wpt/web-platform-tests/css/css-fonts/support/Revalia.woff b/tests/wpt/web-platform-tests/css/css-fonts/support/Revalia.woff new file mode 100644 index 00000000000..631bee6de90 Binary files /dev/null and b/tests/wpt/web-platform-tests/css/css-fonts/support/Revalia.woff differ diff --git a/tests/wpt/web-platform-tests/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-001.html b/tests/wpt/web-platform-tests/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-001.html new file mode 100644 index 00000000000..849567c600a --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-001.html @@ -0,0 +1,39 @@ + + +CSS Grid Layout Test: Grid positioned items in auto-fit tracks + + + + + + + + + + + +
+
+
+
+ + +
+
+ diff --git a/tests/wpt/web-platform-tests/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-002.html b/tests/wpt/web-platform-tests/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-002.html new file mode 100644 index 00000000000..7271081ea6f --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-002.html @@ -0,0 +1,39 @@ + + +CSS Grid Layout Test: Grid positioned items in auto-fit tracks + + + + + + + + + + + +
+
+
+
+ + +
+
+ diff --git a/tests/wpt/web-platform-tests/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-003.html b/tests/wpt/web-platform-tests/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-003.html new file mode 100644 index 00000000000..05ac15dd289 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-003.html @@ -0,0 +1,39 @@ + + +CSS Grid Layout Test: Grid positioned items in auto-fit tracks + + + + + + + + + + + +
+
+
+
+ + +
+
+ diff --git a/tests/wpt/web-platform-tests/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-004.html b/tests/wpt/web-platform-tests/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-004.html new file mode 100644 index 00000000000..13b29ea9c53 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-004.html @@ -0,0 +1,40 @@ + + +CSS Grid Layout Test: Grid positioned items in auto-fit tracks and gaps + + + + + + + + + + + +
+
+
+
+ + +
+
+ diff --git a/tests/wpt/web-platform-tests/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-005.html b/tests/wpt/web-platform-tests/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-005.html new file mode 100644 index 00000000000..70695c4e128 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-005.html @@ -0,0 +1,40 @@ + + +CSS Grid Layout Test: Grid positioned items in auto-fit tracks and gaps + + + + + + + + + + + +
+
+
+
+ + +
+
+ diff --git a/tests/wpt/web-platform-tests/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-006.html b/tests/wpt/web-platform-tests/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-006.html new file mode 100644 index 00000000000..5b792205ab3 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-006.html @@ -0,0 +1,40 @@ + + +CSS Grid Layout Test: Grid positioned items in auto-fit tracks and gaps + + + + + + + + + + + +
+
+
+
+ + +
+
+ diff --git a/tests/wpt/web-platform-tests/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-007.html b/tests/wpt/web-platform-tests/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-007.html new file mode 100644 index 00000000000..1f9958029cc --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-007.html @@ -0,0 +1,40 @@ + + +CSS Grid Layout Test: Grid positioned items in auto-fit tracks and gaps + + + + + + + + + + + +
+
+
+
+ + +
+
+ diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-017.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-017.html new file mode 100644 index 00000000000..2c005e154e7 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-017.html @@ -0,0 +1,85 @@ + + +CSS Grid Layout Test: Self-Alignment along column axis of absolute positioned items with 'definite' grid positions + + + + + + + + + + + +
+
X XX X
+
XX X
X XXX X
XX XXX
+
X XX X
+
XX X
X XXX
X
XX XXX
+
+ +
+
X XX X
+
XX X
X XXX X
XX XXX
+
X XX X
+
XX X
X XXX
X
XX XXX
+
+ +

+ +
+
X XX X
+
XX X
X XXX X
XX XXX
+
X XX X
+
XX X
X XXX
X
XX XXX
+
+ +
+
X XX X
+
XX X
X XXX X
XX XXX
+
X XX X
+
XX X
X XXX
X
XX XXX
+
+ diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-017.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-017.html new file mode 100644 index 00000000000..6cc1e4e4b7a --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-017.html @@ -0,0 +1,85 @@ + + +CSS Grid Layout Test: Self-Alignment along row axis of absolute positioned items with 'definite' grid positions + + + + + + + + + + + +
+
X XX X
+
XX X
X XXX X
XX XXX
+
X XX X
+
XX X
X XXX
X
XX XXX
+
+ +
+
X XX X
+
XX X
X XXX X
XX XXX
+
X XX X
+
XX X
X XXX
X
XX XXX
+
+ +

+ +
+
X XX X
+
XX X
X XXX X
XX XXX
+
X XX X
+
XX X
X XXX
X
XX XXX
+
+ +
+
X XX X
+
XX X
X XXX X
XX XXX
+
X XX X
+
XX X
X XXX
X
XX XXX
+
+ diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-template-columns-fit-content-001-ref.html b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-template-columns-fit-content-001-ref.html index 22a293990f6..cb7a582ab10 100644 --- a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-template-columns-fit-content-001-ref.html +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-template-columns-fit-content-001-ref.html @@ -15,26 +15,6 @@ grid-column-gap: 5px; } -.fc0 { grid-template-columns: minmax(auto, 0px);} -.fc40 { grid-template-columns: minmax(auto, 40px); } -.fc80 { grid-template-columns: minmax(auto, 80px); } -.fc110 { grid-template-columns: auto; } - -.fc0x2 { grid-template-columns: repeat(2, minmax(auto, 0px));} -.fc40x2 { grid-template-columns: repeat(2, minmax(auto, 40px)); } -.fc80x2 { grid-template-columns: repeat(2, minmax(auto, 80px)); } -.fc110x2 { grid-template-columns: auto auto; } - -.fc0p { grid-template-columns: minmax(auto, 0%); } -.fc30p { grid-template-columns: minmax(auto, 30%); } -.fc90p { grid-template-columns: minmax(auto, 90%); } -.fc110p { grid-template-columns: auto; } - -.fc0px2 { grid-template-columns: repeat(2, minmax(auto, 0%)); } -.fc30px2 { grid-template-columns: repeat(2, minmax(auto, 30%)); } -.fc90px2 { grid-template-columns: repeat(2, minmax(auto, 90%)); } -.fc110px2 { grid-template-columns: auto auto; } - .item { font: 10px/1 Ahem; background: cyan; @@ -67,19 +47,19 @@ h3 { font-size: 1em; }

Only fit-content() and with fixed size tracks.

-
+
XXX
-
+
XXX
XXX
-
+
XXX XXX
@@ -90,45 +70,45 @@ h3 { font-size: 1em; }
-
+
XXX XXX
XXX XXX
-
+
XXX XXX XXX
-
+
XXX XXX XXX
-
+
XXX XXX XXX
XXX XXX XXX
-
+
XXX XX XXX
-
+
XXXXX
XXX XX XXX
-
+
XXXXX
XXX XX XXX
@@ -139,68 +119,68 @@ h3 { font-size: 1em; }

fit-content() with other content-sized tracks.

-
+
XXX XX XXX
-
+
XXXXX
XXX XX XXX
-
+
XXXXX
XXX XX XXX
-
+
XXX XX XXX
-
+
XXXXX
XXX XX XXX
-
+
XXXXX
XXX XX XXX
-
+
XXX XX XXX
-
+
XXX XX XXX
-
+
XXX XX XXX
-
+
XXX XX
XXX XX XXX
@@ -208,7 +188,7 @@ h3 { font-size: 1em; }
-
+
XXX XX
XXX XX XXX
@@ -216,7 +196,7 @@ h3 { font-size: 1em; }
-
+
XXX XX
XXX XX XXX
@@ -227,48 +207,48 @@ h3 { font-size: 1em; }

fit-content() with percentage arguments.

-
+
XXX
-
+
XXX
XXX
-
+
XX XX
-
+
XXX XXX
-
+
X X X
XXX XXX
-
+
XXX XXX XXX
-
+
XXX XXX XXX
-
+
XXX XXX XXX
XXX XXX XXX
@@ -277,47 +257,47 @@ h3 { font-size: 1em; }
-

max-content < fit-content() argument.

+

max-content < fit-content() argument.

-
+
XXX XXX
-
+
XXX XXX
-
+
XXX XXX
XXX XXX
-
+
XXX XXX
-
+
XX
XXX XXX
-
+
XX XX XX XX
XXX XXX
-
+
XX XX XX XX
XXX XXX
diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-template-columns-fit-content-001.html b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-template-columns-fit-content-001.html index 808b91c32b1..d492d4585f8 100644 --- a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-template-columns-fit-content-001.html +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-template-columns-fit-content-001.html @@ -281,7 +281,7 @@ h3 { font-size: 1em; }
-

max-content < fit-content() argument.

+

max-content < fit-content() argument.

XXX XXX
diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-template-rows-fit-content-001-ref.html b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-template-rows-fit-content-001-ref.html index bff6447c6f7..a1f83dc85af 100644 --- a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-template-rows-fit-content-001-ref.html +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-template-rows-fit-content-001-ref.html @@ -18,26 +18,6 @@ float: left; } -.fc0 { grid-template-rows: minmax(auto, 0px);} -.fc40 { grid-template-rows: minmax(auto, 40px); } -.fc80 { grid-template-rows: minmax(auto, 80px); } -.fc110 { grid-template-rows: auto; } - -.fc0x2 { grid-template-rows: repeat(2, minmax(auto, 0px));} -.fc40x2 { grid-template-rows: repeat(2, minmax(auto, 40px)); } -.fc80x2 { grid-template-rows: repeat(2, minmax(auto, 80px)); } -.fc110x2 { grid-template-rows: auto auto; } - -.fc0p { grid-template-rows: minmax(auto, 0%); } -.fc30p { grid-template-rows: minmax(auto, 30px); } -.fc90p { grid-template-rows: minmax(auto, 90px); } -.fc110p { grid-template-rows: auto; } - -.fc0px2 { grid-template-rows: repeat(2, minmax(auto, 0%)); } -.fc30px2 { grid-template-rows: repeat(2, minmax(auto, 30px)); } -.fc90px2 { grid-template-rows: repeat(2, minmax(auto, 90px)); } -.fc110px2 { grid-template-rows: auto auto; } - .item { font: 10px/1 Ahem; background: cyan; @@ -68,68 +48,68 @@ div.grid > div { writing-mode: vertical-lr; }

The test passes if it has the same output than the reference.

-
+
XXX
-
+
XXX
XXX
-
+
XXX XXX
-
+
XXX XXX
-
+
XXX XXX
XXX XXX
-
+
XXX XXX XXX
-
+
XXX XXX XXX
-
+
XXX XXX XXX
XXX XXX XXX
-
+
XXX XX XXX
-
+
XXXXX
XXX XX XXX
-
+
XXXXX
XXX XX XXX
@@ -139,68 +119,68 @@ div.grid > div { writing-mode: vertical-lr; }

-
+
XXX XX XXX
-
+
XXXXX
XXX XX XXX
-
+
XXXXX
XXX XX XXX
-
+
XXX XX XXX
-
+
XXXXX
XXX XX XXX
-
+
XXXXX
XXX XX XXX
-
+
XXX XX XXX
-
+
XXX XX XXX
-
+
XXX XX XXX
-
+
XXX XX
XXX XX XXX
@@ -208,7 +188,7 @@ div.grid > div { writing-mode: vertical-lr; }
-
+
XXX XX
XXX XX XXX
@@ -216,7 +196,7 @@ div.grid > div { writing-mode: vertical-lr; }
-
+
XXX XX
XXX XX XXX
@@ -227,48 +207,48 @@ div.grid > div { writing-mode: vertical-lr; }

-
+
XXX
-
+
XXX
XXX
-
+
XX XX
-
+
XXX XXX
-
+
X X X
XXX XXX
-
+
XXX XXX XXX
-
+
XXX XXX XXX
-
+
XXX XXX XXX
XXX XXX XXX
@@ -278,45 +258,45 @@ div.grid > div { writing-mode: vertical-lr; }

-
+
XXX XXX
-
+
XXX XXX
-
+
XXX XXX
XXX XXX
-
+
XXX XXX
-
+
XX
XXX XXX
-
+
XX XX XX XX
XXX XXX
-
+
XX XX XX XX
XXX XXX
diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-items/explicitly-sized-grid-item-as-table.html b/tests/wpt/web-platform-tests/css/css-grid/grid-items/explicitly-sized-grid-item-as-table.html new file mode 100644 index 00000000000..53a0979622c --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-items/explicitly-sized-grid-item-as-table.html @@ -0,0 +1,12 @@ + +CSS Grid Layout Test: Explicitly sized grid item as table with narrow contents + + + + +

Test passes if there is a filled green square.

+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-items/grid-minimum-size-grid-items-017.html b/tests/wpt/web-platform-tests/css/css-grid/grid-items/grid-minimum-size-grid-items-017.html index 6cd2dfb0f8d..4cb74022aaf 100644 --- a/tests/wpt/web-platform-tests/css/css-grid/grid-items/grid-minimum-size-grid-items-017.html +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-items/grid-minimum-size-grid-items-017.html @@ -4,11 +4,11 @@ - + + + + + + + +
+ +
grid-template-columns: auto;
+ +
+
XXXXXXXXXX
+
+
+ +
grid-template-columns: 0px;
+ +
+
XXXXXXXXXX
+
+
+ +
grid-template-columns: 25px;
+ +
+
XXXXXXXXXX
+
+
+ +
grid-template-columns: minmax(auto, 0px);
+ +
+
XXXXXXXXXX
+
+
+ +
grid-template-columns: minmax(auto, 25px);
+ +
+
XXXXXXXXXX
+
+
+ +
grid-template-columns: minmax(auto, 0px); item width: 10px;
+ +
+
XXXXXXXXXX
+
+
+ +
grid-template-columns: minmax(auto, 25px); item width: 10px;
+ +
+
XXXXXXXXXX
+
+
+ +
grid-template-columns: minmax(auto, 0px); item margin width: 10px;
+ +
+
+
+
+ +
grid-template-columns: minmax(auto, 25px); item margin width: 10px;
+ +
+
+
+
+ +
grid-template-columns: minmax(auto, 0px); item padding width: 10px;
+ +
+
+
+
+ +
grid-template-columns: minmax(auto, 25px); item padding width: 10px;
+ +
+
+
+
+ +
grid-template-columns: minmax(auto, 0px); item border width: 10px;
+ +
+
+
+
+ +
grid-template-columns: minmax(auto, 25px); item border width: 10px;
+ +
+
+
+
+ +
grid-template-columns: minmax(auto, 0px); item width + margin + border + padding: 10px;
+ +
+
+
+
+ +
grid-template-columns: minmax(auto, 25px); item width + margin + border + padding: 10px;
+ +
+
+
+
diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-items/grid-minimum-size-grid-items-023.html b/tests/wpt/web-platform-tests/css/css-grid/grid-items/grid-minimum-size-grid-items-023.html new file mode 100644 index 00000000000..d821e5c735c --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-items/grid-minimum-size-grid-items-023.html @@ -0,0 +1,248 @@ + + +CSS Grid Layout Test: Minimum size of grid items + + + + + + + + + + + +
+ +

writing-mode: vertical-lr;

+ +
grid-template-rows: auto;
+ +
+
XXXXXXXXXX
+
+
+ +
grid-template-rows: 0px;
+ +
+
XXXXXXXXXX
+
+
+ +
grid-template-rows: 25px;
+ +
+
XXXXXXXXXX
+
+
+ +
grid-template-rows: minmax(auto, 0px);
+ +
+
XXXXXXXXXX
+
+
+ +
grid-template-rows: minmax(auto, 25px);
+ +
+
XXXXXXXXXX
+
+
+ +
grid-template-rows: minmax(auto, 0px); item height: 10px;
+ +
+
XXXXXXXXXX
+
+
+ +
grid-template-rows: minmax(auto, 25px); item height: 10px;
+ +
+
XXXXXXXXXX
+
+
+ +
grid-template-rows: minmax(auto, 0px); item margin height: 10px;
+ +
+
+
+
+ +
grid-template-rows: minmax(auto, 25px); item margin height: 10px;
+ +
+
+
+
+ +
grid-template-rows: minmax(auto, 0px); item padding height: 10px;
+ +
+
+
+
+ +
grid-template-rows: minmax(auto, 25px); item padding height: 10px;
+ +
+
+
+
+ +
grid-template-rows: minmax(auto, 0px); item border height: 10px;
+ +
+
+
+
+ +
grid-template-rows: minmax(auto, 25px); item border height: 10px;
+ +
+
+
+
+ +
grid-template-rows: minmax(auto, 0px); item height + margin + border + padding: 10px;
+ +
+
+
+
+ +
grid-template-rows: minmax(auto, 25px); item height + margin + border + padding: 10px;
+ +
+
+
+
+ +

writing-mode: vertical-rl;

+ +
grid-template-rows: auto;
+ +
+
XXXXXXXXXX
+
+
+ +
grid-template-rows: 0px;
+ +
+
XXXXXXXXXX
+
+
+ +
grid-template-rows: 25px;
+ +
+
XXXXXXXXXX
+
+
+ +
grid-template-rows: minmax(auto, 0px);
+ +
+
XXXXXXXXXX
+
+
+ +
grid-template-rows: minmax(auto, 25px);
+ +
+
XXXXXXXXXX
+
+
+ +
grid-template-rows: minmax(auto, 0px); item height: 10px;
+ +
+
XXXXXXXXXX
+
+
+ +
grid-template-rows: minmax(auto, 25px); item height: 10px;
+ +
+
XXXXXXXXXX
+
+
+ +
grid-template-rows: minmax(auto, 0px); item margin height: 10px;
+ +
+
+
+
+ +
grid-template-rows: minmax(auto, 25px); item margin height: 10px;
+ +
+
+
+
+ +
grid-template-rows: minmax(auto, 0px); item padding height: 10px;
+ +
+
+
+
+ +
grid-template-rows: minmax(auto, 25px); item padding height: 10px;
+ +
+
+
+
+ +
grid-template-rows: minmax(auto, 0px); item border height: 10px;
+ +
+
+
+
+ +
grid-template-rows: minmax(auto, 25px); item border height: 10px;
+ +
+
+
+
+ +
grid-template-rows: minmax(auto, 0px); item height + margin + border + padding: 10px;
+ +
+
+
+
+ +
grid-template-rows: minmax(auto, 25px); item height + margin + border + padding: 10px;
+ +
+
+
+
+ diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-layout-properties.html b/tests/wpt/web-platform-tests/css/css-grid/grid-layout-properties.html index 2e66fb21539..249c4a738f7 100644 --- a/tests/wpt/web-platform-tests/css/css-grid/grid-layout-properties.html +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-layout-properties.html @@ -54,7 +54,7 @@ Object.keys(data).forEach(function(prop){ test(function(){ - assert_own_property(myDiv.style, prop) + assert_true(prop in myDiv.style) }, prop) if ('initial' in data[prop]) test(function(){ @@ -66,7 +66,7 @@ var syntaxTests = data[prop] Object.keys(syntaxTests).forEach(function(testcase){ test(function(){ - assert_own_property(myDiv.style, prop) + assert_true(prop in myDiv.style) myDiv.style[prop] = syntaxTests[testcase][0] assert_equals(myDiv.style[prop], syntaxTests[testcase][0], testcase) assert_equals(getComputedStyle(myDiv)[prop], syntaxTests[testcase][1], testcase) diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-model/grid-container-ignores-first-letter-001.html b/tests/wpt/web-platform-tests/css/css-grid/grid-model/grid-container-ignores-first-letter-001.html new file mode 100644 index 00000000000..f94fdcfe965 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-model/grid-container-ignores-first-letter-001.html @@ -0,0 +1,108 @@ + + +CSS Grid Layout Test: '::first-letter' is ignored in grid containers + + + + + + + + + + + + +
+ +
+
+
The first item.
+
The second item.
+
+
+ +
+
+
The first item.
+
The second item.
+
+
+ +
+
+ Anonymous item. +
+
+ +
+
+ Anonymous item. +
+
+ +
+
+
The first item.
+
The second item.
+
+
Out of grid.
+
+ +
+
+
The first item.
+
The second item.
+
+
Out of grid.
+
+ +
+
+ Anonymous item. +
+
Out of grid.
+
+ +
+
+ Anonymous item. +
+
Out of grid.
+
+ +
+
+
The first item.
+
The second item.
+
+
Out of grid.
+
+ +
+
+
The first item.
+
The second item.
+
+
Out of grid.
+
+ +
+
+ Anonymous item. +
+
Out of grid.
+
+ +
+
+ Anonymous item. +
+
Out of grid.
+
+ + diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-model/grid-container-ignores-first-line-001.html b/tests/wpt/web-platform-tests/css/css-grid/grid-model/grid-container-ignores-first-line-001.html new file mode 100644 index 00000000000..b491298f3ea --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-model/grid-container-ignores-first-line-001.html @@ -0,0 +1,92 @@ + + +CSS Grid Layout Test: '::first-line' is ignored in grid containers + + + + + + + + + + + + +
+ +
+
The first item.
+
The second item.
+
+ +
+
The first item.
+
The second item.
+
+ +
+ Anonymous item. +
+ +
+ Anonymous item. +
+ +
+
+
The first item.
+
The second item.
+
+
+ +
+
+
The first item.
+
The second item.
+
+
+ +
+
+ Anonymous item. +
+
+ +
+
+ Anonymous item. +
+
+ +
+
+
The first item.
+
The second item.
+
+
+ +
+
+
The first item.
+
The second item.
+
+
+ +
+
+ Anonymous item. +
+
+ +
+
+ Anonymous item. +
+
+ + diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-model/grid-item-accepts-first-letter-001.html b/tests/wpt/web-platform-tests/css/css-grid/grid-model/grid-item-accepts-first-letter-001.html new file mode 100644 index 00000000000..c9454fe30e7 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-model/grid-item-accepts-first-letter-001.html @@ -0,0 +1,30 @@ + + +CSS Grid Layout Test: '::first-letter' is valid in grid items + + + + + + + + + + + + +
+ +
+
The first item.
+
The second item.
+
+ +
+
The first item.
+
The second item.
+
+ + diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-model/grid-item-accepts-first-line-001.html b/tests/wpt/web-platform-tests/css/css-grid/grid-model/grid-item-accepts-first-line-001.html new file mode 100644 index 00000000000..1330b376318 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-model/grid-item-accepts-first-line-001.html @@ -0,0 +1,30 @@ + + +CSS Grid Layout Test: '::first-line' is valid in grid items + + + + + + + + + + + + +
+ +
+
The first item.
+
The second item.
+
+ +
+
The first item.
+
The second item.
+
+ + diff --git a/tests/wpt/web-platform-tests/css/css-grid/reference/grid-collapsed-row-gutters-ref.html b/tests/wpt/web-platform-tests/css/css-grid/reference/grid-collapsed-row-gutters-ref.html index 7d33e57eaff..a0ff682c6a5 100644 --- a/tests/wpt/web-platform-tests/css/css-grid/reference/grid-collapsed-row-gutters-ref.html +++ b/tests/wpt/web-platform-tests/css/css-grid/reference/grid-collapsed-row-gutters-ref.html @@ -38,6 +38,7 @@ } +

The test passes if it has the same visual effect as reference. Column gap should be percentage of width. Row gap should resolve to auto, and therefore collapse to 0 height.

diff --git a/tests/wpt/web-platform-tests/css/css-grid/reference/grid-different-gutters-ref.html b/tests/wpt/web-platform-tests/css/css-grid/reference/grid-different-gutters-ref.html index 52ee9e0676e..57d27ff3aae 100644 --- a/tests/wpt/web-platform-tests/css/css-grid/reference/grid-different-gutters-ref.html +++ b/tests/wpt/web-platform-tests/css/css-grid/reference/grid-different-gutters-ref.html @@ -38,6 +38,7 @@ } +

The test passes if it has the same visual effect as reference.

diff --git a/tests/wpt/web-platform-tests/css/css-grid/reference/grid-equal-gutters-ref.html b/tests/wpt/web-platform-tests/css/css-grid/reference/grid-equal-gutters-ref.html index 3d9952679b1..caea89a8be0 100644 --- a/tests/wpt/web-platform-tests/css/css-grid/reference/grid-equal-gutters-ref.html +++ b/tests/wpt/web-platform-tests/css/css-grid/reference/grid-equal-gutters-ref.html @@ -38,6 +38,7 @@ } +

The test passes if it has the same visual effect as reference.

diff --git a/tests/wpt/web-platform-tests/css/css-lists/counter-7-ref.html b/tests/wpt/web-platform-tests/css/css-lists/counter-7-ref.html new file mode 100644 index 00000000000..3d1b67228fb --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-lists/counter-7-ref.html @@ -0,0 +1,6 @@ + + +CSS Test Reference + +

You should see the number 7 below.

+
7
diff --git a/tests/wpt/web-platform-tests/css/css-lists/counter-increment-inside-display-contents.html b/tests/wpt/web-platform-tests/css/css-lists/counter-increment-inside-display-contents.html new file mode 100644 index 00000000000..ebfe1774da6 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-lists/counter-increment-inside-display-contents.html @@ -0,0 +1,20 @@ + + +CSS Lists: counter-increment on child of display:contents + + + + +

You should see the number 7 below.

+
+ + + + + +
diff --git a/tests/wpt/web-platform-tests/css/css-lists/counter-reset-increment-display-contents.html b/tests/wpt/web-platform-tests/css/css-lists/counter-reset-increment-display-contents.html new file mode 100644 index 00000000000..a59576b2534 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-lists/counter-reset-increment-display-contents.html @@ -0,0 +1,19 @@ + + +CSS Lists: counter-reset and counter-increment on display:contents + + + + +

You should see the number 7 below.

+
+ + + +
diff --git a/tests/wpt/web-platform-tests/css/css-lists/counter-reset-increment-display-none.html b/tests/wpt/web-platform-tests/css/css-lists/counter-reset-increment-display-none.html new file mode 100644 index 00000000000..3b344a751c1 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-lists/counter-reset-increment-display-none.html @@ -0,0 +1,19 @@ + + +CSS Lists: counter-reset and counter-increment on display:none + + + + +

You should see the number 7 below.

+
+ + + +
diff --git a/tests/wpt/web-platform-tests/css/css-lists/counter-reset-inside-display-contents.html b/tests/wpt/web-platform-tests/css/css-lists/counter-reset-inside-display-contents.html new file mode 100644 index 00000000000..85c137e675e --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-lists/counter-reset-inside-display-contents.html @@ -0,0 +1,21 @@ + + +CSS Lists: counter-reset on child of display:contents + + + + +

You should see the number 7 below.

+
+ + + + + +
diff --git a/tests/wpt/web-platform-tests/css/css-masking/clip/clip-rect-auto-001.html b/tests/wpt/web-platform-tests/css/css-masking/clip/clip-rect-auto-001.html index 36cc49d7f3a..6a1a064059b 100644 --- a/tests/wpt/web-platform-tests/css/css-masking/clip/clip-rect-auto-001.html +++ b/tests/wpt/web-platform-tests/css/css-masking/clip/clip-rect-auto-001.html @@ -12,7 +12,7 @@ in the bottom right corner of the blue square."> -

The test passes if there is a blue square and a smaller green square in the bottom right corner of the blue square .

+

The test passes if there is a blue square and a smaller green square in the bottom right corner of the blue square.

diff --git a/tests/wpt/web-platform-tests/css/css-masking/clip/clip-rect-comma-002.html b/tests/wpt/web-platform-tests/css/css-masking/clip/clip-rect-comma-002.html index abe56bbfa47..aad2aebe673 100644 --- a/tests/wpt/web-platform-tests/css/css-masking/clip/clip-rect-comma-002.html +++ b/tests/wpt/web-platform-tests/css/css-masking/clip/clip-rect-comma-002.html @@ -12,6 +12,6 @@

The test passes if there is a green square with a blue border.

-
+
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-masking/clip/reference/clip-horizontal-stripe-ref.html b/tests/wpt/web-platform-tests/css/css-masking/clip/reference/clip-horizontal-stripe-ref.html index d90a5ec785d..fccb18318d2 100644 --- a/tests/wpt/web-platform-tests/css/css-masking/clip/reference/clip-horizontal-stripe-ref.html +++ b/tests/wpt/web-platform-tests/css/css-masking/clip/reference/clip-horizontal-stripe-ref.html @@ -5,7 +5,7 @@ -

The test passes if there is only a vertical blue stripe.

+

The test passes if there is only a horizontal blue stripe.

\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-multicol/OWNERS b/tests/wpt/web-platform-tests/css/css-multicol/OWNERS index 1048ba69fda..3247ab2dea0 100644 --- a/tests/wpt/web-platform-tests/css/css-multicol/OWNERS +++ b/tests/wpt/web-platform-tests/css/css-multicol/OWNERS @@ -1,2 +1,3 @@ @frivoal +@mstensho @rachelandrew diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-br-inside-avoidcolumn-001.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-br-inside-avoidcolumn-001.xht index 419a88bded6..d3f2c9ec5da 100644 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-br-inside-avoidcolumn-001.xht +++ b/tests/wpt/web-platform-tests/css/css-multicol/multicol-br-inside-avoidcolumn-001.xht @@ -5,47 +5,33 @@ multicol | break-inside: avoid-column - + -

You should not see the word FAIL

- -
- FAIL +

Test passes if there is a filled green square and no red.

+
+
+
+
- -
- FAIL -
- -
- FAIL -
- diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-br-inside-avoidcolumn-ref.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-br-inside-avoidcolumn-ref.xht deleted file mode 100644 index fc465568215..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-br-inside-avoidcolumn-ref.xht +++ /dev/null @@ -1,30 +0,0 @@ - - - -multicol | break-inside: avoid-column - - - - -
-

You should not see the word FAIL

-
- - - diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-break-001-ref.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-break-001-ref.xht index b363c2bffeb..f7535180965 100644 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-break-001-ref.xht +++ b/tests/wpt/web-platform-tests/css/css-multicol/multicol-break-001-ref.xht @@ -21,9 +21,9 @@

Test passes if the 2 horizontal bars are identical.

-
  Image download support must be enabled Image download support must be enabled Image download support must be enabled
+
Image download support must be enabled Image download support must be enabled Image download support must be enabled
-
  Image download support must be enabled Image download support must be enabled Image download support must be enabled
+
Image download support must be enabled Image download support must be enabled Image download support must be enabled
- \ No newline at end of file + diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-break-001.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-break-001.xht index 8c3f6a785ca..a03667411ac 100644 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-break-001.xht +++ b/tests/wpt/web-platform-tests/css/css-multicol/multicol-break-001.xht @@ -47,7 +47,7 @@
C
-
  Image download support must be enabled Image download support must be enabled Image download support must be enabled
+
Image download support must be enabled Image download support must be enabled Image download support must be enabled
- \ No newline at end of file + diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-count-computed-001.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-count-computed-001.xht deleted file mode 100644 index 3c9ea3a36b8..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-count-computed-001.xht +++ /dev/null @@ -1,50 +0,0 @@ - - - -multicolumn | column-rule - - - - - - - - - - -
- xxxx - xxxx - xxxx - xxxx -
- - - diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-count-computed-002.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-count-computed-002.xht deleted file mode 100644 index 7bd1b3effdf..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-count-computed-002.xht +++ /dev/null @@ -1,50 +0,0 @@ - - - -multicolumn | column-rule - - - - - - - - - - -
- xxxx - xxxx - xxxx - xxxx -
- - - diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-count-computed-2-ref.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-count-computed-2-ref.xht deleted file mode 100644 index 15d365cfcc6..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-count-computed-2-ref.xht +++ /dev/null @@ -1,58 +0,0 @@ - - - -multicolumn | column-rule - - - - - - -
- xxxx - xxxx - xxxx - xxxx -
- - - diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-count-computed-ref.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-count-computed-ref.xht deleted file mode 100644 index ac6d8c12114..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-count-computed-ref.xht +++ /dev/null @@ -1,69 +0,0 @@ - - - -multicolumn | column-rule - - - - - - -
- xxxx - xxxx - xxxx - xxxx - -
- - - diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-count-large-001.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-count-large-001.xht deleted file mode 100644 index 78fff42cf7d..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-count-large-001.xht +++ /dev/null @@ -1,42 +0,0 @@ - - - -multicolumn | column-count - - - - - - - - - -
- xx xx - xx xx - xx xx - xx xx -
- - - diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-count-large-002.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-count-large-002.xht deleted file mode 100644 index 09b296ab638..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-count-large-002.xht +++ /dev/null @@ -1,42 +0,0 @@ - - - -multicolumn | column-count - - - - - - - - - -
- xx xx - xx xx - xx xx - xx xx -
- - - diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-count-large-2-ref.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-count-large-2-ref.xht deleted file mode 100644 index cb4b26f367e..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-count-large-2-ref.xht +++ /dev/null @@ -1,40 +0,0 @@ - - - -multicolumn | column-count - - - - - - -
- x -
- - - diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-count-large-ref.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-count-large-ref.xht deleted file mode 100644 index a561c94c2dd..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-count-large-ref.xht +++ /dev/null @@ -1,30 +0,0 @@ - - - -multicolumn | column-count - - - - - - -
xx
- - - diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-fill-auto-block-children-002-ref.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-fill-auto-block-children-002-ref.xht index f57fa435920..3cec0f55425 100644 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-fill-auto-block-children-002-ref.xht +++ b/tests/wpt/web-platform-tests/css/css-multicol/multicol-fill-auto-block-children-002-ref.xht @@ -6,13 +6,15 @@ @@ -72,8 +42,8 @@

Test passes if "PASS!" is
on the right ↘

- PASS!
+ PASS! diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-fill-auto-block-children-002.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-fill-auto-block-children-002.xht index 9097e3c18c4..d79fa95f16c 100644 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-fill-auto-block-children-002.xht +++ b/tests/wpt/web-platform-tests/css/css-multicol/multicol-fill-auto-block-children-002.xht @@ -18,16 +18,11 @@ background-color: blue; height: 200px; margin: 8px; - width: 680px; + width: 60%; column-count: 3; column-fill: auto; column-gap: 10px; - - /* - So, each column box should be - [680px minus (2 mult 10px)] divided by 3 == 220px wide - */ } h1 @@ -75,25 +70,5 @@

PASS!

- - diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-fill-auto-ref.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-fill-auto-ref.xht deleted file mode 100644 index b287fb2805b..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-fill-auto-ref.xht +++ /dev/null @@ -1,53 +0,0 @@ - - - -multicolumn | column-gap - - - - - - -
-
one two three four - five six seven eight - nine ten eleven twelve - thirtn fourtn fiftn sixtn - seventn eightn ninetn twenty - hundred thousand million billion - trillion - one two three four - five six seven eight - nine ten eleven twelve - thirtn fourtn fiftn sixtn - seventn eightn ninetn twenty - hundred
-
thousand million billion - trillion - one two three four - five six seven eight - nine ten eleven twelve - thirtn fourtn fiftn sixtn - seventn eightn ninetn twenty - hundred thousand million billion - trillion
-
- - - diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-fill-auto.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-fill-auto.xht deleted file mode 100644 index 20fe7e47f8c..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-fill-auto.xht +++ /dev/null @@ -1,49 +0,0 @@ - - - -multicolumn | column-fill-auto - - - - - - - - - - -
-
-
-o
t
-o
t
-
- -
-oo
t
o -
- - - diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-fill-ref.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-fill-ref.xht deleted file mode 100644 index 176631b9ad1..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-fill-ref.xht +++ /dev/null @@ -1,21 +0,0 @@ - - - -multicolumn | column-gap - - - - - - -
- - - diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-gap-animation-001.html b/tests/wpt/web-platform-tests/css/css-multicol/multicol-gap-animation-001.html new file mode 100644 index 00000000000..6a3a8d33780 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-multicol/multicol-gap-animation-001.html @@ -0,0 +1,45 @@ + + +CSS Multi-column Layout Test: column-gap test animation + + + + + + + + +
+
+ + + diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-gap-animation-002.html b/tests/wpt/web-platform-tests/css/css-multicol/multicol-gap-animation-002.html new file mode 100644 index 00000000000..de3756c67b5 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-multicol/multicol-gap-animation-002.html @@ -0,0 +1,34 @@ + + +CSS Multi-column Layout Test: column-gap normal test animation + + + + + + + + +
+
+ + + diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-gap-animation-003.html b/tests/wpt/web-platform-tests/css/css-multicol/multicol-gap-animation-003.html new file mode 100644 index 00000000000..71182fafbe8 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-multicol/multicol-gap-animation-003.html @@ -0,0 +1,33 @@ + + +CSS Multi-column Layout Test: Default column-gap test animation + + + + + + + + +
+
+ + + diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-gap-fraction-002.html b/tests/wpt/web-platform-tests/css/css-multicol/multicol-gap-fraction-002.html new file mode 100644 index 00000000000..ae1aaaad774 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-multicol/multicol-gap-fraction-002.html @@ -0,0 +1,68 @@ + +CSS Multi-column Layout Test: 'column-gap' with sub-pixel values + + + + + + +

There should be nothing below.

+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-height-block-child-001-ref.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-height-block-child-001-ref.xht index 27a87c3fe3a..b238d5c94f2 100644 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-height-block-child-001-ref.xht +++ b/tests/wpt/web-platform-tests/css/css-multicol/multicol-height-block-child-001-ref.xht @@ -5,51 +5,34 @@ - -
Image download support must be enabled
- -
Image download support must be enabled
+
+
+
+
+
+
+
- \ No newline at end of file + diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-height-block-child-001.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-height-block-child-001.xht index d7dfd3de5fa..b62d92eee53 100644 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-height-block-child-001.xht +++ b/tests/wpt/web-platform-tests/css/css-multicol/multicol-height-block-child-001.xht @@ -54,40 +54,35 @@
diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-inherit-004.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-inherit-004.xht deleted file mode 100644 index 2272c431750..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-inherit-004.xht +++ /dev/null @@ -1,55 +0,0 @@ - - - -multicolumn | inheritance - - - - - - - - - -
-
- xx xx - xx xx - xx xx - xx xx -
-
- xx xx - xx xx - xx xx - xx xx -
-
- xx xx - xx xx - xx xx - xx xx -
-
- - - diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-inherit-4-ref.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-inherit-4-ref.xht deleted file mode 100644 index 2972d713206..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-inherit-4-ref.xht +++ /dev/null @@ -1,37 +0,0 @@ - - - -multicolumn | inheritance - - - - - - -
-
-
-
- - - diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-nested-column-rule-001-ref.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-nested-column-rule-001-ref.xht index 8d86b42a690..e373c9a60b6 100644 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-nested-column-rule-001-ref.xht +++ b/tests/wpt/web-platform-tests/css/css-multicol/multicol-nested-column-rule-001-ref.xht @@ -5,41 +5,8 @@ - - -
-
-
-
- +
- \ No newline at end of file + diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-nested-column-rule-001.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-nested-column-rule-001.xht index 11a44f46c2f..322551e185f 100644 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-nested-column-rule-001.xht +++ b/tests/wpt/web-platform-tests/css/css-multicol/multicol-nested-column-rule-001.xht @@ -18,7 +18,7 @@ { column-rule: blue solid 1em; font: 1.25em/1 Ahem; - width: 42em; + width: 36em; } /* diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-fraction-3-ref.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-fraction-3-ref.xht index 9189b97d3c5..f4d3b845d0f 100644 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-fraction-3-ref.xht +++ b/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-fraction-3-ref.xht @@ -32,9 +32,9 @@ div div { background: blue; width: 1em; } -#a1 {left: 2.43em;} +#a1 {left: 2.4em;} #a2 {left: 3.75em;} -#a3 {left: 6.13em;} +#a3 {left: 6.15em;} #a4 {left: 7.5em;} #a5 {left: 9.9em;} #a6 {left: 11.25em;} diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-samelength-001.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-samelength-001.xht index 431eb74e4f1..e7eab8e8d47 100644 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-samelength-001.xht +++ b/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-samelength-001.xht @@ -1,7 +1,7 @@ - CSS Multi-column Layout Test: 'column-rule-width' has same lenght as 'column-gap' + CSS Multi-column Layout Test: 'column-rule-width' has same length as 'column-gap' @@ -68,4 +68,4 @@ --> - \ No newline at end of file + diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-style-groove-001-ref.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-style-groove-001-ref.xht deleted file mode 100644 index a32a71ef4b6..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-style-groove-001-ref.xht +++ /dev/null @@ -1,44 +0,0 @@ - - - - CSS Reftest Reference - - - - - - - -

Test passes if the 2 orange squares are identical.

- -
T
- -
T
- - - \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-style-groove-001.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-style-groove-001.xht deleted file mode 100644 index 43a4a213ecd..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-style-groove-001.xht +++ /dev/null @@ -1,71 +0,0 @@ - - - - CSS Multi-column Layout Test: 'column-rule-style' groove - - - - - - - - - - -

Test passes if the 2 orange squares are identical.

- -
T
- -
Le ft Co lu mn Ri gh Co lu mn
- - - - - \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-style-inset-001.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-style-inset-001.xht deleted file mode 100644 index d50bec9325d..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-style-inset-001.xht +++ /dev/null @@ -1,71 +0,0 @@ - - - - CSS Multi-column Layout Test: 'column-rule-style' inset - - - - - - - - - - -

Test passes if the 2 orange squares are identical.

- -
T
- -
Le ft Co lu mn Ri gh Co lu mn
- - - - - \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-style-outset-001.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-style-outset-001.xht deleted file mode 100644 index ea8c3320fff..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-style-outset-001.xht +++ /dev/null @@ -1,71 +0,0 @@ - - - - CSS Multi-column Layout Test: 'column-rule-style' outset - - - - - - - - - - -

Test passes if the 2 orange squares are identical.

- -
T
- -
Le ft Co lu mn Ri gh Co lu mn
- - - - - \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-style-ridge-001-ref.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-style-ridge-001-ref.xht deleted file mode 100644 index 4da6ec849d4..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-style-ridge-001-ref.xht +++ /dev/null @@ -1,44 +0,0 @@ - - - - CSS Reftest Reference - - - - - - - -

Test passes if the 2 orange squares are identical.

- -
T
- -
T
- - - \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-style-ridge-001.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-style-ridge-001.xht deleted file mode 100644 index 1cc97df5640..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-rule-style-ridge-001.xht +++ /dev/null @@ -1,71 +0,0 @@ - - - - CSS Multi-column Layout Test: 'column-rule-style' ridge - - - - - - - - - - -

Test passes if the 2 orange squares are identical.

- -
T
- -
Le ft Co lu mn Ri gh Co lu mn
- - - - - \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-span-all-003.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-span-all-003.xht index 9986f930ce4..fb4a508f50a 100644 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-span-all-003.xht +++ b/tests/wpt/web-platform-tests/css/css-multicol/multicol-span-all-003.xht @@ -26,6 +26,8 @@ column-count: 4; column-gap: 0; + orphans: 1; + widows: 1; } h4 @@ -45,4 +47,4 @@ 1 22  1 22  1     1 333 1 333 1 333 55555 1 22  1 22  1     1 22  1 22  1 22  55555 1 333 1 333 1     4444 4444 1     55555 1 333 1 333 1     4444 4444 1     55555
- \ No newline at end of file + diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-span-all-child-001-ref.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-span-all-child-001-ref.xht deleted file mode 100644 index fe82d6a1162..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-span-all-child-001-ref.xht +++ /dev/null @@ -1,109 +0,0 @@ - - - - CSS Reftest Reference - - - - - - - -
- -
-
-
-
-
-
-
-
- -
- - - diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-span-all-child-001.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-span-all-child-001.xht deleted file mode 100644 index ebc38abf7d6..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-span-all-child-001.xht +++ /dev/null @@ -1,53 +0,0 @@ - - - - CSS Multi-column Layout Test: 'column-span: all' element with block children (complex) - - - - - - - - - - - - -
- block - block - block -
- - - \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-span-all-child-002-ref.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-span-all-child-002-ref.xht deleted file mode 100644 index 417bbe110fd..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-span-all-child-002-ref.xht +++ /dev/null @@ -1,32 +0,0 @@ - - - - CSS Reftest Reference - - - - - - - -
- -
abc deg
ghk mno
- - - diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-span-all-child-002.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-span-all-child-002.xht deleted file mode 100644 index 72cd8e6b026..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-span-all-child-002.xht +++ /dev/null @@ -1,86 +0,0 @@ - - - - CSS Multi-column Layout Test: 'column-span: all' element with block children (complex) - - - - - - - - - - - - -
- FAIL - FAIL - FAIL - FAIL -
- -

abc deg ghk mno

- - - - - diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-span-all-margin-nested-003.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-span-all-margin-nested-003.xht deleted file mode 100644 index 9aef675ccf9..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-span-all-margin-nested-003.xht +++ /dev/null @@ -1,39 +0,0 @@ - - - -multicolomn | column-span inside block - - - - - - - - - -
-
-
x
-
- FAIL FAIL FAIL FAIL -
- - - diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-span-all-margin-nested-3-ref.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-span-all-margin-nested-3-ref.xht deleted file mode 100644 index 105d22bf498..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-span-all-margin-nested-3-ref.xht +++ /dev/null @@ -1,23 +0,0 @@ - - - -multicolomn | column-span inside block - - - - - - -
-
- - - diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-table-cell-vertical-align-001.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-table-cell-vertical-align-001.xht index 5f73cec0976..f50d0afe79c 100644 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-table-cell-vertical-align-001.xht +++ b/tests/wpt/web-platform-tests/css/css-multicol/multicol-table-cell-vertical-align-001.xht @@ -10,13 +10,13 @@ diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-width-ems-001.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-width-ch-001.xht similarity index 52% rename from tests/wpt/web-platform-tests/css/css-multicol/multicol-width-ems-001.xht rename to tests/wpt/web-platform-tests/css/css-multicol/multicol-width-ch-001.xht index c227ab4032e..c3e3b353028 100644 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-width-ems-001.xht +++ b/tests/wpt/web-platform-tests/css/css-multicol/multicol-width-ch-001.xht @@ -5,38 +5,30 @@ multicolumn | column-width - + -
- one two three four - five six seven eight - nineten eleven twelve - thirtn fourtnfiftn sixtn - seventn eightn ninetn twenty - hundred thousand million billion - trillion -
- +
+ one two three four + five six seven eight + nineten eleven twelve + thirtn fourtnfiftn sixtn + seventn eightn ninetn twenty + hundred thousand million billion + trillion +
diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-width-ch-ref.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-width-ch-ref.xht new file mode 100644 index 00000000000..133ad3e4b24 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-multicol/multicol-width-ch-ref.xht @@ -0,0 +1,49 @@ + + + +multicolumn | column-width + + + + + +
+ + one two three four + five six seven eight + + + nineten eleven twelve + thirtn + + + fourtnfiftn sixtn + seventn eightn ninetn + + + twenty + hundred thousand + + + million billion + trillion + +
+ + diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-width-ems-ref.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-width-ems-ref.xht deleted file mode 100644 index b3ca468106a..00000000000 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-width-ems-ref.xht +++ /dev/null @@ -1,59 +0,0 @@ - - - -multicolumn | column-width - - - - - - -
- - one two three four - five six seven eight - - - nineten eleven twelve - thirtn - - - fourtnfiftn sixtn - seventn eightn - - - ninetn twenty - hundred thousand - - - million billion - trillion - -
- - - diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-width-small-001.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-width-small-001.xht index 362aeb17f1e..c034815060b 100644 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-width-small-001.xht +++ b/tests/wpt/web-platform-tests/css/css-multicol/multicol-width-small-001.xht @@ -10,7 +10,7 @@
- Bl ac - - bl ue - - - bl ue - - Bl ac +
+ Bl ac + + bl ue + + + bl ue + + Bl ac +
- - -
Image download support must be enabled
+
- \ No newline at end of file + diff --git a/tests/wpt/web-platform-tests/css/css-multicol/multicol-zero-height-001.xht b/tests/wpt/web-platform-tests/css/css-multicol/multicol-zero-height-001.xht index 5cf3f12ea6f..4472bc209e2 100644 --- a/tests/wpt/web-platform-tests/css/css-multicol/multicol-zero-height-001.xht +++ b/tests/wpt/web-platform-tests/css/css-multicol/multicol-zero-height-001.xht @@ -5,6 +5,7 @@ + @@ -41,4 +35,4 @@
- \ No newline at end of file + diff --git a/tests/wpt/web-platform-tests/css/css-overflow/input-scrollable-region-001.html b/tests/wpt/web-platform-tests/css/css-overflow/input-scrollable-region-001.html new file mode 100644 index 00000000000..016f9b9278c --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-overflow/input-scrollable-region-001.html @@ -0,0 +1,26 @@ + + +CSS Input Text Padding and Overflow: css-overflow-3 + + + + + + + + diff --git a/tests/wpt/web-platform-tests/css/css-overflow/reference/input-scrollable-region-001-ref.html b/tests/wpt/web-platform-tests/css/css-overflow/reference/input-scrollable-region-001-ref.html new file mode 100644 index 00000000000..de894fab610 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-overflow/reference/input-scrollable-region-001-ref.html @@ -0,0 +1,21 @@ + + +CSS Basic User Interface Reference File + + + + + diff --git a/tests/wpt/web-platform-tests/css/css-paint-api/geometry-with-float-size-ref.html b/tests/wpt/web-platform-tests/css/css-paint-api/geometry-with-float-size-ref.html new file mode 100644 index 00000000000..c24a9d7bc0d --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-paint-api/geometry-with-float-size-ref.html @@ -0,0 +1,12 @@ + + + + + + + diff --git a/tests/wpt/web-platform-tests/css/css-paint-api/geometry-with-float-size.https.html b/tests/wpt/web-platform-tests/css/css-paint-api/geometry-with-float-size.https.html new file mode 100644 index 00000000000..6cd3ecada36 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-paint-api/geometry-with-float-size.https.html @@ -0,0 +1,35 @@ + + + + + + + + +
+ + + + + + diff --git a/tests/wpt/web-platform-tests/css/css-paint-api/registered-properties-in-custom-paint.https.html b/tests/wpt/web-platform-tests/css/css-paint-api/registered-properties-in-custom-paint.https.html index d77a33f0bc7..c446347557f 100644 --- a/tests/wpt/web-platform-tests/css/css-paint-api/registered-properties-in-custom-paint.https.html +++ b/tests/wpt/web-platform-tests/css/css-paint-api/registered-properties-in-custom-paint.https.html @@ -44,7 +44,7 @@ registerPaint('geometry', class { ctx.strokeStyle = 'red'; if (serializedStrings[1] != "--length-initial: [CSSUnitValue=20px]") ctx.strokeStyle = 'blue'; - if (serializedStrings[2] != "--number: [CSSStyleValue=10]") + if (serializedStrings[2] != "--number: [CSSUnitValue=10]") ctx.strokeStyle = 'yellow'; ctx.lineWidth = 4; ctx.strokeRect(0, 0, geom.width, geom.height); diff --git a/tests/wpt/web-platform-tests/css/css-paint-api/style-background-image.https.html b/tests/wpt/web-platform-tests/css/css-paint-api/style-background-image.https.html index 716c28c1606..cb894e57f2d 100644 --- a/tests/wpt/web-platform-tests/css/css-paint-api/style-background-image.https.html +++ b/tests/wpt/web-platform-tests/css/css-paint-api/style-background-image.https.html @@ -43,7 +43,7 @@ registerPaint('geometry', class { ctx.strokeStyle = 'green'; if (serializedStrings[0] != "--bar: [null]") ctx.strokeStyle = 'red'; - if (serializedStrings[1] != "--foo: [CSSStyleValue= bar]") + if (serializedStrings[1] != "--foo: [CSSUnparsedValue= bar]") ctx.strokeStyle = 'blue'; if (serializedStrings[2] != "align-items: [CSSKeywordValue=normal]") ctx.strokeStyle = 'yellow'; diff --git a/tests/wpt/web-platform-tests/css/css-paint-api/style-before-pseudo.https.html b/tests/wpt/web-platform-tests/css/css-paint-api/style-before-pseudo.https.html index 8ba4cdbc612..707d02ba41d 100644 --- a/tests/wpt/web-platform-tests/css/css-paint-api/style-before-pseudo.https.html +++ b/tests/wpt/web-platform-tests/css/css-paint-api/style-before-pseudo.https.html @@ -46,7 +46,7 @@ registerPaint('geometry', class { ctx.strokeStyle = 'green'; if (serializedStrings[0] != "--bar: [null]") ctx.strokeStyle = 'red'; - if (serializedStrings[1] != "--foo: [CSSStyleValue= bar]") + if (serializedStrings[1] != "--foo: [CSSUnparsedValue= bar]") ctx.strokeStyle = 'blue'; if (serializedStrings[2] != "border-radius: [CSSStyleValue=2px]") ctx.strokeStyle = 'yellow'; diff --git a/tests/wpt/web-platform-tests/css/css-position/position-sticky-offset-overflow.html b/tests/wpt/web-platform-tests/css/css-position/position-sticky-offset-overflow.html new file mode 100644 index 00000000000..f4afed406ae --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-position/position-sticky-offset-overflow.html @@ -0,0 +1,60 @@ + +Sticky positioning can cause overflow but must be accessible. + + + + + + + + +
+
+
+ +
+
+
+ + diff --git a/tests/wpt/web-platform-tests/css/css-position/position-sticky-table-parts-ref.html b/tests/wpt/web-platform-tests/css/css-position/position-sticky-table-parts-ref.html new file mode 100644 index 00000000000..e6988eef855 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-position/position-sticky-table-parts-ref.html @@ -0,0 +1,48 @@ + +Nested position:sticky table elements should render correctly + + + + +
+
+
+ + + + +
+
+
+
There should be a green square at the top of the scroll view and no red visible.
diff --git a/tests/wpt/web-platform-tests/css/css-position/position-sticky-table-parts.html b/tests/wpt/web-platform-tests/css/css-position/position-sticky-table-parts.html new file mode 100644 index 00000000000..c1cca833325 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-position/position-sticky-table-parts.html @@ -0,0 +1,72 @@ + +Nested position:sticky table elements should render correctly + + + + + + + + +
+
+
+ + + + + + + + + + +
+
+
+
There should be a green square at the top of the scroll view and no red visible.
diff --git a/tests/wpt/web-platform-tests/css/css-pseudo/marker-font-properties-ref.html b/tests/wpt/web-platform-tests/css/css-pseudo/marker-font-properties-ref.html index 093674d81b2..a8fb980ff09 100644 --- a/tests/wpt/web-platform-tests/css/css-pseudo/marker-font-properties-ref.html +++ b/tests/wpt/web-platform-tests/css/css-pseudo/marker-font-properties-ref.html @@ -5,6 +5,10 @@ CSS Test: ::marker formatting with font properties reference file - - -

This sentence must be green on a green background.

-

This sentence must be green on a green background.

- - diff --git a/tests/wpt/web-platform-tests/css/css-style-attr/style-attr-urls-003.xht b/tests/wpt/web-platform-tests/css/css-style-attr/style-attr-urls-003.xht index 893790418ae..d1326f87747 100644 --- a/tests/wpt/web-platform-tests/css/css-style-attr/style-attr-urls-003.xht +++ b/tests/wpt/web-platform-tests/css/css-style-attr/style-attr-urls-003.xht @@ -1,28 +1,23 @@ - CSS Test: URLs in style attributes (with xml:base and <base>) - + CSS Test: URLs in style attributes (with xml:base) - - - + + - + + -

+

This sentence must be green on a green background. - [Your UA does not support xml:base. This test is therefore Not Applicable.] -

-

- This sentence must be green on a green background. - [Your UA does not support xml:base. This test is therefore Not Applicable.]

diff --git a/tests/wpt/web-platform-tests/css/css-tables/zero-rowspan-001-ref.html b/tests/wpt/web-platform-tests/css/css-tables/zero-rowspan-001-ref.html new file mode 100644 index 00000000000..4f1dbdf96d3 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-tables/zero-rowspan-001-ref.html @@ -0,0 +1,11 @@ + +CSS Test: Reference Test + + + + + + + +
Foo
Foo
Foo
Foo
+ diff --git a/tests/wpt/web-platform-tests/css/css-tables/zero-rowspan-001.html b/tests/wpt/web-platform-tests/css/css-tables/zero-rowspan-001.html new file mode 100644 index 00000000000..bef5b947fcc --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-tables/zero-rowspan-001.html @@ -0,0 +1,12 @@ + +CSS Test: Overflow clipping in cells that span columns + + + + + + + + +
Foo
Foo
Foo
Foo
+ diff --git a/tests/wpt/web-platform-tests/css/css-tables/zero-rowspan-002-ref.html b/tests/wpt/web-platform-tests/css/css-tables/zero-rowspan-002-ref.html new file mode 100644 index 00000000000..3ccac78bd82 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-tables/zero-rowspan-002-ref.html @@ -0,0 +1,9 @@ + +CSS Test: Reference Test + + + + + + +
123
123
123
diff --git a/tests/wpt/web-platform-tests/css/css-tables/zero-rowspan-002.html b/tests/wpt/web-platform-tests/css/css-tables/zero-rowspan-002.html new file mode 100644 index 00000000000..7a79fc37b0a --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-tables/zero-rowspan-002.html @@ -0,0 +1,11 @@ + +CSS Test: Overflow clipping in cells that span columns + + + + + + + +
123
123
123
+ diff --git a/tests/wpt/web-platform-tests/css/css-text-decor/line-through-vertical.html b/tests/wpt/web-platform-tests/css/css-text-decor/line-through-vertical.html new file mode 100644 index 00000000000..633c5c00392 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text-decor/line-through-vertical.html @@ -0,0 +1,16 @@ + + + + + +
+ ABC + ABC +
diff --git a/tests/wpt/web-platform-tests/css/css-text-decor/reference/line-through-vertical-ref.html b/tests/wpt/web-platform-tests/css/css-text-decor/reference/line-through-vertical-ref.html new file mode 100644 index 00000000000..979512787a1 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text-decor/reference/line-through-vertical-ref.html @@ -0,0 +1,13 @@ + + +
+ ABC + ABC +
diff --git a/tests/wpt/web-platform-tests/css/css-text-decor/reference/text-decoration-color-recalc-ref.html b/tests/wpt/web-platform-tests/css/css-text-decor/reference/text-decoration-color-recalc-ref.html new file mode 100644 index 00000000000..7bc557337f3 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text-decor/reference/text-decoration-color-recalc-ref.html @@ -0,0 +1,12 @@ + + +

Test that changes in text-decoration-color are recalculated correctly. PASS +if the text below has a solid green underline, and no red.

+
+ Filler text +
diff --git a/tests/wpt/web-platform-tests/css/css-text-decor/reference/text-decoration-color-ref.html b/tests/wpt/web-platform-tests/css/css-text-decor/reference/text-decoration-color-ref.html new file mode 100644 index 00000000000..33272cbe1da --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text-decor/reference/text-decoration-color-ref.html @@ -0,0 +1,43 @@ + + + + CSS Test: CSS3 text-decoration-color + + + +

Each line of this test should match its text decoration color description:

+
Gray text with blue underline

+
Green text with black overline

+
Black text with gold line-through

+
+ + + Black text with blue underline, gray overline and green line-through + + +

+
+ subscript text + superscript text +

+
Transparent fill with black stroke text and green underline

+ + diff --git a/tests/wpt/web-platform-tests/css/css-text-decor/reference/text-decoration-line-recalc-ref.html b/tests/wpt/web-platform-tests/css/css-text-decor/reference/text-decoration-line-recalc-ref.html new file mode 100644 index 00000000000..92baa6bf433 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text-decor/reference/text-decoration-line-recalc-ref.html @@ -0,0 +1,12 @@ + + +

Test that changes in text-decoration-line are recalculated correctly. PASS +if the text below has a solid green overline, and no underline.

+
+ Filler text +
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-text-decor/reference/text-decoration-line-ref.html b/tests/wpt/web-platform-tests/css/css-text-decor/reference/text-decoration-line-ref.html new file mode 100644 index 00000000000..f14d25a70ba --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text-decor/reference/text-decoration-line-ref.html @@ -0,0 +1,33 @@ + + + + + +
Each line of this test should match its style description (text-decoration-line resets text-decoration, except when the latter is set as important):

+
This text is underlined (also inside span).

+
This text is overlined (also inside span).

+
This text has a line-through (also inside span).

+
This text contains no decorations.

+
This text is underlined.

+
This text contains no decorations.

+
This text is overlined.

+
This text contains no decorations.

+
This text has a line-through.

+
This text contains no decorations.

+
This text is underlined, overlined and has a line-through.

+
This text contains no decorations.

+
This text is overlined.

+
This text is overlined.

+
This text is underlined.
+
This text contains no decorations.

+
This text contains no decorations.

+
This text contains no decorations.

+
This text contains no decorations.

+ + diff --git a/tests/wpt/web-platform-tests/css/css-text-decor/reference/text-decoration-style-multiple-ref.html b/tests/wpt/web-platform-tests/css/css-text-decor/reference/text-decoration-style-multiple-ref.html new file mode 100644 index 00000000000..f80396930e1 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text-decor/reference/text-decoration-style-multiple-ref.html @@ -0,0 +1,19 @@ + + +
AAAAAAAAAAAA
diff --git a/tests/wpt/web-platform-tests/css/css-text-decor/reference/text-decoration-style-recalc-ref.html b/tests/wpt/web-platform-tests/css/css-text-decor/reference/text-decoration-style-recalc-ref.html new file mode 100644 index 00000000000..30592b44cec --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text-decor/reference/text-decoration-style-recalc-ref.html @@ -0,0 +1,12 @@ + + +

Test that changes in text-decoration-style are recalculated correctly. PASS +if the text below has a dashed green underline, and not a solid green underline.

+
+ Filler text +
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-text-decor/text-decoration-color-recalc.html b/tests/wpt/web-platform-tests/css/css-text-decor/text-decoration-color-recalc.html new file mode 100644 index 00000000000..b7cde934fcf --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text-decor/text-decoration-color-recalc.html @@ -0,0 +1,19 @@ + + + + + +

Test that changes in text-decoration-color are recalculated correctly. PASS +if the text below has a solid green underline, and no red.

+
+ Filler text +
diff --git a/tests/wpt/web-platform-tests/css/css-text-decor/text-decoration-color.html b/tests/wpt/web-platform-tests/css/css-text-decor/text-decoration-color.html new file mode 100644 index 00000000000..fd5bc5da3a8 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text-decor/text-decoration-color.html @@ -0,0 +1,64 @@ + + + + CSS Test: CSS3 text-decoration-color + + + + + +

Each line of this test should match its text decoration color description:

+ + +
Gray text with blue underline

+
Green text with black overline

+
Black text with gold line-through

+ + +
+ + + Black text with blue underline, gray overline and green line-through + + +

+ + +
+ + subscript text + superscript text + +

+ + +
Transparent fill with black stroke text and green underline

+ + diff --git a/tests/wpt/web-platform-tests/css/css-text-decor/text-decoration-line-recalc.html b/tests/wpt/web-platform-tests/css/css-text-decor/text-decoration-line-recalc.html new file mode 100644 index 00000000000..321aea9f3d9 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text-decor/text-decoration-line-recalc.html @@ -0,0 +1,19 @@ + + + + + +

Test that changes in text-decoration-line are recalculated correctly. PASS +if the text below has a solid green overline, and no underline.

+
+ Filler text +
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/css/css-text-decor/text-decoration-line.html b/tests/wpt/web-platform-tests/css/css-text-decor/text-decoration-line.html new file mode 100644 index 00000000000..ea6a0c86c19 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text-decor/text-decoration-line.html @@ -0,0 +1,35 @@ + + + + + + + +
Each line of this test should match its style description (text-decoration-line resets text-decoration, except when the latter is set as important):

+
This text is underlined (also inside span).

+
This text is overlined (also inside span).

+
This text has a line-through (also inside span).

+
This text contains no decorations.

+
This text is underlined.

+
This text contains no decorations.

+
This text is overlined.

+
This text contains no decorations.

+
This text has a line-through.

+
This text contains no decorations.

+
This text is underlined, overlined and has a line-through.

+
This text contains no decorations.

+
This text is overlined.

+
This text is overlined.

+
This text is underlined.
+
This text contains no decorations.

+
This text contains no decorations.

+
This text contains no decorations.

+
This text contains no decorations.

+ + diff --git a/tests/wpt/web-platform-tests/css/css-text-decor/text-decoration-serialization.tentative.html b/tests/wpt/web-platform-tests/css/css-text-decor/text-decoration-serialization.tentative.html new file mode 100644 index 00000000000..2f7b2f55fea --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text-decor/text-decoration-serialization.tentative.html @@ -0,0 +1,17 @@ + +text-decoration shorthand serialization + + + + +
+ diff --git a/tests/wpt/web-platform-tests/css/css-text-decor/text-decoration-style-multiple.html b/tests/wpt/web-platform-tests/css/css-text-decor/text-decoration-style-multiple.html new file mode 100644 index 00000000000..567229f6e57 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text-decor/text-decoration-style-multiple.html @@ -0,0 +1,21 @@ + + + + +
AAAAAAAAAAAA
diff --git a/tests/wpt/web-platform-tests/css/css-text-decor/text-decoration-style-recalc.html b/tests/wpt/web-platform-tests/css/css-text-decor/text-decoration-style-recalc.html new file mode 100644 index 00000000000..d4538e7c7b4 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text-decor/text-decoration-style-recalc.html @@ -0,0 +1,19 @@ + + + + + +

Test that changes in text-decoration-style are recalculated correctly. PASS +if the text below has a dashed green underline, and not a solid green underline.

+
+ Filler text +
diff --git a/tests/wpt/web-platform-tests/css/css-transforms/css-transform-inherit-scale.html b/tests/wpt/web-platform-tests/css/css-transforms/css-transform-inherit-scale.html index b4702f8fda2..fa9b5bbbc02 100644 --- a/tests/wpt/web-platform-tests/css/css-transforms/css-transform-inherit-scale.html +++ b/tests/wpt/web-platform-tests/css/css-transforms/css-transform-inherit-scale.html @@ -1,50 +1,49 @@ - + CSS Transforms Test: CSS transforms scale 2 inheritance on div elements - + - - -

The test passes if there is a green square and no red.

-
-
-
-
- + + +

Test passes if there is a filled green square and no red.

+
+
+
+
+
+
+ diff --git a/tests/wpt/web-platform-tests/css/css-transforms/transform-2d-getComputedStyle-001.html b/tests/wpt/web-platform-tests/css/css-transforms/transform-2d-getComputedStyle-001.html index 543dd9a1fee..a085b794fc4 100644 --- a/tests/wpt/web-platform-tests/css/css-transforms/transform-2d-getComputedStyle-001.html +++ b/tests/wpt/web-platform-tests/css/css-transforms/transform-2d-getComputedStyle-001.html @@ -45,15 +45,6 @@ transform: matrix(1, 2, 3, 4, 5, 6); } - diff --git a/tests/wpt/web-platform-tests/css/css-transforms/transform-box/fill-box-mutation.html b/tests/wpt/web-platform-tests/css/css-transforms/transform-box/fill-box-mutation.html new file mode 100644 index 00000000000..ae602e3509d --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-transforms/transform-box/fill-box-mutation.html @@ -0,0 +1,24 @@ + + +transform-box: fill-box, shape mutated + + + +

There should be a green 200x200 rectangle below, and no red.

+ + + + + diff --git a/tests/wpt/web-platform-tests/css/css-transforms/transform-box/fill-box.html b/tests/wpt/web-platform-tests/css/css-transforms/transform-box/fill-box.html new file mode 100644 index 00000000000..eaea02a5dfe --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-transforms/transform-box/fill-box.html @@ -0,0 +1,33 @@ + +transform-box: fill-box + + + +

There should be a green 200x200 rectangle below, and no red.

+ + + + + + diff --git a/tests/wpt/web-platform-tests/css/css-transforms/transform-box/support/greensquare200x200.html b/tests/wpt/web-platform-tests/css/css-transforms/transform-box/support/greensquare200x200.html new file mode 100644 index 00000000000..bee8bc70fe5 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-transforms/transform-box/support/greensquare200x200.html @@ -0,0 +1,3 @@ + +

There should be a green 200x200 rectangle below, and no red.

+
diff --git a/tests/wpt/web-platform-tests/css/css-transforms/transform-box/value-changed.html b/tests/wpt/web-platform-tests/css/css-transforms/transform-box/value-changed.html new file mode 100644 index 00000000000..825403ef7b6 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-transforms/transform-box/value-changed.html @@ -0,0 +1,19 @@ + + +transform-box: value change from 'view-box' to 'fill-box' + + +

There should be a green 200x200 rectangle below, and no red.

+ + + + + diff --git a/tests/wpt/web-platform-tests/css/css-transforms/transform-box/view-box-nested.html b/tests/wpt/web-platform-tests/css/css-transforms/transform-box/view-box-nested.html new file mode 100644 index 00000000000..7f59777f15b --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-transforms/transform-box/view-box-nested.html @@ -0,0 +1,17 @@ + +transform-box: view-box, relative to nested viewport + + + +

There should be a green 200x200 rectangle below, and no red.

+ + + + + + diff --git a/tests/wpt/web-platform-tests/css/css-transforms/transform-box/view-box-viewbox-nested.html b/tests/wpt/web-platform-tests/css/css-transforms/transform-box/view-box-viewbox-nested.html new file mode 100644 index 00000000000..4f667e20ba8 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-transforms/transform-box/view-box-viewbox-nested.html @@ -0,0 +1,17 @@ + +transform-box: view-box, relative to viewport defined by nested viewBox + + + +

There should be a green 200x200 rectangle below, and no red.

+ + + + + + diff --git a/tests/wpt/web-platform-tests/css/css-transforms/transform-box/view-box-viewbox.html b/tests/wpt/web-platform-tests/css/css-transforms/transform-box/view-box-viewbox.html new file mode 100644 index 00000000000..cd040c1ba33 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-transforms/transform-box/view-box-viewbox.html @@ -0,0 +1,15 @@ + +transform-box: view-box, relative to viewport defined by viewBox + + + +

There should be a green 200x200 rectangle below, and no red.

+ + + + diff --git a/tests/wpt/web-platform-tests/css/css-transforms/transform-box/view-box.html b/tests/wpt/web-platform-tests/css/css-transforms/transform-box/view-box.html new file mode 100644 index 00000000000..3345467c904 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-transforms/transform-box/view-box.html @@ -0,0 +1,33 @@ + +transform-box: view-box + + + +

There should be a green 200x200 rectangle below, and no red.

+ + + + + + diff --git a/tests/wpt/web-platform-tests/css/css-transitions/before-DOMContentLoaded-001.html b/tests/wpt/web-platform-tests/css/css-transitions/before-DOMContentLoaded-001.html index 4e6c3d112d3..152f77760cf 100644 --- a/tests/wpt/web-platform-tests/css/css-transitions/before-DOMContentLoaded-001.html +++ b/tests/wpt/web-platform-tests/css/css-transitions/before-DOMContentLoaded-001.html @@ -26,13 +26,6 @@ height: 100000px; } - - diff --git a/tests/wpt/web-platform-tests/css/css-transitions/before-load-001.html b/tests/wpt/web-platform-tests/css/css-transitions/before-load-001.html index 4cb43708978..ee633cf37c4 100644 --- a/tests/wpt/web-platform-tests/css/css-transitions/before-load-001.html +++ b/tests/wpt/web-platform-tests/css/css-transitions/before-load-001.html @@ -26,13 +26,6 @@ height: 100000px; } - - diff --git a/tests/wpt/web-platform-tests/css/css-transitions/changing-while-transition.html b/tests/wpt/web-platform-tests/css/css-transitions/changing-while-transition.html index 99a2bea201d..2e7d0bb1bf7 100644 --- a/tests/wpt/web-platform-tests/css/css-transitions/changing-while-transition.html +++ b/tests/wpt/web-platform-tests/css/css-transitions/changing-while-transition.html @@ -25,13 +25,6 @@ height: 100000px; } - - diff --git a/tests/wpt/web-platform-tests/css/css-transitions/currentcolor-animation-001.html b/tests/wpt/web-platform-tests/css/css-transitions/currentcolor-animation-001.html index 138fec656b7..e36e7481506 100644 --- a/tests/wpt/web-platform-tests/css/css-transitions/currentcolor-animation-001.html +++ b/tests/wpt/web-platform-tests/css/css-transitions/currentcolor-animation-001.html @@ -9,7 +9,6 @@ -
diff --git a/tests/wpt/web-platform-tests/css/css-transitions/detached-container-001.html b/tests/wpt/web-platform-tests/css/css-transitions/detached-container-001.html index 096147ea06f..efbc34f7774 100644 --- a/tests/wpt/web-platform-tests/css/css-transitions/detached-container-001.html +++ b/tests/wpt/web-platform-tests/css/css-transitions/detached-container-001.html @@ -26,13 +26,6 @@ height: 100000px; } - - diff --git a/tests/wpt/web-platform-tests/css/css-transitions/hidden-container-001.html b/tests/wpt/web-platform-tests/css/css-transitions/hidden-container-001.html index 6bb27ec02cb..4d17d4ad41e 100644 --- a/tests/wpt/web-platform-tests/css/css-transitions/hidden-container-001.html +++ b/tests/wpt/web-platform-tests/css/css-transitions/hidden-container-001.html @@ -22,13 +22,6 @@ display: none; } - - diff --git a/tests/wpt/web-platform-tests/css/css-transitions/properties-value-001.html b/tests/wpt/web-platform-tests/css/css-transitions/properties-value-001.html index ade0c0eca35..9182930ed78 100644 --- a/tests/wpt/web-platform-tests/css/css-transitions/properties-value-001.html +++ b/tests/wpt/web-platform-tests/css/css-transitions/properties-value-001.html @@ -27,573 +27,6 @@ height: 100000px; } - - diff --git a/tests/wpt/web-platform-tests/css/css-transitions/properties-value-002.html b/tests/wpt/web-platform-tests/css/css-transitions/properties-value-002.html index ca0277c8d09..7298070b1e3 100644 --- a/tests/wpt/web-platform-tests/css/css-transitions/properties-value-002.html +++ b/tests/wpt/web-platform-tests/css/css-transitions/properties-value-002.html @@ -27,29 +27,6 @@ height: 100000px; } - - diff --git a/tests/wpt/web-platform-tests/css/css-transitions/properties-value-003.html b/tests/wpt/web-platform-tests/css/css-transitions/properties-value-003.html index e32cd36f211..23385d15817 100644 --- a/tests/wpt/web-platform-tests/css/css-transitions/properties-value-003.html +++ b/tests/wpt/web-platform-tests/css/css-transitions/properties-value-003.html @@ -27,203 +27,6 @@ height: 100000px; } - - diff --git a/tests/wpt/web-platform-tests/css/css-transitions/properties-value-auto-001.html b/tests/wpt/web-platform-tests/css/css-transitions/properties-value-auto-001.html index fd4befc055b..087f6bbb3fa 100644 --- a/tests/wpt/web-platform-tests/css/css-transitions/properties-value-auto-001.html +++ b/tests/wpt/web-platform-tests/css/css-transitions/properties-value-auto-001.html @@ -26,63 +26,6 @@ height: 100000px; } - - diff --git a/tests/wpt/web-platform-tests/css/css-transitions/properties-value-implicit-001.html b/tests/wpt/web-platform-tests/css/css-transitions/properties-value-implicit-001.html index 26d37803129..4d93083434d 100644 --- a/tests/wpt/web-platform-tests/css/css-transitions/properties-value-implicit-001.html +++ b/tests/wpt/web-platform-tests/css/css-transitions/properties-value-implicit-001.html @@ -26,71 +26,6 @@ height: 100000px; } - - diff --git a/tests/wpt/web-platform-tests/css/css-transitions/properties-value-inherit-001.html b/tests/wpt/web-platform-tests/css/css-transitions/properties-value-inherit-001.html index 97d497f036c..2de40b4cc4e 100644 --- a/tests/wpt/web-platform-tests/css/css-transitions/properties-value-inherit-001.html +++ b/tests/wpt/web-platform-tests/css/css-transitions/properties-value-inherit-001.html @@ -26,573 +26,6 @@ height: 100000px; } - - diff --git a/tests/wpt/web-platform-tests/css/css-transitions/properties-value-inherit-002.html b/tests/wpt/web-platform-tests/css/css-transitions/properties-value-inherit-002.html index 14a36d513e8..f2741bd16e1 100644 --- a/tests/wpt/web-platform-tests/css/css-transitions/properties-value-inherit-002.html +++ b/tests/wpt/web-platform-tests/css/css-transitions/properties-value-inherit-002.html @@ -26,573 +26,6 @@ height: 100000px; } - - diff --git a/tests/wpt/web-platform-tests/css/css-transitions/properties-value-inherit-003.html b/tests/wpt/web-platform-tests/css/css-transitions/properties-value-inherit-003.html index d8d3e8eb75b..43d0229613a 100644 --- a/tests/wpt/web-platform-tests/css/css-transitions/properties-value-inherit-003.html +++ b/tests/wpt/web-platform-tests/css/css-transitions/properties-value-inherit-003.html @@ -26,71 +26,6 @@ height: 100000px; } - - diff --git a/tests/wpt/web-platform-tests/css/css-transitions/pseudo-elements-001.html b/tests/wpt/web-platform-tests/css/css-transitions/pseudo-elements-001.html index ceaff564077..cf1d2545b24 100644 --- a/tests/wpt/web-platform-tests/css/css-transitions/pseudo-elements-001.html +++ b/tests/wpt/web-platform-tests/css/css-transitions/pseudo-elements-001.html @@ -28,15 +28,6 @@ height: 100000px; } - - diff --git a/tests/wpt/web-platform-tests/css/css-transitions/transition-001.html b/tests/wpt/web-platform-tests/css/css-transitions/transition-001.html index 8b27eb21596..bf01393bbba 100644 --- a/tests/wpt/web-platform-tests/css/css-transitions/transition-001.html +++ b/tests/wpt/web-platform-tests/css/css-transitions/transition-001.html @@ -13,23 +13,6 @@ - - diff --git a/tests/wpt/web-platform-tests/css/css-transitions/transition-delay-001.html b/tests/wpt/web-platform-tests/css/css-transitions/transition-delay-001.html index d58b003d974..921525ea72d 100644 --- a/tests/wpt/web-platform-tests/css/css-transitions/transition-delay-001.html +++ b/tests/wpt/web-platform-tests/css/css-transitions/transition-delay-001.html @@ -14,32 +14,6 @@ - - diff --git a/tests/wpt/web-platform-tests/css/css-transitions/transition-duration-001.html b/tests/wpt/web-platform-tests/css/css-transitions/transition-duration-001.html index 9b7fe1e0b4d..b5c095f001e 100644 --- a/tests/wpt/web-platform-tests/css/css-transitions/transition-duration-001.html +++ b/tests/wpt/web-platform-tests/css/css-transitions/transition-duration-001.html @@ -14,32 +14,6 @@ - - diff --git a/tests/wpt/web-platform-tests/css/css-transitions/transition-property-001.html b/tests/wpt/web-platform-tests/css/css-transitions/transition-property-001.html index ad078bc1b45..47a1417070f 100644 --- a/tests/wpt/web-platform-tests/css/css-transitions/transition-property-001.html +++ b/tests/wpt/web-platform-tests/css/css-transitions/transition-property-001.html @@ -13,16 +13,6 @@ - - diff --git a/tests/wpt/web-platform-tests/css/css-transitions/transition-property-002.html b/tests/wpt/web-platform-tests/css/css-transitions/transition-property-002.html index 504b0a0ba63..99196b6d1d4 100644 --- a/tests/wpt/web-platform-tests/css/css-transitions/transition-property-002.html +++ b/tests/wpt/web-platform-tests/css/css-transitions/transition-property-002.html @@ -13,18 +13,6 @@ - - diff --git a/tests/wpt/web-platform-tests/css/css-transitions/transition-timing-function-001.html b/tests/wpt/web-platform-tests/css/css-transitions/transition-timing-function-001.html index c51ac05c711..68669c7d126 100644 --- a/tests/wpt/web-platform-tests/css/css-transitions/transition-timing-function-001.html +++ b/tests/wpt/web-platform-tests/css/css-transitions/transition-timing-function-001.html @@ -13,31 +13,6 @@ - - diff --git a/tests/wpt/web-platform-tests/css/css-typed-om/factory-absolute-length.html b/tests/wpt/web-platform-tests/css/css-typed-om/factory-absolute-length.html index a65cf5d44e3..5712ca99f8e 100644 --- a/tests/wpt/web-platform-tests/css/css-typed-om/factory-absolute-length.html +++ b/tests/wpt/web-platform-tests/css/css-typed-om/factory-absolute-length.html @@ -26,11 +26,11 @@ }, 'CSS.mm() produces mm length'); test(function(){ - var length = CSS.q(30); + var length = CSS.Q(30); assert_true(length instanceof CSSUnitValue); assert_equals(length.value, 30); assert_equals(length.unit, 'q'); - }, 'CSS.q() produces q length'); + }, 'CSS.Q() produces q length'); test(function(){ var length = CSS.in(40); diff --git a/tests/wpt/web-platform-tests/css/css-typed-om/styleMap-update-function.html b/tests/wpt/web-platform-tests/css/css-typed-om/styleMap-update-function.html index 4dea0095120..19f63997694 100644 --- a/tests/wpt/web-platform-tests/css/css-typed-om/styleMap-update-function.html +++ b/tests/wpt/web-platform-tests/css/css-typed-om/styleMap-update-function.html @@ -10,7 +10,7 @@ diff --git a/tests/wpt/web-platform-tests/css/css-typed-om/stylevalue-objects/interface.html b/tests/wpt/web-platform-tests/css/css-typed-om/stylevalue-objects/interface.html new file mode 100644 index 00000000000..8d346b1ab9a --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-typed-om/stylevalue-objects/interface.html @@ -0,0 +1,21 @@ + + +CSSStyleValue IDL + + + + + + + diff --git a/tests/wpt/web-platform-tests/css/css-typed-om/stylevalue-subclasses/cssKeywordValue-interface.html b/tests/wpt/web-platform-tests/css/css-typed-om/stylevalue-subclasses/cssKeywordValue-interface.html new file mode 100644 index 00000000000..444e08093ed --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-typed-om/stylevalue-subclasses/cssKeywordValue-interface.html @@ -0,0 +1,24 @@ + + +CSSKeywordValue IDL + + + + + + + diff --git a/tests/wpt/web-platform-tests/css/css-values/calc-unit-analysis.html b/tests/wpt/web-platform-tests/css/css-values/calc-unit-analysis.html index 346a8292ade..1520b4d3fa2 100644 --- a/tests/wpt/web-platform-tests/css/css-values/calc-unit-analysis.html +++ b/tests/wpt/web-platform-tests/css/css-values/calc-unit-analysis.html @@ -9,19 +9,6 @@ -
diff --git a/tests/wpt/web-platform-tests/css/css-values/iframe/vh-support-transform-origin-iframe.html b/tests/wpt/web-platform-tests/css/css-values/support/vh-support-transform-origin-iframe.html similarity index 100% rename from tests/wpt/web-platform-tests/css/css-values/iframe/vh-support-transform-origin-iframe.html rename to tests/wpt/web-platform-tests/css/css-values/support/vh-support-transform-origin-iframe.html diff --git a/tests/wpt/web-platform-tests/css/css-values/iframe/vh-support-transform-translate-iframe.html b/tests/wpt/web-platform-tests/css/css-values/support/vh-support-transform-translate-iframe.html similarity index 100% rename from tests/wpt/web-platform-tests/css/css-values/iframe/vh-support-transform-translate-iframe.html rename to tests/wpt/web-platform-tests/css/css-values/support/vh-support-transform-translate-iframe.html diff --git a/tests/wpt/web-platform-tests/css/css-values/vh-support-transform-origin.html b/tests/wpt/web-platform-tests/css/css-values/vh-support-transform-origin.html index 4b06a09fc36..38d17d2fdc8 100644 --- a/tests/wpt/web-platform-tests/css/css-values/vh-support-transform-origin.html +++ b/tests/wpt/web-platform-tests/css/css-values/vh-support-transform-origin.html @@ -36,7 +36,7 @@ - + diff --git a/tests/wpt/web-platform-tests/css/css-values/vh-support-transform-translate.html b/tests/wpt/web-platform-tests/css/css-values/vh-support-transform-translate.html index e273026a02c..900b653d494 100644 --- a/tests/wpt/web-platform-tests/css/css-values/vh-support-transform-translate.html +++ b/tests/wpt/web-platform-tests/css/css-values/vh-support-transform-translate.html @@ -36,7 +36,7 @@ - + diff --git a/tests/wpt/web-platform-tests/css/css-variables/test_variable_legal_values.html b/tests/wpt/web-platform-tests/css/css-variables/test_variable_legal_values.html index 0b39c248b57..2e074389f7a 100644 --- a/tests/wpt/web-platform-tests/css/css-variables/test_variable_legal_values.html +++ b/tests/wpt/web-platform-tests/css/css-variables/test_variable_legal_values.html @@ -9,33 +9,6 @@ -
diff --git a/tests/wpt/web-platform-tests/css/css-writing-modes/bidi-table-001.html b/tests/wpt/web-platform-tests/css/css-writing-modes/bidi-table-001.html index fc6902a0367..5e2ae76b2c3 100644 --- a/tests/wpt/web-platform-tests/css/css-writing-modes/bidi-table-001.html +++ b/tests/wpt/web-platform-tests/css/css-writing-modes/bidi-table-001.html @@ -6,6 +6,7 @@ + @@ -36,10 +37,11 @@ Key to entities used below:
-
+

 > a > ב > c >
 > א > b > ג >
 > a > ב > c >
+
 
@@ -55,4 +57,4 @@ Key to entities used below: - \ No newline at end of file + diff --git a/tests/wpt/web-platform-tests/css/cssom-view/elementFromPosition.html b/tests/wpt/web-platform-tests/css/cssom-view/elementFromPosition.html index d4da36ff1f7..ed86d16b7de 100644 --- a/tests/wpt/web-platform-tests/css/cssom-view/elementFromPosition.html +++ b/tests/wpt/web-platform-tests/css/cssom-view/elementFromPosition.html @@ -8,26 +8,6 @@ - @@ -139,5 +119,3 @@ - - diff --git a/tests/wpt/web-platform-tests/css/cssom-view/offsetParent_element_test.html b/tests/wpt/web-platform-tests/css/cssom-view/offsetParent_element_test.html index aa4a1e55e27..bb5686d41da 100644 --- a/tests/wpt/web-platform-tests/css/cssom-view/offsetParent_element_test.html +++ b/tests/wpt/web-platform-tests/css/cssom-view/offsetParent_element_test.html @@ -8,12 +8,6 @@ - +
+
+
+
+
+
+ diff --git a/tests/wpt/web-platform-tests/css/cssom-view/scrollTop-display-change-ref.html b/tests/wpt/web-platform-tests/css/cssom-view/scrollTop-display-change-ref.html new file mode 100644 index 00000000000..9f1259787bb --- /dev/null +++ b/tests/wpt/web-platform-tests/css/cssom-view/scrollTop-display-change-ref.html @@ -0,0 +1,8 @@ + + +
+
+ I should be visible. +
+ I should not be visible. +
diff --git a/tests/wpt/web-platform-tests/css/cssom-view/scrollTop-display-change.html b/tests/wpt/web-platform-tests/css/cssom-view/scrollTop-display-change.html new file mode 100644 index 00000000000..916bfecfeb5 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/cssom-view/scrollTop-display-change.html @@ -0,0 +1,17 @@ + + +Setting scrollTop to 0 immediately after toggling display from "none" on an element that had nonzero scrollTop before should work. + +
+
+ I should be visible. +
+ I should not be visible. +
+ diff --git a/tests/wpt/web-platform-tests/css/cssom-view/scrollWidthHeight.xht b/tests/wpt/web-platform-tests/css/cssom-view/scrollWidthHeight.xht index b4696e13630..77b01dbf50b 100644 --- a/tests/wpt/web-platform-tests/css/cssom-view/scrollWidthHeight.xht +++ b/tests/wpt/web-platform-tests/css/cssom-view/scrollWidthHeight.xht @@ -38,21 +38,6 @@ height:150px; } ]]> - diff --git a/tests/wpt/web-platform-tests/css/cssom-view/scrollWidthHeightWhenNotScrollable.xht b/tests/wpt/web-platform-tests/css/cssom-view/scrollWidthHeightWhenNotScrollable.xht index e8c7f1298bc..f0fd373b1de 100644 --- a/tests/wpt/web-platform-tests/css/cssom-view/scrollWidthHeightWhenNotScrollable.xht +++ b/tests/wpt/web-platform-tests/css/cssom-view/scrollWidthHeightWhenNotScrollable.xht @@ -37,21 +37,6 @@ height:150px; } ]]> - diff --git a/tests/wpt/web-platform-tests/css/cssom-view/window-interface.xht b/tests/wpt/web-platform-tests/css/cssom-view/window-interface.xht index 2ed64cba6e6..163124b6e78 100644 --- a/tests/wpt/web-platform-tests/css/cssom-view/window-interface.xht +++ b/tests/wpt/web-platform-tests/css/cssom-view/window-interface.xht @@ -13,22 +13,6 @@
-
diff --git a/tests/wpt/web-platform-tests/css/cssom/computed-style-001.html b/tests/wpt/web-platform-tests/css/cssom/computed-style-001.html index 2cdfc9eb8b4..80bf06c300e 100644 --- a/tests/wpt/web-platform-tests/css/cssom/computed-style-001.html +++ b/tests/wpt/web-platform-tests/css/cssom/computed-style-001.html @@ -23,14 +23,6 @@ height: 100px; } - diff --git a/tests/wpt/web-platform-tests/css/cssom/getComputedStyle-pseudo.html b/tests/wpt/web-platform-tests/css/cssom/getComputedStyle-pseudo.html index fa358d6d3d3..ec7a863a94c 100644 --- a/tests/wpt/web-platform-tests/css/cssom/getComputedStyle-pseudo.html +++ b/tests/wpt/web-platform-tests/css/cssom/getComputedStyle-pseudo.html @@ -38,12 +38,19 @@ #flex-no-pseudo { display: flex; } +#contents-pseudos::before, +#contents-pseudos::after { + display: contents; + content: "foo"; + position: absolute; +}
+
diff --git a/tests/wpt/web-platform-tests/css/cssom/inline-style-001.html b/tests/wpt/web-platform-tests/css/cssom/inline-style-001.html index 3a9eebf7e72..b8b1aaaf707 100644 --- a/tests/wpt/web-platform-tests/css/cssom/inline-style-001.html +++ b/tests/wpt/web-platform-tests/css/cssom/inline-style-001.html @@ -9,22 +9,6 @@ -
diff --git a/tests/wpt/web-platform-tests/css/cssom/medialist-dynamic-001-ref.html b/tests/wpt/web-platform-tests/css/cssom/medialist-dynamic-001-ref.html new file mode 100644 index 00000000000..9715b5acb8f --- /dev/null +++ b/tests/wpt/web-platform-tests/css/cssom/medialist-dynamic-001-ref.html @@ -0,0 +1,5 @@ + + +CSS Test Reference + +Should not be red. diff --git a/tests/wpt/web-platform-tests/css/cssom/medialist-dynamic-001.html b/tests/wpt/web-platform-tests/css/cssom/medialist-dynamic-001.html new file mode 100644 index 00000000000..ab9c1345680 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/cssom/medialist-dynamic-001.html @@ -0,0 +1,12 @@ + + +CSS Test: Dynamic changes to the stylesheet media attributes via CSSOM get reflected + + + + +Should not be red. + diff --git a/tests/wpt/web-platform-tests/css/cssom/medialist-interfaces-001.html b/tests/wpt/web-platform-tests/css/cssom/medialist-interfaces-001.html index ad95394d5c5..f5dbb569538 100644 --- a/tests/wpt/web-platform-tests/css/cssom/medialist-interfaces-001.html +++ b/tests/wpt/web-platform-tests/css/cssom/medialist-interfaces-001.html @@ -9,30 +9,6 @@ - diff --git a/tests/wpt/web-platform-tests/css/cssom/medialist-interfaces-002.html b/tests/wpt/web-platform-tests/css/cssom/medialist-interfaces-002.html index d3dfff8e42b..bba25a1ebb5 100644 --- a/tests/wpt/web-platform-tests/css/cssom/medialist-interfaces-002.html +++ b/tests/wpt/web-platform-tests/css/cssom/medialist-interfaces-002.html @@ -9,15 +9,6 @@ - - - diff --git a/tests/wpt/web-platform-tests/css/cssom/medialist-interfaces-003.html b/tests/wpt/web-platform-tests/css/cssom/medialist-interfaces-003.html index 717c39d618f..649f9485f44 100644 --- a/tests/wpt/web-platform-tests/css/cssom/medialist-interfaces-003.html +++ b/tests/wpt/web-platform-tests/css/cssom/medialist-interfaces-003.html @@ -10,16 +10,6 @@ -
diff --git a/tests/wpt/web-platform-tests/css/cssom/medialist-interfaces-004.html b/tests/wpt/web-platform-tests/css/cssom/medialist-interfaces-004.html index 2fe6ff915d7..416addae7b5 100644 --- a/tests/wpt/web-platform-tests/css/cssom/medialist-interfaces-004.html +++ b/tests/wpt/web-platform-tests/css/cssom/medialist-interfaces-004.html @@ -8,14 +8,6 @@ - - - diff --git a/tests/wpt/web-platform-tests/css/cssom/setproperty-null-undefined.html b/tests/wpt/web-platform-tests/css/cssom/setproperty-null-undefined.html new file mode 100644 index 00000000000..3de142c0b46 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/cssom/setproperty-null-undefined.html @@ -0,0 +1,47 @@ + + + + + + + + + + + diff --git a/tests/wpt/web-platform-tests/css/cssom/style-sheet-interfaces-001.html b/tests/wpt/web-platform-tests/css/cssom/style-sheet-interfaces-001.html index fb1fde86eff..79c485038dd 100644 --- a/tests/wpt/web-platform-tests/css/cssom/style-sheet-interfaces-001.html +++ b/tests/wpt/web-platform-tests/css/cssom/style-sheet-interfaces-001.html @@ -13,31 +13,6 @@ * { margin: 0; padding: 0; } - diff --git a/tests/wpt/web-platform-tests/css/cssom/style-sheet-interfaces-002.html b/tests/wpt/web-platform-tests/css/cssom/style-sheet-interfaces-002.html index ad5b1ac5861..51b0eb336be 100644 --- a/tests/wpt/web-platform-tests/css/cssom/style-sheet-interfaces-002.html +++ b/tests/wpt/web-platform-tests/css/cssom/style-sheet-interfaces-002.html @@ -13,15 +13,6 @@ - diff --git a/tests/wpt/web-platform-tests/css/cssom/ttwf-cssom-doc-ext-load-count.html b/tests/wpt/web-platform-tests/css/cssom/ttwf-cssom-doc-ext-load-count.html index f507a961032..5296aa3a8bc 100644 --- a/tests/wpt/web-platform-tests/css/cssom/ttwf-cssom-doc-ext-load-count.html +++ b/tests/wpt/web-platform-tests/css/cssom/ttwf-cssom-doc-ext-load-count.html @@ -11,13 +11,6 @@ -
diff --git a/tests/wpt/web-platform-tests/css/mediaqueries/mq-calc-002.html b/tests/wpt/web-platform-tests/css/mediaqueries/mq-calc-002.html index 60fb1ca4b25..f6f2fc15039 100644 --- a/tests/wpt/web-platform-tests/css/mediaqueries/mq-calc-002.html +++ b/tests/wpt/web-platform-tests/css/mediaqueries/mq-calc-002.html @@ -19,11 +19,19 @@ @media (min-width: calc(1em)){ div { background-color: green; } } - +

Test passes if there is a filled green square and no red.

+ + diff --git a/tests/wpt/web-platform-tests/css/mediaqueries/mq-calc-003.html b/tests/wpt/web-platform-tests/css/mediaqueries/mq-calc-003.html index 785570c8537..cadc448efe5 100644 --- a/tests/wpt/web-platform-tests/css/mediaqueries/mq-calc-003.html +++ b/tests/wpt/web-platform-tests/css/mediaqueries/mq-calc-003.html @@ -19,11 +19,19 @@ @media (min-width: calc(1ex)){ div { background-color: green; } } - +

Test passes if there is a filled green square and no red.

+ + diff --git a/tests/wpt/web-platform-tests/css/mediaqueries/mq-calc-004.html b/tests/wpt/web-platform-tests/css/mediaqueries/mq-calc-004.html index f3b5fbf6ed0..63190347b65 100644 --- a/tests/wpt/web-platform-tests/css/mediaqueries/mq-calc-004.html +++ b/tests/wpt/web-platform-tests/css/mediaqueries/mq-calc-004.html @@ -16,14 +16,19 @@ height: 100px; background-color: red; } - @media (min-width: calc(1ch)){ - div { background-color: green; } - }

Test passes if there is a filled green square and no red.

+ + diff --git a/tests/wpt/web-platform-tests/css/mediaqueries/mq-calc-005.html b/tests/wpt/web-platform-tests/css/mediaqueries/mq-calc-005.html index 234865f9730..df7409b7481 100644 --- a/tests/wpt/web-platform-tests/css/mediaqueries/mq-calc-005.html +++ b/tests/wpt/web-platform-tests/css/mediaqueries/mq-calc-005.html @@ -16,14 +16,19 @@ height: 100px; background-color: red; } - @media (min-width: calc(1rem)){ - div { background-color: green; } - }

Test passes if there is a filled green square and no red.

+ + diff --git a/tests/wpt/web-platform-tests/css/mediaqueries/relative-units-001.html b/tests/wpt/web-platform-tests/css/mediaqueries/relative-units-001.html index 74821418acd..fac94d78edf 100644 --- a/tests/wpt/web-platform-tests/css/mediaqueries/relative-units-001.html +++ b/tests/wpt/web-platform-tests/css/mediaqueries/relative-units-001.html @@ -16,11 +16,6 @@ body { background: red; } -@media (min-width: 1rem) { - body { - background: green; - } -} p { font-size: 24px; } @@ -28,5 +23,15 @@ p {

This should have a green background.

+ + diff --git a/tests/wpt/web-platform-tests/css/mediaqueries/relative-units-002.html b/tests/wpt/web-platform-tests/css/mediaqueries/relative-units-002.html index 40af3b67631..310e18f5242 100644 --- a/tests/wpt/web-platform-tests/css/mediaqueries/relative-units-002.html +++ b/tests/wpt/web-platform-tests/css/mediaqueries/relative-units-002.html @@ -16,11 +16,6 @@ body { background: red; } -@media (min-width: 1em) { - body { - background: green; - } -} p { font-size: 24px; } @@ -28,5 +23,15 @@ p {

This should have a green background.

+ + diff --git a/tests/wpt/web-platform-tests/css/mediaqueries/relative-units-003.html b/tests/wpt/web-platform-tests/css/mediaqueries/relative-units-003.html index 1ee2a90b63c..461db324224 100644 --- a/tests/wpt/web-platform-tests/css/mediaqueries/relative-units-003.html +++ b/tests/wpt/web-platform-tests/css/mediaqueries/relative-units-003.html @@ -16,11 +16,6 @@ body { background: red; } -@media (min-width: 1ex) { - body { - background: green; - } -} p { font-size: 24px; } @@ -28,5 +23,15 @@ p {

This should have a green background.

+ + diff --git a/tests/wpt/web-platform-tests/css/mediaqueries/relative-units-004.html b/tests/wpt/web-platform-tests/css/mediaqueries/relative-units-004.html index 9db6821bd02..b0f3765358d 100644 --- a/tests/wpt/web-platform-tests/css/mediaqueries/relative-units-004.html +++ b/tests/wpt/web-platform-tests/css/mediaqueries/relative-units-004.html @@ -16,11 +16,6 @@ body { background: red; } -@media (min-width: 1ch) { - body { - background: green; - } -} p { font-size: 24px; } @@ -28,5 +23,15 @@ p {

This should have a green background.

+ + diff --git a/tests/wpt/web-platform-tests/css/mediaqueries/test_media_queries.html b/tests/wpt/web-platform-tests/css/mediaqueries/test_media_queries.html index 44161acef01..a305d7a032b 100644 --- a/tests/wpt/web-platform-tests/css/mediaqueries/test_media_queries.html +++ b/tests/wpt/web-platform-tests/css/mediaqueries/test_media_queries.html @@ -8,373 +8,6 @@ -
@@ -394,7 +27,7 @@ function run() { function query_applies(q) { style.setAttribute("media", q); - return body_cs.getPropertyValue("text-decoration") == "underline"; + return body_cs.getPropertyValue("text-decoration-line") == "underline"; } function should_apply(q) { diff --git a/tests/wpt/web-platform-tests/css/motion/animation/offset-path-interpolation-001.html b/tests/wpt/web-platform-tests/css/motion/animation/offset-path-interpolation-001.html new file mode 100644 index 00000000000..279152e1033 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/motion/animation/offset-path-interpolation-001.html @@ -0,0 +1,110 @@ + + + + + offset-distance interpolation + + + + + + + + + + + diff --git a/tests/wpt/web-platform-tests/css/motion/animation/offset-path-interpolation-002.html b/tests/wpt/web-platform-tests/css/motion/animation/offset-path-interpolation-002.html new file mode 100644 index 00000000000..742e9d0a9ed --- /dev/null +++ b/tests/wpt/web-platform-tests/css/motion/animation/offset-path-interpolation-002.html @@ -0,0 +1,93 @@ + + + + + offset-distance interpolation + + + + + + + + + + + diff --git a/tests/wpt/web-platform-tests/css/motion/animation/offset-path-interpolation-003.html b/tests/wpt/web-platform-tests/css/motion/animation/offset-path-interpolation-003.html new file mode 100644 index 00000000000..a6d4e89efd0 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/motion/animation/offset-path-interpolation-003.html @@ -0,0 +1,118 @@ + + + + + offset-distance interpolation + + + + + + + + + + + diff --git a/tests/wpt/web-platform-tests/css/motion/animation/offset-path-interpolation-004.html b/tests/wpt/web-platform-tests/css/motion/animation/offset-path-interpolation-004.html new file mode 100644 index 00000000000..f3e07ab97b4 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/motion/animation/offset-path-interpolation-004.html @@ -0,0 +1,123 @@ + + + + + offset-distance interpolation + + + + + + + + + + + diff --git a/tests/wpt/web-platform-tests/css/motion/animation/offset-path-interpolation-005.html b/tests/wpt/web-platform-tests/css/motion/animation/offset-path-interpolation-005.html new file mode 100644 index 00000000000..617fff0490d --- /dev/null +++ b/tests/wpt/web-platform-tests/css/motion/animation/offset-path-interpolation-005.html @@ -0,0 +1,81 @@ + + + + + offset-distance interpolation + + + + + + + + + + + diff --git a/tests/wpt/web-platform-tests/css/reference/nothing.html b/tests/wpt/web-platform-tests/css/reference/nothing.html new file mode 100644 index 00000000000..98ee818a846 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/reference/nothing.html @@ -0,0 +1,4 @@ + +CSS Reftest Reference + +

There should be nothing below.

diff --git a/tests/wpt/web-platform-tests/css/reference/ref-filled-green-100px-square-only.html b/tests/wpt/web-platform-tests/css/reference/ref-filled-green-100px-square-only.html new file mode 100644 index 00000000000..82fcaa3b2aa --- /dev/null +++ b/tests/wpt/web-platform-tests/css/reference/ref-filled-green-100px-square-only.html @@ -0,0 +1,4 @@ + + +

Test passes if there is a filled green square.

+
diff --git a/tests/wpt/web-platform-tests/css/selectors/any-link-dynamic-001-ref.html b/tests/wpt/web-platform-tests/css/selectors/any-link-dynamic-001-ref.html new file mode 100644 index 00000000000..b5407429be8 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/selectors/any-link-dynamic-001-ref.html @@ -0,0 +1,10 @@ + + +CSS test reference + + + + This should be green + diff --git a/tests/wpt/web-platform-tests/css/selectors/any-link-dynamic-001.html b/tests/wpt/web-platform-tests/css/selectors/any-link-dynamic-001.html new file mode 100644 index 00000000000..e84989fd0c2 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/selectors/any-link-dynamic-001.html @@ -0,0 +1,14 @@ + + +CSS test: Handling of dynamic changes to :any-link selectors + + + + + + This should be green + diff --git a/tests/wpt/web-platform-tests/css/selectors/invalidation/any-link-pseudo.html b/tests/wpt/web-platform-tests/css/selectors/invalidation/any-link-pseudo.html new file mode 100644 index 00000000000..9792fd0ebe1 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/selectors/invalidation/any-link-pseudo.html @@ -0,0 +1,36 @@ + + + + CSS Selectors Invalidation: :any-link + + + + + + + This link should have a green background. +
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/custom-elements/parser/parser-uses-registry-of-owner-document.html b/tests/wpt/web-platform-tests/custom-elements/parser/parser-uses-registry-of-owner-document.html index efdc3a2a47c..51e3e5ddfb1 100644 --- a/tests/wpt/web-platform-tests/custom-elements/parser/parser-uses-registry-of-owner-document.html +++ b/tests/wpt/web-platform-tests/custom-elements/parser/parser-uses-registry-of-owner-document.html @@ -8,6 +8,7 @@ +
@@ -71,17 +72,14 @@ test(function () { document.body.removeChild(iframe); test(function () { - var windowlessDocument = document.implementation.createHTMLDocument(); - windowlessDocument.open(); - windowlessDocument.write(''); - windowlessDocument.close(); + var windowlessDocument = (new DOMParser()).parseFromString('', "text/html"); var instance = windowlessDocument.querySelector('my-custom-element'); assert_true(instance instanceof HTMLElement); assert_false(instance instanceof MyCustomElement); -}, 'HTML parser must use the registry of window.document in a document created by document.implementation.createHTMLDocument()'); +}, 'HTML parser must use the registry of window.document in a document created by DOMParser'); test(function () { var windowlessDocument = document.implementation.createDocument ('http://www.w3.org/1999/xhtml', 'html', null); @@ -108,19 +106,51 @@ test(function () { promise_test(function () { return new Promise(function (resolve, reject) { var xhr = new XMLHttpRequest(); - xhr.open('GET', '../resources/empty-html-document.html'); + xhr.open('GET', '../resources/my-custom-element-html-document.html'); xhr.overrideMimeType('text/xml'); xhr.onload = function () { resolve(xhr.responseXML); } xhr.onerror = function () { reject('Failed to fetch the document'); } xhr.send(); }).then(function (doc) { - doc.documentElement.innerHTML = ''; var instance = doc.querySelector('my-custom-element'); assert_true(instance instanceof Element); - assert_false(instance instanceof MyCustomElement); + assert_false(instance instanceof MyCustomElement); + + doc.documentElement.innerHTML = ''; + var instance2 = doc.querySelector('my-custom-element'); + assert_true(instance2 instanceof Element); + assert_false(instance2 instanceof MyCustomElement); }); }, 'HTML parser must use the registry of window.document in a document created by XMLHttpRequest'); +test_with_window(function (contentWindow, contentDocument) { + const element = define_custom_element_in_window(contentWindow, 'my-custom-element', []); + // document-open-steps spec doesn't match most browsers; see https://github.com/whatwg/html/issues/1698. + // However, as explained in https://github.com/whatwg/html/issues/1698#issuecomment-298748641 + // the custom element registry will be replaced after document-open-steps. + contentDocument.write(''); + + var instance = contentDocument.querySelector('my-custom-element'); + + assert_true(instance instanceof contentWindow.HTMLElement); + assert_false(instance instanceof element.class); + +}, 'document.write() must not instantiate a custom element without a defined insertion point'); + +test_with_window(function (contentWindow, contentDocument) { + const element = define_custom_element_in_window(contentWindow, 'my-custom-element', []); + // document-open-steps spec doesn't match most browsers; see https://github.com/whatwg/html/issues/1698. + // However, as explained in https://github.com/whatwg/html/issues/1698#issuecomment-298748641 + // the custom element registry will be replaced after document-open-steps. + contentDocument.writeln(''); + + var instance = contentDocument.querySelector('my-custom-element'); + + assert_true(instance instanceof contentWindow.HTMLElement); + assert_false(instance instanceof element.class); + +}, 'document.writeln() must not instantiate a custom element without a defined insertion point'); + diff --git a/tests/wpt/web-platform-tests/custom-elements/reactions/Document.html b/tests/wpt/web-platform-tests/custom-elements/reactions/Document.html index 98c642bcf26..721ad1f4ced 100644 --- a/tests/wpt/web-platform-tests/custom-elements/reactions/Document.html +++ b/tests/wpt/web-platform-tests/custom-elements/reactions/Document.html @@ -129,6 +129,12 @@ test_with_window(function (contentWindow, contentDocument) { }, 'write on Document must enqueue disconnectedCallback when removing a custom element'); test_with_window(function (contentWindow, contentDocument) { + contentWindow.document.open(); + // document.open()'s spec doesn't match most browsers; see https://github.com/whatwg/html/issues/1698. + // However, as explained in https://github.com/whatwg/html/issues/1698#issuecomment-298748641 + // the custom element registry will be replaced after document.open() call, + // So call customElements.define() after that in order to register defintion + // to correct custom elements registry. const element = define_custom_element_in_window(contentWindow, 'custom-element', []); contentWindow.document.write(''); assert_array_equals(element.takeLog().types(), ['constructed', 'connected']); @@ -144,6 +150,12 @@ test_with_window(function (contentWindow, contentDocument) { }, 'writeln on Document must enqueue disconnectedCallback when removing a custom element'); test_with_window(function (contentWindow) { + contentWindow.document.open(); + // document.open()'s spec doesn't match most browsers; see https://github.com/whatwg/html/issues/1698. + // However, as explained in https://github.com/whatwg/html/issues/1698#issuecomment-298748641 + // the custom element registry will be replaced after document.open() call, + // So call customElements.define() after that in order to register defintion + // to correct custom elements registry. const element = define_custom_element_in_window(contentWindow, 'custom-element', []); contentWindow.document.writeln(''); assert_array_equals(element.takeLog().types(), ['constructed', 'connected']); diff --git a/tests/wpt/web-platform-tests/custom-elements/reactions/with-exceptions.html b/tests/wpt/web-platform-tests/custom-elements/reactions/with-exceptions.html new file mode 100644 index 00000000000..82e0f59c930 --- /dev/null +++ b/tests/wpt/web-platform-tests/custom-elements/reactions/with-exceptions.html @@ -0,0 +1,31 @@ + + +Custom Elements: CEReactions interaction with exceptions + + + + + + + + +
+ + diff --git a/tests/wpt/web-platform-tests/custom-elements/resources/my-custom-element-html-document.html b/tests/wpt/web-platform-tests/custom-elements/resources/my-custom-element-html-document.html new file mode 100644 index 00000000000..b9bfdf90a2d --- /dev/null +++ b/tests/wpt/web-platform-tests/custom-elements/resources/my-custom-element-html-document.html @@ -0,0 +1,6 @@ + + + + + + diff --git a/tests/wpt/web-platform-tests/dom/events/Event-subclasses-constructors.html b/tests/wpt/web-platform-tests/dom/events/Event-subclasses-constructors.html index 1741b960025..1fd70d4222b 100644 --- a/tests/wpt/web-platform-tests/dom/events/Event-subclasses-constructors.html +++ b/tests/wpt/web-platform-tests/dom/events/Event-subclasses-constructors.html @@ -21,6 +21,23 @@ function assert_props(iface, event, defaults) { } } +// Class declarations don't go on the global by default, so put it there ourselves: + +self.SubclassedEvent = class SubclassedEvent extends Event { + constructor(name, props) { + super(name, props); + if (props && typeof(props) == "object" && "customProp" in props) { + this.customProp = props.customProp; + } else { + this.customProp = 5; + } + } + + get fixedProp() { + return 17; + } +} + var EventModifierInit = [ ["ctrlKey", false, true], ["shiftKey", false, true], @@ -32,6 +49,7 @@ var expected = { "properties": [ ["bubbles", false, true], ["cancelable", false, true], + ["isTrusted", false, false], ], }, @@ -93,6 +111,14 @@ var expected = { ["data", "", "string"], ], }, + + "SubclassedEvent": { + "parent": "Event", + "properties": [ + ["customProp", 5, 8], + ["fixedProp", 17, 17], + ], + }, }; Object.keys(expected).forEach(function(iface) { diff --git a/tests/wpt/web-platform-tests/dom/events/EventListener-invoke-legacy.html b/tests/wpt/web-platform-tests/dom/events/EventListener-invoke-legacy.html index 85a4b0a5fe6..a01afcd8d19 100644 --- a/tests/wpt/web-platform-tests/dom/events/EventListener-invoke-legacy.html +++ b/tests/wpt/web-platform-tests/dom/events/EventListener-invoke-legacy.html @@ -51,22 +51,16 @@ function runLegacyEventTest(type, legacyType, ctor, setup) { } function setupTransition(elem) { - elem.style.transition = ''; - requestAnimationFrame(function() { - elem.style.color = 'red'; - elem.style.transition = 'color 30ms'; - requestAnimationFrame(function() { - elem.style.color = 'green'; - }); - }); + getComputedStyle(elem).color; + elem.style.color = 'green'; + elem.style.transition = 'color 30ms'; } function setupAnimation(elem) { - elem.style.animation = 'test 30ms 2'; + elem.style.animation = 'test 30ms'; } runLegacyEventTest('transitionend', 'webkitTransitionEnd', "TransitionEvent", setupTransition); runLegacyEventTest('animationend', 'webkitAnimationEnd', "AnimationEvent", setupAnimation); -runLegacyEventTest('animationiteration', 'webkitAnimationIteration', "AnimationEvent", setupAnimation); runLegacyEventTest('animationstart', 'webkitAnimationStart', "AnimationEvent", setupAnimation); diff --git a/tests/wpt/web-platform-tests/dom/historical.html b/tests/wpt/web-platform-tests/dom/historical.html index c6fd00ff55c..388366c084c 100644 --- a/tests/wpt/web-platform-tests/dom/historical.html +++ b/tests/wpt/web-platform-tests/dom/historical.html @@ -178,4 +178,14 @@ var EventRemoved = [ "CHANGE" ] EventRemoved.forEach(isRemovedFromEvent) + +var EventPrototypeRemoved = [ + "getPreventDefault", +] +EventPrototypeRemoved.forEach(name => { + test(() => { + assert_equals(Event.prototype[name], undefined) + assert_equals((new Event("test"))[name], undefined) + }, "Event.prototype should not have this property: " + name) +}) diff --git a/tests/wpt/web-platform-tests/encoding/big5-encoder.html b/tests/wpt/web-platform-tests/encoding/big5-encoder.html index 7260b6b155b..58d60d50db1 100644 --- a/tests/wpt/web-platform-tests/encoding/big5-encoder.html +++ b/tests/wpt/web-platform-tests/encoding/big5-encoder.html @@ -15,8 +15,8 @@ encode("ab", "ab", "very basic") // edge cases - encode("\u9EA6", "%26%2340614%3B", "Highest-pointer BMP character excluded from encoder"); - encode("\uD858\uDE6B", "%26%23156267%3B", "Highest-pointer character excluded from encoder"); + encode("\u9EA6", "&%2340614;", "Highest-pointer BMP character excluded from encoder"); + encode("\uD858\uDE6B", "&%23156267;", "Highest-pointer character excluded from encoder"); encode("\u3000", "%A1@", "Lowest-pointer character included in encoder"); encode("\u20AC", "%A3%E1", "Euro; the highest-pointer character before a range of 30 unmapped pointers"); encode("\u4E00", "%A4@", "The lowest-pointer character after the range of 30 unmapped pointers"); @@ -24,8 +24,8 @@ encode("\uFFE2", "%C8%CD", "The lowest-pointer character after the range of 41 unmapped pointers"); encode("\u79D4", "%FE%FE", "The last character in the index"); // not in index - encode("\u2603", "%26%239731%3B", "The canonical BMP test character that is not in the index"); - encode("\uD83D\uDCA9", "%26%23128169%3B", "The canonical astral test character that is not in the index"); + encode("\u2603", "&%239731;", "The canonical BMP test character that is not in the index"); + encode("\uD83D\uDCA9", "&%23128169;", "The canonical astral test character that is not in the index"); // duplicate low bits encode("\uD840\uDFB5", "%FDj", "A Plane 2 character whose low 16 bits match a BMP character that has a lower pointer"); // prefer last diff --git a/tests/wpt/web-platform-tests/encoding/gbk-encoder.html b/tests/wpt/web-platform-tests/encoding/gbk-encoder.html index a6074f975d3..90d0824ce23 100644 --- a/tests/wpt/web-platform-tests/encoding/gbk-encoder.html +++ b/tests/wpt/web-platform-tests/encoding/gbk-encoder.html @@ -17,5 +17,5 @@ encode("\u4E02", "%81@", "character") encode("\uE4C6", "%A1@", "PUA") encode("\uE4C5", "%FE%FE", "PUA #2") - encode("\ud83d\udca9", "%26%23128169%3B", "poo") + encode("\ud83d\udca9", "&%23128169;", "poo") diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-check-initdata-type.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-check-initdata-type.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-check-initdata-type.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-check-initdata-type.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-events-session-closed-event.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-events-session-closed-event.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-events-session-closed-event.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-events-session-closed-event.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-events.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-events.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-events.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-events.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-generate-request-disallowed-input.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-generate-request-disallowed-input.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-generate-request-disallowed-input.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-generate-request-disallowed-input.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-invalid-license.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-invalid-license.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-invalid-license.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-invalid-license.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-keystatuses-multiple-sessions.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-keystatuses-multiple-sessions.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-keystatuses-multiple-sessions.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-keystatuses-multiple-sessions.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-keystatuses.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-keystatuses.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-keystatuses.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-keystatuses.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-destroy-persistent-license.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-destroy-persistent-license.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-destroy-persistent-license.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-destroy-persistent-license.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-persistent-license-events.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-persistent-license-events.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-persistent-license-events.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-persistent-license-events.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-persistent-license.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-persistent-license.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-persistent-license.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-persistent-license.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-persistent-usage-record-events.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-persistent-usage-record-events.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-persistent-usage-record-events.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-persistent-usage-record-events.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-persistent-usage-record.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-persistent-usage-record.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-persistent-usage-record.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-persistent-usage-record.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-retrieve-destroy-persistent-license.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-retrieve-destroy-persistent-license.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-retrieve-destroy-persistent-license.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-retrieve-destroy-persistent-license.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-retrieve-persistent-license.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-retrieve-persistent-license.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-retrieve-persistent-license.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-retrieve-persistent-license.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-retrieve-persistent-usage-record.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-retrieve-persistent-usage-record.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-retrieve-persistent-usage-record.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-retrieve-persistent-usage-record.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-clear-encrypted.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-clear-encrypted.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-clear-encrypted.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-clear-encrypted.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-encrypted-clear-sources.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-encrypted-clear-sources.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-encrypted-clear-sources.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-encrypted-clear-sources.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-encrypted-clear.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-encrypted-clear.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-encrypted-clear.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-encrypted-clear.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-events.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-events.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-events.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-events.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-multikey-sequential-readyState.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-multikey-sequential-readyState.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-multikey-sequential-readyState.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-multikey-sequential-readyState.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-multikey-sequential.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-multikey-sequential.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-multikey-sequential.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-multikey-sequential.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-multikey.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-multikey.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-multikey.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-multikey.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-multisession.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-multisession.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-multisession.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-multisession.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-after-src.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-after-src.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-after-src.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-after-src.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-after-update.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-after-update.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-after-update.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-after-update.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-immediately.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-immediately.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-immediately.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-immediately.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-onencrypted.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-onencrypted.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-onencrypted.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-setMediaKeys-onencrypted.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-two-videos.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-two-videos.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-two-videos.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-two-videos.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-waitingforkey.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-waitingforkey.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-waitingforkey.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary-waitingforkey.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-playback-temporary.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-requestmediakeysystemaccess.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-requestmediakeysystemaccess.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-requestmediakeysystemaccess.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-requestmediakeysystemaccess.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-reset-src-after-setmediakeys.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-reset-src-after-setmediakeys.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-reset-src-after-setmediakeys.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-reset-src-after-setmediakeys.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys-again-after-playback.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys-again-after-playback.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys-again-after-playback.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys-again-after-playback.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys-again-after-resetting-src.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys-again-after-resetting-src.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys-again-after-resetting-src.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys-again-after-resetting-src.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys-at-same-time.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys-at-same-time.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys-at-same-time.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys-at-same-time.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys-multiple-times-with-different-mediakeys.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys-multiple-times-with-different-mediakeys.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys-multiple-times-with-different-mediakeys.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys-multiple-times-with-different-mediakeys.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys-multiple-times-with-the-same-mediakeys.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys-multiple-times-with-the-same-mediakeys.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys-multiple-times-with-the-same-mediakeys.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys-multiple-times-with-the-same-mediakeys.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys-to-multiple-video-elements.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys-to-multiple-video-elements.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys-to-multiple-video-elements.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys-to-multiple-video-elements.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-setmediakeys.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-syntax-mediakeys.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-syntax-mediakeys.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-syntax-mediakeys.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-syntax-mediakeys.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-syntax-mediakeysession.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-syntax-mediakeysession.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-syntax-mediakeysession.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-syntax-mediakeysession.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-syntax-mediakeysystemaccess.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-syntax-mediakeysystemaccess.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-syntax-mediakeysystemaccess.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-syntax-mediakeysystemaccess.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-unique-origin.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-unique-origin.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-unique-origin.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-unique-origin.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-update-disallowed-input.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-update-disallowed-input.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-update-disallowed-input.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-update-disallowed-input.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-waiting-for-a-key.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-waiting-for-a-key.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-waiting-for-a-key.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-mp4-waiting-for-a-key.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-not-callable-after-createsession.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-not-callable-after-createsession.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-not-callable-after-createsession.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-not-callable-after-createsession.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/clearkey-update-non-ascii-input.html b/tests/wpt/web-platform-tests/encrypted-media/clearkey-update-non-ascii-input.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/clearkey-update-non-ascii-input.html rename to tests/wpt/web-platform-tests/encrypted-media/clearkey-update-non-ascii-input.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-check-initdata-type.html b/tests/wpt/web-platform-tests/encrypted-media/drm-check-initdata-type.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-check-initdata-type.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-check-initdata-type.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-events-session-closed-event.html b/tests/wpt/web-platform-tests/encrypted-media/drm-events-session-closed-event.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-events-session-closed-event.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-events-session-closed-event.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-events.html b/tests/wpt/web-platform-tests/encrypted-media/drm-events.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-events.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-events.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-expiration.html b/tests/wpt/web-platform-tests/encrypted-media/drm-expiration.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-expiration.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-expiration.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-generate-request-disallowed-input.html b/tests/wpt/web-platform-tests/encrypted-media/drm-generate-request-disallowed-input.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-generate-request-disallowed-input.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-generate-request-disallowed-input.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-invalid-license.html b/tests/wpt/web-platform-tests/encrypted-media/drm-invalid-license.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-invalid-license.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-invalid-license.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-keystatuses-multiple-sessions.html b/tests/wpt/web-platform-tests/encrypted-media/drm-keystatuses-multiple-sessions.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-keystatuses-multiple-sessions.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-keystatuses-multiple-sessions.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-keystatuses.html b/tests/wpt/web-platform-tests/encrypted-media/drm-keystatuses.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-keystatuses.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-keystatuses.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-onencrypted.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-onencrypted.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-onencrypted.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-onencrypted.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-destroy-persistent-license.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-destroy-persistent-license.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-destroy-persistent-license.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-destroy-persistent-license.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-persistent-license-events.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-persistent-license-events.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-persistent-license-events.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-persistent-license-events.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-persistent-license.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-persistent-license.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-persistent-license.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-persistent-license.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-persistent-usage-record-events.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-persistent-usage-record-events.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-persistent-usage-record-events.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-persistent-usage-record-events.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-persistent-usage-record.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-persistent-usage-record.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-persistent-usage-record.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-persistent-usage-record.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-retrieve-destroy-persistent-license.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-retrieve-destroy-persistent-license.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-retrieve-destroy-persistent-license.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-retrieve-destroy-persistent-license.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-retrieve-persistent-license.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-retrieve-persistent-license.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-retrieve-persistent-license.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-retrieve-persistent-license.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-retrieve-persistent-usage-record.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-retrieve-persistent-usage-record.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-retrieve-persistent-usage-record.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-retrieve-persistent-usage-record.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-clear-encrypted.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-clear-encrypted.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-clear-encrypted.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-clear-encrypted.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-encrypted-clear-sources.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-encrypted-clear-sources.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-encrypted-clear-sources.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-encrypted-clear-sources.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-encrypted-clear.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-encrypted-clear.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-encrypted-clear.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-encrypted-clear.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-events.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-events.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-events.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-events.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-expired.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-expired.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-expired.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-expired.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-multikey-sequential-readyState.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-multikey-sequential-readyState.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-multikey-sequential-readyState.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-multikey-sequential-readyState.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-multikey-sequential.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-multikey-sequential.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-multikey-sequential.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-multikey-sequential.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-multikey.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-multikey.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-multikey.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-multikey.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-multisession.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-multisession.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-multisession.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-multisession.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-after-src.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-after-src.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-after-src.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-after-src.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-after-update.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-after-update.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-after-update.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-after-update.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-immediately.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-immediately.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-immediately.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-immediately.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-onencrypted.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-onencrypted.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-onencrypted.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-onencrypted.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-two-videos.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-two-videos.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-two-videos.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-two-videos.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-waitingforkey.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-waitingforkey.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-waitingforkey.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-waitingforkey.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-playback-temporary.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-requestmediakeysystemaccess.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-requestmediakeysystemaccess.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-requestmediakeysystemaccess.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-requestmediakeysystemaccess.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-reset-src-after-setmediakeys.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-reset-src-after-setmediakeys.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-reset-src-after-setmediakeys.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-reset-src-after-setmediakeys.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-again-after-playback.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-again-after-playback.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-again-after-playback.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-again-after-playback.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-again-after-resetting-src.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-again-after-resetting-src.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-again-after-resetting-src.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-again-after-resetting-src.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-at-same-time.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-at-same-time.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-at-same-time.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-at-same-time.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-multiple-times-with-different-mediakeys.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-multiple-times-with-different-mediakeys.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-multiple-times-with-different-mediakeys.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-multiple-times-with-different-mediakeys.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-multiple-times-with-the-same-mediakeys.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-multiple-times-with-the-same-mediakeys.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-multiple-times-with-the-same-mediakeys.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-multiple-times-with-the-same-mediakeys.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-to-multiple-video-elements.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-to-multiple-video-elements.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-to-multiple-video-elements.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-to-multiple-video-elements.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-setmediakeys.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-syntax-mediakeys.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-syntax-mediakeys.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-syntax-mediakeys.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-syntax-mediakeys.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-syntax-mediakeysession.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-syntax-mediakeysession.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-syntax-mediakeysession.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-syntax-mediakeysession.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-syntax-mediakeysystemaccess.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-syntax-mediakeysystemaccess.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-syntax-mediakeysystemaccess.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-syntax-mediakeysystemaccess.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-unique-origin.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-unique-origin.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-unique-origin.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-unique-origin.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-waiting-for-a-key.html b/tests/wpt/web-platform-tests/encrypted-media/drm-mp4-waiting-for-a-key.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-mp4-waiting-for-a-key.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-mp4-waiting-for-a-key.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-not-callable-after-createsession.html b/tests/wpt/web-platform-tests/encrypted-media/drm-not-callable-after-createsession.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-not-callable-after-createsession.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-not-callable-after-createsession.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/drm-temporary-license-type.html b/tests/wpt/web-platform-tests/encrypted-media/drm-temporary-license-type.https.html similarity index 100% rename from tests/wpt/web-platform-tests/encrypted-media/drm-temporary-license-type.html rename to tests/wpt/web-platform-tests/encrypted-media/drm-temporary-license-type.https.html diff --git a/tests/wpt/web-platform-tests/encrypted-media/idlharness.html b/tests/wpt/web-platform-tests/encrypted-media/idlharness.https.html similarity index 90% rename from tests/wpt/web-platform-tests/encrypted-media/idlharness.html rename to tests/wpt/web-platform-tests/encrypted-media/idlharness.https.html index e65ad5e30ba..e7e035e4576 100644 --- a/tests/wpt/web-platform-tests/encrypted-media/idlharness.html +++ b/tests/wpt/web-platform-tests/encrypted-media/idlharness.https.html @@ -30,9 +30,7 @@ .then( function( idls ) { var idl_array = new IdlArray(); - idl_array.add_untested_idls("[PrimaryGlobal] interface Window {};"); idl_array.add_untested_idls("interface Navigator {};"); - idl_array.add_untested_idls("interface ArrayBuffer {};"); idl_array.add_untested_idls("interface HTMLMediaElement {};"); idl_array.add_untested_idls("interface Event {};"); idl_array.add_untested_idls("interface EventTarget {};"); diff --git a/tests/wpt/web-platform-tests/encrypted-media/resources/clearkey-retrieve-destroy-persistent-license.html b/tests/wpt/web-platform-tests/encrypted-media/resources/clearkey-retrieve-destroy-persistent-license.html index b1bec547e99..3178c860150 100644 --- a/tests/wpt/web-platform-tests/encrypted-media/resources/clearkey-retrieve-destroy-persistent-license.html +++ b/tests/wpt/web-platform-tests/encrypted-media/resources/clearkey-retrieve-destroy-persistent-license.html @@ -40,7 +40,7 @@ config.messagehandler = (new MessageHandler( 'org.w3.clearkey')).messagehandler; function onComplete() { - window.opener.postMessage(assertions, '*'); + window.opener.postMessage({ testResult: assertions }, '*'); } function onFailure(error) { diff --git a/tests/wpt/web-platform-tests/encrypted-media/resources/clearkey-retrieve-persistent-license.html b/tests/wpt/web-platform-tests/encrypted-media/resources/clearkey-retrieve-persistent-license.html index 78ca4e1bb3a..0562322203c 100644 --- a/tests/wpt/web-platform-tests/encrypted-media/resources/clearkey-retrieve-persistent-license.html +++ b/tests/wpt/web-platform-tests/encrypted-media/resources/clearkey-retrieve-persistent-license.html @@ -35,7 +35,7 @@ config.video = document.getElementById('videoelement'); function onComplete() { - window.opener.postMessage(assertions, '*'); + window.opener.postMessage({ testResult: assertions }, '*'); } function onFailure(error) { @@ -54,9 +54,10 @@ .then(function(access) { return access.createMediaKeys(); }).then(function(mediaKeys) { - config.video.setMediaKeys(mediaKeys); + return config.video.setMediaKeys(mediaKeys); + }).then(function() { config.video.addEventListener('timeupdate', onTimeupdate, true); - _mediaKeySession = mediaKeys.createSession( 'persistent-license' ); + _mediaKeySession = config.video.mediaKeys.createSession( 'persistent-license' ); _mediaKeySession.closed.then(onComplete); return _mediaKeySession.load(event.data.sessionId); }).then(function( success ) { diff --git a/tests/wpt/web-platform-tests/encrypted-media/resources/drm-retrieve-destroy-persistent-license.html b/tests/wpt/web-platform-tests/encrypted-media/resources/drm-retrieve-destroy-persistent-license.html index 39798fe43ef..0803eb14960 100644 --- a/tests/wpt/web-platform-tests/encrypted-media/resources/drm-retrieve-destroy-persistent-license.html +++ b/tests/wpt/web-platform-tests/encrypted-media/resources/drm-retrieve-destroy-persistent-license.html @@ -40,7 +40,7 @@ config.messagehandler = (new MessageHandler(config.keysystem, config.content, 'persistent-license')).messagehandler; function onComplete() { - window.opener.postMessage(assertions, '*'); + window.opener.postMessage({ testResult: assertions }, '*'); } function onFailure(error) { diff --git a/tests/wpt/web-platform-tests/encrypted-media/resources/drm-retrieve-persistent-license.html b/tests/wpt/web-platform-tests/encrypted-media/resources/drm-retrieve-persistent-license.html index 3b7da8e9570..b6a0ae2a6cf 100644 --- a/tests/wpt/web-platform-tests/encrypted-media/resources/drm-retrieve-persistent-license.html +++ b/tests/wpt/web-platform-tests/encrypted-media/resources/drm-retrieve-persistent-license.html @@ -33,7 +33,7 @@ config.video = document.getElementById('videoelement'); function onComplete() { - window.opener.postMessage(assertions, '*'); + window.opener.postMessage({ testResult: assertions }, '*'); } function onFailure(error) { @@ -58,9 +58,10 @@ .then(function(access) { return access.createMediaKeys(); }).then(function(mediaKeys) { - config.video.setMediaKeys(mediaKeys); + return config.video.setMediaKeys(mediaKeys); + }).then(function() { config.video.addEventListener('timeupdate', onTimeupdate); - _mediaKeySession = mediaKeys.createSession( 'persistent-license' ); + _mediaKeySession = config.video.mediaKeys.createSession( 'persistent-license' ); return _mediaKeySession.load(event.data.sessionId); }).then(function( success ) { if ( !success ) throw new DOMException( 'Could not load session' ); diff --git a/tests/wpt/web-platform-tests/encrypted-media/resources/drm-retrieve-persistent-usage-record.html b/tests/wpt/web-platform-tests/encrypted-media/resources/drm-retrieve-persistent-usage-record.html index 935f777488a..a98c438ef5c 100644 --- a/tests/wpt/web-platform-tests/encrypted-media/resources/drm-retrieve-persistent-usage-record.html +++ b/tests/wpt/web-platform-tests/encrypted-media/resources/drm-retrieve-persistent-usage-record.html @@ -33,7 +33,7 @@ function onFailure(error) { assertions.push( { actual: false, expected: true, message: error } ); - window.opener.postMessage(assertions, '*'); + window.opener.postMessage({ testResult: assertions }, '*'); } function onMessage( event ) @@ -56,13 +56,13 @@ _mediaKeySession = _mediaKeys.createSession( 'persistent-usage-record' ); _mediaKeySession.addEventListener( 'message', onMessage ); _mediaKeySession.closed.then( function() { - window.opener.postMessage(assertions, '*'); + window.opener.postMessage({ testResult: assertions }, '*'); }); return _mediaKeySession.load( event.data.sessionId ); }).then(function( success ) { if ( !success ) { assertions.push( { actual: success, expected: true, message: "Error loading session" } ); - window.opener.postMessage(assertions, '*'); + window.opener.postMessage({ testResult: assertions }, '*'); } }).catch( onFailure ); }); diff --git a/tests/wpt/web-platform-tests/encrypted-media/resources/retrieve-persistent-usage-record.html b/tests/wpt/web-platform-tests/encrypted-media/resources/retrieve-persistent-usage-record.html index 339e3c3aed5..3a4262b179c 100644 --- a/tests/wpt/web-platform-tests/encrypted-media/resources/retrieve-persistent-usage-record.html +++ b/tests/wpt/web-platform-tests/encrypted-media/resources/retrieve-persistent-usage-record.html @@ -55,7 +55,7 @@ assertions.push( { actual: false, expected: true, message: error } ); - window.opener.postMessage(assertions, '*'); + window.opener.postMessage({ testResult: assertions }, '*'); }); }); } @@ -71,7 +71,7 @@ mediaKeySession.addEventListener( 'message', onMessage ); mediaKeySession.closed.then( function() { - window.opener.postMessage(assertions, '*'); + window.opener.postMessage({ testResult: assertions }, '*'); }); @@ -81,7 +81,7 @@ assertions.push( { actual: false, expected: true, message: error.toString() } ); - window.opener.postMessage(assertions, '*'); + window.opener.postMessage({ testResult: assertions }, '*'); }); diff --git a/tests/wpt/web-platform-tests/encrypted-media/scripts/playback-retrieve-persistent-license.js b/tests/wpt/web-platform-tests/encrypted-media/scripts/playback-retrieve-persistent-license.js index e8d9d02be30..83cba34028e 100644 --- a/tests/wpt/web-platform-tests/encrypted-media/scripts/playback-retrieve-persistent-license.js +++ b/tests/wpt/web-platform-tests/encrypted-media/scripts/playback-retrieve-persistent-license.js @@ -74,12 +74,14 @@ function runTest(config,qualifier) { // Lisen for an event from the new window containing its test assertions window.addEventListener('message', test.step_func(function(messageEvent) { - messageEvent.data.forEach(test.step_func(function(assertion) { - assert_equals(assertion.actual, assertion.expected, assertion.message); - })); + if (messageEvent.data.testResult) { + messageEvent.data.testResult.forEach(test.step_func(function(assertion) { + assert_equals(assertion.actual, assertion.expected, assertion.message); + })); - win.close(); - test.done(); + win.close(); + test.done(); + } })); // Delete things which can't be cloned and posted over to the new window @@ -96,7 +98,8 @@ function runTest(config,qualifier) { return access.createMediaKeys(); }).then(function(mediaKeys) { _mediaKeys = mediaKeys; - _video.setMediaKeys( mediaKeys ); + return _video.setMediaKeys( mediaKeys ); + }).then(function() { _mediaKeySession = _mediaKeys.createSession('persistent-license'); waitForEventAndRunStep('encrypted', _video, onEncrypted, test); waitForEventAndRunStep('playing', _video, onPlaying, test); diff --git a/tests/wpt/web-platform-tests/encrypted-media/scripts/playback-retrieve-persistent-usage-record.js b/tests/wpt/web-platform-tests/encrypted-media/scripts/playback-retrieve-persistent-usage-record.js index 9467fd5d867..a04f97d2ca9 100644 --- a/tests/wpt/web-platform-tests/encrypted-media/scripts/playback-retrieve-persistent-usage-record.js +++ b/tests/wpt/web-platform-tests/encrypted-media/scripts/playback-retrieve-persistent-usage-record.js @@ -45,7 +45,7 @@ function runTest(config,qualifier) { config.messagehandler( event.messageType, event.message ).then(function(response) { return _mediaKeySession.update(response); }).then(function() { - _video.setMediaKeys(_mediaKeys); + return _video.setMediaKeys(_mediaKeys); }).catch(onFailure); } @@ -70,13 +70,17 @@ function runTest(config,qualifier) { _video.setMediaKeys( null ); var win = window.open(config.windowscript); - window.addEventListener('message', test.step_func(function(event) { - event.data.forEach(test.step_func(function(assertion) { - assert_equals(assertion.actual, assertion.expected, assertion.message); - })); + assert_not_equals(win, null, "Popup windows not allowed?"); - win.close(); - test.done(); + window.addEventListener('message', test.step_func(function(event) { + if (event.data.testResult) { + event.data.testResult.forEach(test.step_func(function(assertion) { + assert_equals(assertion.actual, assertion.expected, assertion.message); + })); + + win.close(); + test.done(); + } })); delete config.video; diff --git a/tests/wpt/web-platform-tests/encrypted-media/scripts/unique-origin.js b/tests/wpt/web-platform-tests/encrypted-media/scripts/unique-origin.js index ff1122db4de..015ea9d4e92 100644 --- a/tests/wpt/web-platform-tests/encrypted-media/scripts/unique-origin.js +++ b/tests/wpt/web-platform-tests/encrypted-media/scripts/unique-origin.js @@ -10,7 +10,7 @@ function runTest(config) { resolve(iframe); }; iframe.sandbox = sandbox; - iframe.src = src; + iframe.srcdoc = src; document.documentElement.appendChild(iframe); }); } @@ -25,7 +25,7 @@ function runTest(config) { } promise_test(function (test) { - var script = 'data:text/html,' + + var script = ' + + + + + + + + diff --git a/tests/wpt/web-platform-tests/feature-policy/autoplay-allowed-by-feature-policy-attribute.https.sub.html b/tests/wpt/web-platform-tests/feature-policy/autoplay-allowed-by-feature-policy-attribute.https.sub.html new file mode 100644 index 00000000000..59b33d7c4d2 --- /dev/null +++ b/tests/wpt/web-platform-tests/feature-policy/autoplay-allowed-by-feature-policy-attribute.https.sub.html @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/tests/wpt/web-platform-tests/feature-policy/autoplay-allowed-by-feature-policy.https.sub.html b/tests/wpt/web-platform-tests/feature-policy/autoplay-allowed-by-feature-policy.https.sub.html new file mode 100644 index 00000000000..63479c0cb6f --- /dev/null +++ b/tests/wpt/web-platform-tests/feature-policy/autoplay-allowed-by-feature-policy.https.sub.html @@ -0,0 +1,39 @@ + + + + + + + + + + + diff --git a/tests/wpt/web-platform-tests/feature-policy/autoplay-allowed-by-feature-policy.https.sub.html.headers b/tests/wpt/web-platform-tests/feature-policy/autoplay-allowed-by-feature-policy.https.sub.html.headers new file mode 100644 index 00000000000..08461fadc28 --- /dev/null +++ b/tests/wpt/web-platform-tests/feature-policy/autoplay-allowed-by-feature-policy.https.sub.html.headers @@ -0,0 +1 @@ +Feature-Policy: autoplay * diff --git a/tests/wpt/web-platform-tests/feature-policy/autoplay-default-feature-policy.https.sub.html b/tests/wpt/web-platform-tests/feature-policy/autoplay-default-feature-policy.https.sub.html new file mode 100644 index 00000000000..763073e437d --- /dev/null +++ b/tests/wpt/web-platform-tests/feature-policy/autoplay-default-feature-policy.https.sub.html @@ -0,0 +1,39 @@ + + + + + + + + + + + diff --git a/tests/wpt/web-platform-tests/feature-policy/autoplay-disabled-by-feature-policy.https.sub.html b/tests/wpt/web-platform-tests/feature-policy/autoplay-disabled-by-feature-policy.https.sub.html new file mode 100644 index 00000000000..3dd3afbf771 --- /dev/null +++ b/tests/wpt/web-platform-tests/feature-policy/autoplay-disabled-by-feature-policy.https.sub.html @@ -0,0 +1,39 @@ + + + + + + + + + + + diff --git a/tests/wpt/web-platform-tests/feature-policy/autoplay-disabled-by-feature-policy.https.sub.html.headers b/tests/wpt/web-platform-tests/feature-policy/autoplay-disabled-by-feature-policy.https.sub.html.headers new file mode 100644 index 00000000000..69ce436270a --- /dev/null +++ b/tests/wpt/web-platform-tests/feature-policy/autoplay-disabled-by-feature-policy.https.sub.html.headers @@ -0,0 +1 @@ +Feature-Policy: autoplay 'none' diff --git a/tests/wpt/web-platform-tests/feature-policy/payment-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html b/tests/wpt/web-platform-tests/feature-policy/payment-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html index 9a792173f4a..daa2aa182da 100644 --- a/tests/wpt/web-platform-tests/feature-policy/payment-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html +++ b/tests/wpt/web-platform-tests/feature-policy/payment-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html @@ -16,24 +16,24 @@ test_feature_availability( 'PaymentRequest()', t, same_origin_src, expect_feature_available_default, 'payment'); - }, header + ' allows same-origin relocation.'); + }, header + ' allows same-origin navigation in an iframe.'); async_test(t => { test_feature_availability( 'PaymentRequest()', t, cross_origin_src, expect_feature_unavailable_default, 'payment'); - }, header + ' disallows cross-origin relocation.'); + }, header + ' disallows cross-origin navigation in an iframe.'); async_test(t => { test_feature_availability( 'PaymentRequest()', t, same_origin_src, expect_feature_available_default, 'payment', 'allowpaymentrequest'); - }, header + ' allowpaymentrequest=true allows same-origin relocation.'); + }, header + ' allowpaymentrequest=true allows same-origin navigation in an iframe.'); async_test(t => { test_feature_availability( 'PaymentRequest()', t, cross_origin_src, expect_feature_unavailable_default, 'payment', 'allowpaymentrequest'); - }, header + ' allowpaymentrequest=true disallows cross-origin relocation.'); + }, header + ' allowpaymentrequest=true disallows cross-origin navigation in an iframe.'); diff --git a/tests/wpt/web-platform-tests/feature-policy/resources/autoplay.js b/tests/wpt/web-platform-tests/feature-policy/resources/autoplay.js new file mode 100644 index 00000000000..56780cf6dc0 --- /dev/null +++ b/tests/wpt/web-platform-tests/feature-policy/resources/autoplay.js @@ -0,0 +1,28 @@ + + +function simulateGesture(t, callback) { + // Get or create the target element. + let target = document.getElementById('target'); + if (!target) { + target = document.createElement('button'); + target.setAttribute('id', 'target'); + document.body.appendChild(target); + } + + // Simulate a gesture in the top frame to remove any gesture based autoplay + // restrictions. + test_driver.click(target).then(callback, t.unreached_func('click failed')); +} + +function isAutoplayAllowed() { + return new Promise((resolve, reject) => { + const video = document.createElement('video'); + video.src = getVideoURI('/media/A4'); + video.play().then(() => resolve(true), (e) => { + if (e.name == 'NotAllowedError') + resolve(false); + else + resolve(true); + }); + }); +} diff --git a/tests/wpt/web-platform-tests/feature-policy/resources/feature-policy-autoplay.html b/tests/wpt/web-platform-tests/feature-policy/resources/feature-policy-autoplay.html new file mode 100644 index 00000000000..79f8eefb9d6 --- /dev/null +++ b/tests/wpt/web-platform-tests/feature-policy/resources/feature-policy-autoplay.html @@ -0,0 +1,11 @@ + + + diff --git a/tests/wpt/web-platform-tests/feature-policy/resources/feature-policy-generic-sensor.html b/tests/wpt/web-platform-tests/feature-policy/resources/feature-policy-generic-sensor.html new file mode 100644 index 00000000000..59652e2e7ae --- /dev/null +++ b/tests/wpt/web-platform-tests/feature-policy/resources/feature-policy-generic-sensor.html @@ -0,0 +1,11 @@ + diff --git a/tests/wpt/web-platform-tests/fetch/api/cors/cors-expose-star.js b/tests/wpt/web-platform-tests/fetch/api/cors/cors-expose-star.js index e37ddb4c3f2..edf4d424179 100644 --- a/tests/wpt/web-platform-tests/fetch/api/cors/cors-expose-star.js +++ b/tests/wpt/web-platform-tests/fetch/api/cors/cors-expose-star.js @@ -31,7 +31,7 @@ promise_test(() => { }, "* for credentialed fetches only matches literally") promise_test(() => { - const headers = "header(Access-Control-Allow-Origin,*)|header(Access-Control-Expose-Headers,set-cookie)" + const headers = "header(Access-Control-Allow-Origin,*)|header(Access-Control-Expose-Headers,set-cookie\\,*)" return fetch(url + sharedHeaders + headers).then(resp => { assert_equals(resp.status, 200) assert_equals(resp.type , "cors") diff --git a/tests/wpt/web-platform-tests/fetch/api/redirect/redirect-method.js b/tests/wpt/web-platform-tests/fetch/api/redirect/redirect-method.js index 13433a1bb39..0a7f2df2c2b 100644 --- a/tests/wpt/web-platform-tests/fetch/api/redirect/redirect-method.js +++ b/tests/wpt/web-platform-tests/fetch/api/redirect/redirect-method.js @@ -3,14 +3,22 @@ if (this.document === undefined) { importScripts("../resources/utils.js"); } -function redirectMethod(desc, redirectUrl, redirectLocation, redirectStatus, method, expectedMethod) { +// Creates a promise_test that fetches a URL that returns a redirect response. +// +// |opts| has additional options: +// |opts.body|: the request body as a string or blob (default is empty body) +// |opts.expectedBodyAsString|: the expected response body as a string. The +// server is expected to echo the request body. The default is the empty string +// if the request after redirection isn't POST; otherwise it's |opts.body|. +function redirectMethod(desc, redirectUrl, redirectLocation, redirectStatus, method, expectedMethod, opts) { var url = redirectUrl; var urlParameters = "?redirect_status=" + redirectStatus; urlParameters += "&location=" + encodeURIComponent(redirectLocation); var requestInit = {"method": method, "redirect": "follow"}; - if (method != "GET" && method != "HEAD") - requestInit.body = "this is my body"; + opts = opts || {}; + if (opts.body) + requestInit.body = opts.body; promise_test(function(test) { return fetch(url + urlParameters, requestInit).then(function(resp) { @@ -19,7 +27,10 @@ function redirectMethod(desc, redirectUrl, redirectLocation, redirectStatus, met assert_equals(resp.headers.get("x-request-method"), expectedMethod, "Request method after redirection is " + expectedMethod); assert_true(resp.redirected); return resp.text().then(function(text) { - assert_equals(text, expectedMethod == "POST" ? requestInit.body : ""); + let expectedBody = ""; + if (expectedMethod == "POST") + expectedBody = opts.expectedBodyAsString || requestInit.body; + assert_equals(text, expectedBody, "request body"); }); }); }, desc); @@ -36,20 +47,25 @@ promise_test(function(test) { var redirUrl = RESOURCES_DIR + "redirect.py"; var locationUrl = "method.py"; +const stringBody = "this is my body"; +const blobBody = new Blob(["it's me the blob!", " ", "and more blob!"]); +const blobBodyAsString = "it's me the blob! and more blob!"; + redirectMethod("Redirect 301 with GET", redirUrl, locationUrl, 301, "GET", "GET"); -redirectMethod("Redirect 301 with POST", redirUrl, locationUrl, 301, "POST", "GET"); +redirectMethod("Redirect 301 with POST", redirUrl, locationUrl, 301, "POST", "GET", { body: stringBody }); redirectMethod("Redirect 301 with HEAD", redirUrl, locationUrl, 301, "HEAD", "HEAD"); redirectMethod("Redirect 302 with GET", redirUrl, locationUrl, 302, "GET", "GET"); -redirectMethod("Redirect 302 with POST", redirUrl, locationUrl, 302, "POST", "GET"); +redirectMethod("Redirect 302 with POST", redirUrl, locationUrl, 302, "POST", "GET", { body: stringBody }); redirectMethod("Redirect 302 with HEAD", redirUrl, locationUrl, 302, "HEAD", "HEAD"); redirectMethod("Redirect 303 with GET", redirUrl, locationUrl, 303, "GET", "GET"); -redirectMethod("Redirect 303 with POST", redirUrl, locationUrl, 303, "POST", "GET"); +redirectMethod("Redirect 303 with POST", redirUrl, locationUrl, 303, "POST", "GET", { body: stringBody }); redirectMethod("Redirect 303 with HEAD", redirUrl, locationUrl, 303, "HEAD", "HEAD"); redirectMethod("Redirect 307 with GET", redirUrl, locationUrl, 307, "GET", "GET"); -redirectMethod("Redirect 307 with POST", redirUrl, locationUrl, 307, "POST", "POST"); +redirectMethod("Redirect 307 with POST (string body)", redirUrl, locationUrl, 307, "POST", "POST", { body: stringBody }); +redirectMethod("Redirect 307 with POST (blob body)", redirUrl, locationUrl, 307, "POST", "POST", { body: blobBody, expectedBodyAsString: blobBodyAsString }); redirectMethod("Redirect 307 with HEAD", redirUrl, locationUrl, 307, "HEAD", "HEAD"); done(); diff --git a/tests/wpt/web-platform-tests/fetch/api/request/destination/fetch-destination.https.html b/tests/wpt/web-platform-tests/fetch/api/request/destination/fetch-destination.https.html new file mode 100644 index 00000000000..b504bb9c238 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/api/request/destination/fetch-destination.https.html @@ -0,0 +1,134 @@ + +Service Worker: the body of FetchEvent using XMLHttpRequest + + + + + + diff --git a/tests/wpt/web-platform-tests/tools/py/testing/log/__init__.py b/tests/wpt/web-platform-tests/fetch/api/request/destination/resources/dummy similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/testing/log/__init__.py rename to tests/wpt/web-platform-tests/fetch/api/request/destination/resources/dummy diff --git a/tests/wpt/web-platform-tests/fetch/api/request/destination/resources/dummy.png b/tests/wpt/web-platform-tests/fetch/api/request/destination/resources/dummy.png new file mode 100644 index 00000000000..01c9666a8de Binary files /dev/null and b/tests/wpt/web-platform-tests/fetch/api/request/destination/resources/dummy.png differ diff --git a/tests/wpt/web-platform-tests/fetch/api/request/destination/resources/dummy_audio.mp3 b/tests/wpt/web-platform-tests/fetch/api/request/destination/resources/dummy_audio.mp3 new file mode 100644 index 00000000000..0091330f1ec Binary files /dev/null and b/tests/wpt/web-platform-tests/fetch/api/request/destination/resources/dummy_audio.mp3 differ diff --git a/tests/wpt/web-platform-tests/fetch/api/request/destination/resources/dummy_audio.oga b/tests/wpt/web-platform-tests/fetch/api/request/destination/resources/dummy_audio.oga new file mode 100644 index 00000000000..239ad2bd08c Binary files /dev/null and b/tests/wpt/web-platform-tests/fetch/api/request/destination/resources/dummy_audio.oga differ diff --git a/tests/wpt/web-platform-tests/fetch/api/request/destination/resources/dummy_video.mp4 b/tests/wpt/web-platform-tests/fetch/api/request/destination/resources/dummy_video.mp4 new file mode 100644 index 00000000000..7022e75c15e Binary files /dev/null and b/tests/wpt/web-platform-tests/fetch/api/request/destination/resources/dummy_video.mp4 differ diff --git a/tests/wpt/web-platform-tests/fetch/api/request/destination/resources/dummy_video.ogv b/tests/wpt/web-platform-tests/fetch/api/request/destination/resources/dummy_video.ogv new file mode 100644 index 00000000000..de99616eceb Binary files /dev/null and b/tests/wpt/web-platform-tests/fetch/api/request/destination/resources/dummy_video.ogv differ diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/__init__.py b/tests/wpt/web-platform-tests/fetch/api/request/destination/resources/empty.https.html similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/__init__.py rename to tests/wpt/web-platform-tests/fetch/api/request/destination/resources/empty.https.html diff --git a/tests/wpt/web-platform-tests/fetch/api/request/destination/resources/fetch-destination-worker.js b/tests/wpt/web-platform-tests/fetch/api/request/destination/resources/fetch-destination-worker.js new file mode 100644 index 00000000000..f8e8e2669d0 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/api/request/destination/resources/fetch-destination-worker.js @@ -0,0 +1,11 @@ +self.addEventListener('fetch', function(event) { + if (event.request.url.includes('dummy')) { + let destination = new URL(event.request.url).searchParams.get("dest"); + if (event.request.destination == destination) { + event.respondWith(fetch(event.request)); + } else { + event.respondWith(Response.error()); + } + } +}); + diff --git a/tests/wpt/web-platform-tests/fetch/api/request/request-idl.html b/tests/wpt/web-platform-tests/fetch/api/request/request-idl.html index f78f0ca894a..f7833779ce2 100644 --- a/tests/wpt/web-platform-tests/fetch/api/request/request-idl.html +++ b/tests/wpt/web-platform-tests/fetch/api/request/request-idl.html @@ -15,9 +15,7 @@ typedef any JSON; typedef (Blob or BufferSource or FormData or URLSearchParams or USVString) BodyInit; - [NoInterfaceObject, - Exposed=(Window,Worker)] - interface Body { + interface mixin Body { readonly attribute ReadableStream? body; readonly attribute boolean bodyUsed; [NewObject] Promise arrayBuffer(); @@ -48,7 +46,7 @@ [NewObject] Request clone(); }; - Request implements Body; + Request includes Body; dictionary RequestInit { ByteString method; diff --git a/tests/wpt/web-platform-tests/fetch/api/request/request-keepalive-quota.html b/tests/wpt/web-platform-tests/fetch/api/request/request-keepalive-quota.html index dacc6382667..19596cea2c8 100644 --- a/tests/wpt/web-platform-tests/fetch/api/request/request-keepalive-quota.html +++ b/tests/wpt/web-platform-tests/fetch/api/request/request-keepalive-quota.html @@ -12,81 +12,80 @@ diff --git a/tests/wpt/web-platform-tests/fetch/api/resources/trickle.py b/tests/wpt/web-platform-tests/fetch/api/resources/trickle.py index 0e709445c59..319ecd21f45 100644 --- a/tests/wpt/web-platform-tests/fetch/api/resources/trickle.py +++ b/tests/wpt/web-platform-tests/fetch/api/resources/trickle.py @@ -3,6 +3,8 @@ import time def main(request, response): delay = float(request.GET.first("ms", 500)) / 1E3 count = int(request.GET.first("count", 50)) + # Read request body + request.body time.sleep(delay) response.headers.set("Content-type", "text/plain") response.write_status_headers() diff --git a/tests/wpt/web-platform-tests/fetch/api/response/response-idl.html b/tests/wpt/web-platform-tests/fetch/api/response/response-idl.html index 3bbf54e6f3c..bd265fa203d 100644 --- a/tests/wpt/web-platform-tests/fetch/api/response/response-idl.html +++ b/tests/wpt/web-platform-tests/fetch/api/response/response-idl.html @@ -15,9 +15,7 @@ typedef any JSON; typedef (Blob or BufferSource or FormData or URLSearchParams or USVString) BodyInit; - [NoInterfaceObject, - Exposed=(Window,Worker)] - interface Body { + interface mixin Body { readonly attribute ReadableStream? body; readonly attribute boolean bodyUsed; [NewObject] Promise arrayBuffer(); @@ -45,7 +43,7 @@ [NewObject] Response clone(); }; - Response implements Body; + Response includes Body; dictionary ResponseInit { unsigned short status = 200; diff --git a/tests/wpt/web-platform-tests/fetch/nosniff/resources/css.py b/tests/wpt/web-platform-tests/fetch/nosniff/resources/css.py index 7c4c63b596a..55712c5e23e 100644 --- a/tests/wpt/web-platform-tests/fetch/nosniff/resources/css.py +++ b/tests/wpt/web-platform-tests/fetch/nosniff/resources/css.py @@ -1,15 +1,23 @@ def main(request, response): - outcome = request.GET.first("outcome", "f") type = request.GET.first("type", None) + is_revalidation = request.headers.get("If-Modified-Since", None) content = "/* nothing to see here */" response.add_required_headers = False - response.writer.write_status(200) - response.writer.write_header("x-content-type-options", "nosniff") - response.writer.write_header("content-length", len(content)) - if(type != None): - response.writer.write_header("content-type", type) - response.writer.end_headers() - - response.writer.write(content) + if is_revalidation is not None: + response.writer.write_status(304) + response.writer.write_header("x-content-type-options", "nosniff") + response.writer.write_header("content-length", 0) + if(type != None): + response.writer.write_header("content-type", type) + response.writer.end_headers() + response.writer.write("") + else: + response.writer.write_status(200) + response.writer.write_header("x-content-type-options", "nosniff") + response.writer.write_header("content-length", len(content)) + if(type != None): + response.writer.write_header("content-type", type) + response.writer.end_headers() + response.writer.write(content) diff --git a/tests/wpt/web-platform-tests/fetch/nosniff/stylesheet.html b/tests/wpt/web-platform-tests/fetch/nosniff/stylesheet.html index 9e47f757b97..3d3c9f088da 100644 --- a/tests/wpt/web-platform-tests/fetch/nosniff/stylesheet.html +++ b/tests/wpt/web-platform-tests/fetch/nosniff/stylesheet.html @@ -18,21 +18,43 @@ async_test(function(t) { var link = document.createElement("link") link.rel = "stylesheet" - link.onerror = t.step_func_done(function(){}) + link.onerror = t.step_func_done() link.onload = t.unreached_func("Unexpected load event") link.href = get_url(mime) document.body.appendChild(link) }, "URL query: " + mime) }) + fails.forEach(function(mime) { + async_test(function(t) { + var link = document.createElement("link") + link.rel = "stylesheet" + link.onerror = t.step_func_done() + link.onload = t.unreached_func("Unexpected load event") + link.href = get_url(mime) + document.body.appendChild(link) + }, "Revalidated URL query: " + mime) + }) + + passes.forEach(function(mime) { + async_test(function(t) { + var link = document.createElement("link") + link.rel = "stylesheet" + link.onerror = t.unreached_func("Unexpected error event") + link.onload = t.step_func_done() + link.href = get_url(mime) + document.body.appendChild(link) + }, "URL query: " + mime) + }) + passes.forEach(function(mime) { async_test(function(t) { var link = document.createElement("link") link.rel = "stylesheet" link.onerror = t.unreached_func("Unexpected error event") - link.onload = t.step_func_done(function(){}) + link.onload = t.step_func_done() link.href = get_url(mime) document.body.appendChild(link) - }, "URL query: " + mime) + }, "Revalidated URL query: " + mime) }) diff --git a/tests/wpt/web-platform-tests/fullscreen/model/move-to-fullscreen-iframe-manual.html b/tests/wpt/web-platform-tests/fullscreen/model/move-to-fullscreen-iframe-manual.html new file mode 100644 index 00000000000..d152f7d144b --- /dev/null +++ b/tests/wpt/web-platform-tests/fullscreen/model/move-to-fullscreen-iframe-manual.html @@ -0,0 +1,32 @@ + +Moving fullscreen document's body into a fullscreen iframe + + + + + diff --git a/tests/wpt/web-platform-tests/fullscreen/rendering/ua-style-iframe-manual.html b/tests/wpt/web-platform-tests/fullscreen/rendering/ua-style-iframe-manual.html new file mode 100644 index 00000000000..bf93aa28c3f --- /dev/null +++ b/tests/wpt/web-platform-tests/fullscreen/rendering/ua-style-iframe-manual.html @@ -0,0 +1,35 @@ + +User-agent levels style sheet defaults for iframe + + + + +
+
+ diff --git a/tests/wpt/web-platform-tests/generic-sensor/generic-sensor-feature-policy-test.sub.js b/tests/wpt/web-platform-tests/generic-sensor/generic-sensor-feature-policy-test.sub.js new file mode 100644 index 00000000000..f722315cfb2 --- /dev/null +++ b/tests/wpt/web-platform-tests/generic-sensor/generic-sensor-feature-policy-test.sub.js @@ -0,0 +1,159 @@ +const feature_policies = { + "AmbientLightSensor" : ["ambient-light-sensor"], + "Accelerometer" : ["accelerometer"], + "LinearAccelerationSensor" : ["accelerometer"], + "GravitySensor" : ["accelerometer"], + "Gyroscope" : ["gyroscope"], + "GeolocationSensor" : ["geolocation"], + "Magnetometer" : ["magnetometer"], + "UncalibratedMagnetometer" : ["magnetometer"], + "AbsoluteOrientationSensor" : ["accelerometer", "gyroscope", "magnetometer"], + "RelativeOrientationSensor" : ["accelerometer", "gyroscope"] +}; + +const same_origin_src = + "/feature-policy/resources/feature-policy-generic-sensor.html#"; +const cross_origin_src = + "https://{{domains[www]}}:{{ports[https][0]}}" + same_origin_src; +const base_src = "/feature-policy/resources/redirect-on-load.html#"; + +function run_fp_tests_disabled(sensorType) { + const sensorName = sensorType.name; + const featureNameList = feature_policies[sensorName]; + const header = "Feature-Policy header " + featureNameList.join(" 'none';") + " 'none'"; + const desc = "'new " + sensorName + "()'"; + + test(() => { + assert_throws("SecurityError", () => {new sensorType()}); + }, `${sensorName}: ${header} disallows the top-level document.`); + + async_test(t => { + test_feature_availability( + desc, + t, + same_origin_src + sensorName, + expect_feature_unavailable_default + ); + }, `${sensorName}: ${header} disallows same-origin iframes.`); + + async_test(t => { + test_feature_availability( + desc, + t, + cross_origin_src + sensorName, + expect_feature_unavailable_default + ); + }, `${sensorName}: ${header} disallows cross-origin iframes.`); +} + +function run_fp_tests_enabled(sensorType) { + const sensorName = sensorType.name; + const featureNameList = feature_policies[sensorName]; + const header = "Feature-Policy header " + featureNameList.join(" *;") + " *"; + const desc = "'new " + sensorName + "()'"; + + test(() => { + assert_true(sensorName in window); + }, `${sensorName}: ${header} allows the top-level document.`); + + async_test(t => { + test_feature_availability( + desc, + t, + same_origin_src + sensorName, + expect_feature_available_default + ); + }, `${sensorName}: ${header} allows same-origin iframes.`); + + async_test(t => { + test_feature_availability( + desc, + t, + cross_origin_src + sensorName, + expect_feature_available_default + ); + }, `${sensorName}: ${header} allows cross-origin iframes.`); +} + +function run_fp_tests_enabled_by_attribute(sensorType) { + const sensorName = sensorType.name; + const featureNameList = feature_policies[sensorName]; + const header = "Feature-Policy allow='" + featureNameList.join(" ") + "' attribute"; + const desc = "'new " + sensorName + "()'"; + + async_test(t => { + test_feature_availability( + desc, + t, + same_origin_src + sensorName, + expect_feature_available_default, + featureNameList.join(";") + ); + }, `${sensorName}: ${header} allows same-origin iframe`); + + async_test(t => { + test_feature_availability( + desc, + t, + cross_origin_src + sensorName, + expect_feature_available_default, + featureNameList.join(";") + ); + }, `${sensorName}: ${header} allows cross-origin iframe`); +} + +function run_fp_tests_enabled_by_attribute_redirect_on_load(sensorType) { + const sensorName = sensorType.name; + const featureNameList = feature_policies[sensorName]; + const header = "Feature-Policy allow='" + featureNameList.join(" ") + "' attribute"; + const desc = "'new " + sensorName + "()'"; + + async_test(t => { + test_feature_availability( + desc, + t, + base_src + same_origin_src + sensorName, + expect_feature_available_default, + featureNameList.join(";") + ); + }, `${sensorName}: ${header} allows same-origin relocation`); + + async_test(t => { + test_feature_availability( + desc, + t, + base_src + cross_origin_src + sensorName, + expect_feature_unavailable_default, + featureNameList.join(";") + ); + }, `${sensorName}: ${header} disallows cross-origin relocation`); +} + +function run_fp_tests_enabled_on_self_origin(sensorType) { + const sensorName = sensorType.name; + const featureNameList = feature_policies[sensorName]; + const header = "Feature-Policy header " + featureNameList.join(" 'self';") + " 'self'"; + const desc = "'new " + sensorName + "()'"; + + test(() => { + assert_true(sensorName in window); + }, `${sensorName}: ${header} allows the top-level document.`); + + async_test(t => { + test_feature_availability( + desc, + t, + same_origin_src + sensorName, + expect_feature_available_default + ); + }, `${sensorName}: ${header} allows same-origin iframes.`); + + async_test(t => { + test_feature_availability( + desc, + t, + cross_origin_src + sensorName, + expect_feature_unavailable_default + ); + }, `${sensorName}: ${header} disallows cross-origin iframes.`); +} diff --git a/tests/wpt/web-platform-tests/generic-sensor/generic-sensor-tests.js b/tests/wpt/web-platform-tests/generic-sensor/generic-sensor-tests.js index afa0f462d90..cde23741d68 100644 --- a/tests/wpt/web-platform-tests/generic-sensor/generic-sensor-tests.js +++ b/tests/wpt/web-platform-tests/generic-sensor/generic-sensor-tests.js @@ -1,15 +1,16 @@ -let unreached = event => { - assert_unreached(event.error.name + ": " + event.error.message); -}; - -let properties = { +const properties = { 'AmbientLightSensor' : ['timestamp', 'illuminance'], 'Accelerometer' : ['timestamp', 'x', 'y', 'z'], 'LinearAccelerationSensor' : ['timestamp', 'x', 'y', 'z'], + "GravitySensor" : ['timestamp', 'x', 'y', 'z'], 'Gyroscope' : ['timestamp', 'x', 'y', 'z'], 'Magnetometer' : ['timestamp', 'x', 'y', 'z'], + "UncalibratedMagnetometer" : ['timestamp', 'x', 'y', 'z', + 'xBias', 'yBias', 'zBias'], 'AbsoluteOrientationSensor' : ['timestamp', 'quaternion'], - 'RelativeOrientationSensor' : ['timestamp', 'quaternion'] + 'RelativeOrientationSensor' : ['timestamp', 'quaternion'], + 'GeolocationSensor' : ['timestamp', 'latitude', 'longitude', 'altitude', + 'accuracy', 'altitudeAccuracy', 'heading', 'speed'] }; function assert_reading_not_null(sensor) { @@ -27,7 +28,7 @@ function assert_reading_null(sensor) { } function reading_to_array(sensor) { - let arr = new Array(); + const arr = new Array(); for (let property in properties[sensor.constructor.name]) { let propertyName = properties[sensor.constructor.name][property]; arr[property] = sensor[propertyName]; @@ -36,159 +37,129 @@ function reading_to_array(sensor) { } function runGenericSensorTests(sensorType) { - async_test(t => { - let sensor = new sensorType(); - sensor.onreading = t.step_func_done(() => { - assert_reading_not_null(sensor); - assert_true(sensor.hasReading); - sensor.stop(); - assert_reading_null(sensor); - assert_false(sensor.hasReading); - }); - sensor.onerror = t.step_func_done(unreached); + promise_test(async t => { + const sensor = new sensorType(); + const sensorWatcher = new EventWatcher(t, sensor, ["reading", "error"]); sensor.start(); + + await sensorWatcher.wait_for("reading"); + assert_reading_not_null(sensor); + assert_true(sensor.hasReading); + + sensor.stop(); + assert_reading_null(sensor); + assert_false(sensor.hasReading); }, `${sensorType.name}: Test that 'onreading' is called and sensor reading is valid`); - async_test(t => { - let sensor1 = new sensorType(); - let sensor2 = new sensorType(); - sensor1.onreading = t.step_func_done(() => { - // Reading values are correct for both sensors. - assert_reading_not_null(sensor1); - assert_reading_not_null(sensor2); - - //After first sensor stops its reading values are null, - //reading values for the second sensor remains - sensor1.stop(); - assert_reading_null(sensor1); - assert_reading_not_null(sensor2); - sensor2.stop(); - assert_reading_null(sensor2); - }); - sensor1.onerror = t.step_func_done(unreached); - sensor2.onerror = t.step_func_done(unreached); + promise_test(async t => { + const sensor1 = new sensorType(); + const sensor2 = new sensorType(); + const sensorWatcher = new EventWatcher(t, sensor1, ["reading", "error"]); sensor2.start(); sensor1.start(); + + await sensorWatcher.wait_for("reading"); + // Reading values are correct for both sensors. + assert_reading_not_null(sensor1); + assert_reading_not_null(sensor2); + + //After first sensor stops its reading values are null, + //reading values for the second sensor remains + sensor1.stop(); + assert_reading_null(sensor1); + assert_reading_not_null(sensor2); + sensor2.stop(); + assert_reading_null(sensor2); }, `${sensorType.name}: sensor reading is correct`); - async_test(t => { - let sensor = new sensorType(); - let cachedTimeStamp1; - sensor.onreading = () => { - cachedTimeStamp1 = sensor.timestamp; - }; - sensor.onerror = t.step_func_done(unreached); + promise_test(async t => { + const sensor = new sensorType(); + const sensorWatcher = new EventWatcher(t, sensor, ["reading", "error"]); sensor.start(); - t.step_timeout(() => { - sensor.onreading = t.step_func_done(() => { - //sensor.timestamp changes. - let cachedTimeStamp2 = sensor.timestamp; - assert_greater_than(cachedTimeStamp2, cachedTimeStamp1); - sensor.stop(); - }); - }, 1000); + + await sensorWatcher.wait_for("reading"); + const cachedTimeStamp1 = sensor.timestamp; + + await sensorWatcher.wait_for("reading"); + const cachedTimeStamp2 = sensor.timestamp; + + assert_greater_than(cachedTimeStamp2, cachedTimeStamp1); + sensor.stop(); }, `${sensorType.name}: sensor timestamp is updated when time passes`); - async_test(t => { - let sensor = new sensorType(); - sensor.onerror = t.step_func_done(unreached); + promise_test(async t => { + const sensor = new sensorType(); + const sensorWatcher = new EventWatcher(t, sensor, ["activate", "error"]); assert_false(sensor.activated); - sensor.onreading = t.step_func_done(() => { - assert_true(sensor.activated); - sensor.stop(); - assert_false(sensor.activated); - }); sensor.start(); assert_false(sensor.activated); + + await sensorWatcher.wait_for("activate"); + assert_true(sensor.activated); + + sensor.stop(); + assert_false(sensor.activated); }, `${sensorType.name}: Test that sensor can be successfully created and its states are correct.`); - test(() => { - let sensor, start_return; - sensor = new sensorType(); - sensor.onerror = unreached; - start_return = sensor.start(); + promise_test(async t => { + const sensor = new sensorType(); + const sensorWatcher = new EventWatcher(t, sensor, ["activate", "error"]); + const start_return = sensor.start(); + + await sensorWatcher.wait_for("activate"); assert_equals(start_return, undefined); sensor.stop(); }, `${sensorType.name}: sensor.start() returns undefined`); - test(() => { - try { - let sensor = new sensorType(); - sensor.onerror = unreached; - sensor.start(); - sensor.start(); - assert_false(sensor.activated); - sensor.stop(); - } catch (e) { - assert_unreached(e.name + ": " + e.message); - } + promise_test(async t => { + const sensor = new sensorType(); + const sensorWatcher = new EventWatcher(t, sensor, ["activate", "error"]); + sensor.start(); + sensor.start(); + + await sensorWatcher.wait_for("activate"); + assert_true(sensor.activated); + sensor.stop(); }, `${sensorType.name}: no exception is thrown when calling start() on already started sensor`); - test(() => { - let sensor, stop_return; - sensor = new sensorType(); - sensor.onerror = unreached; + promise_test(async t => { + const sensor = new sensorType(); + const sensorWatcher = new EventWatcher(t, sensor, ["activate", "error"]); sensor.start(); - stop_return = sensor.stop(); + + await sensorWatcher.wait_for("activate"); + const stop_return = sensor.stop(); assert_equals(stop_return, undefined); }, `${sensorType.name}: sensor.stop() returns undefined`); - test(() => { - try { - let sensor = new sensorType(); - sensor.onerror = unreached; - sensor.start(); - sensor.stop(); - sensor.stop(); - assert_false(sensor.activated); - } catch (e) { - assert_unreached(e.name + ": " + e.message); - } + promise_test(async t => { + const sensor = new sensorType(); + const sensorWatcher = new EventWatcher(t, sensor, ["activate", "error"]); + sensor.start(); + + await sensorWatcher.wait_for("activate"); + sensor.stop(); + sensor.stop(); + assert_false(sensor.activated); }, `${sensorType.name}: no exception is thrown when calling stop() on already stopped sensor`); - promise_test(() => { - return new Promise((resolve,reject) => { - let iframe = document.createElement('iframe'); - iframe.srcdoc = ' + + + + + diff --git a/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor-disabled-by-feature-policy.https.html.headers b/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor-disabled-by-feature-policy.https.html.headers new file mode 100644 index 00000000000..7e75481ea6d --- /dev/null +++ b/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor-disabled-by-feature-policy.https.html.headers @@ -0,0 +1 @@ +Feature-Policy: geolocation 'none' diff --git a/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor-enabled-by-feature-policy-attribute-redirect-on-load.https.html b/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor-enabled-by-feature-policy-attribute-redirect-on-load.https.html new file mode 100644 index 00000000000..62c5d456f0c --- /dev/null +++ b/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor-enabled-by-feature-policy-attribute-redirect-on-load.https.html @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor-enabled-by-feature-policy-attribute.https.html b/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor-enabled-by-feature-policy-attribute.https.html new file mode 100644 index 00000000000..1e5bfb36a2b --- /dev/null +++ b/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor-enabled-by-feature-policy-attribute.https.html @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor-enabled-by-feature-policy.https.html b/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor-enabled-by-feature-policy.https.html new file mode 100644 index 00000000000..afe935efeb0 --- /dev/null +++ b/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor-enabled-by-feature-policy.https.html @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor-enabled-by-feature-policy.https.html.headers b/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor-enabled-by-feature-policy.https.html.headers new file mode 100644 index 00000000000..40e9bc16ff9 --- /dev/null +++ b/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor-enabled-by-feature-policy.https.html.headers @@ -0,0 +1 @@ +Feature-Policy: geolocation * diff --git a/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor-enabled-on-self-origin-by-feature-policy.https.html b/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor-enabled-on-self-origin-by-feature-policy.https.html new file mode 100644 index 00000000000..46be7fba6f6 --- /dev/null +++ b/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor-enabled-on-self-origin-by-feature-policy.https.html @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor-enabled-on-self-origin-by-feature-policy.https.html.headers b/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor-enabled-on-self-origin-by-feature-policy.https.html.headers new file mode 100644 index 00000000000..b83264eee76 --- /dev/null +++ b/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor-enabled-on-self-origin-by-feature-policy.https.html.headers @@ -0,0 +1 @@ +Feature-Policy: geolocation 'self' diff --git a/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor.https.html b/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor.https.html new file mode 100644 index 00000000000..625963870f6 --- /dev/null +++ b/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor.https.html @@ -0,0 +1,13 @@ + + +GeolocationSensor Test + + + + + + diff --git a/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor_insecure_context.html b/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor_insecure_context.html new file mode 100644 index 00000000000..6a3a126c785 --- /dev/null +++ b/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor_insecure_context.html @@ -0,0 +1,13 @@ + + +GeolocationSensor Test: insecure context + + + + + + diff --git a/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor_onerror-manual.https.html b/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor_onerror-manual.https.html new file mode 100644 index 00000000000..b449346546f --- /dev/null +++ b/tests/wpt/web-platform-tests/geolocation-sensor/GeolocationSensor_onerror-manual.https.html @@ -0,0 +1,19 @@ + + +GeolocationSensor Test: onerror + + + + + +

Precondition

+
    +
  1. + Disable the Geolocation sensor or run test on a device without Geolocation sensor. +
  2. +
+ diff --git a/tests/wpt/web-platform-tests/geolocation-sensor/OWNERS b/tests/wpt/web-platform-tests/geolocation-sensor/OWNERS index a21fb0e4b54..71305991859 100644 --- a/tests/wpt/web-platform-tests/geolocation-sensor/OWNERS +++ b/tests/wpt/web-platform-tests/geolocation-sensor/OWNERS @@ -1 +1,2 @@ @anssiko +@Honry diff --git a/tests/wpt/web-platform-tests/geolocation-sensor/idlharness.https.html b/tests/wpt/web-platform-tests/geolocation-sensor/idlharness.https.html index e2aee5c1cb8..183b3f865ce 100644 --- a/tests/wpt/web-platform-tests/geolocation-sensor/idlharness.https.html +++ b/tests/wpt/web-platform-tests/geolocation-sensor/idlharness.https.html @@ -1,15 +1,19 @@ + Geolocation Sensor IDL tests - - - - + + + + + + diff --git a/tests/wpt/web-platform-tests/gyroscope/Gyroscope-disabled-by-feature-policy.https.html b/tests/wpt/web-platform-tests/gyroscope/Gyroscope-disabled-by-feature-policy.https.html new file mode 100644 index 00000000000..70add9b38bd --- /dev/null +++ b/tests/wpt/web-platform-tests/gyroscope/Gyroscope-disabled-by-feature-policy.https.html @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/tests/wpt/web-platform-tests/gyroscope/Gyroscope-disabled-by-feature-policy.https.html.headers b/tests/wpt/web-platform-tests/gyroscope/Gyroscope-disabled-by-feature-policy.https.html.headers new file mode 100644 index 00000000000..3d91d5840be --- /dev/null +++ b/tests/wpt/web-platform-tests/gyroscope/Gyroscope-disabled-by-feature-policy.https.html.headers @@ -0,0 +1 @@ +Feature-Policy: gyroscope 'none' diff --git a/tests/wpt/web-platform-tests/gyroscope/Gyroscope-enabled-by-feature-policy-attribute-redirect-on-load.https.html b/tests/wpt/web-platform-tests/gyroscope/Gyroscope-enabled-by-feature-policy-attribute-redirect-on-load.https.html new file mode 100644 index 00000000000..6d8c48645ed --- /dev/null +++ b/tests/wpt/web-platform-tests/gyroscope/Gyroscope-enabled-by-feature-policy-attribute-redirect-on-load.https.html @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/tests/wpt/web-platform-tests/gyroscope/Gyroscope-enabled-by-feature-policy-attribute.https.html b/tests/wpt/web-platform-tests/gyroscope/Gyroscope-enabled-by-feature-policy-attribute.https.html new file mode 100644 index 00000000000..07624624ce7 --- /dev/null +++ b/tests/wpt/web-platform-tests/gyroscope/Gyroscope-enabled-by-feature-policy-attribute.https.html @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/tests/wpt/web-platform-tests/gyroscope/Gyroscope-enabled-by-feature-policy.https.html b/tests/wpt/web-platform-tests/gyroscope/Gyroscope-enabled-by-feature-policy.https.html new file mode 100644 index 00000000000..1f1418b2014 --- /dev/null +++ b/tests/wpt/web-platform-tests/gyroscope/Gyroscope-enabled-by-feature-policy.https.html @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/tests/wpt/web-platform-tests/gyroscope/Gyroscope-enabled-by-feature-policy.https.html.headers b/tests/wpt/web-platform-tests/gyroscope/Gyroscope-enabled-by-feature-policy.https.html.headers new file mode 100644 index 00000000000..0fd938b4aa9 --- /dev/null +++ b/tests/wpt/web-platform-tests/gyroscope/Gyroscope-enabled-by-feature-policy.https.html.headers @@ -0,0 +1 @@ +Feature-Policy: gyroscope * diff --git a/tests/wpt/web-platform-tests/gyroscope/Gyroscope-enabled-on-self-origin-by-feature-policy.https.html b/tests/wpt/web-platform-tests/gyroscope/Gyroscope-enabled-on-self-origin-by-feature-policy.https.html new file mode 100644 index 00000000000..19ab572b382 --- /dev/null +++ b/tests/wpt/web-platform-tests/gyroscope/Gyroscope-enabled-on-self-origin-by-feature-policy.https.html @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/tests/wpt/web-platform-tests/gyroscope/Gyroscope-enabled-on-self-origin-by-feature-policy.https.html.headers b/tests/wpt/web-platform-tests/gyroscope/Gyroscope-enabled-on-self-origin-by-feature-policy.https.html.headers new file mode 100644 index 00000000000..7cf4fd8f6bd --- /dev/null +++ b/tests/wpt/web-platform-tests/gyroscope/Gyroscope-enabled-on-self-origin-by-feature-policy.https.html.headers @@ -0,0 +1 @@ +Feature-Policy: gyroscope 'self' diff --git a/tests/wpt/web-platform-tests/hr-time/idlharness.html b/tests/wpt/web-platform-tests/hr-time/idlharness.html index d0c648c1bb7..c3fd9070ad0 100644 --- a/tests/wpt/web-platform-tests/hr-time/idlharness.html +++ b/tests/wpt/web-platform-tests/hr-time/idlharness.html @@ -13,63 +13,34 @@

High Resolution Time IDL tests

- - - -
-typedef double DOMHighResTimeStamp;
-
-[Exposed=(Window,Worker)]
-interface Performance : EventTarget {
-    DOMHighResTimeStamp now();
-    readonly attribute DOMHighResTimeStamp timeOrigin;
-    [Default] object              toJSON();
-};
-
-partial interface WindowOrWorkerGlobalScope {
-    [Replaceable]
-    readonly attribute Performance performance;
-};
-
- diff --git a/tests/wpt/web-platform-tests/hr-time/performance-tojson.html b/tests/wpt/web-platform-tests/hr-time/performance-tojson.html new file mode 100644 index 00000000000..fd8049cb9a1 --- /dev/null +++ b/tests/wpt/web-platform-tests/hr-time/performance-tojson.html @@ -0,0 +1,76 @@ + + + + + + + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/browsers/browsing-the-web/history-traversal/PopStateEvent.html b/tests/wpt/web-platform-tests/html/browsers/browsing-the-web/history-traversal/PopStateEvent.html index 85205c1497b..8db1d2788c0 100644 --- a/tests/wpt/web-platform-tests/html/browsers/browsing-the-web/history-traversal/PopStateEvent.html +++ b/tests/wpt/web-platform-tests/html/browsers/browsing-the-web/history-traversal/PopStateEvent.html @@ -10,6 +10,11 @@ test(function () { 'There should be no PopStateEvent#initPopStateEvent'); }, 'initPopStateEvent'); +test(function () { + var popStateEvent = new PopStateEvent("popstate"); + assert_equals(popStateEvent.state, null, "the PopStateEvent.state"); +}, "Initial value of PopStateEvent.state must be null"); + test(function () { var state = history.state; var data; diff --git a/tests/wpt/web-platform-tests/html/browsers/browsing-the-web/history-traversal/hashchange_event.html b/tests/wpt/web-platform-tests/html/browsers/browsing-the-web/history-traversal/hashchange_event.html index 4b701ad04e2..287e7a6ef1d 100644 --- a/tests/wpt/web-platform-tests/html/browsers/browsing-the-web/history-traversal/hashchange_event.html +++ b/tests/wpt/web-platform-tests/html/browsers/browsing-the-web/history-traversal/hashchange_event.html @@ -18,6 +18,12 @@ window.onload = t.step_func(function () { location.hash = 'foo'; window.onhashchange = t.step_func(function (e) { + assert_true(e.isTrusted); + assert_equals(e.target, window); + assert_equals(e.type, "hashchange"); + assert_true(e instanceof HashChangeEvent); + assert_true(e.bubbles, "bubble"); + assert_false(e.cancelable, "cancelable"); oldURLs.push(e.oldURL); newURLs.push(e.newURL); if (newURLs.length === 2) { diff --git a/tests/wpt/web-platform-tests/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/scroll-restoration-fragment-scrolling-cross-origin.html b/tests/wpt/web-platform-tests/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/scroll-restoration-fragment-scrolling-cross-origin.html index 4594a1ed954..7d9a31d0d40 100644 --- a/tests/wpt/web-platform-tests/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/scroll-restoration-fragment-scrolling-cross-origin.html +++ b/tests/wpt/web-platform-tests/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/scroll-restoration-fragment-scrolling-cross-origin.html @@ -1,20 +1,18 @@ Precedence of scroll restoration mode over fragment scrolling in cross-origin history traversal + + + - - - - - - - - - - + +Media documents: video + + + + + + +
- - -
- - - diff --git a/tests/wpt/web-platform-tests/html/browsers/history/the-session-history-of-browsing-contexts/navigation-in-onload.tentative.html b/tests/wpt/web-platform-tests/html/browsers/history/the-session-history-of-browsing-contexts/navigation-in-onload.tentative.html index 1b7183bd0ed..3e021c65ac8 100644 --- a/tests/wpt/web-platform-tests/html/browsers/history/the-session-history-of-browsing-contexts/navigation-in-onload.tentative.html +++ b/tests/wpt/web-platform-tests/html/browsers/history/the-session-history-of-browsing-contexts/navigation-in-onload.tentative.html @@ -14,7 +14,7 @@ var t = async_test(); function scheduleNextTest() { - t.step_timeout(runNextTest, 0); + setTimeout(runNextTest, 0); } function runNextTest() { @@ -28,9 +28,9 @@ } function verify(actual, expected, desc) { - t.step_timeout(function() { + setTimeout(t.step_func(function() { assert_equals(actual, expected, desc); - }, 0); + }), 0); } diff --git a/tests/wpt/web-platform-tests/html/browsers/history/the-session-history-of-browsing-contexts/navigation-in-onload_form-submission-2.tentative.html b/tests/wpt/web-platform-tests/html/browsers/history/the-session-history-of-browsing-contexts/navigation-in-onload_form-submission-2.tentative.html index 10cc69ae0f4..11fbe2a2ba8 100644 --- a/tests/wpt/web-platform-tests/html/browsers/history/the-session-history-of-browsing-contexts/navigation-in-onload_form-submission-2.tentative.html +++ b/tests/wpt/web-platform-tests/html/browsers/history/the-session-history-of-browsing-contexts/navigation-in-onload_form-submission-2.tentative.html @@ -9,10 +9,10 @@ function verify() { // Navigation in onload handler through form submission should not // increse history length. - var testRunner = window.top.opener; - testRunner.verify(history.length, 1, + var runner = window.top.opener; + runner.verify(history.length, 1, "history.length of subtest '" + top.document.title + "'."); - testRunner.scheduleNextTest(); + runner.scheduleNextTest(); setTimeout(window.close.bind(top), 0); } diff --git a/tests/wpt/web-platform-tests/html/browsers/sandboxing/noscript-iframe.html b/tests/wpt/web-platform-tests/html/browsers/sandboxing/noscript-iframe.html new file mode 100644 index 00000000000..677b5fc83aa --- /dev/null +++ b/tests/wpt/web-platform-tests/html/browsers/sandboxing/noscript-iframe.html @@ -0,0 +1,3 @@ + + + diff --git a/tests/wpt/web-platform-tests/html/browsers/sandboxing/sandbox-parse-noscript-ref.html b/tests/wpt/web-platform-tests/html/browsers/sandboxing/sandbox-parse-noscript-ref.html new file mode 100644 index 00000000000..9cf92768f78 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/browsers/sandboxing/sandbox-parse-noscript-ref.html @@ -0,0 +1,6 @@ + + +noscript parsing when sandbox disables scripting + + + diff --git a/tests/wpt/web-platform-tests/html/browsers/sandboxing/sandbox-parse-noscript.html b/tests/wpt/web-platform-tests/html/browsers/sandboxing/sandbox-parse-noscript.html new file mode 100644 index 00000000000..bb7ced0a14b --- /dev/null +++ b/tests/wpt/web-platform-tests/html/browsers/sandboxing/sandbox-parse-noscript.html @@ -0,0 +1,7 @@ + + +noscript parsing when sandbox disables scripting + + + + diff --git a/tests/wpt/web-platform-tests/html/browsers/windows/browsing-context.html b/tests/wpt/web-platform-tests/html/browsers/windows/browsing-context.html index ad3a01fd3eb..5e99bb522f1 100644 --- a/tests/wpt/web-platform-tests/html/browsers/windows/browsing-context.html +++ b/tests/wpt/web-platform-tests/html/browsers/windows/browsing-context.html @@ -44,11 +44,6 @@ assert_equals(doc.referrer, document.URL, "The document's referrer should be its creator document's address."); assert_equals(iframe.contentWindow.parent.document, document); }, "Check the document properties corresponding to the creator browsing context"); - - test(function () { - assert_equals(iframe.contentWindow.history.length, 1, "The history.length should be 1."); - }, "Check the history.length of the created browsing context"); - diff --git a/tests/wpt/web-platform-tests/html/dom/elements-embedded.js b/tests/wpt/web-platform-tests/html/dom/elements-embedded.js index 176da29d4f6..d0c5dbcb76b 100644 --- a/tests/wpt/web-platform-tests/html/dom/elements-embedded.js +++ b/tests/wpt/web-platform-tests/html/dom/elements-embedded.js @@ -11,6 +11,7 @@ var embeddedElements = { width: {type: "unsigned long", customGetter: true}, height: {type: "unsigned long", customGetter: true}, referrerPolicy: {type: "enum", keywords: ["", "no-referrer", "no-referrer-when-downgrade", "same-origin", "origin", "strict-origin", "origin-when-cross-origin", "strict-origin-when-cross-origin", "unsafe-url"]}, + decoding: {type: "enum", keywords: ["async", "sync", "auto"], defaultVal: "auto", invalidVal: "auto"}, // Obsolete name: "string", diff --git a/tests/wpt/web-platform-tests/html/dom/elements-forms.js b/tests/wpt/web-platform-tests/html/dom/elements-forms.js index fc455352578..051bc2087f3 100644 --- a/tests/wpt/web-platform-tests/html/dom/elements-forms.js +++ b/tests/wpt/web-platform-tests/html/dom/elements-forms.js @@ -1,17 +1,3 @@ -var inputModeKeywords = [ - "verbatim", - "latin", - "latin-name", - "latin-prose", - "full-width-latin", - "kana", - "kana-name", - "katakana", - "numeric", - "tel", - "email", - "url", -]; var formElements = { form: { acceptCharset: {type: "string", domAttrName: "accept-charset"}, @@ -52,7 +38,6 @@ var formElements = { formNoValidate: "boolean", formTarget: "string", height: {type: "unsigned long", customGetter: true}, - inputMode: {type: "enum", keywords: inputModeKeywords}, max: "string", maxLength: "limited long", min: "string", @@ -118,7 +103,6 @@ var formElements = { cols: {type: "limited unsigned long with fallback", defaultVal: 20}, dirName: "string", disabled: "boolean", - inputMode: {type: "enum", keywords: inputModeKeywords}, maxLength: "limited long", minLength: "limited long", name: "string", diff --git a/tests/wpt/web-platform-tests/html/dom/elements-metadata.js b/tests/wpt/web-platform-tests/html/dom/elements-metadata.js index f30459013cb..8af6a6a67c0 100644 --- a/tests/wpt/web-platform-tests/html/dom/elements-metadata.js +++ b/tests/wpt/web-platform-tests/html/dom/elements-metadata.js @@ -12,7 +12,7 @@ var metadataElements = { rel: "string", as: { type: "enum", - keywords: ["fetch", "audio", "document", "embed", "font", "image", "manifest", "object", "report", "script", "serviceworker", "sharedworker", "style", "track", "video", "worker", "xslt"], + keywords: ["fetch", "audio", "document", "embed", "font", "image", "manifest", "object", "report", "script", "sharedworker", "style", "track", "video", "worker", "xslt"], defaultVal: "", invalidVal: "" }, @@ -24,19 +24,6 @@ var metadataElements = { type: "string", sizes: "settable tokenlist", referrerPolicy: {type: "enum", keywords: ["", "no-referrer", "no-referrer-when-downgrade", "same-origin", "origin", "strict-origin", "origin-when-cross-origin", "strict-origin-when-cross-origin", "unsafe-url"]}, - scope: "string", - workerType: { - type: "enum", - keywords: ["classic", "module"], - defaultVal: "classic", - invalidVal: "", - }, - updateViaCache: { - type: "enum", - keywords: ["imports", "all", "none"], - defaultVal: "imports", - invalidVal: "imports" - }, // Obsolete charset: "string", diff --git a/tests/wpt/web-platform-tests/html/dom/elements-misc.js b/tests/wpt/web-platform-tests/html/dom/elements-misc.js index 43cdf5f32da..df415aef159 100644 --- a/tests/wpt/web-platform-tests/html/dom/elements-misc.js +++ b/tests/wpt/web-platform-tests/html/dom/elements-misc.js @@ -52,7 +52,9 @@ var miscElements = { }, // Global attributes should exist even on unknown elements - undefinedelement: {}, + undefinedelement: { + inputMode: {type: "enum", keywords: ["none", "text", "tel", "url", "email", "numeric", "decimal", "search"]}, + }, }; mergeElements(miscElements); diff --git a/tests/wpt/web-platform-tests/html/dom/reflection.js b/tests/wpt/web-platform-tests/html/dom/reflection.js index 337e053d0c8..9a98478b9dc 100644 --- a/tests/wpt/web-platform-tests/html/dom/reflection.js +++ b/tests/wpt/web-platform-tests/html/dom/reflection.js @@ -669,8 +669,12 @@ ReflectionTests.reflects = function(data, idlName, idlObj, domName, domObj) { } if (data.keywords[i].length > 1) { - domTests.push(data.keywords[i].slice(1)); - idlTests.push(data.keywords[i].slice(1)); + var sliced = data.keywords[i].slice(1); + // If slicing a value yields another valid value, then skip it since it results in duplicate tests. + if (data.keywords.indexOf(sliced) == -1) { + domTests.push(sliced); + idlTests.push(sliced); + } } if (data.keywords[i] != data.keywords[i].toLowerCase()) { diff --git a/tests/wpt/web-platform-tests/html/dom/usvstring-reflection.html b/tests/wpt/web-platform-tests/html/dom/usvstring-reflection.html new file mode 100644 index 00000000000..c3a79e779e9 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/dom/usvstring-reflection.html @@ -0,0 +1,89 @@ + +USVString test relate to url + + +
+ diff --git a/tests/wpt/web-platform-tests/html/form-elements/the-textarea-element/multiline-placeholder-cr.html b/tests/wpt/web-platform-tests/html/form-elements/the-textarea-element/multiline-placeholder-cr.html new file mode 100644 index 00000000000..8879ca46479 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/form-elements/the-textarea-element/multiline-placeholder-cr.html @@ -0,0 +1 @@ + textarea multiline placeholder (CR) \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/form-elements/the-textarea-element/multiline-placeholder-crlf.html b/tests/wpt/web-platform-tests/html/form-elements/the-textarea-element/multiline-placeholder-crlf.html new file mode 100644 index 00000000000..9632ef1bb6c --- /dev/null +++ b/tests/wpt/web-platform-tests/html/form-elements/the-textarea-element/multiline-placeholder-crlf.html @@ -0,0 +1,21 @@ + + + +textarea multiline placeholder (CRLF) + + + + + + + + + + diff --git a/tests/wpt/web-platform-tests/html/form-elements/the-textarea-element/multiline-placeholder-ref.html b/tests/wpt/web-platform-tests/html/form-elements/the-textarea-element/multiline-placeholder-ref.html new file mode 100644 index 00000000000..0234ed64c9a --- /dev/null +++ b/tests/wpt/web-platform-tests/html/form-elements/the-textarea-element/multiline-placeholder-ref.html @@ -0,0 +1,15 @@ + + + + + + diff --git a/tests/wpt/web-platform-tests/html/form-elements/the-textarea-element/multiline-placeholder.html b/tests/wpt/web-platform-tests/html/form-elements/the-textarea-element/multiline-placeholder.html new file mode 100644 index 00000000000..00bb9696d1a --- /dev/null +++ b/tests/wpt/web-platform-tests/html/form-elements/the-textarea-element/multiline-placeholder.html @@ -0,0 +1,22 @@ + + + +textarea multiline placeholder + + + + + + + + + + + diff --git a/tests/wpt/web-platform-tests/html/form-elements/the-textarea-element/support/placeholder.css b/tests/wpt/web-platform-tests/html/form-elements/the-textarea-element/support/placeholder.css new file mode 100644 index 00000000000..9aaed05c86a --- /dev/null +++ b/tests/wpt/web-platform-tests/html/form-elements/the-textarea-element/support/placeholder.css @@ -0,0 +1,6 @@ +textarea.placeholder, +textarea::placeholder { + /* revert browser styling of the placeholder */ + color: GrayText; /* blink/webkit use colour */ + opacity: 1.0; /* gecko uses opacity */ +} diff --git a/tests/wpt/web-platform-tests/html/input/the-placeholder-attribute/multiline-cr.html b/tests/wpt/web-platform-tests/html/input/the-placeholder-attribute/multiline-cr.html new file mode 100644 index 00000000000..4184ab2c5ce --- /dev/null +++ b/tests/wpt/web-platform-tests/html/input/the-placeholder-attribute/multiline-cr.html @@ -0,0 +1 @@ + input multiline placeholder (CRLF) \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/input/the-placeholder-attribute/multiline-crlf.html b/tests/wpt/web-platform-tests/html/input/the-placeholder-attribute/multiline-crlf.html new file mode 100644 index 00000000000..50c91fbe35e --- /dev/null +++ b/tests/wpt/web-platform-tests/html/input/the-placeholder-attribute/multiline-crlf.html @@ -0,0 +1,19 @@ + + + +input multiline placeholder (CRLF) + + + + + + + + diff --git a/tests/wpt/web-platform-tests/html/input/the-placeholder-attribute/multiline-ref.html b/tests/wpt/web-platform-tests/html/input/the-placeholder-attribute/multiline-ref.html new file mode 100644 index 00000000000..2812f86e1e6 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/input/the-placeholder-attribute/multiline-ref.html @@ -0,0 +1,5 @@ + + + + + diff --git a/tests/wpt/web-platform-tests/html/input/the-placeholder-attribute/multiline.html b/tests/wpt/web-platform-tests/html/input/the-placeholder-attribute/multiline.html new file mode 100644 index 00000000000..2d7102bd4ac --- /dev/null +++ b/tests/wpt/web-platform-tests/html/input/the-placeholder-attribute/multiline.html @@ -0,0 +1,19 @@ + + + +input multiline placeholder + + + + + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLMediaElement/crossOrigin.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLMediaElement/crossOrigin.html new file mode 100644 index 00000000000..e29f2b0fbcd --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLMediaElement/crossOrigin.html @@ -0,0 +1,60 @@ + +HTMLMediaElement.crossOrigin + + +
+ diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLTrackElement/readyState.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLTrackElement/readyState.html index e18f21934de..cde21e694e5 100644 --- a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLTrackElement/readyState.html +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLTrackElement/readyState.html @@ -8,4 +8,11 @@ test(function(){ var track = document.createElement('track'); assert_equals(track.readyState, 0); }, document.title + ' default value'); + +test(function(){ + assert_equals(HTMLTrackElement.NONE, 0); + assert_equals(HTMLTrackElement.LOADING, 1); + assert_equals(HTMLTrackElement.LOADED, 2); + assert_equals(HTMLTrackElement.ERROR, 3); +}, document.title + ' values'); diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/interfaces/TextTrackCue/constructor.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/interfaces/TextTrackCue/constructor.html new file mode 100644 index 00000000000..c066f60399b --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/interfaces/TextTrackCue/constructor.html @@ -0,0 +1,23 @@ + + + + TextTrackCue constructor + + + + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/align-positioning-bad.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/align-positioning-bad.vtt new file mode 100644 index 00000000000..ff4c3fb5cd4 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/align-positioning-bad.vtt @@ -0,0 +1,20 @@ +WEBVTT +Either one or both of positioning and alignment values are invalid. + +1 +00:00:00.000 --> 00:00:30.500 position:10% align: start +Bear is Coming!!!!! +Positioning on the left bottom, middle aligned, +because the alignment is mistyped. + +2 +00:00:31.000 --> 00:00:45.500 position:200% align:middle +I said Bear is coming!!!! +Positioning on the bottom middle, middle aligned, +because the positioning is off. + +3 +00:01:01.000 --> 00:02:00.500 position:-80% align:ends +I said Bear is coming now!!!! +Positioning on the bottom middle, middle aligned, +because both the alignment and positioning don't apply. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/align-positioning.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/align-positioning.vtt new file mode 100644 index 00000000000..a6e6af2ef96 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/align-positioning.vtt @@ -0,0 +1,20 @@ +WEBVTT +Cues should position at different horizontal positions with different alignments. + +1 +00:00:00.000 --> 00:00:30.500 position:10% align:start +Bear is Coming!!!!! +Positioning on the left bottom, start aligned, and +first character rendering position is at 10% of width. + +2 +00:00:31.000 --> 00:00:45.500 position:20% align:middle +I said Bear is coming!!!! +Positioning on the bottom left, middle aligned, and +middle character rendering position of each line is at 20% of width. + +3 +00:01:01.000 --> 00:02:00.500 align:end position:80% +I said Bear is coming now!!!! +Positioning on the bottom right, end aligned, and +last character rendering position of each line is at 80% of width. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/align-text-line-position-bad.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/align-text-line-position-bad.vtt new file mode 100644 index 00000000000..b196f13a207 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/align-text-line-position-bad.vtt @@ -0,0 +1,21 @@ +WEBVTT +One or more of line/text positioning and alignment values are invalid (settings are ignored). + +1 +00:00:00.000 --> 00:00:30.500 position: 0% align: start line: 0% +Bear is Coming!!!!! +None of the cue settings will be applied, just the default. + +2 +00:00:31.000 --> 00:00:01.500 position:0% align:end line:-30% +I said Bear is coming!!!! +The line position setting is ignored. +No text is visible though because it's off-screen at position +0 and the last character is at position 0%. + +3 +00:01:01.000 --> 00:01:30.000 line:-3 align:middler position:60% +I said Bear is coming now!!!! +Positioning on line 3 from the viewport bottom, middle aligned, +with middle character of cue at 60% width. +The alignment is ignored. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/align-text-line-position.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/align-text-line-position.vtt new file mode 100644 index 00000000000..dd3a6debb89 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/align-text-line-position.vtt @@ -0,0 +1,28 @@ +WEBVTT +Cues with valid alignment, line and text position settings. + +1 +00:00:00.000 --> 00:00:15.000 position:10% align:start line:0% +Bear is Coming!!!!! +Positioning on the top of the viewport at 10% horizontally, +start aligned. + +00:00:15.500 --> 00:00:30.500 line:0 align:start +Bear is Coming!!!!! +This is line 0, middle aligned, first character at 50% width. + +2 +00:00:31.000 --> 00:00:45.500 position:80% line:80% +I said Bear is coming!!!! +Middle aligned, middle of cue's character is at 80% width and 80% height. + +00:00:46.000 --> 00:01:00.500 line:5 align:end position:30% +I said Bear is coming!!!! +This is line 6 from the top of the video viewport, +end aligned with last character at 30% of viewport width. + +3 +00:01:01.000 --> 00:01:30.000 line:-3 align:middle position:60% +I said Bear is coming now!!!! +Positioning on line 3 from the viewport bottom, middle aligned, +with middle character of cue at 60% width. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/alignment-bad.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/alignment-bad.vtt new file mode 100644 index 00000000000..5beb376f450 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/alignment-bad.vtt @@ -0,0 +1,22 @@ +WEBVTT +Cue alignment may only be start, middle, or end. These are all misspelled and so will default to middle. + +1 +00:00:00.000 --> 00:00:30.500 align:starta +Bear is Coming!!!!! +Erroneous alignment value -> middle. + +2 +00:00:31.000 --> 00:01:00.500 align:-start +I said Bear is coming!!!! +Erroneous alignment value --> middle. + +3 +00:01:01.000 --> 00:02:00.500 align: end +I said Bear is coming now!!!! +Erroneous alignment value with surplus whitespace --> middle. + +4 +00:02:01.000 --> 100:20:00.500 align:piugjk +I said Bear is coming now!!!! +Erroneous alignment value -> middle. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/alignment-ltr.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/alignment-ltr.vtt new file mode 100644 index 00000000000..673b29ac851 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/alignment-ltr.vtt @@ -0,0 +1,22 @@ +WEBVTT +Cue alignment may be start, middle, or end (default is middle). + +1 +00:00:00.000 --> 00:00:30.500 align:start +الدب قادم!!!!! +بدء محاذاته. + +2 +00:00:31.000 --> 00:01:00.500 align:middle +قلت الدب قادم!! +محاذاة الوسط. + +3 +00:01:01.000 --> 00:02:00.500 align:end +قلت الدب قادم الآن!! +محاذاة الغاية. + +4 +00:02:01.000 --> 100:20:00.500 +قلت الدب قادم الآن!! +الافتراضية هي محاذاة الوسط. \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/alignment.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/alignment.vtt new file mode 100644 index 00000000000..ad7792f7724 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/alignment.vtt @@ -0,0 +1,22 @@ +WEBVTT +Cue alignment may be start, middle, or end (default is middle). + +1 +00:00:00.000 --> 00:00:30.500 align:start +Bear is Coming!!!!! +Start align. + +2 +00:00:31.000 --> 00:01:00.500 align:middle +I said Bear is coming!!!! +Middle align. + +3 +00:01:01.000 --> 00:02:00.500 align:end +I said Bear is coming now!!!! +End align. + +4 +00:02:01.000 --> 100:20:00.500 +I said Bear is coming now!!!! +Default is middle alignment. \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/bom.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/bom.vtt new file mode 100644 index 00000000000..0c8de32bcb7 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/bom.vtt @@ -0,0 +1,10 @@ +WEBVTT FILE +A BOM character at the start of a file should be ignored. + +1 +00:00:00.000 --> 00:00:30.500 +Bear is Coming!!!!! + +2 +00:00:31.000 --> 00:20:00.500 +I said Bear is coming!!!! \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/captions-fast.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/captions-fast.vtt new file mode 100644 index 00000000000..cd138fd32af --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/captions-fast.vtt @@ -0,0 +1,13 @@ +WEBVTT + +1 +00:00:00.000 --> 00:00:00.300 +Lorem + +2 +00:00:00.300 --> 00:00:00.700 +ipsum + +3 +00:00:01.200 --> 00:00:01.500 +dolor diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/captions-gaps.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/captions-gaps.vtt new file mode 100644 index 00000000000..44c74665c25 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/captions-gaps.vtt @@ -0,0 +1,18 @@ +WEBVTT + +1 +00:00:01.000 --> 00:00:02.000 +Lorem ipsum dolor sit amet, + +2 +00:00:03.000 --> 00:00:04.000 +consectetuer adipiscing elit, + +3 +00:00:05.000 --> 00:00:06.000 +sed diam nonummy nibh euismod tincidunt + +4 +00:00:07.000 --> 00:00:08.000 +ut laoreet dolore magna aliquam erat volutpat. + diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/captions-html.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/captions-html.vtt new file mode 100644 index 00000000000..0730f8bc40b --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/captions-html.vtt @@ -0,0 +1,18 @@ +WEBVTT + +1 +00:00:00.000 --> 00:00:01.000 +Lorem ipsum dolor sit amet, + +2 +00:00:03.000 --> 00:00:04.000 +consectetuer adipiscing elit, + +3 +00:00:05.000 --> 00:00:06.000 +sed diam nonummy nibh euismod tincidunt + +4 +00:00:07.000 --> 00:00:08.000 +ut laoreet dolore magna aliquam erat volutpat. + diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/captions.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/captions.vtt new file mode 100644 index 00000000000..787c4308687 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/captions.vtt @@ -0,0 +1,18 @@ +WEBVTT + +1 +00:00:00.000 --> 00:00:01.000 +Lorem + +2 +00:00:01.000 --> 00:00:02.000 +ipsum + +3 +00:00:02.000 --> 00:00:03.000 +dolor + +4 +00:00:03.000 --> 00:00:04.000 +sit + diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/class-bad.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/class-bad.vtt new file mode 100644 index 00000000000..650ea2c4960 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/class-bad.vtt @@ -0,0 +1,17 @@ +WEBVTT +Invalid class markup. + +1 +00:00:00.000 --> 00:00:30.500 align:start position:20% +Bear is Coming!!!!! +The space signified an annotation start. + +2 +00:00:31.000 --> 00:01:00.500 align:start position:20% +I said Bear is coming!!!! +Probably should only allow characters that CSS allows in class names. + +3 +00:01:01.000 --> 00:02:00.500 align:start position:20% +I said Bear is coming now!!!! +Probably should only allow characters that CSS allows in class names. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/class.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/class.vtt new file mode 100644 index 00000000000..ea3ef623f59 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/class.vtt @@ -0,0 +1,14 @@ +WEBVTT +Cue text fragment with class markup is mapped to HTML element with CSS classes. + +1 +00:00:00.000 --> 00:00:30.500 align:start position:20% +Bear is Coming!!!!! + +2 +00:00:31.000 --> 00:01:00.500 align:start position:20% +I said Bear is coming!!!! + +3 +00:01:01.000 --> 00:02:00.500 align:start position:20% +I said Bear is coming now!!!! diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-id-error.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-id-error.vtt new file mode 100644 index 00000000000..2b5db0c1da4 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-id-error.vtt @@ -0,0 +1,14 @@ +WEBVTT +Cue identifiers cannot contain the string "-->". + +-->random_id +00:00:00.000 --> 00:00:30.500 +Bear is Coming!!!!! + +another random identifier--> +00:00:31.000 --> 00:01:00.500 +I said Bear is coming!!!! + +identifier-->too +00:01:01.000 --> 00:20:00.500 +I said Bear is coming now!!!! \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-id.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-id.vtt new file mode 100644 index 00000000000..39021186208 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-id.vtt @@ -0,0 +1,18 @@ +WEBVTT +Random text is accepted for cue identifiers. + +random_id +00:00:00.000 --> 00:00:30.500 +Bear is Coming!!!!! + +another random identifier +00:00:31.000 --> 00:01:00.500 +I said Bear is coming!!!! + +identifier--too +00:01:01.000 --> 00:02:00.500 +I said Bear is coming now!!!! + +identifier--too +00:02:01.000 --> 00:03:00.500 +Duplicate identifier \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-no-id-error.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-no-id-error.vtt new file mode 100644 index 00000000000..111bae6344b --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-no-id-error.vtt @@ -0,0 +1,14 @@ +WEBVTT +Cue identifiers cannot contain "-->". Whole cue is ignored. + +--> +00:00:00.000 --> 00:00:30.500 +Bear is Coming!!!!! + +--> +00:00:31.000 --> 00:01:00.500 +I said Bear is coming!!!! + +--> +00:01:01.000 --> 00:20:00.500 +I said Bear is coming now!!!! \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-no-id.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-no-id.vtt new file mode 100644 index 00000000000..0d52a70ee4b --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-no-id.vtt @@ -0,0 +1,11 @@ +WEBVTT +Cues don't have to have identifiers. + +00:00:00.000 --> 00:00:30.500 +Bear is Coming!!!!! + +00:00:31.000 --> 00:01:00.500 +I said Bear is coming!!!! + +00:01:01.000 --> 00:20:00.500 +I said Bear is coming now!!!! \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-recovery-cuetext.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-recovery-cuetext.vtt new file mode 100644 index 00000000000..88f56cceca8 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-recovery-cuetext.vtt @@ -0,0 +1,6 @@ +WEBVTT + +00:00.000 --> 00:01.000 +Valid cue 1 +00:02.000 --> 00:03.000 +Valid cue 2 diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-recovery-header.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-recovery-header.vtt new file mode 100644 index 00000000000..205955e3e49 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-recovery-header.vtt @@ -0,0 +1,6 @@ +WEBVTT +00:00.000 --> 00:01.000 +Valid cue 1 + +00:02.000 --> 00:03.000 +Valid cue 2 diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-recovery-note.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-recovery-note.vtt new file mode 100644 index 00000000000..56defcc48b0 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-recovery-note.vtt @@ -0,0 +1,9 @@ +WEBVTT + +00:00.000 --> 00:01.000 +Valid cue 1 + +NOTE about something +NOTE or something else - maybe an identifier +00:02.000 --> 00:03.000 +Valid cue 2 diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-size-align-bad.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-size-align-bad.vtt new file mode 100644 index 00000000000..5e4a61a5e40 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-size-align-bad.vtt @@ -0,0 +1,18 @@ +WEBVTT +Either size or alignment are invalid. + +1 +00:00:00.000 --> 00:00:30.500 size:100% align:@start +Bear is Coming!!!!! +Box for the cue is 100% of the video viewport width, alignment is ignored. + +2 +00:00:31.000 --> 00:01:00.500 size:-10% align:end +I said Bear is coming!!!! +Box for the cue is as big as the text, no line wrapping, +(except if viewport is too small) and end aligned. + +3 +00:01:01.000 --> 00:02:00.500 size:110% align:@end +I said Bear is coming now!!!! +Both cue size and alignment are ignored. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-size-align.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-size-align.vtt new file mode 100644 index 00000000000..6d365365396 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-size-align.vtt @@ -0,0 +1,19 @@ +WEBVTT +Valid cue size with alignment settings. + +1 +00:00:00.000 --> 00:00:30.500 size:100% align:start +Bear is Coming!!!!! +Box for the cue is 100% of the video viewport width +and because of the start align, all text is left aligned on the video viewport. + +2 +00:00:31.000 --> 00:01:00.500 size:10% align:end +I said Bear is coming!!!! +Box for the cue is 10% of the video viewport width, which will mean that automatic line wrapping will happen +and the text is aligned to the end. + +3 +00:01:01.000 --> 00:02:00.500 size:0% align:middle +I said Bear is coming now!!!! +Cue text box size of 0 is acceptable, even if not visible. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-size-bad.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-size-bad.vtt new file mode 100644 index 00000000000..700600d7a79 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-size-bad.vtt @@ -0,0 +1,17 @@ +WEBVTT +Invalid cue sizes (all settings are ignored). + +1 +00:00:00.000 --> 00:00:30.500 size: 50% +Bear is Coming!!!!! +Cue size setting doesn't parse and is ignored. + +2 +00:00:31.000 --> 00:01:00.500 size:-10% +I said Bear is coming!!!! +Negative cue size setting is not acceptable and is ignored. + +3 +00:01:01.000 --> 00:02:00.500 size:4000% +I said Bear is coming now!!!! +Cue size beyond 100% is not acceptable and is ignored. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-size.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-size.vtt new file mode 100644 index 00000000000..017d59a18bc --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cue-size.vtt @@ -0,0 +1,19 @@ +WEBVTT +Valid cue size values. + +1 +00:00:00.000 --> 00:00:30.500 size:100% +Bear is Coming!!!!! +Box for the cue is 100% of the video viewport width, +exemplified through background color, +even if the text needs less. + +2 +00:00:31.000 --> 00:01:00.500 size:10% +I said Bear is coming!!!! +Box for the cue is 10% of the video viewport width, which will mean that automatic line wrapping will happen. + +3 +00:01:01.000 --> 00:02:00.500 size:0% +I said Bear is coming now!!!! +Cue text box size of 0 is acceptable, even if not visible. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cues-no-separation.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cues-no-separation.vtt new file mode 100644 index 00000000000..9062c67edee --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cues-no-separation.vtt @@ -0,0 +1,11 @@ +WEBVTT +Cues must be separated by at least one blank line, otherwise treated like one big cue. + +1 +00:00:00.000 --> 00:00:30.500 +Bear is Coming!!!!! +2 +00:00:31.000 --> 00:01:00.500 +I said Bear is coming!!!! +00:01:01.000 --> 100:20:00.500 +I said Bear is coming now!!!! \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cues-overlapping.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cues-overlapping.vtt new file mode 100644 index 00000000000..3f035d331f0 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cues-overlapping.vtt @@ -0,0 +1,14 @@ +WEBVTT +Cues that have overlapping time ranges. + +1 +00:00:01.000 --> 00:00:06.000 +Bear is Coming!!!!! + +2 +00:00:01.500 --> 00:00:05.000 +I said Bear is coming!!!! + +3 +00:00:02.000 --> 00:00:05.000 +I said Bear is coming now!!!! \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cues.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cues.vtt new file mode 100644 index 00000000000..125ed667855 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/cues.vtt @@ -0,0 +1,17 @@ +WEBVTT +Cues may be separated by one or more blank lines. + +1 +00:00:00.000 --> 00:00:30.500 +Bear is Coming!!!!! + + +2 +00:00:31.000 --> 00:01:00.500 +I said Bear is coming!!!! + + + +3 +00:01:01.000 --> 100:20:00.500 +I said Bear is coming now!!!! \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/default-styles.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/default-styles.vtt new file mode 100644 index 00000000000..d890ca3f71a --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/default-styles.vtt @@ -0,0 +1,19 @@ +WEBVTT + +COMMENT--> +this is a comment, that will parse as part of the header; +the STYLE and DEFAULTS below are parsed as invalid cues + +STYLE--> +::cue(.narration) { color: blue; } + +DEFAULTS --> +line:-1 align:middle size:50% + +1 +00:00:00.000 --> 00:00:30.500 +Bear is Coming!!!!! + +2 +00:00:31.000 --> 00:20:00.500 +I said Bear is coming!!!! \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/degenerate-cues.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/degenerate-cues.vtt new file mode 100644 index 00000000000..c04390420f7 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/degenerate-cues.vtt @@ -0,0 +1,5 @@ +WEBVTT + +00:00.000 --> 00:01.000 +00:02.000 --> 00:03.000 +00:04.000 --> 00:05.000 diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/empty-cue.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/empty-cue.vtt new file mode 100644 index 00000000000..dbfde34b697 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/empty-cue.vtt @@ -0,0 +1,11 @@ +WEBVTT +Empty cues should not be discarded. + +1 +00:00:00.000 --> 00:00:30.500 align:start position:20% + +2 +00:00:31.000 --> 00:01:00.500 align:start position:20% + +3 +00:01:01.000 --> 00:02:00.500 align:start position:20% diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/entities-wrong.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/entities-wrong.vtt new file mode 100644 index 00000000000..f45fee4793f --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/entities-wrong.vtt @@ -0,0 +1,15 @@ +WEBVTT +Invalid use of < and > characters. + +2 +00:00:31.000 --> 00:01:00.500 align:start position:20% +This cue has a less than < character. +It turns everything from there on into an annotation +for an empty tag and ends only at the next > or & character. + + +3 +00:01:01.000 --> 00:02:00.500 align:start position:20% +This cue has a greater than > character. +Since it's not related to a < character, +it's just interpreted as text. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/entities.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/entities.vtt new file mode 100644 index 00000000000..a8817954a60 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/entities.vtt @@ -0,0 +1,30 @@ +WEBVTT +Cue content with escape characters for &, <, >, LRM, RLM and non-breaking space. + +1 +00:00:00.000 --> 00:00:30.500 align:start position:20% +This cue has an ampersand & character. + +2 +00:00:31.000 --> 00:01:00.500 align:start position:20% +This cue has a less than < character. + +3 +00:01:01.000 --> 00:02:00.500 align:start position:20% +This cue has a greater than > character. + +4 +00:02:01.000 --> 00:02:30.500 align:start position:20% +This cue has a Left-to-Right Mark ‎. + +5 +00:02:31.000 --> 00:03:00.500 align:start position:20% +This cue has a Right-to-Left Mark ‏. + +6 +00:03:01.000 --> 00:03:30.500 align:start position:20% +This cue has a non-breaking space  . + +7 +00:03:31.000 --> 00:04:00.500 +This & is parsed to the same as &. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/interspersed-non-cue.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/interspersed-non-cue.vtt new file mode 100644 index 00000000000..c825ab32e2e --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/interspersed-non-cue.vtt @@ -0,0 +1,9 @@ +WEBVTT + +00:00.000 --> 00:01.000 +First + +Stray Id or other non-cue content + +00:02.000 --> 00:03.000 +Second diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/iso2022jp3.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/iso2022jp3.vtt new file mode 100644 index 00000000000..10a16243864 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/iso2022jp3.vtt @@ -0,0 +1,10 @@ +WEBVTT FILE +Different encodings (iconv) should not be recognized as WebVTT a file. + +1 +00:00:00.000 --> 00:00:30.500 +$B7J5$H=CG(B + +2 +00:00:31.000 --> 00:20:00.500 +$BEENOITB-(B diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/large-timestamp.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/large-timestamp.vtt new file mode 100644 index 00000000000..e6c18ce3bd6 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/large-timestamp.vtt @@ -0,0 +1,5 @@ +WEBVTT + +1 +1234567:00:00.000 --> 1234567890:00:00.000 +A very long cue. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/line-position-bad.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/line-position-bad.vtt new file mode 100644 index 00000000000..3d52175729d --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/line-position-bad.vtt @@ -0,0 +1,30 @@ +WEBVTT +Invalid positioning values (all settings are ignored). + +1 +00:00:00.000 --> 00:00:15.000 line:-0% +Bear is Coming!!!!! +Negative percentages are not allowed. +Line position is ignored. + +2 +00:00:31.000 --> 00:00:45.500 line:+50% +I said Bear is coming!!!! +Non-numbers are not allowed. +Line position is ignored. + +00:00:46.000 --> 00:01:00.500 line:+5 +I said Bear is coming!!!! +Plus sign is not allowed. +Line position is ignored. + +3 +00:01:01.000 --> 00:01:30.000 line:10%0% +I said Bear is coming now!!!! +Doesn't parse into a percentage. +Line position is ignored. + +00:01:31.000 --> 00:02:00.500 line:-10l +I said Bear is coming now!!!! +Doesn't parse into a number. +Line position is ignored. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/line-position.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/line-position.vtt new file mode 100644 index 00000000000..82f7e2a5234 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/line-position.vtt @@ -0,0 +1,37 @@ +WEBVTT +Cues with valid vertical line positioning values. + +1 +00:00:00.000 --> 00:00:15.000 line:0% +Bear is Coming!!!!! +Positioning on the top of the viewport, in the middle. + +00:00:15.500 --> 00:00:30.500 line:0 +Bear is Coming!!!!! +This is line 0. +Positioning on the top of the viewport, in the middle. + +2 +00:00:31.000 --> 00:00:45.500 line:50% +I said Bear is coming!!!! +Positioning on the center of the video. + + +00:00:46.000 --> 00:01:00.500 line:5 +I said Bear is coming!!!! +This is line 6 from the top of the video viewport. + +3 +00:01:01.000 --> 00:01:30.000 line:100% +I said Bear is coming now!!!! +Positioning on the bottom middle. + +00:01:31.000 --> 00:02:00.500 line:-1 +I said Bear is coming now!!!! +This is the first line at the bottom of the video viewport. +Positioning on the bottom middle. Only 1 line shows. + +00:02:01.000 --> 00:02:30.000 line:500 +I said Bear is coming now!!!! +This is legal, +even though the line will likely not be within the video viewport. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/markup-bad.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/markup-bad.vtt new file mode 100644 index 00000000000..4ff7add2d72 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/markup-bad.vtt @@ -0,0 +1,22 @@ +WEBVTT +Cue text has invalid markup of , , , and . Has a bad effect on the remainder of the cue. + +1 +00:00:00.000 --> 00:00:15.000 align:start position:20% +The following bear starts bold but end is broken: +Bear is Coming!!!!! + +00:00:15.500 --> 00:00:30.500 align:start position:20% +The following bear is not in italics but the markup is removed: +< i>Bear is Coming!!!!! + +2 +00:00:31.000 --> 00:01:00.500 align:start position:20% +The following bear is not underlined and markup is removed: +I said < u >Bear is coming!!!! + +3 +00:01:01.000 --> 00:01:30.000 align:start position:20% +The following bear is not ruby annotated and markup is removed: +I said Bearbear with me is coming!!!! + diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/markup.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/markup.vtt new file mode 100644 index 00000000000..252a599b5fd --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/markup.vtt @@ -0,0 +1,22 @@ +WEBVTT +Cues with , , , and tags (all valid). + +1 +00:00:00.000 --> 00:00:15.000 align:start position:20% +The following bear is bold: +Bear is Coming!!!!! + +00:00:15.500 --> 00:00:30.500 align:start position:20% +The following bear is in italics and has a class of "larger": +Bear is Coming!!!!! + +2 +00:00:31.000 --> 00:01:00.500 align:start position:20% +The following bear is underlined even though the element has a blank: +I said Bear is coming!!!! + +3 +00:01:01.000 --> 00:01:30.000 align:start position:20% +The following bear is ruby annotated: +I said Bearbear with me is coming!!!! + diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/metadata-area.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/metadata-area.vtt new file mode 100644 index 00000000000..255298aeb01 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/metadata-area.vtt @@ -0,0 +1,14 @@ +WEBVTT +This is where metadata would go and these lines should be skipped. +author = silviapf@google.com +COMMENT--> +this is a comment, that will parse as part of the header; +the STYLE and DEFAULTS below are parsed as invalid cues + +1 +00:00:00.000 --> 00:00:30.500 +Bear is Coming!!!!! + +2 +00:00:31.000 --> 00:20:00.500 +I said Bear is coming!!!! \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/metadata.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/metadata.vtt new file mode 100644 index 00000000000..03d8cf4a1c3 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/metadata.vtt @@ -0,0 +1,38 @@ +WEBVTT + +00:00:00.000 --> 00:00:01.000 +Lorem ipsum dolor sit amet, + +00:00:02.000 --> 00:00:03.000 +consectetuer adipiscing elit, + +00:00:04.000 --> 00:00:05.000 +sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. + +00:00:06.000 --> 00:00:07.000 +Ut wisi enim ad minim veniam, + +00:00:08.000 --> 00:00:09.000 +quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. + +00:00:10.000 --> 00:00:11.000 +Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, + +00:00:12.000 --> 00:00:13.000 +vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio + +00:00:14.000 --> 00:00:15.000 +dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. + +00:00:16.000 --> 00:00:17.000 +Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id + +00:00:18.000 --> 00:00:19.000 +quod mazim placerat facer possim assum. + +00:00:20.000 --> 00:00:21.000 +Typi non habent claritatem insitam; + +00:00:22.000 --> 00:00:23.000 +est usus legentis in iis qui facit eorum claritatem. + diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/missed-cues.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/missed-cues.vtt new file mode 100644 index 00000000000..36e8366e908 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/missed-cues.vtt @@ -0,0 +1,31 @@ +WEBVTT +Events should be triggered for missed (skipped) cues during normal playback. + +1 +00:00:00.000 --> 00:00:01.500 align:start position:20% +Bear is Coming!!!!! +And what kind of a bear it is - just have look. + +2 +00:00:02.000 --> 00:00:02.500 align:start position:20% +I said Bear is coming!!!! + +3 +00:00:05.500 --> 00:00:05.501 align:start position:20% +I said Bear is coming now!!!! + +4 +00:00:05.700 --> 00:00:05.701 align:start position:20% +This is the second missed cue in the test. + +5 +00:00:05.800 --> 00:00:05.800 align:start position:20% +Third missed cue - zero-length cue. + +6 +00:00:05.850 --> 00:00:05.851 align:start position:20% +Fourth missed cue. + +7 +00:00:05.950 --> 00:00:01.100 +Negative length cue. Should be treated correctly. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/no-newline-at-eof.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/no-newline-at-eof.vtt new file mode 100644 index 00000000000..49e4e9051a2 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/no-newline-at-eof.vtt @@ -0,0 +1,6 @@ +WEBVTT +A file with no line terminator at the end should be fine (last cue should be recognized). + +1 +00:00:00.000 --> 00:00:30.500 +Bear is Coming!!!!! \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/no-timings.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/no-timings.vtt new file mode 100644 index 00000000000..4cb85b6df27 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/no-timings.vtt @@ -0,0 +1,13 @@ +WEBVTT +Cues without timings are ignored. + +1 +00:00:00.000 +Bear is Coming!!!!! + +2 +00h:00m:31s.000ms +I said Bear is coming!!!! + +3 +I said Bear is coming now!!!! \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/no-webvtt.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/no-webvtt.vtt new file mode 100644 index 00000000000..12053b2703c --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/no-webvtt.vtt @@ -0,0 +1,10 @@ +AWEBVTT FILE +A file with wrong file header should not be recognized as a webvtt file. + +1 +00:00:00.000 --> 00:00:30.500 +Bear is Coming!!!!! + +2 +00:00:31.000 --> 00:20:00.500 +I said Bear is coming!!!! \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/positioning-bad.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/positioning-bad.vtt new file mode 100644 index 00000000000..58ca6792be7 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/positioning-bad.vtt @@ -0,0 +1,39 @@ +WEBVTT +Invalid horizontal positioning values (all settings are ignored). + +1 +00:00:00.000 --> 00:00:15.500 position:-5% +Bear is Coming!!!!! +This would be off screen -> ignored. + +00:00:16.000 --> 00:00:30.500 position:150% +Bear is Coming!!!!! +This would be off screen -> ignored. + +2 +00:00:31.000 --> 00:00:45.500 position:50 +I said Bear is coming!!!! +Missing percent sign -> ignored. + +2 +00:00:46.000 --> 00:01:00.500 position:50a% +I said Bear is coming!!!! +Surplus character between number and percent sign -> ignored. + +3 +00:01:01.000 --> 00:01:30.500 position:100%-fj +I said Bear is coming now!!!! +Surplus characters after percent sign -> ignored. + + +00:01:31.000 --> 00:02:00.500 position:100asdf +I said Bear is coming now!!!! +Surplus characters and no percent sign -> ignored. + +00:02:01.000 --> 00:02:02.000 position:e50% +I said Bear is coming now!!!! +Surplus characters at beginning of size string -> ignored. + +00:02:02.100 --> 00:02:02.500 position:5g0% +I said Bear is coming now!!!! +Surplus characters in middle of size string -> ignored. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/positioning-ltr.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/positioning-ltr.vtt new file mode 100644 index 00000000000..b23a7446b7f --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/positioning-ltr.vtt @@ -0,0 +1,21 @@ +WEBVTT +Valid horizontal positioning values. + +1 +00:00:00.000 --> 00:00:30.500 position:0% +الدب قادم!!!!! +تحديد المواقع في أسفل اليمين. + +2 +00:00:31.000 --> 00:00:45.500 position:50% +قلت الدب قادم!! +تحديد المواقع في منتصف القاع. + +00:00:46.000 --> 00:01:00.500 +قلت الدب قادم!! +المواقع الافتراضية على منتصف أسفل تزال قائمة. + +3 +00:01:01.000 --> 00:02:00.500 position:100% +قلت الدب قادم الآن!! +غادر لتحديد المواقع في القاع. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/positioning.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/positioning.vtt new file mode 100644 index 00000000000..ccf6024da06 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/positioning.vtt @@ -0,0 +1,21 @@ +WEBVTT +Valid horizontal positioning values. + +1 +00:00:00.000 --> 00:00:30.500 position:0% +Bear is Coming!!!!! +Positioning on the left bottom. + +2 +00:00:31.000 --> 00:00:45.500 position:50% +I said Bear is coming!!!! +Positioning on the bottom middle. + +00:00:46.000 --> 00:01:00.500 +I said Bear is coming!!!! +Default positioning on the bottom middle still. + +3 +00:01:01.000 --> 00:02:00.500 position:100% +I said Bear is coming now!!!! +Positioning on the bottom right. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/settings-bad-separation.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/settings-bad-separation.vtt new file mode 100644 index 00000000000..cbfe6ea6e92 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/settings-bad-separation.vtt @@ -0,0 +1,20 @@ +WEBVTT +Cues settings may only be separated by spaces or tabs, but illegal characters +between settings are ignored. + +1 +00:00:00.000 --> 00:00:30.500 - line:43% position:10% - +Bear is Coming!!!!! Bad separator ignored. + +2 +00:00:31.000 --> 00:01:00.500 --> position:50% Vertical:lr align:end +I said Bear is coming!!!! Bad separator and setting ignored. + +3 +00:01:01.000 --> 00:02:00.500 +I said Bear is coming now!!!! Bad setting markup. Not ignored because the settings are +not delimited by spaces or tabs. + +4 +00:02:01.000 --> 100:20:00.500 / vertical:lr | position:90% +I said Bear is coming now!!!! Bad separator ignored. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/settings.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/settings.vtt new file mode 100644 index 00000000000..dd6b02296af --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/settings.vtt @@ -0,0 +1,18 @@ +WEBVTT +Cue settings may be separated by spaces or tabs. + +1 +00:00:00.000 --> 00:00:30.500 line:100% align:start +Bear is Coming!!!!! One blank. + +2 +00:00:31.000 --> 00:01:00.500 position:40% vertical:rl line:15% +I said Bear is coming!!!! Several blanks. + +3 +00:01:01.000 --> 00:02:00.500 align:middle position:10% +I said Bear is coming now!!!! Tab separator. + +4 +00:02:01.000 --> 100:20:00.500 line:95% vertical:lr align:end +I said Bear is coming now!!!! Tab separators. \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/simple-captions.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/simple-captions.vtt new file mode 100644 index 00000000000..9815b111da5 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/simple-captions.vtt @@ -0,0 +1,17 @@ +WEBVTT + +0 +00:00:04.000 --> 00:00:04.500 +First cue + +1 +00:00:04.500 --> 00:00:05.000 +Lorem + +2 +00:00:05.000 --> 00:00:05.500 +ipsum + +3 +00:00:05.500 --> 00:00:05.501 +Missed cue with pause-on-exit diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/sorted-dispatch.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/sorted-dispatch.vtt new file mode 100644 index 00000000000..438ea6abf99 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/sorted-dispatch.vtt @@ -0,0 +1,34 @@ +WEBVTT +Enter and exit events should be dispatched in a sorted order according to their times. + +0 +00:00:04.000 --> 00:00:04.500 +Missed cue that should not be considered because of seeking. + +1 +00:00:05.100 --> 00:00:05.800 align:start position:20% +Bear is Coming!!!!! + +2 +00:00:05.100 --> 00:00:05.101 +Missed cue 1 + +3 +00:00:05.100 --> 00:00:05.301 +And what kind of a bear it is - just have look. + +4 +00:00:05.100 --> 00:00:05.101 +Missed Cue 2 + +5 +00:00:05.300 --> 00:00:05.800 align:start position:20% +I said Bear is coming!!!! + +6 +00:00:05.990 --> 00:00:05.993 align:start position:20% +I said Bear is coming now!!!! + +7 +00:00:05.994 --> 00:00:05.998 align:start position:20% +Bear is already here diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/timestamp-bad.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/timestamp-bad.vtt new file mode 100644 index 00000000000..4479cdb722f --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/timestamp-bad.vtt @@ -0,0 +1,17 @@ +WEBVTT +Invalid markup. + +1 +00:00:00.000 --> 00:00:30.500 align:start position:20% +This <00:00:05.000>cue <00:00:10.000>is <00:00:12.000>painted <00:00:08.000>on. +But since the last two timestamps are out of order, they are ignored. + +2 +00:00:31.000 --> 00:01:00.500 align:start position:20% +I <00:00:20.000>said <00:00:22.000>Bear <00:00:24.000>is <00:00:26.000>coming!!!! +All of these timestamps are before the start of the cue, so get ignored. + +3 +00:01:01.000 --> 00:02:00.500 align:start position:20% +I <00:02:05.000>said <00:02:10.000>Bear <00:02:15.000>is <00:02:20.000>coming <00:02:25.000>now!!!! +All of these timestamps are after the end of the cue, so get ignored. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/timestamp.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/timestamp.vtt new file mode 100644 index 00000000000..17d464bfedf --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/timestamp.vtt @@ -0,0 +1,14 @@ +WEBVTT +Paint-on text in cues with markup. + +1 +00:00:00.000 --> 00:00:30.500 align:start position:20% +This <00:00:05.000>cue <00:00:10.000>is <00:00:15.000>painted <00:00:20.000>on. + +2 +00:00:31.000 --> 00:01:00.500 align:start position:20% +I <00:00:35.000>said <00:00:40.000>Bear <00:00:45.000>is <00:00:50.000>coming!!!! + +3 +00:01:01.000 --> 00:02:00.500 align:start position:20% +I <00:01:05.000>said <00:01:10.000>Bear <00:01:15.000>is <00:01:20.000>coming <00:01:25.000>now!!!! diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/timings-hour-error.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/timings-hour-error.vtt new file mode 100644 index 00000000000..c33f8a96c3f --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/timings-hour-error.vtt @@ -0,0 +1,22 @@ +WEBVTT +These timings all have errors and all cues should be ignored. + +1 +00:00.00.000 --> 00:00:30.500 +Bear is Coming!!!!! + +2 +00:00:31.000 --> 00:01:00:500 +I said Bear is coming!!!! + +3 +00:01:01.000 --> 00:120:00.500 +I said Bear is coming now!!!! + +4 +00:02:01.000 - 00:03:00.500 +I said Bear is coming now!!!! + +5 +00h:03m:01s.000ms --> 00h:03m:00s.500ms +I said Bear is coming now!!!! diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/timings-hour.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/timings-hour.vtt new file mode 100644 index 00000000000..b708b83338a --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/timings-hour.vtt @@ -0,0 +1,14 @@ +WEBVTT +Timings can optionally contain an hour. + +1 +00:00:00.000 --> 00:00:30.500 +Bear is Coming!!!!! + +2 +00:00:31.000 --> 00:01:00.500 +I said Bear is coming!!!! + +3 +00:01:01.000 --> 100:20:00.500 +I said Bear is coming now!!!! \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/timings-no-hour-errors.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/timings-no-hour-errors.vtt new file mode 100644 index 00000000000..e4bf27d4e6c --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/timings-no-hour-errors.vtt @@ -0,0 +1,22 @@ +WEBVTT +These timings all have errors and all cues should be ignored. + +1 +00.00.000 --> 00:30.500 +Bear is Coming!!!!! + +2 +00:31.000 --> 01:00:500 +I said Bear is coming!!!! + +3 +01:01.000 --> 120:00.500 +I said Bear is coming now!!!! + +4 +01:01.000 - 02:00.500 +I said Bear is coming now!!!! + +5 +02:01.000 --> 03m:00.500 +I said Bear is coming now!!!! diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/timings-no-hour.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/timings-no-hour.vtt new file mode 100644 index 00000000000..745c34ff9fd --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/timings-no-hour.vtt @@ -0,0 +1,18 @@ +WEBVTT +The hour of a timestamp is optional. + +1 +00:00.000 --> 00:30.500 +Bear is Coming!!!!! + +2 +00:31.000 --> 01:00.500 +I said Bear is coming!!!! + +3 +01:01.000 --> 02:00.500 +I said Bear is coming now!!!! + +4 +02:01.000 --> 03:00.500 +tab separators \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/timings-whitespace.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/timings-whitespace.vtt new file mode 100644 index 00000000000..9d9ac9a38a7 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/timings-whitespace.vtt @@ -0,0 +1,51 @@ +WEBVTT +Whitespace (U+0020, U+0009, U+000C) surrounding cue-timings separator ("-->") is optional + +1 +00:00:00.100 -->00:00:01.500 +Single U+0020 SPACE left of cue-timings separator + +2 +00:00:00.100--> 00:00:01.500 +Single U+0020 SPACE right of cue-timings separator + +3 +00:00:00.100 -->00:00:01.500 +Single U+0009 TAB left of cue-timings separator + +4 +00:00:00.100--> 00:00:01.500 +Single U+0009 TAB right of cue-timings separator + +5 +00:00:00.100 -->00:00:01.500 +Single U+000C FORM FEED left of cue-timings separator + +6 +00:00:00.100--> 00:00:01.500 +Single U+000C FORM FEED right of cue-timings separator + +7 +00:00:00.100 -->00:00:01.500 +Several U+0020 SPACE left of cue-timings separator + +8 +00:00:00.100--> 00:00:01.500 +Several U+0020 SPACE right of cue-timings separator + +9 +00:00:00.100 -->00:00:01.500 +Several U+0009 TAB left of cue-timings separator + +10 +00:00:00.100--> 00:00:01.500 +Several U+0009 TAB right of cue-timings separator + +11 +00:00:00.100 -->00:00:01.500 +Several U+000C FORM FEED left of cue-timings separator + +12 +00:00:00.100--> 00:00:01.500 +Several U+000C FORM FEED right of cue-timings separator + diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/unsupported-markup.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/unsupported-markup.vtt new file mode 100644 index 00000000000..b4ea7ea09b5 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/unsupported-markup.vtt @@ -0,0 +1,23 @@ +WEBVTT +Any HTML markup that is not supported should be ignored. + +1 +00:00:00.000 --> 00:00:30.500 align:start position:20% +

Bear is Coming!!!!!

+

And what kind of a bear it is - just have look.

+ +2 +00:00:31.000 --> 00:01:00.500 align:start position:20% +
    +
  • I said Bear is coming!!!!
  • +
  • I said Bear is still coming!!!!
  • +
+ + +3 +00:01:01.000 --> 00:02:00.500 align:start position:20% +
    +
  1. I said Bear is coming now!!!!
  2. +
  3. mighty bear
  4. +
  5. +
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/utf8.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/utf8.vtt new file mode 100644 index 00000000000..8dd8f279488 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/utf8.vtt @@ -0,0 +1,10 @@ +WEBVTT +UTF-8 encoded characters should be recognized. + +1 +00:00:00.000 --> 00:00:30.500 +景気判断 + +2 +00:00:31.000 --> 00:20:00.500 +電力不足 \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/valign-bad.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/valign-bad.vtt new file mode 100644 index 00000000000..8e7b3b738dc --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/valign-bad.vtt @@ -0,0 +1,17 @@ +WEBVTT +Invalid vertical direction settings (all settings are ignored). + +1 +00:00:00.000 --> 00:00:30.500 vertical:#vertical +Bear is Coming!!!!! +Normal rendering - direction setting is ignored. + +2 +00:00:31.000 --> 00:01:00.500 vertical:verticallr +I said Bear is coming!!!! +Normal rendering - direction setting is ignored. + +3 +00:01:01.000 --> 00:02:00.500 vertical:vertical-rl +I said Bear is coming now!!!! +Normal rendering - direction setting is ignored. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/valign-ltr.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/valign-ltr.vtt new file mode 100644 index 00000000000..74838369d23 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/valign-ltr.vtt @@ -0,0 +1,20 @@ +WEBVTT +Valid vertical direction settings. + +1 +00:00:00.000 --> 00:00:30.500 vertical:rl +الدب قادم!!!!! +يجعل على الجانب الأيمن من المعاينة الفيديو والمتوسطة الانحياز ، +أسفل إلى أعلى، وتزايد اليسار. + +2 +00:00:31.000 --> 00:01:00.500 vertical:lr +قلت الدب قادم!! +يجعل على الجانب الأيسر من المعاينة الفيديو والمتوسطة الانحياز ، +أسفل إلى أعلى، وتنامي اليمين. + +3 +00:01:01.000 --> 00:02:00.500 vertical:rl align:start position:0% +قلت الدب قادم الآن!! +يجعل على الجانب الأيمن من المعاينة الفيديو ، على حد سواء أسفل محاذاة +لمربع جديلة والنص داخل النص ، من أسفل إلى أعلى، وتزايد اليسار. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/valign.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/valign.vtt new file mode 100644 index 00000000000..f757a365e36 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/valign.vtt @@ -0,0 +1,20 @@ +WEBVTT +Valid vertical direction settings. + +1 +00:00:00.000 --> 00:00:30.500 vertical:rl +Bear is Coming!!!!! +Renders on the right side of the video viewport, middle aligned, +top to bottom, growing left. + +2 +00:00:31.000 --> 00:01:00.500 vertical:lr +I said Bear is coming!!!! +Renders on the left side of the video viewport, middle aligned, +top to bottom, growing right. + +3 +00:01:01.000 --> 00:02:00.500 vertical:rl align:start position:0% +I said Bear is coming now!!!! +Renders on the right side of the video viewport, top aligned both +for the cue box and the text within, text from top to bottom, growing left. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/voice-bad.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/voice-bad.vtt new file mode 100644 index 00000000000..12ffdeb82ef --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/voice-bad.vtt @@ -0,0 +1,17 @@ +WEBVTT +Invalid voice markup. + +1 +00:00:00.000 --> 00:00:30.500 align:start position:20% +< v Speaker>Bear is Coming!!!!! +This is two annotations for an empty tag. + +2 +00:00:31.000 --> 00:01:00.500 align:start position:20% +I said Bear is coming!!!! +This does not parse as a voice tag. + +3 +00:01:01.000 --> 00:02:00.500 align:start position:20% +I said Bear is coming now!!!! +This does not parse as a voice tag. diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/voice.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/voice.vtt new file mode 100644 index 00000000000..d6cfc6887ff --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/voice.vtt @@ -0,0 +1,15 @@ +WEBVTT +Cue text fragment with voice markup mapped to HTML element with @title for annotation. + +1 +00:00:00.000 --> 00:00:30.500 align:start position:20% +Bear is Coming!!!!! +Text span with a class and an annotation. + +2 +00:00:31.000 --> 00:01:00.500 align:start position:20% +I said Bear is coming!!!! + +3 +00:01:01.000 --> 00:02:00.500 align:start position:20% +I said Bear is coming now!!!! diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/vp8-vorbis-webvtt.webm b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/vp8-vorbis-webvtt.webm new file mode 100644 index 00000000000..c626f86e336 Binary files /dev/null and b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/vp8-vorbis-webvtt.webm differ diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/webvtt-file.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/webvtt-file.vtt new file mode 100644 index 00000000000..0c1a5fb158c --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/webvtt-file.vtt @@ -0,0 +1,9 @@ +WEBVTT FILE + +1 +00:00:00.000 --> 00:00:30.500 +Bear is Coming!!!!! + +2 +00:00:31.000 --> 00:20:00.500 +I said Bear is coming!!!! \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/webvtt-rubbish.vtt b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/webvtt-rubbish.vtt new file mode 100644 index 00000000000..dacc215409c --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/resources/webvtt-rubbish.vtt @@ -0,0 +1,10 @@ +WEBVTT asdfasdfauhio +Rubbish after the WEBVTT header should be ignored. + +1 +00:00:00.000 --> 00:00:30.500 +Bear is Coming!!!!! + +2 +00:00:31.000 --> 00:20:00.500 +I said Bear is coming!!!! \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-active-cues.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-active-cues.html new file mode 100644 index 00000000000..67ab3bdb138 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-active-cues.html @@ -0,0 +1,39 @@ + +Ensure that no text track cues are active after the video is unloaded + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-add-remove-cue.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-add-remove-cue.html new file mode 100644 index 00000000000..1e6c557fb60 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-add-remove-cue.html @@ -0,0 +1,92 @@ + +TextTrack's addCue and removeCue + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-add-track.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-add-track.html new file mode 100644 index 00000000000..7f8ee2fdd47 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-add-track.html @@ -0,0 +1,34 @@ + +'addtrack' event is fired when a TextTrack is created + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-addtrack-kind.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-addtrack-kind.html new file mode 100644 index 00000000000..4503a06bb2c --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-addtrack-kind.html @@ -0,0 +1,25 @@ + +addTextTrack() only accepts known "kind" values + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-cue-empty.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-cue-empty.html new file mode 100644 index 00000000000..59f8fc6c7b8 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-cue-empty.html @@ -0,0 +1,19 @@ + +Invoke getCueAsHTML() on an empty cue + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-cue-inline.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-cue-inline.html new file mode 100644 index 00000000000..3b4c3542a92 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-cue-inline.html @@ -0,0 +1,16 @@ + +Add a track and change its mode through JS + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-cue-mutable-fragment.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-cue-mutable-fragment.html new file mode 100644 index 00000000000..713e7819962 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-cue-mutable-fragment.html @@ -0,0 +1,85 @@ + +Cue fragment is mutable + + + + + +

Fragment 1

+
+

Fragment 2

+
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-cue-mutable.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-cue-mutable.html new file mode 100644 index 00000000000..63c3018aa99 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-cue-mutable.html @@ -0,0 +1,99 @@ + +Modifying attributes of a VTTCue + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-cues-missed.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-cues-missed.html new file mode 100644 index 00000000000..043c941b123 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-cues-missed.html @@ -0,0 +1,59 @@ + +Events are triggered for missed (skipped) cues during normal playback + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-cues-pause-on-exit.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-cues-pause-on-exit.html new file mode 100644 index 00000000000..eaf7e2a1d4f --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-cues-pause-on-exit.html @@ -0,0 +1,35 @@ + +Video is paused after cues having pause-on-exit flag are processed + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-cues-seeking.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-cues-seeking.html new file mode 100644 index 00000000000..99cd2d550e8 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-cues-seeking.html @@ -0,0 +1,31 @@ + +TextTrack's activeCues are indexed and updated during video playback + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-cues-sorted-before-dispatch.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-cues-sorted-before-dispatch.html new file mode 100644 index 00000000000..edc202f4358 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-cues-sorted-before-dispatch.html @@ -0,0 +1,48 @@ + +All events are triggered in chronological order + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-disabled-addcue.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-disabled-addcue.html new file mode 100644 index 00000000000..038e6f6ba71 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-disabled-addcue.html @@ -0,0 +1,33 @@ + +Adding cues to a disabled text track + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-disabled.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-disabled.html new file mode 100644 index 00000000000..d517b9d12c7 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-disabled.html @@ -0,0 +1,28 @@ + +Disabling a track + + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-element-dom-change.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-element-dom-change.html new file mode 100644 index 00000000000..ff447f33f2e --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-element-dom-change.html @@ -0,0 +1,16 @@ + +Simple DOM mutations with track element + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-element-src-change-error.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-element-src-change-error.html new file mode 100644 index 00000000000..ffc8ec0682d --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-element-src-change-error.html @@ -0,0 +1,92 @@ + +HTMLTrackElement 'src' attribute mutations + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-element-src-change.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-element-src-change.html new file mode 100644 index 00000000000..34a53d15319 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-element-src-change.html @@ -0,0 +1,57 @@ + +HTMLTrackElement 'src' attribute mutations + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-helpers.js b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-helpers.js new file mode 100644 index 00000000000..09c85dd7bc1 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-helpers.js @@ -0,0 +1,83 @@ +function enableAllTextTracks(textTracks) { + for (var i = 0; i < textTracks.length; i++) { + var track = textTracks[i]; + if (track.mode == "disabled") + track.mode = "hidden"; + } +} + +function assert_cues_equal(cues, expected) { + assert_equals(cues.length, expected.length); + for (var i = 0; i < cues.length; i++) { + assert_equals(cues[i].id, expected[i].id); + assert_equals(cues[i].startTime, expected[i].startTime); + assert_equals(cues[i].endTime, expected[i].endTime); + assert_equals(cues[i].text, expected[i].text); + } +} + +function assert_cues_match(cues, expected) { + assert_equals(cues.length, expected.length); + for (var i = 0; i < cues.length; i++) { + var cue = cues[i]; + var expectedItem = expected[i]; + for (var property of Object.getOwnPropertyNames(expectedItem)) + assert_equals(cue[property], expectedItem[property]); + } +} + +function assert_cues_html_content(cues, expected) { + assert_equals(cues.length, expected.length); + for (var i = 0; i < cues.length; i++) { + var expectedItem = expected[i]; + var property = Object.getOwnPropertyNames(expectedItem)[0]; + var propertyValue = expectedItem[property]; + assert_equals(propertyValue(cues[i]), expectedItem.expected); + } +} + +function check_cues_from_track(src, func) { + async_test(function(t) { + var video = document.createElement("video"); + var trackElement = document.createElement("track"); + trackElement.src = src; + trackElement.default = true; + video.appendChild(trackElement); + + trackElement.onload = t.step_func_done(function() { + func(trackElement.track); + }); + }, "Check cues from " + src); +} + +function assert_cue_fragment(cue, children) { + var fragment = createFragment(children); + assert_true(fragment.isEqualNode(cue.getCueAsHTML())); +} + +function assert_cue_fragment_as_textcontent(cue, children) { + var fragment = createFragment(children); + assert_equals(cue.getCueAsHTML().textContent, fragment.textContent); +} + +function createFragment(children) { + var fragment = document.createDocumentFragment(); + cloneChildrenToFragment(fragment, children); + return fragment; +} + +function cloneChildrenToFragment(root, children) { + for (var child of children) { + var childElement; + if (child.type == "text") { + childElement = document.createTextNode(child.value); + } else { + childElement = document.createElement(child.type); + var styles = child.style || {}; + for (var attr of Object.getOwnPropertyNames(styles)) + childElement[attr] = styles[attr]; + cloneChildrenToFragment(childElement, child.value); + } + root.appendChild(childElement); + } +} \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-large-timestamp.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-large-timestamp.html new file mode 100644 index 00000000000..bae1852cf83 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-large-timestamp.html @@ -0,0 +1,19 @@ + +Very large timestamp is parsed correctly + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-load-error-readyState.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-load-error-readyState.html new file mode 100644 index 00000000000..8e232bff537 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-load-error-readyState.html @@ -0,0 +1,15 @@ + +Error event on HTMLTrackElement and ERROR readyState on TextTrack + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-load-from-element-readyState.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-load-from-element-readyState.html new file mode 100644 index 00000000000..62a68f65439 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-load-from-element-readyState.html @@ -0,0 +1,15 @@ + +Load event on HTMLTrackElement and LOADED readyState on TextTrack when src is set on the element + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-load-from-src-readyState.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-load-from-src-readyState.html new file mode 100644 index 00000000000..e569eeb96fd --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-load-from-src-readyState.html @@ -0,0 +1,20 @@ + +Load event on HTMLTrackElement and LOADED readyState on TextTrack when src is set from JavaScript + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-mode-disabled.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-mode-disabled.html new file mode 100644 index 00000000000..6b46bf4e344 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-mode-disabled.html @@ -0,0 +1,34 @@ + +Cues are properly removed from the active cue list when their track changes mode to disabled + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-mode-not-changed-by-new-track.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-mode-not-changed-by-new-track.html new file mode 100644 index 00000000000..2902ba90bc9 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-mode-not-changed-by-new-track.html @@ -0,0 +1,73 @@ + +A track appended after the initial track configuration does not change other tracks + + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-mode-triggers-loading.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-mode-triggers-loading.html new file mode 100644 index 00000000000..2e29d704690 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-mode-triggers-loading.html @@ -0,0 +1,37 @@ + +A "metadata" track does not load automatically, but it does load when the mode is changed + + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-mode.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-mode.html new file mode 100644 index 00000000000..29208a33c21 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-mode.html @@ -0,0 +1,61 @@ + +TextTrack mode attribute + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-remove-active-cue.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-remove-active-cue.html new file mode 100644 index 00000000000..176e0065c59 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-remove-active-cue.html @@ -0,0 +1,35 @@ + +Removing an active cue + + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-remove-by-setting-innerHTML.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-remove-by-setting-innerHTML.html new file mode 100644 index 00000000000..95929bc83fb --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-remove-by-setting-innerHTML.html @@ -0,0 +1,31 @@ + +Removing a track by setting video.innerHTML doesn't crash + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-remove-insert-ready-state.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-remove-insert-ready-state.html new file mode 100644 index 00000000000..1c854aca0ed --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-remove-insert-ready-state.html @@ -0,0 +1,38 @@ + +Attaching a media element again to the document, having a child track that failed loading doesn't block video from playing + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-remove-quickly.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-remove-quickly.html new file mode 100644 index 00000000000..4be040c5f87 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-remove-quickly.html @@ -0,0 +1,14 @@ + +Removing a track element before it has been processed doesn't crash + + + +
+ \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-remove-track.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-remove-track.html new file mode 100644 index 00000000000..29938e31029 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-remove-track.html @@ -0,0 +1,105 @@ + + + + + + + + + + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-align-positioning.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-align-positioning.html new file mode 100644 index 00000000000..07ebfd622b0 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-align-positioning.html @@ -0,0 +1,52 @@ + +Cue text position and alignment from settings + + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-align-text-line-position.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-align-text-line-position.html new file mode 100644 index 00000000000..deb389916ad --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-align-text-line-position.html @@ -0,0 +1,54 @@ + +Cue alignment, line and text position from settings + + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-alignment.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-alignment.html new file mode 100644 index 00000000000..e8f47e876a8 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-alignment.html @@ -0,0 +1,31 @@ + +Cue alignment from settings + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-blank-lines.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-blank-lines.html new file mode 100644 index 00000000000..114aebc38c3 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-blank-lines.html @@ -0,0 +1,26 @@ + +Cues are affected neither by multiple newlines \n, \r, and \r\n nor by the absence of a seperating line + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-bom.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-bom.html new file mode 100644 index 00000000000..c138f96af57 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-bom.html @@ -0,0 +1,34 @@ + +Parser properly ignores a UTF-8 BOM character at the beginning of a file and all other cues are properly parsed + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-class-markup.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-class-markup.html new file mode 100644 index 00000000000..fe3c868c587 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-class-markup.html @@ -0,0 +1,55 @@ + +Tests cues with class markup <c>. + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-identifiers.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-identifiers.html new file mode 100644 index 00000000000..02b0a15187a --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-identifiers.html @@ -0,0 +1,27 @@ + +Any text other than "-->" is recognized as optional cue identifier + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-no-id.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-no-id.html new file mode 100644 index 00000000000..b2f4b770831 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-no-id.html @@ -0,0 +1,19 @@ + +Empty cue identifiers, but having "-->" leads to discarded cue + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-recovery.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-recovery.html new file mode 100644 index 00000000000..6a104916b7c --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-recovery.html @@ -0,0 +1,19 @@ + +A cue is recovered when a line with a "-->" is encountered without blank line separator + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-size-align.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-size-align.html new file mode 100644 index 00000000000..a1243a95e7d --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-size-align.html @@ -0,0 +1,26 @@ + +Cue size and alignment from settings + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-size.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-size.html new file mode 100644 index 00000000000..d8e03edce7f --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-cue-size.html @@ -0,0 +1,26 @@ + +Cue size from settings + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-degenerate-cues.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-degenerate-cues.html new file mode 100644 index 00000000000..8d2569993c2 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-degenerate-cues.html @@ -0,0 +1,16 @@ + +Degenerate cues without separating blank lines + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-empty-cue.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-empty-cue.html new file mode 100644 index 00000000000..e1f55702500 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-empty-cue.html @@ -0,0 +1,10 @@ + +Empty cues should not be discarded + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-entities.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-entities.html new file mode 100644 index 00000000000..a5295795ef0 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-entities.html @@ -0,0 +1,42 @@ + +Entities in the cue text + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-header-comment.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-header-comment.html new file mode 100644 index 00000000000..f9b35576f34 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-header-comment.html @@ -0,0 +1,50 @@ + +Optional comment area under the "WEBVTT" file header is properly ignored and also, default settings and styling are currently ignored (treated as faulty cues) + + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-interspersed-non-cue.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-interspersed-non-cue.html new file mode 100644 index 00000000000..2287cc2830e --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-interspersed-non-cue.html @@ -0,0 +1,15 @@ + +An empty line after an identifier line discards the current cue and restarts the cue loop + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-line-position.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-line-position.html new file mode 100644 index 00000000000..bea4acb917a --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-line-position.html @@ -0,0 +1,58 @@ + +Cue line position from settings + + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-magic-header.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-magic-header.html new file mode 100644 index 00000000000..ff4637a8a5f --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-magic-header.html @@ -0,0 +1,57 @@ + +Magic file header "WEBVTT" leads to the file properly recognized as a WebVTT file + + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-markup.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-markup.html new file mode 100644 index 00000000000..2b044379f14 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-markup.html @@ -0,0 +1,89 @@ + +Cues with <b>, <i>, <u>, <rt> and <ruby> tags + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-newlines.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-newlines.html new file mode 100644 index 00000000000..4da7e6b1b9c --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-newlines.html @@ -0,0 +1,26 @@ + +A cue with no newline at eof is parsed properly + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-no-timings.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-no-timings.html new file mode 100644 index 00000000000..a39a2c37aa5 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-no-timings.html @@ -0,0 +1,17 @@ + +Cue without timings are ignored + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-positioning.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-positioning.html new file mode 100644 index 00000000000..d14a5768d3a --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-positioning.html @@ -0,0 +1,35 @@ + +Cue text position from settings + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-settings.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-settings.html new file mode 100644 index 00000000000..9ad98ffa1aa --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-settings.html @@ -0,0 +1,28 @@ + +WebVTT settings + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-timestamp.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-timestamp.html new file mode 100644 index 00000000000..e311f121f25 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-timestamp.html @@ -0,0 +1,36 @@ + +Cues with <timestamps> tags + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-timings-hour.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-timings-hour.html new file mode 100644 index 00000000000..c03e182c79e --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-timings-hour.html @@ -0,0 +1,61 @@ + +Cue timings and various syntax errors in timings, with hours + + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-timings-no-hours.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-timings-no-hours.html new file mode 100644 index 00000000000..e81ae03cc24 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-timings-no-hours.html @@ -0,0 +1,67 @@ + +Cue timings and various syntax errors in timings, without hours + + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-timings-whitespace.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-timings-whitespace.html new file mode 100644 index 00000000000..db1346d23ad --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-timings-whitespace.html @@ -0,0 +1,25 @@ + +"Skip whitespace" step around cue-timings separator + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-unsupported-markup.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-unsupported-markup.html new file mode 100644 index 00000000000..ed3107f89b2 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-unsupported-markup.html @@ -0,0 +1,37 @@ + +Unsupported markup is properly ignored + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-utf8.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-utf8.html new file mode 100644 index 00000000000..eb44c85ba83 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-utf8.html @@ -0,0 +1,57 @@ + + +UTF-8 encoded characters are recognized properly and different encodings (iconv) are not recognized as a WebVTT file + + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-valign.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-valign.html new file mode 100644 index 00000000000..ace07607400 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-valign.html @@ -0,0 +1,28 @@ + +Cue vertical alignment (direction) from settings + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-voice.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-voice.html new file mode 100644 index 00000000000..5df8b4057ae --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-voice.html @@ -0,0 +1,54 @@ + +Cues with voice markup <v> + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-area-element/area-download-click.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-area-element/area-download-click.html index 7554c9b03bc..8100ada9d5f 100644 --- a/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-area-element/area-download-click.html +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-area-element/area-download-click.html @@ -6,22 +6,27 @@ - - - - - - + + diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-area-element/resources/area-download-click.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-area-element/resources/area-download-click.html new file mode 100644 index 00000000000..c0679f8233d --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-area-element/resources/area-download-click.html @@ -0,0 +1,5 @@ + + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange.html b/tests/wpt/web-platform-tests/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange.html index 8650876207c..3aba6b7adb3 100644 --- a/tests/wpt/web-platform-tests/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange.html +++ b/tests/wpt/web-platform-tests/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange.html @@ -10,6 +10,17 @@
+ + +
+ +
+ + diff --git a/tests/wpt/web-platform-tests/html/semantics/forms/the-select-element/selected-index.html b/tests/wpt/web-platform-tests/html/semantics/forms/the-select-element/selected-index.html index 6c30698a8ae..46f19da7da2 100644 --- a/tests/wpt/web-platform-tests/html/semantics/forms/the-select-element/selected-index.html +++ b/tests/wpt/web-platform-tests/html/semantics/forms/the-select-element/selected-index.html @@ -70,7 +70,7 @@ test(function () { assertSelectedIndex(select, 0); select.selectedIndex = 2; assertSelectedIndex(select, 2); - this.add_cleanup(() => select.selectedIndex = 0); + this.add_cleanup(() => { select.selectedIndex = 0; }); }, "set (HTMLSelectElement)"); test(function () { @@ -78,7 +78,7 @@ test(function () { assertSelectedIndex(select, 0); select.options.selectedIndex = 2; assertSelectedIndex(select, 2); - this.add_cleanup(() => select.selectedIndex = 0); + this.add_cleanup(() => { select.selectedIndex = 0; }); }, "set (HTMLOptionsCollection)"); test(function () { diff --git a/tests/wpt/web-platform-tests/html/semantics/interactive-elements/the-dialog-element/abspos-dialog-layout.html b/tests/wpt/web-platform-tests/html/semantics/interactive-elements/the-dialog-element/abspos-dialog-layout.html new file mode 100644 index 00000000000..e97ebee59f4 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/interactive-elements/the-dialog-element/abspos-dialog-layout.html @@ -0,0 +1,223 @@ + + + +Tests layout of absolutely positioned modal dialogs. + + + + +It is my dialog. +
+
+
+ diff --git a/tests/wpt/web-platform-tests/html/semantics/interactive-elements/the-dialog-element/dialog-scrolled-viewport.html b/tests/wpt/web-platform-tests/html/semantics/interactive-elements/the-dialog-element/dialog-scrolled-viewport.html new file mode 100644 index 00000000000..8a59ba23e43 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/interactive-elements/the-dialog-element/dialog-scrolled-viewport.html @@ -0,0 +1,45 @@ + + + + + + + + +
+ + +
+ + + diff --git a/tests/wpt/web-platform-tests/html/semantics/interactive-elements/the-dialog-element/inert-does-not-match-disabled-selector.html b/tests/wpt/web-platform-tests/html/semantics/interactive-elements/the-dialog-element/inert-does-not-match-disabled-selector.html new file mode 100644 index 00000000000..b3b0c0a9297 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/interactive-elements/the-dialog-element/inert-does-not-match-disabled-selector.html @@ -0,0 +1,35 @@ + + + + + + + + + + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/interactive-elements/the-dialog-element/inert-node-is-unfocusable.html b/tests/wpt/web-platform-tests/html/semantics/interactive-elements/the-dialog-element/inert-node-is-unfocusable.html new file mode 100644 index 00000000000..49d6690d673 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/interactive-elements/the-dialog-element/inert-node-is-unfocusable.html @@ -0,0 +1,58 @@ + + + + + + + + + +
+ + + + +
I'm editable
+ I'm tabindexed.
+ + Link +
+ + + diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/defer.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/defer.js new file mode 100644 index 00000000000..c4449ca7c8a --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/defer.js @@ -0,0 +1,4 @@ +t.step(() => { + assert_equals(script_run_status, "deferred", "the script run status"); +}); +t.done(); diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1.html new file mode 100644 index 00000000000..73a6ce3db00 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1.html @@ -0,0 +1,36 @@ + +Choice of parse errors + + + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1a.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1a.js new file mode 100644 index 00000000000..f479e5e1fac --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1a.js @@ -0,0 +1,2 @@ +import './choice-of-error-1b.js'; +import './syntaxerror.js?1c'; diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1b.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1b.js new file mode 100644 index 00000000000..257f4a46784 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1b.js @@ -0,0 +1,2 @@ +import './choice-of-error-1a.js'; +import './syntaxerror.js?1d'; diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2.html new file mode 100644 index 00000000000..0d67cb819a9 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2.html @@ -0,0 +1,36 @@ + +Choice of instantiation errors + + + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2a.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2a.js new file mode 100644 index 00000000000..2dc7aac11a8 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2a.js @@ -0,0 +1,2 @@ +import './choice-of-error-2b.js'; +import './instantiation-error-1.js?2c'; diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2b.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2b.js new file mode 100644 index 00000000000..2adb9eea597 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2b.js @@ -0,0 +1,2 @@ +import './choice-of-error-2a.js'; +import './instantiation-error-1.js?2d'; diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3.html new file mode 100644 index 00000000000..5c0adff6ea8 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3.html @@ -0,0 +1,37 @@ + +Choice of evaluation errors + + + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3a.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3a.js new file mode 100644 index 00000000000..71154674a34 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3a.js @@ -0,0 +1,2 @@ +import './choice-of-error-3b.js'; +import './throw.js?3c'; diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3b.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3b.js new file mode 100644 index 00000000000..2131a35eff1 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3b.js @@ -0,0 +1,2 @@ +import './choice-of-error-3a.js'; +import './throw2.js?3d'; diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html index 9390ce0a7a8..1578f8570e4 100644 --- a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html @@ -9,7 +9,7 @@ const cases = [ ["parse error", "../syntaxerror.js", new SyntaxError], ["bad module specifier", "does-not-start-with-dot.js", new TypeError, { differentErrorObjects: true }], ["bad module specifier in a dependency", "../bad-module-specifier.js", new TypeError], - ["instantiation error", "../instantiation-error-1.js", new SyntaxError], + ["instantiation error", "../instantiation-error-1.js", new SyntaxError, { differentErrorObjects: true }], ["evaluation error", "../throw-error.js", new Error] ]; diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/Function.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/Function.js new file mode 100644 index 00000000000..bc88bf7bd63 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/Function.js @@ -0,0 +1 @@ +Function(`import('../../imports-a.js?label=' + window.label).then(window.continueTest, window.errorTest)`)(); diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/eval.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/eval.js new file mode 100644 index 00000000000..a8bcffe9f81 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/eval.js @@ -0,0 +1 @@ +eval(`import('../../imports-a.js?label=' + window.label).then(window.continueTest, window.errorTest)`); diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/inline-event-handlers-UA-code.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/inline-event-handlers-UA-code.js new file mode 100644 index 00000000000..c0bd8655873 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/inline-event-handlers-UA-code.js @@ -0,0 +1,2 @@ +window.dummyDiv.setAttribute("onclick", `import('../../imports-a.js?label=' + window.label).then(window.continueTest, window.errorTest)`); +window.dummyDiv.click(); // different from **on**click() diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/reflected-inline-event-handlers.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/reflected-inline-event-handlers.js new file mode 100644 index 00000000000..f19ec2b03f9 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/reflected-inline-event-handlers.js @@ -0,0 +1,2 @@ +window.dummyDiv.setAttribute("onclick", `import('../../imports-a.js?label=' + window.label).then(window.continueTest, window.errorTest)`); +window.dummyDiv.onclick(); diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/setTimeout.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/setTimeout.js new file mode 100644 index 00000000000..c6f2dda55aa --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/setTimeout.js @@ -0,0 +1 @@ +setTimeout(`import('../../imports-a.js?label=' + window.label).then(window.continueTest, window.errorTest)`, 0); diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-classic.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-classic.html new file mode 100644 index 00000000000..7cf2dac0ac6 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-classic.html @@ -0,0 +1,52 @@ + + +import() inside compiled strings uses the script base URL inside a classic script that is loaded from a file + + + + + +
+ + diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-module.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-module.html new file mode 100644 index 00000000000..73986c2c997 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-module.html @@ -0,0 +1,53 @@ + + +import() inside compiled strings uses the script base URL inside a module script that is loaded from a file + + + + + +
+ + diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-classic.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-classic.html similarity index 92% rename from tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-classic.html rename to tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-classic.html index 062bb620b9e..1bd6d7dfd75 100644 --- a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-classic.html +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-classic.html @@ -1,6 +1,6 @@ -import() inside compiled strings uses the document base URL inside a classic script +import() inside compiled strings uses the script base URL (= document base URL) inside an inline classic script @@ -21,8 +21,8 @@ function createTestPromise() { const dummyDiv = document.querySelector("#dummy"); const evaluators = { - eval, setTimeout, + eval, "the Function constructor"(x) { Function(x)(); }, diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-module.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-module.html similarity index 92% rename from tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-module.html rename to tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-module.html index de51c9a4cd6..f5b85740f55 100644 --- a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-module.html +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-module.html @@ -1,6 +1,6 @@ -import() inside compiled strings uses the document base URL inside a module script +import() inside compiled strings uses the script base URL (= document base URL) inside an inline module script @@ -21,8 +21,8 @@ function createTestPromise() { const dummyDiv = document.querySelector("#dummy"); const evaluators = { - eval, setTimeout, + eval, "the Function constructor"(x) { Function(x)(); }, diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-classic.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-classic.html new file mode 100644 index 00000000000..666bc7ce479 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-classic.html @@ -0,0 +1,52 @@ + + +import() doesn't have any integrity metadata when initiated by compiled strings inside a classic script + + + + + + +
+ + diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-module.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-module.html new file mode 100644 index 00000000000..497c9d97150 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-module.html @@ -0,0 +1,52 @@ + + +import() doesn't have any integrity metadata when initiated by compiled strings inside a module script + + + + + + +
+ + diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-classic.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-classic.html new file mode 100644 index 00000000000..ba82fe8e7c8 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-classic.html @@ -0,0 +1,103 @@ + + +import() inside compiled strings uses the appropriate nonce inside a classic script + + + + + + + +
+ + diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-module.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-module.html new file mode 100644 index 00000000000..889628f8395 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-module.html @@ -0,0 +1,102 @@ + + +import() inside compiled strings uses the appropriate nonce inside a module script + + + + + + + +
+ + diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/error-type-1.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/error-type-1.html new file mode 100644 index 00000000000..6f119e30064 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/error-type-1.html @@ -0,0 +1,33 @@ + +Handling of different types of errors + + + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/error-type-1.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/error-type-1.js new file mode 100644 index 00000000000..4882d3f2a56 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/error-type-1.js @@ -0,0 +1,2 @@ +import './syntaxerror.js'; +import './404.js'; diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/error-type-2.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/error-type-2.html new file mode 100644 index 00000000000..a7df1df0c86 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/error-type-2.html @@ -0,0 +1,34 @@ + +Handling of different types of errors + + + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/error-type-2.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/error-type-2.js new file mode 100644 index 00000000000..6b113973009 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/error-type-2.js @@ -0,0 +1,2 @@ +import './instantiation-error-1.js'; +import './syntaxerror.js'; diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/error-type-3.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/error-type-3.html new file mode 100644 index 00000000000..9b00df38915 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/error-type-3.html @@ -0,0 +1,34 @@ + +Handling of different types of errors + + + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/error-type-3.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/error-type-3.js new file mode 100644 index 00000000000..542be52846a --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/error-type-3.js @@ -0,0 +1,2 @@ +import './throw.js'; +import './instantiation-error-1.js'; diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html index efdf5879fce..57b40f5baaf 100644 --- a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html @@ -6,17 +6,19 @@ + + + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub.html new file mode 100644 index 00000000000..3623ac2ccb2 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub.html @@ -0,0 +1,66 @@ + + + +Referrer with the origin-when-cross-origin policy + + + + + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/referrer-origin.sub.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/referrer-origin.sub.html new file mode 100644 index 00000000000..f512982a451 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/referrer-origin.sub.html @@ -0,0 +1,62 @@ + + + +Referrer with the origin policy + + + + + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/referrer-same-origin.sub.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/referrer-same-origin.sub.html new file mode 100644 index 00000000000..67b055c217d --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/referrer-same-origin.sub.html @@ -0,0 +1,62 @@ + + + +Referrer with the same-origin policy + + + + + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/referrer-unsafe-url.sub.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/referrer-unsafe-url.sub.html new file mode 100644 index 00000000000..11f60c010f0 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/referrer-unsafe-url.sub.html @@ -0,0 +1,68 @@ + + + +Referrer with the unsafe-url policy + + + + + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js new file mode 100644 index 00000000000..2c7dce9dffa --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js @@ -0,0 +1,2 @@ +import { referrer as referrerImport } from './referrer-checker.py?name={{GET[name]}}'; +export const referrer = referrerImport; diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js.headers b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js.headers new file mode 100644 index 00000000000..cb762eff806 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js.headers @@ -0,0 +1 @@ +Access-Control-Allow-Origin: * diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/resources/import-remote-origin-referrer-checker.sub.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/resources/import-remote-origin-referrer-checker.sub.js new file mode 100644 index 00000000000..45a2520b68c --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/resources/import-remote-origin-referrer-checker.sub.js @@ -0,0 +1,2 @@ +import { referrer as referrerImport } from 'http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py?name={{GET[name]}}'; +export const referrer = referrerImport; diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py new file mode 100644 index 00000000000..b652cbe2c86 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py @@ -0,0 +1,6 @@ +def main(request, response): + referrer = request.headers.get("referer", "") + response_headers = [("Content-Type", "text/javascript"), + ("Access-Control-Allow-Origin", "*")]; + return (200, response_headers, + "export const referrer = '" + referrer + "';") diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/throw2.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/throw2.js new file mode 100644 index 00000000000..2931eec500d --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/throw2.js @@ -0,0 +1,2 @@ +log.push("throw2"); +throw {bar: true} diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/script-defer.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/script-defer.html new file mode 100644 index 00000000000..80eb98dc750 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/script-defer.html @@ -0,0 +1,26 @@ + + +HTML Test: HTMLScriptElement - defer + + + + +
+ + + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/text-level-semantics/the-a-element/a-download-click-404.html b/tests/wpt/web-platform-tests/html/semantics/text-level-semantics/the-a-element/a-download-click-404.html index db9e1cbfb92..3c8adc0b97e 100644 --- a/tests/wpt/web-platform-tests/html/semantics/text-level-semantics/the-a-element/a-download-click-404.html +++ b/tests/wpt/web-platform-tests/html/semantics/text-level-semantics/the-a-element/a-download-click-404.html @@ -11,15 +11,15 @@ async_test(t => { const errorFrame = document.createElement("iframe"); - errorFrame.addEventListener("load", function () { + errorFrame.addEventListener("load", t.step_func(function () { errorFrame.contentWindow.addEventListener( "beforeunload", t.unreached_func("Navigated instead of downloading")); errorFrame.contentDocument.querySelector("#error-url").click(); t.step_timeout(() => t.done(), 1000); - }); + })); errorFrame.src = "resources/a-download-404.html"; document.body.appendChild(errorFrame); }, "Do not navigate to 404 for anchor with download"); - \ No newline at end of file + diff --git a/tests/wpt/web-platform-tests/html/semantics/text-level-semantics/the-a-element/a-download-click.html b/tests/wpt/web-platform-tests/html/semantics/text-level-semantics/the-a-element/a-download-click.html index ad6a3df001e..22d329f2452 100644 --- a/tests/wpt/web-platform-tests/html/semantics/text-level-semantics/the-a-element/a-download-click.html +++ b/tests/wpt/web-platform-tests/html/semantics/text-level-semantics/the-a-element/a-download-click.html @@ -7,18 +7,27 @@ -Click me - + + diff --git a/tests/wpt/web-platform-tests/html/semantics/text-level-semantics/the-a-element/resources/a-download-click.html b/tests/wpt/web-platform-tests/html/semantics/text-level-semantics/the-a-element/resources/a-download-click.html new file mode 100644 index 00000000000..7d36c21d1e4 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/text-level-semantics/the-a-element/resources/a-download-click.html @@ -0,0 +1,2 @@ + +Click me diff --git a/tests/wpt/web-platform-tests/html/semantics/text-level-semantics/the-b-element/b-usage-notref.html b/tests/wpt/web-platform-tests/html/semantics/text-level-semantics/the-b-element/b-usage-notref.html new file mode 100644 index 00000000000..3d3c46a281f --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/text-level-semantics/the-b-element/b-usage-notref.html @@ -0,0 +1,6 @@ + + +HTML Reference File + + +

You enter a small room. Your sword glows brighter. A rat scurries past the corner wall.

diff --git a/tests/wpt/web-platform-tests/html/semantics/text-level-semantics/the-b-element/b-usage.html b/tests/wpt/web-platform-tests/html/semantics/text-level-semantics/the-b-element/b-usage.html new file mode 100644 index 00000000000..ff2105dcae8 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/text-level-semantics/the-b-element/b-usage.html @@ -0,0 +1,8 @@ + + +HTML test: b - highlight keywords + + + + +

You enter a small room. Your sword glows brighter. A rat scurries past the corner wall.

diff --git a/tests/wpt/web-platform-tests/html/semantics/text-level-semantics/the-ruby-element/ruby-usage-notref.html b/tests/wpt/web-platform-tests/html/semantics/text-level-semantics/the-ruby-element/ruby-usage-notref.html new file mode 100644 index 00000000000..f5747811ae4 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/text-level-semantics/the-ruby-element/ruby-usage-notref.html @@ -0,0 +1,6 @@ + + +HTML Reference File + + +

君くん子しは和わして同どうぜず

diff --git a/tests/wpt/web-platform-tests/html/semantics/text-level-semantics/the-ruby-element/ruby-usage.html b/tests/wpt/web-platform-tests/html/semantics/text-level-semantics/the-ruby-element/ruby-usage.html new file mode 100644 index 00000000000..59c076cd092 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/text-level-semantics/the-ruby-element/ruby-usage.html @@ -0,0 +1,8 @@ + + +HTML test: ruby - mark phrasing content + + + + +

くんしてどうぜず

diff --git a/tests/wpt/web-platform-tests/html/webappapis/animation-frames/idlharness.html b/tests/wpt/web-platform-tests/html/webappapis/animation-frames/idlharness.html index acc6657fac6..3a9d1d9b583 100644 --- a/tests/wpt/web-platform-tests/html/webappapis/animation-frames/idlharness.html +++ b/tests/wpt/web-platform-tests/html/webappapis/animation-frames/idlharness.html @@ -15,7 +15,7 @@

This test validates the WebIDL included in the Timing control for script-based animations specification.

diff --git a/tests/wpt/web-platform-tests/html/webappapis/scripting/events/event-handler-spec-example.html b/tests/wpt/web-platform-tests/html/webappapis/scripting/events/event-handler-spec-example.html index c06806e3c77..1f3cff42652 100644 --- a/tests/wpt/web-platform-tests/html/webappapis/scripting/events/event-handler-spec-example.html +++ b/tests/wpt/web-platform-tests/html/webappapis/scripting/events/event-handler-spec-example.html @@ -15,6 +15,7 @@ objects.forEach(function(object) { var uncalled = "t.step(function() { assert_unreached('First event handler.') })" var button = document.createElement('button'); button.onclick = object; // event handler listener is registered here + assert_equals(button.onclick, object); button.addEventListener('click', t.step_func(function () { assert_equals(++i, 2) }), false); button.setAttribute('onclick', uncalled); button.addEventListener('click', t.step_func(function () { assert_equals(++i, 3) }), false); @@ -35,6 +36,7 @@ primitives.forEach(function(primitive) { var uncalled = "t.step(function() { assert_unreached('First event handler.') })" var button = document.createElement('button'); button.onclick = primitive; + assert_equals(button.onclick, null); button.addEventListener('click', t.step_func(function () { assert_equals(++i, 1) }), false); button.setAttribute('onclick', uncalled); // event handler listener is registered here button.addEventListener('click', t.step_func(function () { assert_equals(++i, 3) }), false); diff --git a/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol.html b/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol.html index a9ceee5a846..d090aad609d 100644 --- a/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol.html +++ b/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol.html @@ -58,12 +58,12 @@ test(function () { }, 'an empty url argument should throw SYNTAX_ERR'); test(function () { - assert_throws('SYNTAX_ERR', function () { navigator.registerProtocolHandler('mailto', 'http://%s.com', 'foo') } ); -}, '%s instead of domain name should throw SYNTAX_ERR'); + assert_throws('SECURITY_ERR', function () { navigator.registerProtocolHandler('mailto', 'http://%s.com', 'foo') } ); +}, '%s instead of domain name should throw SECURITY_ERR'); test(function () { - assert_throws('SYNTAX_ERR', function () { navigator.registerProtocolHandler('mailto', 'http://%s.example.com', 'foo') } ); -}, '%s instead of subdomain name should throw SYNTAX_ERR'); + assert_throws('SECURITY_ERR', function () { navigator.registerProtocolHandler('mailto', 'http://%s.example.com', 'foo') } ); +}, '%s instead of subdomain name should throw SECURITY_ERR'); test(function () { assert_throws('SYNTAX_ERR', function () { navigator.registerProtocolHandler('mailto', location.href + '', 'foo') } ); diff --git a/tests/wpt/web-platform-tests/http/resources/securedimage.py b/tests/wpt/web-platform-tests/http/resources/securedimage.py index 311b0c5259c..89cbd72b134 100644 --- a/tests/wpt/web-platform-tests/http/resources/securedimage.py +++ b/tests/wpt/web-platform-tests/http/resources/securedimage.py @@ -6,12 +6,10 @@ def main(request, response): if "authorization" not in request.headers: response.status = 401 response.headers.set("WWW-Authenticate", "Basic") - return response else: auth = request.headers.get("Authorization") if auth != "Basic dGVzdHVzZXI6dGVzdHBhc3M=": response.set_error(403, "Invalid username or password - " + auth) - return response response.status = 301 response.headers.set("Location", image_url) diff --git a/tests/wpt/web-platform-tests/infrastructure/assumptions/ahem-notref.html b/tests/wpt/web-platform-tests/infrastructure/assumptions/ahem-notref.html new file mode 100644 index 00000000000..51767c26ea8 --- /dev/null +++ b/tests/wpt/web-platform-tests/infrastructure/assumptions/ahem-notref.html @@ -0,0 +1,316 @@ + +Ahem checker + + + + + + + + + + + + + + + + + + + +
x + !x + "x + #x + $x + %x + &x + (x + )x + *x + +x + ,x + -x + .x + /x + 0x + 1x +
2x + 3x + 4x + 5x + 6x + 7x + 8x + 9x + :x + ;x + <x + =x + >x + ?x + @x + Ax + Bx +
Cx + Dx + Ex + Fx + Gx + Hx + Ix + Jx + Kx + Lx + Mx + Nx + Ox + Px + Qx + Rx + Sx +
Tx + Ux + Vx + Wx + Xx + Yx + Zx + [x + \x + ]x + ^x + _x + `x + ax + bx + cx + dx +
ex + fx + gx + hx + ix + jx + kx + lx + mx + nx + ox + px + qx + rx + sx + tx + ux +
vx + wx + xx + yx + zx + {x + |x + }x + ~x +  x + ¡x + ¢x + £x + ¤x + ¥x + ¦x + §x +
¨x + ©x + ªx + «x + ¬x + ­x + ®x + ¯x + °x + ±x + ²x + ³x + ´x + µx + ¶x + ·x + ¸x +
¹x + ºx + »x + ¼x + ½x + ¾x + ¿x + Àx + Áx + Âx + Ãx + Äx + Åx + Æx + Çx + Èx + Éx +
Êx + Ëx + Ìx + Íx + Îx + Ïx + Ðx + Ñx + Òx + Óx + Ôx + Õx + Öx + ×x + Øx + Ùx + Úx +
Ûx + Üx + Ýx + Þx + ßx + àx + áx + âx + ãx + äx + åx + æx + çx + èx + éx + êx + ëx +
ìx + íx + îx + ïx + ðx + ñx + òx + óx + ôx + õx + öx + ÷x + øx + ùx + úx + ûx + üx +
ýx + þx + ÿx + ıx + Œx + œx + Ÿx + ƒx + ˆx + ˇx + ˉx + ˘x + ˙x + ˚x + ˛x + ˜x + ˝x +
Δx + Υx + Χx + Ωx + μx + πx +  x +  x +  x +  x +  x +  x +  x + ​x + ‌x + ‍x + ‐x +
–x + —x + ‘x + ’x + ‚x + “x + ”x + „x + †x + ‡x + •x + …x + ‰x + ‹x + ›x + ⁄x + ™x +
Ωx + ∂x + ∆x + ∏x + ∑x + −x + ∙x + √x + ∞x + ∫x + ≈x + ≠x + ≤x + ≥x + ⋲x + ◊x +  x +
〇x + 一x + 七x + 三x + 九x + 二x + 五x + 八x + 六x + 十x + 囗x + 四x + 土x + 木x + 横x + 水x + 火x +
纵x + 金x + x + x + x + x +
diff --git a/tests/wpt/web-platform-tests/infrastructure/assumptions/ahem-ref.html b/tests/wpt/web-platform-tests/infrastructure/assumptions/ahem-ref.html index 971b51c54e4..9116232620f 100644 --- a/tests/wpt/web-platform-tests/infrastructure/assumptions/ahem-ref.html +++ b/tests/wpt/web-platform-tests/infrastructure/assumptions/ahem-ref.html @@ -1,27 +1,25 @@ - Ahem checker + diff --git a/tests/wpt/web-platform-tests/infrastructure/assumptions/ahem.html b/tests/wpt/web-platform-tests/infrastructure/assumptions/ahem.html index b18cd8e9861..068c1d4dee6 100644 --- a/tests/wpt/web-platform-tests/infrastructure/assumptions/ahem.html +++ b/tests/wpt/web-platform-tests/infrastructure/assumptions/ahem.html @@ -1,4 +1,3 @@ - Ahem checker @@ -8,17 +7,15 @@ margin: 0; border: none; } - +td { + width: 34px; +} table { font: 15px/1 Ahem; border-collapse: separate; border-spacing: 1px; table-layout: fixed; } - -td { - width: 34px; -}
diff --git a/tests/wpt/web-platform-tests/infrastructure/assumptions/tools/ahem-generate-table.py b/tests/wpt/web-platform-tests/infrastructure/assumptions/tools/ahem-generate-table.py index d9fb1fbc32d..8790da02e27 100644 --- a/tests/wpt/web-platform-tests/infrastructure/assumptions/tools/ahem-generate-table.py +++ b/tests/wpt/web-platform-tests/infrastructure/assumptions/tools/ahem-generate-table.py @@ -30,52 +30,68 @@ chars_sorted = sorted(chars) per_row = 17 -def build_header(is_test): - rv = [] - - rv.append(""" - -Ahem checker""") - - if is_test: - rv.append(""" -""") - - rv.append(""" -" +style_font_face = """ +@font-face { + font-family: Ahem; + src: url("../../fonts/Ahem.ttf"); +}""".strip() +style_table_font_specified = """ table { font: 15px/1 Ahem; border-collapse: separate; border-spacing: 1px; table-layout: fixed; -} +}""".strip() +style_table_font_unspecified = """ +table { + font-size: 15px; + line-height: 1; + border-collapse: separate; + border-spacing: 1px; + table-layout: fixed; +}""".strip() -td { - width: 34px; -} - -""") - return "".join(rv) +def build_header(is_test, rel, href): + rv = [doctype, title] + + if rel != None and href != None: + rv.append('' % (rel, href)) + + rv.append(style_open) + + if not is_test: + if rel == None and href == None: + # ahem-notref.html + rv.append(style_table_font_unspecified) + else: + # ahem-ref.html + rv.append(style_font_face) + rv.append(style_table_font_specified) + else: + # ahem.html + rv.append(style_table_font_specified) + + rv.append(style_close) + + return "\n".join(rv) def build_table(): - rv = [] + rv = ["\n"] rv.append("
\n") for row in grouper(per_row, chars_sorted): @@ -93,10 +109,21 @@ def build_table(): return "".join(rv) -with open("../ahem.html", "w") as f1: - f1.write(build_header(True)) - f1.write(build_table()) +cases = [ + # file, is_test, rel + ("../ahem.html", True, "match"), + ("../ahem-ref.html", False, "mismatch"), + ("../ahem-notref.html", False, None), +] + +table = build_table() + +for index, case in enumerate(cases): + next_index = index + 1 + file, is_test, rel = case + href = cases[next_index][0][3:] if next_index < len(cases) else None + header = build_header(is_test, rel, href) + + with open(file, "w") as file: + file.write("%s%s" % (header, table)) -with open("../ahem-ref.html", "w") as f1: - f1.write(build_header(False)) - f1.write(build_table()) diff --git a/tests/wpt/web-platform-tests/interfaces/dom.idl b/tests/wpt/web-platform-tests/interfaces/dom.idl index fce74328043..25324787d71 100644 --- a/tests/wpt/web-platform-tests/interfaces/dom.idl +++ b/tests/wpt/web-platform-tests/interfaces/dom.idl @@ -79,26 +79,20 @@ interface AbortSignal : EventTarget { }; -[NoInterfaceObject, - Exposed=Window] -interface NonElementParentNode { +interface mixin NonElementParentNode { Element? getElementById(DOMString elementId); }; -Document implements NonElementParentNode; -DocumentFragment implements NonElementParentNode; +Document includes NonElementParentNode; +DocumentFragment includes NonElementParentNode; -[NoInterfaceObject, - Exposed=Window] -interface DocumentOrShadowRoot { +interface mixin DocumentOrShadowRoot { }; -Document implements DocumentOrShadowRoot; -ShadowRoot implements DocumentOrShadowRoot; +Document includes DocumentOrShadowRoot; +ShadowRoot includes DocumentOrShadowRoot; -[NoInterfaceObject, - Exposed=Window] -interface ParentNode { +interface mixin ParentNode { [SameObject] readonly attribute HTMLCollection children; readonly attribute Element? firstElementChild; readonly attribute Element? lastElementChild; @@ -110,41 +104,35 @@ interface ParentNode { Element? querySelector(DOMString selectors); [NewObject] NodeList querySelectorAll(DOMString selectors); }; -Document implements ParentNode; -DocumentFragment implements ParentNode; -Element implements ParentNode; +Document includes ParentNode; +DocumentFragment includes ParentNode; +Element includes ParentNode; -[NoInterfaceObject, - Exposed=Window] -interface NonDocumentTypeChildNode { +interface mixin NonDocumentTypeChildNode { readonly attribute Element? previousElementSibling; readonly attribute Element? nextElementSibling; }; -Element implements NonDocumentTypeChildNode; -CharacterData implements NonDocumentTypeChildNode; +Element includes NonDocumentTypeChildNode; +CharacterData includes NonDocumentTypeChildNode; -[NoInterfaceObject, - Exposed=Window] -interface ChildNode { +interface mixin ChildNode { [Unscopable] void before((Node or DOMString)... nodes); [Unscopable] void after((Node or DOMString)... nodes); [Unscopable] void replaceWith((Node or DOMString)... nodes); [Unscopable] void remove(); }; -DocumentType implements ChildNode; -Element implements ChildNode; -CharacterData implements ChildNode; +DocumentType includes ChildNode; +Element includes ChildNode; +CharacterData includes ChildNode; -[NoInterfaceObject, - Exposed=Window] -interface Slotable { +interface mixin Slotable { readonly attribute HTMLSlotElement? assignedSlot; }; -Element implements Slotable; -Text implements Slotable; +Element includes Slotable; +Text includes Slotable; [Exposed=Window] diff --git a/tests/wpt/web-platform-tests/interfaces/geolocation-sensor.idl b/tests/wpt/web-platform-tests/interfaces/geolocation-sensor.idl index 7c2e247e46d..81891551e50 100644 --- a/tests/wpt/web-platform-tests/interfaces/geolocation-sensor.idl +++ b/tests/wpt/web-platform-tests/interfaces/geolocation-sensor.idl @@ -1,4 +1,4 @@ -[Constructor(optional SensorOptions options), Exposed=Window] +[Constructor(optional SensorOptions options), SecureContext, Exposed=Window] interface GeolocationSensor : Sensor { readonly attribute unrestricted double? latitude; readonly attribute unrestricted double? longitude; diff --git a/tests/wpt/web-platform-tests/interfaces/hr-time.idl b/tests/wpt/web-platform-tests/interfaces/hr-time.idl new file mode 100644 index 00000000000..ccbbc332326 --- /dev/null +++ b/tests/wpt/web-platform-tests/interfaces/hr-time.idl @@ -0,0 +1,13 @@ +typedef double DOMHighResTimeStamp; + +[Exposed=(Window,Worker)] +interface Performance : EventTarget { + DOMHighResTimeStamp now(); + readonly attribute DOMHighResTimeStamp timeOrigin; + [Default] object toJSON(); +}; + +partial interface WindowOrWorkerGlobalScope { + [Replaceable] + readonly attribute Performance performance; +}; diff --git a/tests/wpt/web-platform-tests/interfaces/html.idl b/tests/wpt/web-platform-tests/interfaces/html.idl index a8693340e9a..e272fb823bc 100644 --- a/tests/wpt/web-platform-tests/interfaces/html.idl +++ b/tests/wpt/web-platform-tests/interfaces/html.idl @@ -4,7 +4,9 @@ interface HTMLAllCollection { readonly attribute unsigned long length; getter Element? (unsigned long index); getter (HTMLCollection or Element)? namedItem(DOMString name); - legacycaller (HTMLCollection or Element)? item(optional DOMString nameOrIndex); + (HTMLCollection or Element)? item(optional DOMString nameOrIndex); + + // Note: HTMLAllCollection objects have a custom [[Call]] internal method and an [[IsHTMLDDA]] internal slot. }; [Exposed=Window] @@ -84,8 +86,8 @@ partial interface Document { // special event handler IDL attributes that only apply to Document objects [LenientThis] attribute EventHandler onreadystatechange; }; -Document implements GlobalEventHandlers; -Document implements DocumentAndElementEventHandlers; +Document includes GlobalEventHandlers; +Document includes DocumentAndElementEventHandlers; [Exposed=Window, HTMLConstructor] @@ -115,9 +117,9 @@ dictionary FocusOptions { boolean preventScroll = false; }; -HTMLElement implements GlobalEventHandlers; -HTMLElement implements DocumentAndElementEventHandlers; -HTMLElement implements ElementContentEditable; +HTMLElement includes GlobalEventHandlers; +HTMLElement includes DocumentAndElementEventHandlers; +HTMLElement includes ElementContentEditable; // Note: intentionally not [HTMLConstructor] interface HTMLUnknownElement : HTMLElement { }; @@ -168,13 +170,12 @@ interface HTMLLinkElement : HTMLElement { [CEReactions] attribute DOMString type; [SameObject, PutForwards=value] readonly attribute DOMTokenList sizes; [CEReactions] attribute DOMString referrerPolicy; - [CEReactions] attribute USVString scope; [CEReactions] attribute DOMString workerType; [CEReactions] attribute DOMString updateViaCache; // also has obsolete members }; -HTMLLinkElement implements LinkStyle; +HTMLLinkElement includes LinkStyle; [Exposed=Window, HTMLConstructor] @@ -193,7 +194,7 @@ interface HTMLStyleElement : HTMLElement { [CEReactions] attribute DOMString nonce; [CEReactions] attribute DOMString type; }; -HTMLStyleElement implements LinkStyle; +HTMLStyleElement includes LinkStyle; [Exposed=Window, HTMLConstructor] @@ -201,7 +202,7 @@ interface HTMLBodyElement : HTMLElement { // also has obsolete members }; -HTMLBodyElement implements WindowEventHandlers; +HTMLBodyElement includes WindowEventHandlers; [Exposed=Window, HTMLConstructor] @@ -293,7 +294,7 @@ interface HTMLAnchorElement : HTMLElement { // also has obsolete members }; -HTMLAnchorElement implements HTMLHyperlinkElementUtils; +HTMLAnchorElement includes HTMLHyperlinkElementUtils; [Exposed=Window, HTMLConstructor] @@ -317,9 +318,7 @@ interface HTMLBRElement : HTMLElement { // also has obsolete members }; -[Exposed=Window, - NoInterfaceObject] -interface HTMLHyperlinkElementUtils { +interface mixin HTMLHyperlinkElementUtils { [CEReactions] stringifier attribute USVString href; readonly attribute USVString origin; [CEReactions] attribute USVString protocol; @@ -686,7 +685,7 @@ interface HTMLAreaElement : HTMLElement { // also has obsolete members }; -HTMLAreaElement implements HTMLHyperlinkElementUtils; +HTMLAreaElement includes HTMLHyperlinkElementUtils; [Exposed=Window, HTMLConstructor] @@ -817,7 +816,6 @@ interface HTMLInputElement : HTMLElement { [CEReactions] attribute DOMString formTarget; [CEReactions] attribute unsigned long height; attribute boolean indeterminate; - [CEReactions] attribute DOMString inputMode; readonly attribute HTMLElement? list; [CEReactions] attribute DOMString max; [CEReactions] attribute long maxLength; @@ -961,7 +959,6 @@ interface HTMLTextAreaElement : HTMLElement { [CEReactions] attribute DOMString dirName; [CEReactions] attribute boolean disabled; readonly attribute HTMLFormElement? form; - [CEReactions] attribute DOMString inputMode; [CEReactions] attribute long maxLength; [CEReactions] attribute long minLength; [CEReactions] attribute DOMString name; @@ -1129,6 +1126,7 @@ interface HTMLTemplateElement : HTMLElement { interface HTMLSlotElement : HTMLElement { [CEReactions] attribute DOMString name; sequence assignedNodes(optional AssignedNodesOptions options); + sequence assignedElements(optional AssignedNodesOptions options); }; dictionary AssignedNodesOptions { @@ -1174,32 +1172,30 @@ interface CanvasRenderingContext2D { // back-reference to the canvas readonly attribute HTMLCanvasElement canvas; }; -CanvasRenderingContext2D implements CanvasState; -CanvasRenderingContext2D implements CanvasTransform; -CanvasRenderingContext2D implements CanvasCompositing; -CanvasRenderingContext2D implements CanvasImageSmoothing; -CanvasRenderingContext2D implements CanvasFillStrokeStyles; -CanvasRenderingContext2D implements CanvasShadowStyles; -CanvasRenderingContext2D implements CanvasFilters; -CanvasRenderingContext2D implements CanvasRect; -CanvasRenderingContext2D implements CanvasDrawPath; -CanvasRenderingContext2D implements CanvasUserInterface; -CanvasRenderingContext2D implements CanvasText; -CanvasRenderingContext2D implements CanvasDrawImage; -CanvasRenderingContext2D implements CanvasImageData; -CanvasRenderingContext2D implements CanvasPathDrawingStyles; -CanvasRenderingContext2D implements CanvasTextDrawingStyles; -CanvasRenderingContext2D implements CanvasPath; +CanvasRenderingContext2D includes CanvasState; +CanvasRenderingContext2D includes CanvasTransform; +CanvasRenderingContext2D includes CanvasCompositing; +CanvasRenderingContext2D includes CanvasImageSmoothing; +CanvasRenderingContext2D includes CanvasFillStrokeStyles; +CanvasRenderingContext2D includes CanvasShadowStyles; +CanvasRenderingContext2D includes CanvasFilters; +CanvasRenderingContext2D includes CanvasRect; +CanvasRenderingContext2D includes CanvasDrawPath; +CanvasRenderingContext2D includes CanvasUserInterface; +CanvasRenderingContext2D includes CanvasText; +CanvasRenderingContext2D includes CanvasDrawImage; +CanvasRenderingContext2D includes CanvasImageData; +CanvasRenderingContext2D includes CanvasPathDrawingStyles; +CanvasRenderingContext2D includes CanvasTextDrawingStyles; +CanvasRenderingContext2D includes CanvasPath; -[NoInterfaceObject, Exposed=(Window,Worker)] -interface CanvasState { +interface mixin CanvasState { // state void save(); // push state on state stack void restore(); // pop state stack and restore state }; -[NoInterfaceObject, Exposed=(Window,Worker)] -interface CanvasTransform { +interface mixin CanvasTransform { // transformations (default transform is the identity matrix) void scale(unrestricted double x, unrestricted double y); void rotate(unrestricted double angle); @@ -1210,37 +1206,30 @@ interface CanvasTransform { void setTransform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f); void setTransform(optional DOMMatrix2DInit transform); void resetTransform(); - }; -[NoInterfaceObject, Exposed=(Window,Worker)] -interface CanvasCompositing { +interface mixin CanvasCompositing { // compositing attribute unrestricted double globalAlpha; // (default 1.0) attribute DOMString globalCompositeOperation; // (default source-over) }; -[NoInterfaceObject, Exposed=(Window,Worker)] -interface CanvasImageSmoothing { +interface mixin CanvasImageSmoothing { // image smoothing attribute boolean imageSmoothingEnabled; // (default true) attribute ImageSmoothingQuality imageSmoothingQuality; // (default low) - }; -[NoInterfaceObject, Exposed=(Window,Worker)] -interface CanvasFillStrokeStyles { +interface mixin CanvasFillStrokeStyles { // colors and styles (see also the CanvasPathDrawingStyles and CanvasTextDrawingStyles interfaces) attribute (DOMString or CanvasGradient or CanvasPattern) strokeStyle; // (default black) attribute (DOMString or CanvasGradient or CanvasPattern) fillStyle; // (default black) CanvasGradient createLinearGradient(double x0, double y0, double x1, double y1); CanvasGradient createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1); CanvasPattern? createPattern(CanvasImageSource image, [TreatNullAs=EmptyString] DOMString repetition); - }; -[NoInterfaceObject, Exposed=(Window,Worker)] -interface CanvasShadowStyles { +interface mixin CanvasShadowStyles { // shadows attribute unrestricted double shadowOffsetX; // (default 0) attribute unrestricted double shadowOffsetY; // (default 0) @@ -1248,22 +1237,19 @@ interface CanvasShadowStyles { attribute DOMString shadowColor; // (default transparent black) }; -[NoInterfaceObject, Exposed=(Window,Worker)] -interface CanvasFilters { +interface mixin CanvasFilters { // filters attribute DOMString filter; // (default "none") }; -[NoInterfaceObject, Exposed=(Window,Worker)] -interface CanvasRect { +interface mixin CanvasRect { // rects void clearRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h); void fillRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h); void strokeRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h); }; -[NoInterfaceObject, Exposed=(Window,Worker)] -interface CanvasDrawPath { +interface mixin CanvasDrawPath { // path API (see also CanvasPath) void beginPath(); void fill(optional CanvasFillRule fillRule = "nonzero"); @@ -1279,34 +1265,28 @@ interface CanvasDrawPath { boolean isPointInStroke(Path2D path, unrestricted double x, unrestricted double y); }; -[Exposed=Window, - NoInterfaceObject] -interface CanvasUserInterface { +interface mixin CanvasUserInterface { void drawFocusIfNeeded(Element element); void drawFocusIfNeeded(Path2D path, Element element); void scrollPathIntoView(); void scrollPathIntoView(Path2D path); }; -[Exposed=Window, - NoInterfaceObject] -interface CanvasText { +interface mixin CanvasText { // text (see also the CanvasPathDrawingStyles and CanvasTextDrawingStyles interfaces) void fillText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth); void strokeText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth); TextMetrics measureText(DOMString text); }; -[NoInterfaceObject, Exposed=(Window,Worker)] -interface CanvasDrawImage { +interface mixin CanvasDrawImage { // drawing images void drawImage(CanvasImageSource image, unrestricted double dx, unrestricted double dy); void drawImage(CanvasImageSource image, unrestricted double dx, unrestricted double dy, unrestricted double dw, unrestricted double dh); void drawImage(CanvasImageSource image, unrestricted double sx, unrestricted double sy, unrestricted double sw, unrestricted double sh, unrestricted double dx, unrestricted double dy, unrestricted double dw, unrestricted double dh); }; -[NoInterfaceObject, Exposed=(Window,Worker)] -interface CanvasImageData { +interface mixin CanvasImageData { // pixel manipulation ImageData createImageData(long sw, long sh); ImageData createImageData(ImageData imagedata); @@ -1321,8 +1301,7 @@ enum CanvasTextAlign { "start", "end", "left", "right", "center" }; enum CanvasTextBaseline { "top", "hanging", "middle", "alphabetic", "ideographic", "bottom" }; enum CanvasDirection { "ltr", "rtl", "inherit" }; -[NoInterfaceObject, Exposed=(Window,Worker)] -interface CanvasPathDrawingStyles { +interface mixin CanvasPathDrawingStyles { // line caps/joins attribute unrestricted double lineWidth; // (default 1) attribute CanvasLineCap lineCap; // (default "butt") @@ -1335,9 +1314,7 @@ interface CanvasPathDrawingStyles { attribute unrestricted double lineDashOffset; }; -[Exposed=Window, - NoInterfaceObject] -interface CanvasTextDrawingStyles { +interface mixin CanvasTextDrawingStyles { // text attribute DOMString font; // (default 10px sans-serif) attribute CanvasTextAlign textAlign; // (default: "start") @@ -1345,8 +1322,7 @@ interface CanvasTextDrawingStyles { attribute CanvasDirection direction; // (default: "inherit") }; -[NoInterfaceObject, Exposed=(Window,Worker)] -interface CanvasPath { +interface mixin CanvasPath { // shared path API methods void closePath(); void moveTo(unrestricted double x, unrestricted double y); @@ -1409,7 +1385,7 @@ interface ImageData { interface Path2D { void addPath(Path2D path, optional DOMMatrix2DInit transform); }; -Path2D implements CanvasPath; +Path2D includes CanvasPath; [Exposed=Window] interface ImageBitmapRenderingContext { @@ -1448,19 +1424,19 @@ interface OffscreenCanvasRenderingContext2D { readonly attribute OffscreenCanvas canvas; }; -OffscreenCanvasRenderingContext2D implements CanvasState; -OffscreenCanvasRenderingContext2D implements CanvasTransform; -OffscreenCanvasRenderingContext2D implements CanvasCompositing; -OffscreenCanvasRenderingContext2D implements CanvasImageSmoothing; -OffscreenCanvasRenderingContext2D implements CanvasFillStrokeStyles; -OffscreenCanvasRenderingContext2D implements CanvasShadowStyles; -OffscreenCanvasRenderingContext2D implements CanvasFilters; -OffscreenCanvasRenderingContext2D implements CanvasRect; -OffscreenCanvasRenderingContext2D implements CanvasDrawPath; -OffscreenCanvasRenderingContext2D implements CanvasDrawImage; -OffscreenCanvasRenderingContext2D implements CanvasImageData; -OffscreenCanvasRenderingContext2D implements CanvasPathDrawingStyles; -OffscreenCanvasRenderingContext2D implements CanvasPath; +OffscreenCanvasRenderingContext2D includes CanvasState; +OffscreenCanvasRenderingContext2D includes CanvasTransform; +OffscreenCanvasRenderingContext2D includes CanvasCompositing; +OffscreenCanvasRenderingContext2D includes CanvasImageSmoothing; +OffscreenCanvasRenderingContext2D includes CanvasFillStrokeStyles; +OffscreenCanvasRenderingContext2D includes CanvasShadowStyles; +OffscreenCanvasRenderingContext2D includes CanvasFilters; +OffscreenCanvasRenderingContext2D includes CanvasRect; +OffscreenCanvasRenderingContext2D includes CanvasDrawPath; +OffscreenCanvasRenderingContext2D includes CanvasDrawImage; +OffscreenCanvasRenderingContext2D includes CanvasImageData; +OffscreenCanvasRenderingContext2D includes CanvasPathDrawingStyles; +OffscreenCanvasRenderingContext2D includes CanvasPath; [Exposed=Window] @@ -1474,11 +1450,10 @@ dictionary ElementDefinitionOptions { DOMString extends; }; -[Exposed=Window, - NoInterfaceObject] -interface ElementContentEditable { +interface mixin ElementContentEditable { [CEReactions] attribute DOMString contentEditable; readonly attribute boolean isContentEditable; + [CEReactions] attribute DOMString inputMode; }; [Exposed=Window, @@ -1529,7 +1504,9 @@ dictionary DragEventInit : MouseEventInit { DataTransfer? dataTransfer = null; }; -[PrimaryGlobal, LegacyUnenumerableNamedProperties] +[Global=Window, + Exposed=Window, + LegacyUnenumerableNamedProperties] interface Window : EventTarget { // the current browsing context [Unforgeable] readonly attribute WindowProxy window; @@ -1583,8 +1560,8 @@ interface Window : EventTarget { // also has obsolete members }; -Window implements GlobalEventHandlers; -Window implements WindowEventHandlers; +Window includes GlobalEventHandlers; +Window includes WindowEventHandlers; callback FrameRequestCallback = void (DOMHighResTimeStamp time); @@ -1692,8 +1669,7 @@ interface ApplicationCache : EventTarget { attribute EventHandler onobsolete; }; -[NoInterfaceObject, Exposed=(Window,Worker)] -interface NavigatorOnLine { +interface mixin NavigatorOnLine { readonly attribute boolean onLine; }; @@ -1737,9 +1713,7 @@ typedef OnErrorEventHandlerNonNull? OnErrorEventHandler; callback OnBeforeUnloadEventHandlerNonNull = DOMString? (Event event); typedef OnBeforeUnloadEventHandlerNonNull? OnBeforeUnloadEventHandler; -[Exposed=Window, - NoInterfaceObject] -interface GlobalEventHandlers { +interface mixin GlobalEventHandlers { attribute EventHandler onabort; attribute EventHandler onauxclick; attribute EventHandler onblur; @@ -1804,9 +1778,7 @@ interface GlobalEventHandlers { attribute EventHandler onwaiting; }; -[Exposed=Window, - NoInterfaceObject] -interface WindowEventHandlers { +interface mixin WindowEventHandlers { attribute EventHandler onafterprint; attribute EventHandler onbeforeprint; attribute OnBeforeUnloadEventHandler onbeforeunload; @@ -1825,9 +1797,7 @@ interface WindowEventHandlers { attribute EventHandler onunload; }; -[Exposed=Window, - NoInterfaceObject] -interface DocumentAndElementEventHandlers { +interface mixin DocumentAndElementEventHandlers { attribute EventHandler oncopy; attribute EventHandler oncut; attribute EventHandler onpaste; @@ -1835,8 +1805,7 @@ interface DocumentAndElementEventHandlers { typedef (DOMString or Function) TimerHandler; -[NoInterfaceObject, Exposed=(Window,Worker)] -interface WindowOrWorkerGlobalScope { +interface mixin WindowOrWorkerGlobalScope { [Replaceable] readonly attribute USVString origin; // base64 utility methods @@ -1853,23 +1822,22 @@ interface WindowOrWorkerGlobalScope { Promise createImageBitmap(ImageBitmapSource image, optional ImageBitmapOptions options); Promise createImageBitmap(ImageBitmapSource image, long sx, long sy, long sw, long sh, optional ImageBitmapOptions options); }; -Window implements WindowOrWorkerGlobalScope; -WorkerGlobalScope implements WindowOrWorkerGlobalScope; +Window includes WindowOrWorkerGlobalScope; +WorkerGlobalScope includes WindowOrWorkerGlobalScope; [Exposed=Window] interface Navigator { // objects implementing this interface also implement the interfaces given below }; -Navigator implements NavigatorID; -Navigator implements NavigatorLanguage; -Navigator implements NavigatorOnLine; -Navigator implements NavigatorContentUtils; -Navigator implements NavigatorCookies; -Navigator implements NavigatorPlugins; -Navigator implements NavigatorConcurrentHardware; +Navigator includes NavigatorID; +Navigator includes NavigatorLanguage; +Navigator includes NavigatorOnLine; +Navigator includes NavigatorContentUtils; +Navigator includes NavigatorCookies; +Navigator includes NavigatorPlugins; +Navigator includes NavigatorConcurrentHardware; -[NoInterfaceObject, Exposed=(Window,Worker)] -interface NavigatorID { +interface mixin NavigatorID { readonly attribute DOMString appCodeName; // constant "Mozilla" readonly attribute DOMString appName; // constant "Netscape" readonly attribute DOMString appVersion; @@ -1888,28 +1856,21 @@ partial interface NavigatorID { [Exposed=Window] readonly attribute DOMString oscpu; }; -[NoInterfaceObject, Exposed=(Window,Worker)] -interface NavigatorLanguage { +interface mixin NavigatorLanguage { readonly attribute DOMString language; readonly attribute FrozenArray languages; }; -[Exposed=Window, - NoInterfaceObject] -interface NavigatorContentUtils { +interface mixin NavigatorContentUtils { void registerProtocolHandler(DOMString scheme, USVString url, DOMString title); void unregisterProtocolHandler(DOMString scheme, USVString url); }; -[Exposed=Window, - NoInterfaceObject] -interface NavigatorCookies { +interface mixin NavigatorCookies { readonly attribute boolean cookieEnabled; }; -[Exposed=Window, - NoInterfaceObject] -interface NavigatorPlugins { +interface mixin NavigatorPlugins { [SameObject] readonly attribute PluginArray plugins; [SameObject] readonly attribute MimeTypeArray mimeTypes; boolean javaEnabled(); @@ -2124,8 +2085,7 @@ interface SharedWorkerGlobalScope : WorkerGlobalScope { attribute EventHandler onconnect; }; -[NoInterfaceObject, Exposed=(Window,Worker)] -interface AbstractWorker { +interface mixin AbstractWorker { attribute EventHandler onerror; }; @@ -2146,26 +2106,25 @@ dictionary WorkerOptions { enum WorkerType { "classic", "module" }; -Worker implements AbstractWorker; +Worker includes AbstractWorker; [Constructor(USVString scriptURL, optional (DOMString or WorkerOptions) options), Exposed=(Window,Worker)] interface SharedWorker : EventTarget { readonly attribute MessagePort port; }; -SharedWorker implements AbstractWorker; +SharedWorker includes AbstractWorker; -[NoInterfaceObject, Exposed=(Window,Worker)] -interface NavigatorConcurrentHardware { +interface mixin NavigatorConcurrentHardware { readonly attribute unsigned long long hardwareConcurrency; }; [Exposed=Worker] interface WorkerNavigator {}; -WorkerNavigator implements NavigatorID; -WorkerNavigator implements NavigatorLanguage; -WorkerNavigator implements NavigatorOnLine; -WorkerNavigator implements NavigatorConcurrentHardware; +WorkerNavigator includes NavigatorID; +WorkerNavigator includes NavigatorLanguage; +WorkerNavigator includes NavigatorOnLine; +WorkerNavigator includes NavigatorConcurrentHardware; [Exposed=Worker] interface WorkerLocation { @@ -2190,19 +2149,15 @@ interface Storage { void clear(); }; -[Exposed=Window, - NoInterfaceObject] -interface WindowSessionStorage { +interface mixin WindowSessionStorage { readonly attribute Storage sessionStorage; }; -Window implements WindowSessionStorage; +Window includes WindowSessionStorage; -[Exposed=Window, - NoInterfaceObject] -interface WindowLocalStorage { +interface mixin WindowLocalStorage { readonly attribute Storage localStorage; }; -Window implements WindowLocalStorage; +Window includes WindowLocalStorage; [Exposed=Window, Constructor(DOMString type, optional StorageEventInit eventInitDict)] @@ -2251,7 +2206,7 @@ interface HTMLFrameSetElement : HTMLElement { [CEReactions] attribute DOMString cols; [CEReactions] attribute DOMString rows; }; -HTMLFrameSetElement implements WindowEventHandlers; +HTMLFrameSetElement includes WindowEventHandlers; [Exposed=Window, HTMLConstructor] diff --git a/tests/wpt/web-platform-tests/interfaces/webrtc-pc.idl b/tests/wpt/web-platform-tests/interfaces/webrtc-pc.idl index ae20055920b..d33562b642f 100644 --- a/tests/wpt/web-platform-tests/interfaces/webrtc-pc.idl +++ b/tests/wpt/web-platform-tests/interfaces/webrtc-pc.idl @@ -507,7 +507,7 @@ partial interface RTCPeerConnection { interface RTCSctpTransport { readonly attribute RTCDtlsTransport transport; - readonly attribute unsigned long maxMessageSize; + readonly attribute unrestricted double maxMessageSize; }; interface RTCDataChannel : EventTarget { diff --git a/tests/wpt/web-platform-tests/lint.whitelist b/tests/wpt/web-platform-tests/lint.whitelist index 3af7264598f..66e3a0e578b 100644 --- a/tests/wpt/web-platform-tests/lint.whitelist +++ b/tests/wpt/web-platform-tests/lint.whitelist @@ -18,7 +18,6 @@ INDENT TABS: pointerlock/* INDENT TABS: shadow-dom/* INDENT TABS: svg/import/* INDENT TABS: tools/* -INDENT TABS: touch-events/* INDENT TABS: web-animations/* INDENT TABS: webaudio/* INDENT TABS: webvtt/* @@ -70,17 +69,20 @@ TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.wasm ## Documentation ## -W3C-TEST.ORG:README.md -W3C-TEST.ORG:*/README.md -W3C-TEST.ORG:docs/* +W3C-TEST.ORG: README.md +W3C-TEST.ORG: */README.md +W3C-TEST.ORG: docs/* SET TIMEOUT: docs/* +WEB-PLATFORM.TEST:README.md +WEB-PLATFORM.TEST:*/README.md +WEB-PLATFORM.TEST:docs/* ## Helper scripts ## -W3C-TEST.ORG:tools/* -PRINT STATEMENT:tools/* -W3C-TEST.ORG:*/tools/* -PRINT STATEMENT:*/tools/* +W3C-TEST.ORG: tools/* +PRINT STATEMENT: tools/* +W3C-TEST.ORG: */tools/* +PRINT STATEMENT: */tools/* ## Deliberate copies of Ahem ## # The allowed copy @@ -92,42 +94,49 @@ AHEM COPY: css/fonts/ahem-extra/AHEM_*.TTF # https://github.com/w3c/web-platform-tests/issues/7437 AHEM COPY: css/vendor-imports/mozilla/mozilla-central-reftests/*/Ahem.ttf -### Test exclusions ## +## Test exclusions ## -CR AT EOL:WebIDL/valid/idl/documentation-dos.widl -CR AT EOL:cors/resources/cors-headers.asis -CR AT EOL:html/semantics/embedded-content/the-canvas-element/size.attributes.parse.whitespace.html -INDENT TABS:html/semantics/embedded-content/the-canvas-element/size.attributes.parse.whitespace.html -CR AT EOL:webvtt/parsing/file-parsing/tests/support/newlines.vtt -PARSE-FAILED:dom/nodes/Document-createElement-namespace-tests/empty.svg -PARSE-FAILED:dom/nodes/Document-createElement-namespace-tests/empty.xhtml -PARSE-FAILED:dom/nodes/Document-createElement-namespace-tests/minimal_html.svg -PARSE-FAILED:dom/nodes/Document-createElement-namespace-tests/minimal_html.xhtml +# Intentional use of CRLF +CR AT EOL: WebIDL/valid/idl/documentation-dos.widl +CR AT EOL: cors/resources/cors-headers.asis +CR AT EOL: html/form-elements/the-textarea-element/multiline-placeholder-cr.html +CR AT EOL: html/form-elements/the-textarea-element/multiline-placeholder-crlf.html +CR AT EOL: html/input/the-placeholder-attribute/multiline-cr.html +CR AT EOL: html/input/the-placeholder-attribute/multiline-crlf.html +CR AT EOL: html/semantics/embedded-content/the-canvas-element/size.attributes.parse.whitespace.html +CR AT EOL: webvtt/parsing/file-parsing/tests/support/newlines.vtt + +# Intentional use of tabs +INDENT TABS: html/semantics/embedded-content/the-canvas-element/size.attributes.parse.whitespace.html # Test generation files containing print statements -PRINT STATEMENT:dom/nodes/Document-createElement-namespace-tests/generate.py -PRINT STATEMENT:encrypted-media/polyfill/make-polyfill-tests.py +PRINT STATEMENT: dom/nodes/Document-createElement-namespace-tests/generate.py +PRINT STATEMENT: encrypted-media/polyfill/make-polyfill-tests.py # semi-legitimate use of console.* -CONSOLE:console/* -CONSOLE:streams/resources/test-utils.js -CONSOLE:service-workers/service-worker/resources/navigation-redirect-other-origin.html -CONSOLE:service-workers/service-worker/navigation-redirect.https.html -CONSOLE:service-workers/service-worker/resources/clients-get-other-origin.html +CONSOLE: console/* +CONSOLE: resources/check-layout-th.js +CONSOLE: resources/chromium/* +CONSOLE: resources/idlharness.js +CONSOLE: streams/resources/test-utils.js +CONSOLE: service-workers/service-worker/resources/navigation-redirect-other-origin.html +CONSOLE: service-workers/service-worker/navigation-redirect.https.html +CONSOLE: service-workers/service-worker/resources/clients-get-other-origin.html # use of console in a public library - annotation-model ensures # it is not actually used -CONSOLE:annotation-model/scripts/ajv.min.js -CONSOLE:annotation-model/scripts/showdown.min.js +CONSOLE: annotation-model/scripts/ajv.min.js +CONSOLE: annotation-model/scripts/showdown.min.js CR AT EOL: annotation-model/scripts/showdown.min.js -# Lint doesn't know about sub.svg I guess -PARSE-FAILED:content-security-policy/svg/including.sub.svg - -#Helper files that aren't valid XML -PARSE-FAILED:dom/nodes/Document-createElement-namespace-tests/empty.xml -PARSE-FAILED:dom/nodes/Document-createElement-namespace-tests/minimal_html.xml -PARSE-FAILED:acid/acid3/empty.xml +# Helper files that aren't valid XML +PARSE-FAILED: acid/acid3/empty.xml +PARSE-FAILED: dom/nodes/Document-createElement-namespace-tests/empty.svg +PARSE-FAILED: dom/nodes/Document-createElement-namespace-tests/empty.xhtml +PARSE-FAILED: dom/nodes/Document-createElement-namespace-tests/empty.xml +PARSE-FAILED: dom/nodes/Document-createElement-namespace-tests/minimal_html.svg +PARSE-FAILED: dom/nodes/Document-createElement-namespace-tests/minimal_html.xhtml +PARSE-FAILED: dom/nodes/Document-createElement-namespace-tests/minimal_html.xml # setTimeout usage (should probably mostly be fixed) SET TIMEOUT: *-manual.* @@ -143,7 +152,6 @@ SET TIMEOUT: css/selectors/selector-placeholder-shown-type-change-002.html SET TIMEOUT: css/selectors/selector-placeholder-shown-type-change-003.html SET TIMEOUT: css/selectors/selector-read-write-type-change-002.html SET TIMEOUT: css/selectors/selector-required-type-change-002.html -SET TIMEOUT: css/css-fonts/font-display/font-display.html SET TIMEOUT: encrypted-media/polyfill/chrome-polyfill.js SET TIMEOUT: encrypted-media/polyfill/clearkey-polyfill.js SET TIMEOUT: encrypted-media/scripts/playback-temporary-events.js @@ -155,6 +163,7 @@ SET TIMEOUT: html/browsers/browsing-the-web/scroll-to-fragid/* SET TIMEOUT: html/browsers/browsing-the-web/unloading-documents/* SET TIMEOUT: html/browsers/history/the-history-interface/* SET TIMEOUT: html/browsers/history/the-location-interface/* +SET TIMEOUT: html/browsers/history/the-session-history-of-browsing-contexts/* SET TIMEOUT: html/browsers/offline/* SET TIMEOUT: html/browsers/the-window-object/* SET TIMEOUT: html/dom/dynamic-markup-insertion/opening-the-input-stream/* @@ -224,6 +233,10 @@ SET TIMEOUT: workers/* SET TIMEOUT: XMLHttpRequest/resources/init.htm SET TIMEOUT: XMLHttpRequest/resources/xmlhttprequest-timeout.js +# generate_tests implementation and sample usage +GENERATE_TESTS: resources/test/tests/generate-callback.html +GENERATE_TESTS: resources/testharness.js + # generate_tests usage (should be got rid of) GENERATE_TESTS: 2dcontext/drawing-images-to-the-canvas/* GENERATE_TESTS: css/css-shapes/shape-outside/values/* @@ -294,29 +307,42 @@ GENERATE_TESTS: shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/w GENERATE_TESTS: shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/window-named-properties-003.html # Intentional use of setTimeout -SET TIMEOUT: html/browsers/history/the-session-history-of-browsing-contexts/navigation-in-onload_form-submission-2.tentative.html +SET TIMEOUT: css/css-fonts/font-display/font-display.html +SET TIMEOUT: css/css-fonts/font-display/font-display-change.html +SET TIMEOUT: css/css-fonts/font-display/font-display-change-ref.html SET TIMEOUT: html/browsers/windows/auxiliary-browsing-contexts/resources/close-opener.html SET TIMEOUT: html/dom/documents/dom-tree-accessors/Document.currentScript.html SET TIMEOUT: html/webappapis/timers/* +SET TIMEOUT: resources/chromium/* +SET TIMEOUT: resources/test/tests/add_cleanup.html +SET TIMEOUT: resources/test/tests/api-tests-1.html +SET TIMEOUT: resources/test/tests/worker.js +SET TIMEOUT: resources/testharness.js # setTimeout use in reftests SET TIMEOUT: acid/acid3/test.html # Travis -W3C-TEST.ORG:.travis.yml +W3C-TEST.ORG: .travis.yml +WEB-PLATFORM.TEST: .travis.yml -# Git submodules are not currently scanned -*:tools/* -*:resources/* -*:css/tools/apiclient/* -*:css/tools/w3ctestlib/* +# Config +WEB-PLATFORM.TEST: config.default.json +WEB-PLATFORM.TEST: resources/test/config.test.json + +# Third party code +*: css/tools/apiclient/* +*: css/tools/w3ctestlib/* +*: resources/webidl2/* +*: tools/* # Build system virtualenv -*:css/tools/_virtualenv/* +*: css/tools/_virtualenv/* ## Third party data files TRAILING WHITESPACE: css/css-writing-modes/tools/generators/ucd/Blocks.txt +TRAILING WHITESPACE: resources/chromium/* ## Test generation files @@ -447,14 +473,6 @@ CONSOLE: css/cssom/index-002.html TRAILING WHITESPACE: css/CSS2/generated-content/before-after-positioned-002.html TRAILING WHITESPACE: css/CSS2/generated-content/before-after-positioned-003.html TRAILING WHITESPACE: css/CSS2/generated-content/before-after-positioned-004.html -TRAILING WHITESPACE: css/css-color/lab-004.html -TRAILING WHITESPACE: css/css-color/lab-005.html -TRAILING WHITESPACE: css/css-color/lab-006.html -TRAILING WHITESPACE: css/css-color/lab-007.html -TRAILING WHITESPACE: css/css-color/lch-004.html -TRAILING WHITESPACE: css/css-color/lch-005.html -TRAILING WHITESPACE: css/css-color/lch-006.html -TRAILING WHITESPACE: css/css-color/lch-007.html TRAILING WHITESPACE: css/css-fonts/support/fonts/gsubtest-lookup3.ufo/features.fea TRAILING WHITESPACE: css/css-scoping/css-scoping-shadow-assigned-node-with-before-after.html TRAILING WHITESPACE: css/css-scoping/css-scoping-shadow-assigned-node-with-rules.html @@ -925,18 +943,38 @@ MISSING-LINK: css/cssom-view/scrolling-quirks-vs-nonquirks.html MISSING-LINK: css/cssom-view/scrollingElement.html MISSING-LINK: css/cssom-view/scrollIntoView-shadow.html MISSING-LINK: css/cssom-view/scrollIntoView-smooth.html +MISSING-LINK: css/cssom-view/scrollTop-display-change.html CSS-COLLIDING-TEST-NAME: css/cssom-view/interfaces.html CSS-COLLIDING-TEST-NAME: css/cssom/interfaces.html # TODO https://github.com/w3c/web-platform-tests/issues/5770 MISSING-LINK: css/geometry/*.worker.js -WEBIDL2.JS:.gitmodules +WEBIDL2.JS: .gitmodules # Manual test that uses console.logs for feedback -CONSOLE:payment-request/payment-request-response-id.html +CONSOLE: payment-request/payment-request-response-id.html # Tests that use WebKit/Blink testing APIs LAYOUTTESTS APIS: css/css-regions/interactivity/* -# Test that uses the same names as the WebKit/Blink testing APIs -LAYOUTTESTS APIS: html/browsers/history/the-session-history-of-browsing-contexts/navigation-in-onload_form-submission-2.tentative.html \ No newline at end of file + +# Existing use of WEB-PLATFORM.TEST +WEB-PLATFORM.TEST: clear-site-data/support/test_utils.sub.js +WEB-PLATFORM.TEST: content-security-policy/base-uri/report-uri-does-not-respect-base-uri.sub.html +WEB-PLATFORM.TEST: content-security-policy/generic/generic-0_8.sub.html +WEB-PLATFORM.TEST: content-security-policy/generic/generic-0_8_1.sub.html +WEB-PLATFORM.TEST: content-security-policy/nonce-hiding/script-nonces-hidden-meta.tentative.html +WEB-PLATFORM.TEST: content-security-policy/nonce-hiding/svgscript-nonces-hidden-meta.tentative.html +WEB-PLATFORM.TEST: fetch/api/request/request-structure.html +WEB-PLATFORM.TEST: html/browsers/origin/relaxing-the-same-origin-restriction/document_domain_setter.html +WEB-PLATFORM.TEST: html/semantics/embedded-content/the-iframe-element/cross_origin_parentage.html +WEB-PLATFORM.TEST: html/semantics/forms/the-label-element/label-attributes.html +WEB-PLATFORM.TEST: longtask-timing/longtask-in-childiframe-crossorigin.html +WEB-PLATFORM.TEST: longtask-timing/longtask-in-sibling-iframe-crossorigin.html +WEB-PLATFORM.TEST: navigation-timing/nav2_test_attributes_values.html +WEB-PLATFORM.TEST: navigation-timing/nav2_test_instance_accessors.html +WEB-PLATFORM.TEST: service-workers/service-worker/update-bytecheck.https.html +WEB-PLATFORM.TEST: webdriver/tests/cookies/add_cookie.py +WEB-PLATFORM.TEST: webdriver/tests/cookies/get_named_cookie.py +WEB-PLATFORM.TEST: webrtc/RTCPeerConnection-getIdentityAssertion.html +WEB-PLATFORM.TEST: webrtc/identity-helper.js diff --git a/tests/wpt/web-platform-tests/longtask-timing/longtask-in-childiframe-crossorigin.html b/tests/wpt/web-platform-tests/longtask-timing/longtask-in-childiframe-crossorigin.html index 4ad9a740efc..2fa0f780cf6 100644 --- a/tests/wpt/web-platform-tests/longtask-timing/longtask-in-childiframe-crossorigin.html +++ b/tests/wpt/web-platform-tests/longtask-timing/longtask-in-childiframe-crossorigin.html @@ -35,7 +35,7 @@ assert_equals(attribution.containerId, 'child-iframe-id'); assert_equals(attribution.containerName, 'child-iframe-name'); assert_equals(attribution.containerSrc, - 'http://www1.web-platform.test:8000/longtask-timing/resources/subframe-with-longtask.html'); + 'resources/subframe-with-longtask.html'); observer.disconnect(); t.done(); }) @@ -44,10 +44,11 @@ const iframe = document.createElement('iframe'); iframe.id = 'child-iframe-id'; iframe.name = 'child-iframe-name'; + // Simulate cross-origin by using sandbox. + iframe.sandbox = "allow-scripts"; document.body.appendChild(iframe); - // TODO(panicker): simulate cross-origin instead - iframe.src = 'http://www1.web-platform.test:8000/longtask-timing/resources/subframe-with-longtask.html'; -}, 'Performance longtask entries in child iframe are observable in parent.'); + iframe.src = 'resources/subframe-with-longtask.html'; +}, 'Performance longtask entries in cross-origin child iframe are observable in parent.'); diff --git a/tests/wpt/web-platform-tests/longtask-timing/longtask-in-parentiframe.html b/tests/wpt/web-platform-tests/longtask-timing/longtask-in-parentiframe.html index 71f309a30e0..be29b6c3287 100644 --- a/tests/wpt/web-platform-tests/longtask-timing/longtask-in-parentiframe.html +++ b/tests/wpt/web-platform-tests/longtask-timing/longtask-in-parentiframe.html @@ -9,7 +9,12 @@ - - - - - diff --git a/tests/wpt/web-platform-tests/longtask-timing/longtask-in-sibling-iframe.html b/tests/wpt/web-platform-tests/longtask-timing/longtask-in-sibling-iframe.html index 9f536218884..d463810964b 100644 --- a/tests/wpt/web-platform-tests/longtask-timing/longtask-in-sibling-iframe.html +++ b/tests/wpt/web-platform-tests/longtask-timing/longtask-in-sibling-iframe.html @@ -9,21 +9,25 @@ + const observingFrame = document.createElement('iframe'); + observingFrame.id = 'observing-iframe-id'; + observingFrame.name = 'observing-iframe-name'; + document.body.appendChild(observingFrame); + observingFrame.src = 'resources/subframe-observing-longtask.html' - - - diff --git a/tests/wpt/web-platform-tests/longtask-timing/longtask-tojson.html b/tests/wpt/web-platform-tests/longtask-timing/longtask-tojson.html new file mode 100644 index 00000000000..bbe0d662c42 --- /dev/null +++ b/tests/wpt/web-platform-tests/longtask-timing/longtask-tojson.html @@ -0,0 +1,71 @@ + + + + + + + + + + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/longtask-timing/resources/subframe-observing-longtask.html b/tests/wpt/web-platform-tests/longtask-timing/resources/subframe-observing-longtask.html index e1e1a934527..b232ecdd47a 100644 --- a/tests/wpt/web-platform-tests/longtask-timing/resources/subframe-observing-longtask.html +++ b/tests/wpt/web-platform-tests/longtask-timing/resources/subframe-observing-longtask.html @@ -15,9 +15,14 @@ return; // TODO(panicker): include containerType. const attribution = longtask.attribution[0]; - const entryContents = longtask.entryType + '+' + longtask.name + '+' + - attribution.name + '+' + attribution.containerId + '+' + - attribution.containerName + '+' + attribution.containerSrc; + const entryContents = { + 'entryType': longtask.entryType, + 'frame-attribution': longtask.name, + 'task-attribution': attribution.name, + 'containerId': attribution.containerId, + 'containerName': attribution.containerName, + 'containerSrc': attribution.containerSrc + }; top.postMessage(entryContents, '*'); } }); diff --git a/tests/wpt/web-platform-tests/magnetometer/Magnetometer-disabled-by-feature-policy.https.html b/tests/wpt/web-platform-tests/magnetometer/Magnetometer-disabled-by-feature-policy.https.html new file mode 100644 index 00000000000..f24b2b35646 --- /dev/null +++ b/tests/wpt/web-platform-tests/magnetometer/Magnetometer-disabled-by-feature-policy.https.html @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/tests/wpt/web-platform-tests/magnetometer/Magnetometer-disabled-by-feature-policy.https.html.headers b/tests/wpt/web-platform-tests/magnetometer/Magnetometer-disabled-by-feature-policy.https.html.headers new file mode 100644 index 00000000000..afbd45465cf --- /dev/null +++ b/tests/wpt/web-platform-tests/magnetometer/Magnetometer-disabled-by-feature-policy.https.html.headers @@ -0,0 +1 @@ +Feature-Policy: magnetometer 'none' diff --git a/tests/wpt/web-platform-tests/magnetometer/Magnetometer-enabled-by-feature-policy-attribute-redirect-on-load.https.html b/tests/wpt/web-platform-tests/magnetometer/Magnetometer-enabled-by-feature-policy-attribute-redirect-on-load.https.html new file mode 100644 index 00000000000..08369810f5f --- /dev/null +++ b/tests/wpt/web-platform-tests/magnetometer/Magnetometer-enabled-by-feature-policy-attribute-redirect-on-load.https.html @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/tests/wpt/web-platform-tests/magnetometer/Magnetometer-enabled-by-feature-policy-attribute.https.html b/tests/wpt/web-platform-tests/magnetometer/Magnetometer-enabled-by-feature-policy-attribute.https.html new file mode 100644 index 00000000000..0086222cbc7 --- /dev/null +++ b/tests/wpt/web-platform-tests/magnetometer/Magnetometer-enabled-by-feature-policy-attribute.https.html @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/tests/wpt/web-platform-tests/magnetometer/Magnetometer-enabled-by-feature-policy.https.html b/tests/wpt/web-platform-tests/magnetometer/Magnetometer-enabled-by-feature-policy.https.html new file mode 100644 index 00000000000..7f8ce1a9675 --- /dev/null +++ b/tests/wpt/web-platform-tests/magnetometer/Magnetometer-enabled-by-feature-policy.https.html @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/tests/wpt/web-platform-tests/magnetometer/Magnetometer-enabled-by-feature-policy.https.html.headers b/tests/wpt/web-platform-tests/magnetometer/Magnetometer-enabled-by-feature-policy.https.html.headers new file mode 100644 index 00000000000..64ec55e3e40 --- /dev/null +++ b/tests/wpt/web-platform-tests/magnetometer/Magnetometer-enabled-by-feature-policy.https.html.headers @@ -0,0 +1 @@ +Feature-Policy: magnetometer * diff --git a/tests/wpt/web-platform-tests/magnetometer/Magnetometer-enabled-on-self-origin-by-feature-policy.https.html b/tests/wpt/web-platform-tests/magnetometer/Magnetometer-enabled-on-self-origin-by-feature-policy.https.html new file mode 100644 index 00000000000..a967576eafc --- /dev/null +++ b/tests/wpt/web-platform-tests/magnetometer/Magnetometer-enabled-on-self-origin-by-feature-policy.https.html @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/tests/wpt/web-platform-tests/magnetometer/Magnetometer-enabled-on-self-origin-by-feature-policy.https.html.headers b/tests/wpt/web-platform-tests/magnetometer/Magnetometer-enabled-on-self-origin-by-feature-policy.https.html.headers new file mode 100644 index 00000000000..4223f53ffa3 --- /dev/null +++ b/tests/wpt/web-platform-tests/magnetometer/Magnetometer-enabled-on-self-origin-by-feature-policy.https.html.headers @@ -0,0 +1 @@ +Feature-Policy: magnetometer 'self' diff --git a/tests/wpt/web-platform-tests/magnetometer/Magnetometer.https.html b/tests/wpt/web-platform-tests/magnetometer/Magnetometer.https.html index f327ed3c43d..a3cefc26169 100644 --- a/tests/wpt/web-platform-tests/magnetometer/Magnetometer.https.html +++ b/tests/wpt/web-platform-tests/magnetometer/Magnetometer.https.html @@ -10,5 +10,6 @@ diff --git a/tests/wpt/web-platform-tests/magnetometer/Magnetometer_insecure_context.html b/tests/wpt/web-platform-tests/magnetometer/Magnetometer_insecure_context.html index 307c19b101b..45ff584b425 100644 --- a/tests/wpt/web-platform-tests/magnetometer/Magnetometer_insecure_context.html +++ b/tests/wpt/web-platform-tests/magnetometer/Magnetometer_insecure_context.html @@ -16,5 +16,6 @@ diff --git a/tests/wpt/web-platform-tests/magnetometer/Magnetometer_onerror-manual.https.html b/tests/wpt/web-platform-tests/magnetometer/Magnetometer_onerror-manual.https.html index 3cd62db8a22..04b987797fa 100644 --- a/tests/wpt/web-platform-tests/magnetometer/Magnetometer_onerror-manual.https.html +++ b/tests/wpt/web-platform-tests/magnetometer/Magnetometer_onerror-manual.https.html @@ -16,5 +16,6 @@ diff --git a/tests/wpt/web-platform-tests/mathml/relations/css-styling/mathvariant-bold-fraktur-ref.html b/tests/wpt/web-platform-tests/mathml/relations/css-styling/mathvariant-bold-fraktur-ref.html index 0007e012deb..b883b12b57d 100644 --- a/tests/wpt/web-platform-tests/mathml/relations/css-styling/mathvariant-bold-fraktur-ref.html +++ b/tests/wpt/web-platform-tests/mathml/relations/css-styling/mathvariant-bold-fraktur-ref.html @@ -23,57 +23,57 @@

Test passes if all the equalities below are true.

- 𝕬=1D56C - 𝕭=1D56D - 𝕮=1D56E - 𝕯=1D56F - 𝕰=1D570 - 𝕱=1D571 - 𝕲=1D572 - 𝕳=1D573 - 𝕴=1D574 - 𝕵=1D575
- 𝕶=1D576 - 𝕷=1D577 - 𝕸=1D578 - 𝕹=1D579 - 𝕺=1D57A - 𝕻=1D57B - 𝕼=1D57C - 𝕽=1D57D - 𝕾=1D57E - 𝕿=1D57F
- 𝖀=1D580 - 𝖁=1D581 - 𝖂=1D582 - 𝖃=1D583 - 𝖄=1D584 - 𝖅=1D585 - 𝖆=1D586 - 𝖇=1D587 - 𝖈=1D588 - 𝖉=1D589
- 𝖊=1D58A - 𝖋=1D58B - 𝖌=1D58C - 𝖍=1D58D - 𝖎=1D58E - 𝖏=1D58F - 𝖐=1D590 - 𝖑=1D591 - 𝖒=1D592 - 𝖓=1D593
- 𝖔=1D594 - 𝖕=1D595 - 𝖖=1D596 - 𝖗=1D597 - 𝖘=1D598 - 𝖙=1D599 - 𝖚=1D59A - 𝖛=1D59B - 𝖜=1D59C - 𝖝=1D59D
- 𝖞=1D59E - 𝖟=1D59F + 𝕬=1D56C + 𝕭=1D56D + 𝕮=1D56E + 𝕯=1D56F + 𝕰=1D570 + 𝕱=1D571 + 𝕲=1D572 + 𝕳=1D573 + 𝕴=1D574 + 𝕵=1D575
+ 𝕶=1D576 + 𝕷=1D577 + 𝕸=1D578 + 𝕹=1D579 + 𝕺=1D57A + 𝕻=1D57B + 𝕼=1D57C + 𝕽=1D57D + 𝕾=1D57E + 𝕿=1D57F
+ 𝖀=1D580 + 𝖁=1D581 + 𝖂=1D582 + 𝖃=1D583 + 𝖄=1D584 + 𝖅=1D585 + 𝖆=1D586 + 𝖇=1D587 + 𝖈=1D588 + 𝖉=1D589
+ 𝖊=1D58A + 𝖋=1D58B + 𝖌=1D58C + 𝖍=1D58D + 𝖎=1D58E + 𝖏=1D58F + 𝖐=1D590 + 𝖑=1D591 + 𝖒=1D592 + 𝖓=1D593
+ 𝖔=1D594 + 𝖕=1D595 + 𝖖=1D596 + 𝖗=1D597 + 𝖘=1D598 + 𝖙=1D599 + 𝖚=1D59A + 𝖛=1D59B + 𝖜=1D59C + 𝖝=1D59D
+ 𝖞=1D59E + 𝖟=1D59F diff --git a/tests/wpt/web-platform-tests/mathml/relations/css-styling/mathvariant-bold-fraktur.html b/tests/wpt/web-platform-tests/mathml/relations/css-styling/mathvariant-bold-fraktur.html index 5182df883d6..487d61d7d85 100644 --- a/tests/wpt/web-platform-tests/mathml/relations/css-styling/mathvariant-bold-fraktur.html +++ b/tests/wpt/web-platform-tests/mathml/relations/css-styling/mathvariant-bold-fraktur.html @@ -5,7 +5,7 @@ mathvariant bold-fraktur - + + + + + + + + + diff --git a/tests/wpt/web-platform-tests/svg/foreignobject/position-svg-root-in-foreign-object-ref.html b/tests/wpt/web-platform-tests/svg/foreignobject/position-svg-root-in-foreign-object-ref.html new file mode 100644 index 00000000000..668eb9b8c7e --- /dev/null +++ b/tests/wpt/web-platform-tests/svg/foreignobject/position-svg-root-in-foreign-object-ref.html @@ -0,0 +1,6 @@ + + +SVG Reftest Reference + +

You should see the word PASS and no red below.

+PASS diff --git a/tests/wpt/web-platform-tests/svg/foreignobject/position-svg-root-in-foreign-object.html b/tests/wpt/web-platform-tests/svg/foreignobject/position-svg-root-in-foreign-object.html new file mode 100644 index 00000000000..5bf38226627 --- /dev/null +++ b/tests/wpt/web-platform-tests/svg/foreignobject/position-svg-root-in-foreign-object.html @@ -0,0 +1,13 @@ + + +SVG: svg root child of foreignObject should be positionable + + + +

You should see the word PASS and no red below.

+ + + PASS + + + diff --git a/tests/wpt/web-platform-tests/svg/import/animate-elem-33-t-manual.svg b/tests/wpt/web-platform-tests/svg/import/animate-elem-33-t-manual.svg index 4b50ae3d564..292201d5c32 100644 --- a/tests/wpt/web-platform-tests/svg/import/animate-elem-33-t-manual.svg +++ b/tests/wpt/web-platform-tests/svg/import/animate-elem-33-t-manual.svg @@ -86,7 +86,7 @@ - caught exception --> frame stack raising - the exception --> current frame stack --> local variables --> - ``ExceptionInfo``) which makes Python keep all objects referenced - from that cycle (including all local variables in the current - frame) alive until the next cyclic garbage collection run. See the - official Python ``try`` statement documentation for more detailed - information. - - """ - __tracebackhide__ = True - if expected_exception is AssertionError: - # we want to catch a AssertionError - # replace our subclass with the builtin one - # see https://github.com/pytest-dev/pytest/issues/176 - from _pytest.assertion.util import BuiltinAssertionError \ - as expected_exception - msg = ("exceptions must be old-style classes or" - " derived from BaseException, not %s") - if isinstance(expected_exception, tuple): - for exc in expected_exception: - if not isclass(exc): - raise TypeError(msg % type(exc)) - elif not isclass(expected_exception): - raise TypeError(msg % type(expected_exception)) - - if not args: - return RaisesContext(expected_exception) - elif isinstance(args[0], str): - code, = args - assert isinstance(code, str) - frame = sys._getframe(1) - loc = frame.f_locals.copy() - loc.update(kwargs) - #print "raises frame scope: %r" % frame.f_locals - try: - code = _pytest._code.Source(code).compile() - py.builtin.exec_(code, frame.f_globals, loc) - # XXX didn'T mean f_globals == f_locals something special? - # this is destroyed here ... - except expected_exception: - return _pytest._code.ExceptionInfo() - else: - func = args[0] - try: - func(*args[1:], **kwargs) - except expected_exception: - return _pytest._code.ExceptionInfo() - pytest.fail("DID NOT RAISE {0}".format(expected_exception)) - -class RaisesContext(object): - def __init__(self, expected_exception): - self.expected_exception = expected_exception - self.excinfo = None - - def __enter__(self): - self.excinfo = object.__new__(_pytest._code.ExceptionInfo) - return self.excinfo - - def __exit__(self, *tp): - __tracebackhide__ = True - if tp[0] is None: - pytest.fail("DID NOT RAISE") - if sys.version_info < (2, 7): - # py26: on __exit__() exc_value often does not contain the - # exception value. - # http://bugs.python.org/issue7853 - if not isinstance(tp[1], BaseException): - exc_type, value, traceback = tp - tp = exc_type, exc_type(value), traceback - self.excinfo.__init__(tp) - return issubclass(self.excinfo.type, self.expected_exception) - -# -# the basic pytest Function item -# - -class Function(FunctionMixin, pytest.Item, FuncargnamesCompatAttr): - """ a Function Item is responsible for setting up and executing a - Python test function. - """ - _genid = None - def __init__(self, name, parent, args=None, config=None, - callspec=None, callobj=NOTSET, keywords=None, session=None, - fixtureinfo=None): - super(Function, self).__init__(name, parent, config=config, - session=session) - self._args = args - if callobj is not NOTSET: - self.obj = callobj - - self.keywords.update(self.obj.__dict__) - if callspec: - self.callspec = callspec - self.keywords.update(callspec.keywords) - if keywords: - self.keywords.update(keywords) - - if fixtureinfo is None: - fixtureinfo = self.session._fixturemanager.getfixtureinfo( - self.parent, self.obj, self.cls, - funcargs=not self._isyieldedfunction()) - self._fixtureinfo = fixtureinfo - self.fixturenames = fixtureinfo.names_closure - self._initrequest() - - def _initrequest(self): - self.funcargs = {} - if self._isyieldedfunction(): - assert not hasattr(self, "callspec"), ( - "yielded functions (deprecated) cannot have funcargs") - else: - if hasattr(self, "callspec"): - callspec = self.callspec - assert not callspec.funcargs - self._genid = callspec.id - if hasattr(callspec, "param"): - self.param = callspec.param - self._request = FixtureRequest(self) - - @property - def function(self): - "underlying python 'function' object" - return getattr(self.obj, 'im_func', self.obj) - - def _getobj(self): - name = self.name - i = name.find("[") # parametrization - if i != -1: - name = name[:i] - return getattr(self.parent.obj, name) - - @property - def _pyfuncitem(self): - "(compatonly) for code expecting pytest-2.2 style request objects" - return self - - def _isyieldedfunction(self): - return getattr(self, "_args", None) is not None - - def runtest(self): - """ execute the underlying test function. """ - self.ihook.pytest_pyfunc_call(pyfuncitem=self) - - def setup(self): - # check if parametrization happend with an empty list - try: - self.callspec._emptyparamspecified - except AttributeError: - pass - else: - fs, lineno = self._getfslineno() - pytest.skip("got empty parameter set, function %s at %s:%d" %( - self.function.__name__, fs, lineno)) - super(Function, self).setup() - fillfixtures(self) - - -scope2props = dict(session=()) -scope2props["module"] = ("fspath", "module") -scope2props["class"] = scope2props["module"] + ("cls",) -scope2props["instance"] = scope2props["class"] + ("instance", ) -scope2props["function"] = scope2props["instance"] + ("function", "keywords") - -def scopeproperty(name=None, doc=None): - def decoratescope(func): - scopename = name or func.__name__ - def provide(self): - if func.__name__ in scope2props[self.scope]: - return func(self) - raise AttributeError("%s not available in %s-scoped context" % ( - scopename, self.scope)) - return property(provide, None, None, func.__doc__) - return decoratescope - - -class FixtureRequest(FuncargnamesCompatAttr): - """ A request for a fixture from a test or fixture function. - - A request object gives access to the requesting test context - and has an optional ``param`` attribute in case - the fixture is parametrized indirectly. - """ - - def __init__(self, pyfuncitem): - self._pyfuncitem = pyfuncitem - #: fixture for which this request is being performed - self.fixturename = None - #: Scope string, one of "function", "cls", "module", "session" - self.scope = "function" - self._funcargs = {} - self._fixturedefs = {} - fixtureinfo = pyfuncitem._fixtureinfo - self._arg2fixturedefs = fixtureinfo.name2fixturedefs.copy() - self._arg2index = {} - self.fixturenames = fixtureinfo.names_closure - self._fixturemanager = pyfuncitem.session._fixturemanager - - @property - def node(self): - """ underlying collection node (depends on current request scope)""" - return self._getscopeitem(self.scope) - - - def _getnextfixturedef(self, argname): - fixturedefs = self._arg2fixturedefs.get(argname, None) - if fixturedefs is None: - # we arrive here because of a a dynamic call to - # getfuncargvalue(argname) usage which was naturally - # not known at parsing/collection time - fixturedefs = self._fixturemanager.getfixturedefs( - argname, self._pyfuncitem.parent.nodeid) - self._arg2fixturedefs[argname] = fixturedefs - # fixturedefs list is immutable so we maintain a decreasing index - index = self._arg2index.get(argname, 0) - 1 - if fixturedefs is None or (-index > len(fixturedefs)): - raise FixtureLookupError(argname, self) - self._arg2index[argname] = index - return fixturedefs[index] - - @property - def config(self): - """ the pytest config object associated with this request. """ - return self._pyfuncitem.config - - - @scopeproperty() - def function(self): - """ test function object if the request has a per-function scope. """ - return self._pyfuncitem.obj - - @scopeproperty("class") - def cls(self): - """ class (can be None) where the test function was collected. """ - clscol = self._pyfuncitem.getparent(pytest.Class) - if clscol: - return clscol.obj - - @property - def instance(self): - """ instance (can be None) on which test function was collected. """ - # unittest support hack, see _pytest.unittest.TestCaseFunction - try: - return self._pyfuncitem._testcase - except AttributeError: - function = getattr(self, "function", None) - if function is not None: - return py.builtin._getimself(function) - - @scopeproperty() - def module(self): - """ python module object where the test function was collected. """ - return self._pyfuncitem.getparent(pytest.Module).obj - - @scopeproperty() - def fspath(self): - """ the file system path of the test module which collected this test. """ - return self._pyfuncitem.fspath - - @property - def keywords(self): - """ keywords/markers dictionary for the underlying node. """ - return self.node.keywords - - @property - def session(self): - """ pytest session object. """ - return self._pyfuncitem.session - - def addfinalizer(self, finalizer): - """ add finalizer/teardown function to be called after the - last test within the requesting test context finished - execution. """ - # XXX usually this method is shadowed by fixturedef specific ones - self._addfinalizer(finalizer, scope=self.scope) - - def _addfinalizer(self, finalizer, scope): - colitem = self._getscopeitem(scope) - self._pyfuncitem.session._setupstate.addfinalizer( - finalizer=finalizer, colitem=colitem) - - def applymarker(self, marker): - """ Apply a marker to a single test function invocation. - This method is useful if you don't want to have a keyword/marker - on all function invocations. - - :arg marker: a :py:class:`_pytest.mark.MarkDecorator` object - created by a call to ``pytest.mark.NAME(...)``. - """ - try: - self.node.keywords[marker.markname] = marker - except AttributeError: - raise ValueError(marker) - - def raiseerror(self, msg): - """ raise a FixtureLookupError with the given message. """ - raise self._fixturemanager.FixtureLookupError(None, self, msg) - - def _fillfixtures(self): - item = self._pyfuncitem - fixturenames = getattr(item, "fixturenames", self.fixturenames) - for argname in fixturenames: - if argname not in item.funcargs: - item.funcargs[argname] = self.getfuncargvalue(argname) - - def cached_setup(self, setup, teardown=None, scope="module", extrakey=None): - """ (deprecated) Return a testing resource managed by ``setup`` & - ``teardown`` calls. ``scope`` and ``extrakey`` determine when the - ``teardown`` function will be called so that subsequent calls to - ``setup`` would recreate the resource. With pytest-2.3 you often - do not need ``cached_setup()`` as you can directly declare a scope - on a fixture function and register a finalizer through - ``request.addfinalizer()``. - - :arg teardown: function receiving a previously setup resource. - :arg setup: a no-argument function creating a resource. - :arg scope: a string value out of ``function``, ``class``, ``module`` - or ``session`` indicating the caching lifecycle of the resource. - :arg extrakey: added to internal caching key of (funcargname, scope). - """ - if not hasattr(self.config, '_setupcache'): - self.config._setupcache = {} # XXX weakref? - cachekey = (self.fixturename, self._getscopeitem(scope), extrakey) - cache = self.config._setupcache - try: - val = cache[cachekey] - except KeyError: - self._check_scope(self.fixturename, self.scope, scope) - val = setup() - cache[cachekey] = val - if teardown is not None: - def finalizer(): - del cache[cachekey] - teardown(val) - self._addfinalizer(finalizer, scope=scope) - return val - - def getfuncargvalue(self, argname): - """ Dynamically retrieve a named fixture function argument. - - As of pytest-2.3, it is easier and usually better to access other - fixture values by stating it as an input argument in the fixture - function. If you only can decide about using another fixture at test - setup time, you may use this function to retrieve it inside a fixture - function body. - """ - return self._get_active_fixturedef(argname).cached_result[0] - - def _get_active_fixturedef(self, argname): - try: - return self._fixturedefs[argname] - except KeyError: - try: - fixturedef = self._getnextfixturedef(argname) - except FixtureLookupError: - if argname == "request": - class PseudoFixtureDef: - cached_result = (self, [0], None) - scope = "function" - return PseudoFixtureDef - raise - # remove indent to prevent the python3 exception - # from leaking into the call - result = self._getfuncargvalue(fixturedef) - self._funcargs[argname] = result - self._fixturedefs[argname] = fixturedef - return fixturedef - - def _get_fixturestack(self): - current = self - l = [] - while 1: - fixturedef = getattr(current, "_fixturedef", None) - if fixturedef is None: - l.reverse() - return l - l.append(fixturedef) - current = current._parent_request - - def _getfuncargvalue(self, fixturedef): - # prepare a subrequest object before calling fixture function - # (latter managed by fixturedef) - argname = fixturedef.argname - funcitem = self._pyfuncitem - scope = fixturedef.scope - try: - param = funcitem.callspec.getparam(argname) - except (AttributeError, ValueError): - param = NOTSET - param_index = 0 - else: - # indices might not be set if old-style metafunc.addcall() was used - param_index = funcitem.callspec.indices.get(argname, 0) - # if a parametrize invocation set a scope it will override - # the static scope defined with the fixture function - paramscopenum = funcitem.callspec._arg2scopenum.get(argname) - if paramscopenum is not None: - scope = scopes[paramscopenum] - - subrequest = SubRequest(self, scope, param, param_index, fixturedef) - - # check if a higher-level scoped fixture accesses a lower level one - subrequest._check_scope(argname, self.scope, scope) - - # clear sys.exc_info before invoking the fixture (python bug?) - # if its not explicitly cleared it will leak into the call - exc_clear() - try: - # call the fixture function - val = fixturedef.execute(request=subrequest) - finally: - # if fixture function failed it might have registered finalizers - self.session._setupstate.addfinalizer(fixturedef.finish, - subrequest.node) - return val - - def _check_scope(self, argname, invoking_scope, requested_scope): - if argname == "request": - return - if scopemismatch(invoking_scope, requested_scope): - # try to report something helpful - lines = self._factorytraceback() - pytest.fail("ScopeMismatch: You tried to access the %r scoped " - "fixture %r with a %r scoped request object, " - "involved factories\n%s" %( - (requested_scope, argname, invoking_scope, "\n".join(lines))), - pytrace=False) - - def _factorytraceback(self): - lines = [] - for fixturedef in self._get_fixturestack(): - factory = fixturedef.func - fs, lineno = getfslineno(factory) - p = self._pyfuncitem.session.fspath.bestrelpath(fs) - args = _format_args(factory) - lines.append("%s:%d: def %s%s" %( - p, lineno, factory.__name__, args)) - return lines - - def _getscopeitem(self, scope): - if scope == "function": - # this might also be a non-function Item despite its attribute name - return self._pyfuncitem - node = get_scope_node(self._pyfuncitem, scope) - if node is None and scope == "class": - # fallback to function item itself - node = self._pyfuncitem - assert node - return node - - def __repr__(self): - return "" %(self.node) - - -class SubRequest(FixtureRequest): - """ a sub request for handling getting a fixture from a - test function/fixture. """ - def __init__(self, request, scope, param, param_index, fixturedef): - self._parent_request = request - self.fixturename = fixturedef.argname - if param is not NOTSET: - self.param = param - self.param_index = param_index - self.scope = scope - self._fixturedef = fixturedef - self.addfinalizer = fixturedef.addfinalizer - self._pyfuncitem = request._pyfuncitem - self._funcargs = request._funcargs - self._fixturedefs = request._fixturedefs - self._arg2fixturedefs = request._arg2fixturedefs - self._arg2index = request._arg2index - self.fixturenames = request.fixturenames - self._fixturemanager = request._fixturemanager - - def __repr__(self): - return "" % (self.fixturename, self._pyfuncitem) - - -class ScopeMismatchError(Exception): - """ A fixture function tries to use a different fixture function which - which has a lower scope (e.g. a Session one calls a function one) - """ - -scopes = "session module class function".split() -scopenum_function = scopes.index("function") -def scopemismatch(currentscope, newscope): - return scopes.index(newscope) > scopes.index(currentscope) - - -class FixtureLookupError(LookupError): - """ could not return a requested Fixture (missing or invalid). """ - def __init__(self, argname, request, msg=None): - self.argname = argname - self.request = request - self.fixturestack = request._get_fixturestack() - self.msg = msg - - def formatrepr(self): - tblines = [] - addline = tblines.append - stack = [self.request._pyfuncitem.obj] - stack.extend(map(lambda x: x.func, self.fixturestack)) - msg = self.msg - if msg is not None: - # the last fixture raise an error, let's present - # it at the requesting side - stack = stack[:-1] - for function in stack: - fspath, lineno = getfslineno(function) - try: - lines, _ = inspect.getsourcelines(get_real_func(function)) - except (IOError, IndexError): - error_msg = "file %s, line %s: source code not available" - addline(error_msg % (fspath, lineno+1)) - else: - addline("file %s, line %s" % (fspath, lineno+1)) - for i, line in enumerate(lines): - line = line.rstrip() - addline(" " + line) - if line.lstrip().startswith('def'): - break - - if msg is None: - fm = self.request._fixturemanager - available = [] - for name, fixturedef in fm._arg2fixturedefs.items(): - parentid = self.request._pyfuncitem.parent.nodeid - faclist = list(fm._matchfactories(fixturedef, parentid)) - if faclist: - available.append(name) - msg = "fixture %r not found" % (self.argname,) - msg += "\n available fixtures: %s" %(", ".join(available),) - msg += "\n use 'py.test --fixtures [testpath]' for help on them." - - return FixtureLookupErrorRepr(fspath, lineno, tblines, msg, self.argname) - -class FixtureLookupErrorRepr(TerminalRepr): - def __init__(self, filename, firstlineno, tblines, errorstring, argname): - self.tblines = tblines - self.errorstring = errorstring - self.filename = filename - self.firstlineno = firstlineno - self.argname = argname - - def toterminal(self, tw): - #tw.line("FixtureLookupError: %s" %(self.argname), red=True) - for tbline in self.tblines: - tw.line(tbline.rstrip()) - for line in self.errorstring.split("\n"): - tw.line(" " + line.strip(), red=True) - tw.line() - tw.line("%s:%d" % (self.filename, self.firstlineno+1)) - -class FixtureManager: - """ - pytest fixtures definitions and information is stored and managed - from this class. - - During collection fm.parsefactories() is called multiple times to parse - fixture function definitions into FixtureDef objects and internal - data structures. - - During collection of test functions, metafunc-mechanics instantiate - a FuncFixtureInfo object which is cached per node/func-name. - This FuncFixtureInfo object is later retrieved by Function nodes - which themselves offer a fixturenames attribute. - - The FuncFixtureInfo object holds information about fixtures and FixtureDefs - relevant for a particular function. An initial list of fixtures is - assembled like this: - - - ini-defined usefixtures - - autouse-marked fixtures along the collection chain up from the function - - usefixtures markers at module/class/function level - - test function funcargs - - Subsequently the funcfixtureinfo.fixturenames attribute is computed - as the closure of the fixtures needed to setup the initial fixtures, - i. e. fixtures needed by fixture functions themselves are appended - to the fixturenames list. - - Upon the test-setup phases all fixturenames are instantiated, retrieved - by a lookup of their FuncFixtureInfo. - """ - - _argprefix = "pytest_funcarg__" - FixtureLookupError = FixtureLookupError - FixtureLookupErrorRepr = FixtureLookupErrorRepr - - def __init__(self, session): - self.session = session - self.config = session.config - self._arg2fixturedefs = {} - self._holderobjseen = set() - self._arg2finish = {} - self._nodeid_and_autousenames = [("", self.config.getini("usefixtures"))] - session.config.pluginmanager.register(self, "funcmanage") - - - def getfixtureinfo(self, node, func, cls, funcargs=True): - if funcargs and not hasattr(node, "nofuncargs"): - if cls is not None: - startindex = 1 - else: - startindex = None - argnames = getfuncargnames(func, startindex) - else: - argnames = () - usefixtures = getattr(func, "usefixtures", None) - initialnames = argnames - if usefixtures is not None: - initialnames = usefixtures.args + initialnames - fm = node.session._fixturemanager - names_closure, arg2fixturedefs = fm.getfixtureclosure(initialnames, - node) - return FuncFixtureInfo(argnames, names_closure, arg2fixturedefs) - - def pytest_plugin_registered(self, plugin): - nodeid = None - try: - p = py.path.local(plugin.__file__) - except AttributeError: - pass - else: - # construct the base nodeid which is later used to check - # what fixtures are visible for particular tests (as denoted - # by their test id) - if p.basename.startswith("conftest.py"): - nodeid = p.dirpath().relto(self.config.rootdir) - if p.sep != "/": - nodeid = nodeid.replace(p.sep, "/") - self.parsefactories(plugin, nodeid) - - def _getautousenames(self, nodeid): - """ return a tuple of fixture names to be used. """ - autousenames = [] - for baseid, basenames in self._nodeid_and_autousenames: - if nodeid.startswith(baseid): - if baseid: - i = len(baseid) - nextchar = nodeid[i:i+1] - if nextchar and nextchar not in ":/": - continue - autousenames.extend(basenames) - # make sure autousenames are sorted by scope, scopenum 0 is session - autousenames.sort( - key=lambda x: self._arg2fixturedefs[x][-1].scopenum) - return autousenames - - def getfixtureclosure(self, fixturenames, parentnode): - # collect the closure of all fixtures , starting with the given - # fixturenames as the initial set. As we have to visit all - # factory definitions anyway, we also return a arg2fixturedefs - # mapping so that the caller can reuse it and does not have - # to re-discover fixturedefs again for each fixturename - # (discovering matching fixtures for a given name/node is expensive) - - parentid = parentnode.nodeid - fixturenames_closure = self._getautousenames(parentid) - def merge(otherlist): - for arg in otherlist: - if arg not in fixturenames_closure: - fixturenames_closure.append(arg) - merge(fixturenames) - arg2fixturedefs = {} - lastlen = -1 - while lastlen != len(fixturenames_closure): - lastlen = len(fixturenames_closure) - for argname in fixturenames_closure: - if argname in arg2fixturedefs: - continue - fixturedefs = self.getfixturedefs(argname, parentid) - if fixturedefs: - arg2fixturedefs[argname] = fixturedefs - merge(fixturedefs[-1].argnames) - return fixturenames_closure, arg2fixturedefs - - def pytest_generate_tests(self, metafunc): - for argname in metafunc.fixturenames: - faclist = metafunc._arg2fixturedefs.get(argname) - if faclist: - fixturedef = faclist[-1] - if fixturedef.params is not None: - func_params = getattr(getattr(metafunc.function, 'parametrize', None), 'args', [[None]]) - # skip directly parametrized arguments - argnames = func_params[0] - if not isinstance(argnames, (tuple, list)): - argnames = [x.strip() for x in argnames.split(",") if x.strip()] - if argname not in func_params and argname not in argnames: - metafunc.parametrize(argname, fixturedef.params, - indirect=True, scope=fixturedef.scope, - ids=fixturedef.ids) - else: - continue # will raise FixtureLookupError at setup time - - def pytest_collection_modifyitems(self, items): - # separate parametrized setups - items[:] = reorder_items(items) - - def parsefactories(self, node_or_obj, nodeid=NOTSET, unittest=False): - if nodeid is not NOTSET: - holderobj = node_or_obj - else: - holderobj = node_or_obj.obj - nodeid = node_or_obj.nodeid - if holderobj in self._holderobjseen: - return - self._holderobjseen.add(holderobj) - autousenames = [] - for name in dir(holderobj): - obj = getattr(holderobj, name, None) - # fixture functions have a pytest_funcarg__ prefix (pre-2.3 style) - # or are "@pytest.fixture" marked - marker = getfixturemarker(obj) - if marker is None: - if not name.startswith(self._argprefix): - continue - if not callable(obj): - continue - marker = defaultfuncargprefixmarker - name = name[len(self._argprefix):] - elif not isinstance(marker, FixtureFunctionMarker): - # magic globals with __getattr__ might have got us a wrong - # fixture attribute - continue - else: - assert not name.startswith(self._argprefix) - fixturedef = FixtureDef(self, nodeid, name, obj, - marker.scope, marker.params, - yieldctx=marker.yieldctx, - unittest=unittest, ids=marker.ids) - faclist = self._arg2fixturedefs.setdefault(name, []) - if fixturedef.has_location: - faclist.append(fixturedef) - else: - # fixturedefs with no location are at the front - # so this inserts the current fixturedef after the - # existing fixturedefs from external plugins but - # before the fixturedefs provided in conftests. - i = len([f for f in faclist if not f.has_location]) - faclist.insert(i, fixturedef) - if marker.autouse: - autousenames.append(name) - if autousenames: - self._nodeid_and_autousenames.append((nodeid or '', autousenames)) - - def getfixturedefs(self, argname, nodeid): - try: - fixturedefs = self._arg2fixturedefs[argname] - except KeyError: - return None - else: - return tuple(self._matchfactories(fixturedefs, nodeid)) - - def _matchfactories(self, fixturedefs, nodeid): - for fixturedef in fixturedefs: - if nodeid.startswith(fixturedef.baseid): - yield fixturedef - - -def fail_fixturefunc(fixturefunc, msg): - fs, lineno = getfslineno(fixturefunc) - location = "%s:%s" % (fs, lineno+1) - source = _pytest._code.Source(fixturefunc) - pytest.fail(msg + ":\n\n" + str(source.indent()) + "\n" + location, - pytrace=False) - -def call_fixture_func(fixturefunc, request, kwargs, yieldctx): - if yieldctx: - if not is_generator(fixturefunc): - fail_fixturefunc(fixturefunc, - msg="yield_fixture requires yield statement in function") - iter = fixturefunc(**kwargs) - next = getattr(iter, "__next__", None) - if next is None: - next = getattr(iter, "next") - res = next() - def teardown(): - try: - next() - except StopIteration: - pass - else: - fail_fixturefunc(fixturefunc, - "yield_fixture function has more than one 'yield'") - request.addfinalizer(teardown) - else: - if is_generator(fixturefunc): - fail_fixturefunc(fixturefunc, - msg="pytest.fixture functions cannot use ``yield``. " - "Instead write and return an inner function/generator " - "and let the consumer call and iterate over it.") - res = fixturefunc(**kwargs) - return res - -class FixtureDef: - """ A container for a factory definition. """ - def __init__(self, fixturemanager, baseid, argname, func, scope, params, - yieldctx, unittest=False, ids=None): - self._fixturemanager = fixturemanager - self.baseid = baseid or '' - self.has_location = baseid is not None - self.func = func - self.argname = argname - self.scope = scope - self.scopenum = scopes.index(scope or "function") - self.params = params - startindex = unittest and 1 or None - self.argnames = getfuncargnames(func, startindex=startindex) - self.yieldctx = yieldctx - self.unittest = unittest - self.ids = ids - self._finalizer = [] - - def addfinalizer(self, finalizer): - self._finalizer.append(finalizer) - - def finish(self): - try: - while self._finalizer: - func = self._finalizer.pop() - func() - finally: - # even if finalization fails, we invalidate - # the cached fixture value - if hasattr(self, "cached_result"): - del self.cached_result - - def execute(self, request): - # get required arguments and register our own finish() - # with their finalization - kwargs = {} - for argname in self.argnames: - fixturedef = request._get_active_fixturedef(argname) - result, arg_cache_key, exc = fixturedef.cached_result - request._check_scope(argname, request.scope, fixturedef.scope) - kwargs[argname] = result - if argname != "request": - fixturedef.addfinalizer(self.finish) - - my_cache_key = request.param_index - cached_result = getattr(self, "cached_result", None) - if cached_result is not None: - result, cache_key, err = cached_result - if my_cache_key == cache_key: - if err is not None: - py.builtin._reraise(*err) - else: - return result - # we have a previous but differently parametrized fixture instance - # so we need to tear it down before creating a new one - self.finish() - assert not hasattr(self, "cached_result") - - fixturefunc = self.func - - if self.unittest: - if request.instance is not None: - # bind the unbound method to the TestCase instance - fixturefunc = self.func.__get__(request.instance) - else: - # the fixture function needs to be bound to the actual - # request.instance so that code working with "self" behaves - # as expected. - if request.instance is not None: - fixturefunc = getimfunc(self.func) - if fixturefunc != self.func: - fixturefunc = fixturefunc.__get__(request.instance) - - try: - result = call_fixture_func(fixturefunc, request, kwargs, - self.yieldctx) - except Exception: - self.cached_result = (None, my_cache_key, sys.exc_info()) - raise - self.cached_result = (result, my_cache_key, None) - return result - - def __repr__(self): - return ("" % - (self.argname, self.scope, self.baseid)) - -def num_mock_patch_args(function): - """ return number of arguments used up by mock arguments (if any) """ - patchings = getattr(function, "patchings", None) - if not patchings: - return 0 - mock = sys.modules.get("mock", sys.modules.get("unittest.mock", None)) - if mock is not None: - return len([p for p in patchings - if not p.attribute_name and p.new is mock.DEFAULT]) - return len(patchings) - - -def getfuncargnames(function, startindex=None): - # XXX merge with main.py's varnames - #assert not isclass(function) - realfunction = function - while hasattr(realfunction, "__wrapped__"): - realfunction = realfunction.__wrapped__ - if startindex is None: - startindex = inspect.ismethod(function) and 1 or 0 - if realfunction != function: - startindex += num_mock_patch_args(function) - function = realfunction - if isinstance(function, functools.partial): - argnames = inspect.getargs(_pytest._code.getrawcode(function.func))[0] - partial = function - argnames = argnames[len(partial.args):] - if partial.keywords: - for kw in partial.keywords: - argnames.remove(kw) - else: - argnames = inspect.getargs(_pytest._code.getrawcode(function))[0] - defaults = getattr(function, 'func_defaults', - getattr(function, '__defaults__', None)) or () - numdefaults = len(defaults) - if numdefaults: - return tuple(argnames[startindex:-numdefaults]) - return tuple(argnames[startindex:]) - -# algorithm for sorting on a per-parametrized resource setup basis -# it is called for scopenum==0 (session) first and performs sorting -# down to the lower scopes such as to minimize number of "high scope" -# setups and teardowns - -def reorder_items(items): - argkeys_cache = {} - for scopenum in range(0, scopenum_function): - argkeys_cache[scopenum] = d = {} - for item in items: - keys = set(get_parametrized_fixture_keys(item, scopenum)) - if keys: - d[item] = keys - return reorder_items_atscope(items, set(), argkeys_cache, 0) - -def reorder_items_atscope(items, ignore, argkeys_cache, scopenum): - if scopenum >= scopenum_function or len(items) < 3: - return items - items_done = [] - while 1: - items_before, items_same, items_other, newignore = \ - slice_items(items, ignore, argkeys_cache[scopenum]) - items_before = reorder_items_atscope( - items_before, ignore, argkeys_cache,scopenum+1) - if items_same is None: - # nothing to reorder in this scope - assert items_other is None - return items_done + items_before - items_done.extend(items_before) - items = items_same + items_other - ignore = newignore - - -def slice_items(items, ignore, scoped_argkeys_cache): - # we pick the first item which uses a fixture instance in the - # requested scope and which we haven't seen yet. We slice the input - # items list into a list of items_nomatch, items_same and - # items_other - if scoped_argkeys_cache: # do we need to do work at all? - it = iter(items) - # first find a slicing key - for i, item in enumerate(it): - argkeys = scoped_argkeys_cache.get(item) - if argkeys is not None: - argkeys = argkeys.difference(ignore) - if argkeys: # found a slicing key - slicing_argkey = argkeys.pop() - items_before = items[:i] - items_same = [item] - items_other = [] - # now slice the remainder of the list - for item in it: - argkeys = scoped_argkeys_cache.get(item) - if argkeys and slicing_argkey in argkeys and \ - slicing_argkey not in ignore: - items_same.append(item) - else: - items_other.append(item) - newignore = ignore.copy() - newignore.add(slicing_argkey) - return (items_before, items_same, items_other, newignore) - return items, None, None, None - -def get_parametrized_fixture_keys(item, scopenum): - """ return list of keys for all parametrized arguments which match - the specified scope. """ - assert scopenum < scopenum_function # function - try: - cs = item.callspec - except AttributeError: - pass - else: - # cs.indictes.items() is random order of argnames but - # then again different functions (items) can change order of - # arguments so it doesn't matter much probably - for argname, param_index in cs.indices.items(): - if cs._arg2scopenum[argname] != scopenum: - continue - if scopenum == 0: # session - key = (argname, param_index) - elif scopenum == 1: # module - key = (argname, param_index, item.fspath) - elif scopenum == 2: # class - key = (argname, param_index, item.fspath, item.cls) - yield key - - -def xunitsetup(obj, name): - meth = getattr(obj, name, None) - if getfixturemarker(meth) is None: - return meth - -def getfixturemarker(obj): - """ return fixturemarker or None if it doesn't exist or raised - exceptions.""" - try: - return getattr(obj, "_pytestfixturefunction", None) - except KeyboardInterrupt: - raise - except Exception: - # some objects raise errors like request (from flask import request) - # we don't expect them to be fixture functions - return None - -scopename2class = { - 'class': Class, - 'module': Module, - 'function': pytest.Item, -} -def get_scope_node(node, scope): - cls = scopename2class.get(scope) - if cls is None: - if scope == "session": - return node.session - raise ValueError("unknown scope") - return node.getparent(cls) diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/recwarn.py b/tests/wpt/web-platform-tests/tools/pytest/_pytest/recwarn.py deleted file mode 100644 index a89474c036a..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/recwarn.py +++ /dev/null @@ -1,221 +0,0 @@ -""" recording warnings during test function execution. """ - -import inspect - -import _pytest._code -import py -import sys -import warnings -import pytest - - -@pytest.yield_fixture -def recwarn(request): - """Return a WarningsRecorder instance that provides these methods: - - * ``pop(category=None)``: return last warning matching the category. - * ``clear()``: clear list of warnings - - See http://docs.python.org/library/warnings.html for information - on warning categories. - """ - wrec = WarningsRecorder() - with wrec: - warnings.simplefilter('default') - yield wrec - - -def pytest_namespace(): - return {'deprecated_call': deprecated_call, - 'warns': warns} - - -def deprecated_call(func=None, *args, **kwargs): - """ assert that calling ``func(*args, **kwargs)`` triggers a - ``DeprecationWarning`` or ``PendingDeprecationWarning``. - - This function can be used as a context manager:: - - >>> with deprecated_call(): - ... myobject.deprecated_method() - - Note: we cannot use WarningsRecorder here because it is still subject - to the mechanism that prevents warnings of the same type from being - triggered twice for the same module. See #1190. - """ - if not func: - return WarningsChecker(expected_warning=DeprecationWarning) - - categories = [] - - def warn_explicit(message, category, *args, **kwargs): - categories.append(category) - old_warn_explicit(message, category, *args, **kwargs) - - def warn(message, category=None, *args, **kwargs): - if isinstance(message, Warning): - categories.append(message.__class__) - else: - categories.append(category) - old_warn(message, category, *args, **kwargs) - - old_warn = warnings.warn - old_warn_explicit = warnings.warn_explicit - warnings.warn_explicit = warn_explicit - warnings.warn = warn - try: - ret = func(*args, **kwargs) - finally: - warnings.warn_explicit = old_warn_explicit - warnings.warn = old_warn - deprecation_categories = (DeprecationWarning, PendingDeprecationWarning) - if not any(issubclass(c, deprecation_categories) for c in categories): - __tracebackhide__ = True - raise AssertionError("%r did not produce DeprecationWarning" % (func,)) - return ret - - -def warns(expected_warning, *args, **kwargs): - """Assert that code raises a particular class of warning. - - Specifically, the input @expected_warning can be a warning class or - tuple of warning classes, and the code must return that warning - (if a single class) or one of those warnings (if a tuple). - - This helper produces a list of ``warnings.WarningMessage`` objects, - one for each warning raised. - - This function can be used as a context manager, or any of the other ways - ``pytest.raises`` can be used:: - - >>> with warns(RuntimeWarning): - ... warnings.warn("my warning", RuntimeWarning) - """ - wcheck = WarningsChecker(expected_warning) - if not args: - return wcheck - elif isinstance(args[0], str): - code, = args - assert isinstance(code, str) - frame = sys._getframe(1) - loc = frame.f_locals.copy() - loc.update(kwargs) - - with wcheck: - code = _pytest._code.Source(code).compile() - py.builtin.exec_(code, frame.f_globals, loc) - else: - func = args[0] - with wcheck: - return func(*args[1:], **kwargs) - - -class RecordedWarning(object): - def __init__(self, message, category, filename, lineno, file, line): - self.message = message - self.category = category - self.filename = filename - self.lineno = lineno - self.file = file - self.line = line - - -class WarningsRecorder(object): - """A context manager to record raised warnings. - - Adapted from `warnings.catch_warnings`. - """ - - def __init__(self, module=None): - self._module = sys.modules['warnings'] if module is None else module - self._entered = False - self._list = [] - - @property - def list(self): - """The list of recorded warnings.""" - return self._list - - def __getitem__(self, i): - """Get a recorded warning by index.""" - return self._list[i] - - def __iter__(self): - """Iterate through the recorded warnings.""" - return iter(self._list) - - def __len__(self): - """The number of recorded warnings.""" - return len(self._list) - - def pop(self, cls=Warning): - """Pop the first recorded warning, raise exception if not exists.""" - for i, w in enumerate(self._list): - if issubclass(w.category, cls): - return self._list.pop(i) - __tracebackhide__ = True - raise AssertionError("%r not found in warning list" % cls) - - def clear(self): - """Clear the list of recorded warnings.""" - self._list[:] = [] - - def __enter__(self): - if self._entered: - __tracebackhide__ = True - raise RuntimeError("Cannot enter %r twice" % self) - self._entered = True - self._filters = self._module.filters - self._module.filters = self._filters[:] - self._showwarning = self._module.showwarning - - def showwarning(message, category, filename, lineno, - file=None, line=None): - self._list.append(RecordedWarning( - message, category, filename, lineno, file, line)) - - # still perform old showwarning functionality - self._showwarning( - message, category, filename, lineno, file=file, line=line) - - self._module.showwarning = showwarning - - # allow the same warning to be raised more than once - - self._module.simplefilter('always') - return self - - def __exit__(self, *exc_info): - if not self._entered: - __tracebackhide__ = True - raise RuntimeError("Cannot exit %r without entering first" % self) - self._module.filters = self._filters - self._module.showwarning = self._showwarning - - -class WarningsChecker(WarningsRecorder): - def __init__(self, expected_warning=None, module=None): - super(WarningsChecker, self).__init__(module=module) - - msg = ("exceptions must be old-style classes or " - "derived from Warning, not %s") - if isinstance(expected_warning, tuple): - for exc in expected_warning: - if not inspect.isclass(exc): - raise TypeError(msg % type(exc)) - elif inspect.isclass(expected_warning): - expected_warning = (expected_warning,) - elif expected_warning is not None: - raise TypeError(msg % type(expected_warning)) - - self.expected_warning = expected_warning - - def __exit__(self, *exc_info): - super(WarningsChecker, self).__exit__(*exc_info) - - # only check if we're not currently handling an exception - if all(a is None for a in exc_info): - if self.expected_warning is not None: - if not any(r.category in self.expected_warning for r in self): - __tracebackhide__ = True - pytest.fail("DID NOT WARN") diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/standalonetemplate.py b/tests/wpt/web-platform-tests/tools/pytest/_pytest/standalonetemplate.py deleted file mode 100755 index 484d5d1b25f..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/standalonetemplate.py +++ /dev/null @@ -1,89 +0,0 @@ -#! /usr/bin/env python - -# Hi There! -# You may be wondering what this giant blob of binary data here is, you might -# even be worried that we're up to something nefarious (good for you for being -# paranoid!). This is a base64 encoding of a zip file, this zip file contains -# a fully functional basic pytest script. -# -# Pytest is a thing that tests packages, pytest itself is a package that some- -# one might want to install, especially if they're looking to run tests inside -# some package they want to install. Pytest has a lot of code to collect and -# execute tests, and other such sort of "tribal knowledge" that has been en- -# coded in its code base. Because of this we basically include a basic copy -# of pytest inside this blob. We do this because it let's you as a maintainer -# or application developer who wants people who don't deal with python much to -# easily run tests without installing the complete pytest package. -# -# If you're wondering how this is created: you can create it yourself if you -# have a complete pytest installation by using this command on the command- -# line: ``py.test --genscript=runtests.py``. - -sources = """ -@SOURCES@""" - -import sys -import base64 -import zlib - -class DictImporter(object): - def __init__(self, sources): - self.sources = sources - - def find_module(self, fullname, path=None): - if fullname == "argparse" and sys.version_info >= (2,7): - # we were generated with = (3, 0): - exec("def do_exec(co, loc): exec(co, loc)\n") - import pickle - sources = sources.encode("ascii") # ensure bytes - sources = pickle.loads(zlib.decompress(base64.decodebytes(sources))) - else: - import cPickle as pickle - exec("def do_exec(co, loc): exec co in loc\n") - sources = pickle.loads(zlib.decompress(base64.decodestring(sources))) - - importer = DictImporter(sources) - sys.meta_path.insert(0, importer) - entry = "@ENTRY@" - do_exec(entry, locals()) # noqa diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/README.md b/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/README.md deleted file mode 100644 index eab7c714fb0..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/README.md +++ /dev/null @@ -1,13 +0,0 @@ -This directory vendors the `pluggy` module. - -For a more detailed discussion for the reasons to vendoring this -package, please see [this issue](https://github.com/pytest-dev/pytest/issues/944). - -To update the current version, execute: - -``` -$ pip install -U pluggy== --no-compile --target=_pytest/vendored_packages -``` - -And commit the modified files. The `pluggy-.dist-info` directory -created by `pip` should be ignored. diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/pluggy-0.3.1.dist-info/DESCRIPTION.rst b/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/pluggy-0.3.1.dist-info/DESCRIPTION.rst deleted file mode 100644 index aa3bbf81297..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/pluggy-0.3.1.dist-info/DESCRIPTION.rst +++ /dev/null @@ -1,10 +0,0 @@ -Plugin registration and hook calling for Python -=============================================== - -This is the plugin manager as used by pytest but stripped -of pytest specific details. - -During the 0.x series this plugin does not have much documentation -except extensive docstrings in the pluggy.py module. - - diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/pluggy-0.3.1.dist-info/METADATA b/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/pluggy-0.3.1.dist-info/METADATA deleted file mode 100644 index ec81f0a6be0..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/pluggy-0.3.1.dist-info/METADATA +++ /dev/null @@ -1,39 +0,0 @@ -Metadata-Version: 2.0 -Name: pluggy -Version: 0.3.1 -Summary: plugin and hook calling mechanisms for python -Home-page: UNKNOWN -Author: Holger Krekel -Author-email: holger at merlinux.eu -License: MIT license -Platform: unix -Platform: linux -Platform: osx -Platform: win32 -Classifier: Development Status :: 4 - Beta -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: POSIX -Classifier: Operating System :: Microsoft :: Windows -Classifier: Operating System :: MacOS :: MacOS X -Classifier: Topic :: Software Development :: Testing -Classifier: Topic :: Software Development :: Libraries -Classifier: Topic :: Utilities -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.6 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 - -Plugin registration and hook calling for Python -=============================================== - -This is the plugin manager as used by pytest but stripped -of pytest specific details. - -During the 0.x series this plugin does not have much documentation -except extensive docstrings in the pluggy.py module. - - diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/pluggy-0.3.1.dist-info/RECORD b/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/pluggy-0.3.1.dist-info/RECORD deleted file mode 100644 index 9626673c43c..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/pluggy-0.3.1.dist-info/RECORD +++ /dev/null @@ -1,8 +0,0 @@ -pluggy.py,sha256=v_RfWzyW6DPU1cJu_EFoL_OHq3t13qloVdR6UaMCXQA,29862 -pluggy-0.3.1.dist-info/top_level.txt,sha256=xKSCRhai-v9MckvMuWqNz16c1tbsmOggoMSwTgcpYHE,7 -pluggy-0.3.1.dist-info/pbr.json,sha256=xX3s6__wOcAyF-AZJX1sdZyW6PUXT-FkfBlM69EEUCg,47 -pluggy-0.3.1.dist-info/RECORD,, -pluggy-0.3.1.dist-info/metadata.json,sha256=nLKltOT78dMV-00uXD6Aeemp4xNsz2q59j6ORSDeLjw,1027 -pluggy-0.3.1.dist-info/METADATA,sha256=1b85Ho2u4iK30M099k7axMzcDDhLcIMb-A82JUJZnSo,1334 -pluggy-0.3.1.dist-info/WHEEL,sha256=AvR0WeTpDaxT645bl5FQxUK6NPsTls2ttpcGJg3j1Xg,110 -pluggy-0.3.1.dist-info/DESCRIPTION.rst,sha256=P5Akh1EdIBR6CeqtV2P8ZwpGSpZiTKPw0NyS7jEiD-g,306 diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/pluggy-0.3.1.dist-info/metadata.json b/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/pluggy-0.3.1.dist-info/metadata.json deleted file mode 100644 index 426a3a7ade1..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/pluggy-0.3.1.dist-info/metadata.json +++ /dev/null @@ -1 +0,0 @@ -{"license": "MIT license", "name": "pluggy", "metadata_version": "2.0", "generator": "bdist_wheel (0.24.0)", "summary": "plugin and hook calling mechanisms for python", "platform": "unix", "version": "0.3.1", "extensions": {"python.details": {"document_names": {"description": "DESCRIPTION.rst"}, "contacts": [{"role": "author", "email": "holger at merlinux.eu", "name": "Holger Krekel"}]}}, "classifiers": ["Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: POSIX", "Operating System :: Microsoft :: Windows", "Operating System :: MacOS :: MacOS X", "Topic :: Software Development :: Testing", "Topic :: Software Development :: Libraries", "Topic :: Utilities", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5"]} \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/pluggy-0.3.1.dist-info/pbr.json b/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/pluggy-0.3.1.dist-info/pbr.json deleted file mode 100644 index d6b79864019..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/pluggy-0.3.1.dist-info/pbr.json +++ /dev/null @@ -1 +0,0 @@ -{"is_release": false, "git_version": "7d4c9cd"} \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/pluggy-0.3.1.dist-info/top_level.txt b/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/pluggy-0.3.1.dist-info/top_level.txt deleted file mode 100644 index 11bdb5c1f5f..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/pluggy-0.3.1.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -pluggy diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/_getdoctarget.py b/tests/wpt/web-platform-tests/tools/pytest/doc/en/_getdoctarget.py deleted file mode 100755 index 20e487bb738..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/_getdoctarget.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env python - -import py - -def get_version_string(): - fn = py.path.local(__file__).join("..", "..", "..", - "_pytest", "__init__.py") - for line in fn.readlines(): - if "version" in line and not line.strip().startswith('#'): - return eval(line.split("=")[-1]) - -def get_minor_version_string(): - return ".".join(get_version_string().split(".")[:2]) - -if __name__ == "__main__": - print (get_minor_version_string()) diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/sprint2016.rst b/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/sprint2016.rst deleted file mode 100644 index e59ccdda772..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/sprint2016.rst +++ /dev/null @@ -1,105 +0,0 @@ -python testing sprint June 20th-26th 2016 -====================================================== - -.. image:: ../img/freiburg2.jpg - :width: 400 - -The pytest core group is heading towards the biggest sprint -in its history, to take place in the black forest town Freiburg -in Germany. As of February 2016 we have started a `funding -campaign on Indiegogo to cover expenses -`_ The page also mentions -some preliminary topics: - -- improving pytest-xdist test scheduling to take into account - fixture setups and explicit user hints. - -- provide info on fixture dependencies during --collect-only - -- tying pytest-xdist to tox so that you can do "py.test -e py34" - to run tests in a particular tox-managed virtualenv. Also - look into making pytest-xdist use tox environments on - remote ssh-sides so that remote dependency management becomes - easier. - -- refactoring the fixture system so more people understand it :) - -- integrating PyUnit setup methods as autouse fixtures. - possibly adding ways to influence ordering of same-scoped - fixtures (so you can make a choice of which fixtures come - before others) - -- fixing bugs and issues from the tracker, really an endless source :) - - -Participants --------------- - -Here are preliminary participants who said they are likely to come, -given some expenses funding:: - - Anatoly Bubenkoff, Netherlands - Andreas Pelme, Personalkollen, Sweden - Anthony Wang, Splunk, US - Brianna Laugher, Australia - Bruno Oliveira, Brazil - Danielle Jenkins, Splunk, US - Dave Hunt, UK - Florian Bruhin, Switzerland - Floris Bruynooghe, Cobe.io, UK - Holger Krekel, merlinux, Germany - Oliver Bestwalter, Avira, Germany - Omar Kohl, Germany - Raphael Pierzina, FanDuel, UK - Tom Viner, UK - - - -Other contributors and experienced newcomers are invited to join as well -but please send a mail to the pytest-dev mailing list if you intend to -do so somewhat soon, also how much funding you need if so. And if you -are working for a company and using pytest heavily you are welcome to -join and we encourage your company to provide some funding for the -sprint. They may see it, and rightfully so, as a very cheap and deep -training which brings you together with the experts in the field :) - - -Sprint organisation, schedule -------------------------------- - -tentative schedule: - -- 19/20th arrival in Freiburg -- 20th social get together, initial hacking -- 21/22th full sprint days -- 23rd break day, hiking -- 24/25th full sprint days -- 26th departure - -We might adjust according to weather to make sure that if -we do some hiking or excursion we'll have good weather. -Freiburg is one of the sunniest places in Germany so -it shouldn't be too much of a constraint. - - -Accomodation ----------------- - -We'll see to arrange for renting a flat with multiple -beds/rooms. Hotels are usually below 100 per night. -The earlier we book the better. - -Money / funding ---------------- - -The Indiegogo campaign asks for 11000 USD which should cover -the costs for flights and accomodation, renting a sprint place -and maybe a bit of food as well. - -If your organisation wants to support the sprint but prefers -to give money according to an invoice, get in contact with -holger at http://merlinux.eu who can invoice your organisation -properly. - -If we have excess money we'll use for further sprint/travel -funding for pytest/tox contributors. diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/contents.rst b/tests/wpt/web-platform-tests/tools/pytest/doc/en/contents.rst deleted file mode 100644 index 48c3471b5e2..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/contents.rst +++ /dev/null @@ -1,39 +0,0 @@ -.. _toc: - -Full pytest documentation -=========================== - -`Download latest version as PDF `_ - -.. `Download latest version as EPUB `_ - -.. toctree:: - :maxdepth: 2 - - overview - apiref - example/index - monkeypatch - tmpdir - capture - recwarn - cache - plugins - - contributing - talks - -.. only:: html - - .. toctree:: - - funcarg_compare - announce/index - -.. only:: html - - .. toctree:: - :hidden: - - changelog - diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/customize.rst b/tests/wpt/web-platform-tests/tools/pytest/doc/en/customize.rst deleted file mode 100644 index 34e319c246a..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/customize.rst +++ /dev/null @@ -1,228 +0,0 @@ -Basic test configuration -=================================== - -Command line options and configuration file settings ------------------------------------------------------------------ - -You can get help on command line options and values in INI-style -configurations files by using the general help option:: - - py.test -h # prints options _and_ config file settings - -This will display command line and configuration file settings -which were registered by installed plugins. - -.. _rootdir: -.. _inifiles: - -initialization: determining rootdir and inifile ------------------------------------------------ - -.. versionadded:: 2.7 - -pytest determines a "rootdir" for each test run which depends on -the command line arguments (specified test files, paths) and on -the existence of inifiles. The determined rootdir and ini-file are -printed as part of the pytest header. The rootdir is used for constructing -"nodeids" during collection and may also be used by plugins to store -project/testrun-specific information. - -Here is the algorithm which finds the rootdir from ``args``: - -- determine the common ancestor directory for the specified ``args``. - -- look for ``pytest.ini``, ``tox.ini`` and ``setup.cfg`` files in the - ancestor directory and upwards. If one is matched, it becomes the - ini-file and its directory becomes the rootdir. An existing - ``pytest.ini`` file will always be considered a match whereas - ``tox.ini`` and ``setup.cfg`` will only match if they contain - a ``[pytest]`` section. - -- if no ini-file was found, look for ``setup.py`` upwards from - the common ancestor directory to determine the ``rootdir``. - -- if no ini-file and no ``setup.py`` was found, use the already - determined common ancestor as root directory. This allows to - work with pytest in structures that are not part of a package - and don't have any particular ini-file configuration. - -Note that options from multiple ini-files candidates are never merged, -the first one wins (``pytest.ini`` always wins even if it does not -contain a ``[pytest]`` section). - -The ``config`` object will subsequently carry these attributes: - -- ``config.rootdir``: the determined root directory, guaranteed to exist. - -- ``config.inifile``: the determined ini-file, may be ``None``. - -The rootdir is used a reference directory for constructing test -addresses ("nodeids") and can be used also by plugins for storing -per-testrun information. - -Example:: - - py.test path/to/testdir path/other/ - -will determine the common ancestor as ``path`` and then -check for ini-files as follows:: - - # first look for pytest.ini files - path/pytest.ini - path/setup.cfg # must also contain [pytest] section to match - path/tox.ini # must also contain [pytest] section to match - pytest.ini - ... # all the way down to the root - - # now look for setup.py - path/setup.py - setup.py - ... # all the way down to the root - - -.. _`how to change command line options defaults`: -.. _`adding default options`: - -How to change command line options defaults ------------------------------------------------- - -It can be tedious to type the same series of command line options -every time you use ``pytest``. For example, if you always want to see -detailed info on skipped and xfailed tests, as well as have terser "dot" -progress output, you can write it into a configuration file: - -.. code-block:: ini - - # content of pytest.ini - # (or tox.ini or setup.cfg) - [pytest] - addopts = -rsxX -q - -Alternatively, you can set a PYTEST_ADDOPTS environment variable to add command -line options while the environment is in use:: - - export PYTEST_ADDOPTS="-rsxX -q" - -From now on, running ``pytest`` will add the specified options. - - - -Builtin configuration file options ----------------------------------------------- - -.. confval:: minversion - - Specifies a minimal pytest version required for running tests. - - minversion = 2.1 # will fail if we run with pytest-2.0 - -.. confval:: addopts - - Add the specified ``OPTS`` to the set of command line arguments as if they - had been specified by the user. Example: if you have this ini file content: - - .. code-block:: ini - - [pytest] - addopts = --maxfail=2 -rf # exit after 2 failures, report fail info - - issuing ``py.test test_hello.py`` actually means:: - - py.test --maxfail=2 -rf test_hello.py - - Default is to add no options. - -.. confval:: norecursedirs - - Set the directory basename patterns to avoid when recursing - for test discovery. The individual (fnmatch-style) patterns are - applied to the basename of a directory to decide if to recurse into it. - Pattern matching characters:: - - * matches everything - ? matches any single character - [seq] matches any character in seq - [!seq] matches any char not in seq - - Default patterns are ``'.*', 'CVS', '_darcs', '{arch}', '*.egg'``. - Setting a ``norecursedirs`` replaces the default. Here is an example of - how to avoid certain directories: - - .. code-block:: ini - - # content of setup.cfg - [pytest] - norecursedirs = .svn _build tmp* - - This would tell ``pytest`` to not look into typical subversion or - sphinx-build directories or into any ``tmp`` prefixed directory. - -.. confval:: testpaths - - .. versionadded:: 2.8 - - Sets list of directories that should be searched for tests when - no specific directories, files or test ids are given in the command line when - executing pytest from the :ref:`rootdir ` directory. - Useful when all project tests are in a known location to speed up - test collection and to avoid picking up undesired tests by accident. - - .. code-block:: ini - - # content of pytest.ini - [pytest] - testpaths = testing doc - - This tells pytest to only look for tests in ``testing`` and ``doc`` - directories when executing from the root directory. - -.. confval:: python_files - - One or more Glob-style file patterns determining which python files - are considered as test modules. - -.. confval:: python_classes - - One or more name prefixes or glob-style patterns determining which classes - are considered for test collection. Here is an example of how to collect - tests from classes that end in ``Suite``: - - .. code-block:: ini - - # content of pytest.ini - [pytest] - python_classes = *Suite - - Note that ``unittest.TestCase`` derived classes are always collected - regardless of this option, as ``unittest``'s own collection framework is used - to collect those tests. - -.. confval:: python_functions - - One or more name prefixes or glob-patterns determining which test functions - and methods are considered tests. Here is an example of how - to collect test functions and methods that end in ``_test``: - - .. code-block:: ini - - # content of pytest.ini - [pytest] - python_functions = *_test - - Note that this has no effect on methods that live on a ``unittest - .TestCase`` derived class, as ``unittest``'s own collection framework is used - to collect those tests. - - See :ref:`change naming conventions` for more detailed examples. - -.. confval:: doctest_optionflags - - One or more doctest flag names from the standard ``doctest`` module. - :doc:`See how py.test handles doctests `. - -.. confval:: confcutdir - - Sets a directory where search upwards for ``conftest.py`` files stops. - By default, pytest will stop searching for ``conftest.py`` files upwards - from ``pytest.ini``/``tox.ini``/``setup.cfg`` of the project if any, - or up to the file-system root. diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/doctest.rst b/tests/wpt/web-platform-tests/tools/pytest/doc/en/doctest.rst deleted file mode 100644 index db764141ecb..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/doctest.rst +++ /dev/null @@ -1,105 +0,0 @@ - -Doctest integration for modules and test files -========================================================= - -By default all files matching the ``test*.txt`` pattern will -be run through the python standard ``doctest`` module. You -can change the pattern by issuing:: - - py.test --doctest-glob='*.rst' - -on the command line. Since version ``2.9``, ``--doctest-glob`` -can be given multiple times in the command-line. - -You can also trigger running of doctests -from docstrings in all python modules (including regular -python test modules):: - - py.test --doctest-modules - -You can make these changes permanent in your project by -putting them into a pytest.ini file like this: - -.. code-block:: ini - - # content of pytest.ini - [pytest] - addopts = --doctest-modules - -If you then have a text file like this:: - - # content of example.rst - - hello this is a doctest - >>> x = 3 - >>> x - 3 - -and another like this:: - - # content of mymodule.py - def something(): - """ a doctest in a docstring - >>> something() - 42 - """ - return 42 - -then you can just invoke ``py.test`` without command line options:: - - $ py.test - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini - collected 1 items - - mymodule.py . - - ======= 1 passed in 0.12 seconds ======== - -It is possible to use fixtures using the ``getfixture`` helper:: - - # content of example.rst - >>> tmp = getfixture('tmpdir') - >>> ... - >>> - -Also, :ref:`usefixtures` and :ref:`autouse` fixtures are supported -when executing text doctest files. - -The standard ``doctest`` module provides some setting flags to configure the -strictness of doctest tests. In py.test You can enable those flags those flags -using the configuration file. To make pytest ignore trailing whitespaces and -ignore lengthy exception stack traces you can just write: - -.. code-block:: ini - - [pytest] - doctest_optionflags= NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL - -py.test also introduces new options to allow doctests to run in Python 2 and -Python 3 unchanged: - -* ``ALLOW_UNICODE``: when enabled, the ``u`` prefix is stripped from unicode - strings in expected doctest output. - -* ``ALLOW_BYTES``: when enabled, the ``b`` prefix is stripped from byte strings - in expected doctest output. - -As with any other option flag, these flags can be enabled in ``pytest.ini`` using -the ``doctest_optionflags`` ini option: - -.. code-block:: ini - - [pytest] - doctest_optionflags = ALLOW_UNICODE ALLOW_BYTES - - -Alternatively, it can be enabled by an inline comment in the doc test -itself:: - - # content of example.rst - >>> get_unicode_greeting() # doctest: +ALLOW_UNICODE - 'Hello' - - diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/layout1/setup.cfg b/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/layout1/setup.cfg deleted file mode 100644 index 02d3750ee40..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/layout1/setup.cfg +++ /dev/null @@ -1,4 +0,0 @@ -[pytest] -testfilepatterns = - ${topdir}/tests/unit/test_${basename} - ${topdir}/tests/functional/*.py diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/feedback.rst b/tests/wpt/web-platform-tests/tools/pytest/doc/en/feedback.rst deleted file mode 100644 index 9c63b7640e0..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/feedback.rst +++ /dev/null @@ -1,8 +0,0 @@ - -What users say: - - `py.test is pretty much the best thing ever`_ (Alex Gaynor) - - -.. _`py.test is pretty much the best thing ever`_ (Alex Gaynor) - http://twitter.com/#!/alex_gaynor/status/22389410366 diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/index.rst b/tests/wpt/web-platform-tests/tools/pytest/doc/en/index.rst deleted file mode 100644 index 04b4512da30..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/index.rst +++ /dev/null @@ -1,61 +0,0 @@ - -.. _features: - -pytest: helps you write better programs -============================================= - -**a mature full-featured Python testing tool** - - - runs on Posix/Windows, Python 2.6-3.5, PyPy and (possibly still) Jython-2.5.1 - - free and open source software, distributed under the terms of the :ref:`MIT license ` - - **well tested** with more than a thousand tests against itself - - **strict backward compatibility policy** for safe pytest upgrades - - :ref:`comprehensive online ` and `PDF documentation `_ - - many :ref:`third party plugins ` and :ref:`builtin helpers `, - - used in :ref:`many small and large projects and organisations ` - - comes with many :ref:`tested examples ` - -**provides easy no-boilerplate testing** - - - makes it :ref:`easy to get started `, - has many :ref:`usage options ` - - :ref:`assert with the assert statement` - - helpful :ref:`traceback and failing assertion reporting ` - - :ref:`print debugging ` and :ref:`the - capturing of standard output during test execution ` - -**scales from simple unit to complex functional testing** - - - :ref:`modular parametrizeable fixtures ` (new in 2.3, - continuously improved) - - :ref:`parametrized test functions ` - - :ref:`mark` - - :ref:`skipping` (improved in 2.4) - - :ref:`distribute tests to multiple CPUs ` through :ref:`xdist plugin ` - - :ref:`continuously re-run failing tests ` - - :doc:`cache` - - flexible :ref:`Python test discovery` - -**integrates with other testing methods and tools**: - - - multi-paradigm: pytest can run ``nose``, ``unittest`` and - ``doctest`` style test suites, including running testcases made for - Django and trial - - supports :ref:`good integration practices ` - - supports extended :ref:`xUnit style setup ` - - supports domain-specific :ref:`non-python tests` - - supports generating `test coverage reports - `_ - - supports :pep:`8` compliant coding styles in tests - -**extensive plugin and customization system**: - - - all collection, reporting, running aspects are delegated to hook functions - - customizations can be per-directory, per-project or per PyPI released plugin - - it is easy to add command line options or customize existing behaviour - - :ref:`easy to write your own plugins ` - - -.. _`easy`: http://bruynooghe.blogspot.com/2009/12/skipping-slow-test-by-default-in-pytest.html - - diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/overview.rst b/tests/wpt/web-platform-tests/tools/pytest/doc/en/overview.rst deleted file mode 100644 index eb261977514..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/overview.rst +++ /dev/null @@ -1,13 +0,0 @@ -================================================== -Getting started basics -================================================== - -.. toctree:: - :maxdepth: 2 - - getting-started - usage - goodpractices - projects - faq - diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/recwarn.rst b/tests/wpt/web-platform-tests/tools/pytest/doc/en/recwarn.rst deleted file mode 100644 index 3c42bfaaf94..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/recwarn.rst +++ /dev/null @@ -1,130 +0,0 @@ - -Asserting Warnings -===================================================== - -.. _warns: - -Asserting warnings with the warns function ------------------------------------------------ - -.. versionadded:: 2.8 - -You can check that code raises a particular warning using ``pytest.warns``, -which works in a similar manner to :ref:`raises `:: - - import warnings - import pytest - - def test_warning(): - with pytest.warns(UserWarning): - warnings.warn("my warning", UserWarning) - -The test will fail if the warning in question is not raised. - -You can also call ``pytest.warns`` on a function or code string:: - - pytest.warns(expected_warning, func, *args, **kwargs) - pytest.warns(expected_warning, "func(*args, **kwargs)") - -The function also returns a list of all raised warnings (as -``warnings.WarningMessage`` objects), which you can query for -additional information:: - - with pytest.warns(RuntimeWarning) as record: - warnings.warn("another warning", RuntimeWarning) - - # check that only one warning was raised - assert len(record) == 1 - # check that the message matches - assert record[0].message.args[0] == "another warning" - -Alternatively, you can examine raised warnings in detail using the -:ref:`recwarn ` fixture (see below). - -.. note:: - ``DeprecationWarning`` and ``PendingDeprecationWarning`` are treated - differently; see :ref:`ensuring_function_triggers`. - -.. _recwarn: - -Recording warnings ------------------------- - -You can record raised warnings either using ``pytest.warns`` or with -the ``recwarn`` fixture. - -To record with ``pytest.warns`` without asserting anything about the warnings, -pass ``None`` as the expected warning type:: - - with pytest.warns(None) as record: - warnings.warn("user", UserWarning) - warnings.warn("runtime", RuntimeWarning) - - assert len(record) == 2 - assert str(record[0].message) == "user" - assert str(record[1].message) == "runtime" - -The ``recwarn`` fixture will record warnings for the whole function:: - - import warnings - - def test_hello(recwarn): - warnings.warn("hello", UserWarning) - assert len(recwarn) == 1 - w = recwarn.pop(UserWarning) - assert issubclass(w.category, UserWarning) - assert str(w.message) == "hello" - assert w.filename - assert w.lineno - -Both ``recwarn`` and ``pytest.warns`` return the same interface for recorded -warnings: a WarningsRecorder instance. To view the recorded warnings, you can -iterate over this instance, call ``len`` on it to get the number of recorded -warnings, or index into it to get a particular recorded warning. It also -provides these methods: - -.. autoclass:: _pytest.recwarn.WarningsRecorder() - :members: - -Each recorded warning has the attributes ``message``, ``category``, -``filename``, ``lineno``, ``file``, and ``line``. The ``category`` is the -class of the warning. The ``message`` is the warning itself; calling -``str(message)`` will return the actual message of the warning. - -.. note:: - ``DeprecationWarning`` and ``PendingDeprecationWarning`` are treated - differently; see :ref:`ensuring_function_triggers`. - -.. _ensuring_function_triggers: - -Ensuring a function triggers a deprecation warning -------------------------------------------------------- - -You can also call a global helper for checking -that a certain function call triggers a ``DeprecationWarning`` or -``PendingDeprecationWarning``:: - - import pytest - - def test_global(): - pytest.deprecated_call(myfunction, 17) - -By default, ``DeprecationWarning`` and ``PendingDeprecationWarning`` will not be -caught when using ``pytest.warns`` or ``recwarn`` because default Python warnings filters hide -them. If you wish to record them in your own code, use the -command ``warnings.simplefilter('always')``:: - - import warnings - import pytest - - def test_deprecation(recwarn): - warnings.simplefilter('always') - warnings.warn("deprecated", DeprecationWarning) - assert len(recwarn) == 1 - assert recwarn.pop(DeprecationWarning) - -You can also use it as a contextmanager:: - - def test_global(): - with pytest.deprecated_call(): - myobject.deprecated_method() diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/setup.rst b/tests/wpt/web-platform-tests/tools/pytest/doc/en/setup.rst deleted file mode 100644 index fe235346544..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/setup.rst +++ /dev/null @@ -1,10 +0,0 @@ - -setup: is now an "autouse fixture" -======================================================== - -During development prior to the pytest-2.3 release the name -``pytest.setup`` was used but before the release it was renamed -and moved to become part of the general fixture mechanism, -namely :ref:`autouse fixtures` - - diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/skipping.rst b/tests/wpt/web-platform-tests/tools/pytest/doc/en/skipping.rst deleted file mode 100644 index 4282afb77ec..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/skipping.rst +++ /dev/null @@ -1,373 +0,0 @@ -.. _`skip and xfail`: - -.. _skipping: - -Skip and xfail: dealing with tests that can not succeed -===================================================================== - -If you have test functions that cannot be run on certain platforms -or that you expect to fail you can mark them accordingly or you -may call helper functions during execution of setup or test functions. - -A *skip* means that you expect your test to pass unless the environment -(e.g. wrong Python interpreter, missing dependency) prevents it to run. -And *xfail* means that your test can run but you expect it to fail -because there is an implementation problem. - -``pytest`` counts and lists *skip* and *xfail* tests separately. Detailed -information about skipped/xfailed tests is not shown by default to avoid -cluttering the output. You can use the ``-r`` option to see details -corresponding to the "short" letters shown in the test progress:: - - py.test -rxs # show extra info on skips and xfails - -(See :ref:`how to change command line options defaults`) - -.. _skipif: -.. _`condition booleans`: - -Marking a test function to be skipped -------------------------------------------- - -.. versionadded:: 2.9 - -The simplest way to skip a test function is to mark it with the ``skip`` decorator -which may be passed an optional ``reason``: - -.. code-block:: python - - @pytest.mark.skip(reason="no way of currently testing this") - def test_the_unknown(): - ... - -``skipif`` -~~~~~~~~~~ - -.. versionadded:: 2.0, 2.4 - -If you wish to skip something conditionally then you can use ``skipif`` instead. -Here is an example of marking a test function to be skipped -when run on a Python3.3 interpreter:: - - import sys - @pytest.mark.skipif(sys.version_info < (3,3), - reason="requires python3.3") - def test_function(): - ... - -During test function setup the condition ("sys.version_info >= (3,3)") is -checked. If it evaluates to True, the test function will be skipped -with the specified reason. Note that pytest enforces specifying a reason -in order to report meaningful "skip reasons" (e.g. when using ``-rs``). -If the condition is a string, it will be evaluated as python expression. - -You can share skipif markers between modules. Consider this test module:: - - # content of test_mymodule.py - - import mymodule - minversion = pytest.mark.skipif(mymodule.__versioninfo__ < (1,1), - reason="at least mymodule-1.1 required") - @minversion - def test_function(): - ... - -You can import it from another test module:: - - # test_myothermodule.py - from test_mymodule import minversion - - @minversion - def test_anotherfunction(): - ... - -For larger test suites it's usually a good idea to have one file -where you define the markers which you then consistently apply -throughout your test suite. - -Alternatively, the pre pytest-2.4 way to specify :ref:`condition strings -` instead of booleans will remain fully supported in future -versions of pytest. It couldn't be easily used for importing markers -between test modules so it's no longer advertised as the primary method. - - -Skip all test functions of a class or module ---------------------------------------------- - -You can use the ``skipif`` decorator (and any other marker) on classes:: - - @pytest.mark.skipif(sys.platform == 'win32', - reason="does not run on windows") - class TestPosixCalls: - - def test_function(self): - "will not be setup or run under 'win32' platform" - -If the condition is true, this marker will produce a skip result for -each of the test methods. - -If you want to skip all test functions of a module, you must use -the ``pytestmark`` name on the global level: - -.. code-block:: python - - # test_module.py - pytestmark = pytest.mark.skipif(...) - -If multiple "skipif" decorators are applied to a test function, it -will be skipped if any of the skip conditions is true. - -.. _`whole class- or module level`: mark.html#scoped-marking - -.. _xfail: - -Mark a test function as expected to fail -------------------------------------------------------- - -You can use the ``xfail`` marker to indicate that you -expect a test to fail:: - - @pytest.mark.xfail - def test_function(): - ... - -This test will be run but no traceback will be reported -when it fails. Instead terminal reporting will list it in the -"expected to fail" (``XFAIL``) or "unexpectedly passing" (``XPASS``) sections. - -``strict`` parameter -~~~~~~~~~~~~~~~~~~~~ - -.. versionadded:: 2.9 - -Both ``XFAIL`` and ``XPASS`` don't fail the test suite, unless the ``strict`` keyword-only -parameter is passed as ``True``: - -.. code-block:: python - - @pytest.mark.xfail(strict=True) - def test_function(): - ... - - -This will make ``XPASS`` ("unexpectedly passing") results from this test to fail the test suite. - -You can change the default value of the ``strict`` parameter using the -``xfail_strict`` ini option: - -.. code-block:: ini - - [pytest] - xfail_strict=true - - -``reason`` parameter -~~~~~~~~~~~~~~~~~~~~ - -As with skipif_ you can also mark your expectation of a failure -on a particular platform:: - - @pytest.mark.xfail(sys.version_info >= (3,3), - reason="python3.3 api changes") - def test_function(): - ... - - -``raises`` parameter -~~~~~~~~~~~~~~~~~~~~ - -If you want to be more specific as to why the test is failing, you can specify -a single exception, or a list of exceptions, in the ``raises`` argument. - -.. code-block:: python - - @pytest.mark.xfail(raises=RuntimeError) - def test_function(): - ... - -Then the test will be reported as a regular failure if it fails with an -exception not mentioned in ``raises``. - -``run`` parameter -~~~~~~~~~~~~~~~~~ - -If a test should be marked as xfail and reported as such but should not be -even executed, use the ``run`` parameter as ``False``: - -.. code-block:: python - - @pytest.mark.xfail(run=False) - def test_function(): - ... - -This is specially useful for marking crashing tests for later inspection. - - -Ignoring xfail marks -~~~~~~~~~~~~~~~~~~~~ - -By specifying on the commandline:: - - pytest --runxfail - -you can force the running and reporting of an ``xfail`` marked test -as if it weren't marked at all. - -Examples -~~~~~~~~ - -Here is a simple test file with the several usages: - -.. literalinclude:: example/xfail_demo.py - -Running it with the report-on-xfail option gives this output:: - - example $ py.test -rx xfail_demo.py - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR/example, inifile: - collected 7 items - - xfail_demo.py xxxxxxx - ======= short test summary info ======== - XFAIL xfail_demo.py::test_hello - XFAIL xfail_demo.py::test_hello2 - reason: [NOTRUN] - XFAIL xfail_demo.py::test_hello3 - condition: hasattr(os, 'sep') - XFAIL xfail_demo.py::test_hello4 - bug 110 - XFAIL xfail_demo.py::test_hello5 - condition: pytest.__version__[0] != "17" - XFAIL xfail_demo.py::test_hello6 - reason: reason - XFAIL xfail_demo.py::test_hello7 - - ======= 7 xfailed in 0.12 seconds ======== - -xfail signature summary -~~~~~~~~~~~~~~~~~~~~~~~ - -Here's the signature of the ``xfail`` marker, using Python 3 keyword-only -arguments syntax: - -.. code-block:: python - - def xfail(condition=None, *, reason=None, raises=None, run=True, strict=False): - - - -.. _`skip/xfail with parametrize`: - -Skip/xfail with parametrize ---------------------------- - -It is possible to apply markers like skip and xfail to individual -test instances when using parametrize:: - - import pytest - - @pytest.mark.parametrize(("n", "expected"), [ - (1, 2), - pytest.mark.xfail((1, 0)), - pytest.mark.xfail(reason="some bug")((1, 3)), - (2, 3), - (3, 4), - (4, 5), - pytest.mark.skipif("sys.version_info >= (3,0)")((10, 11)), - ]) - def test_increment(n, expected): - assert n + 1 == expected - - -Imperative xfail from within a test or setup function ------------------------------------------------------- - -If you cannot declare xfail- of skipif conditions at import -time you can also imperatively produce an according outcome -imperatively, in test or setup code:: - - def test_function(): - if not valid_config(): - pytest.xfail("failing configuration (but should work)") - # or - pytest.skip("unsupported configuration") - - -Skipping on a missing import dependency --------------------------------------------------- - -You can use the following import helper at module level -or within a test or test setup function:: - - docutils = pytest.importorskip("docutils") - -If ``docutils`` cannot be imported here, this will lead to a -skip outcome of the test. You can also skip based on the -version number of a library:: - - docutils = pytest.importorskip("docutils", minversion="0.3") - -The version will be read from the specified -module's ``__version__`` attribute. - - -.. _string conditions: - -specifying conditions as strings versus booleans ----------------------------------------------------------- - -Prior to pytest-2.4 the only way to specify skipif/xfail conditions was -to use strings:: - - import sys - @pytest.mark.skipif("sys.version_info >= (3,3)") - def test_function(): - ... - -During test function setup the skipif condition is evaluated by calling -``eval('sys.version_info >= (3,0)', namespace)``. The namespace contains -all the module globals, and ``os`` and ``sys`` as a minimum. - -Since pytest-2.4 `condition booleans`_ are considered preferable -because markers can then be freely imported between test modules. -With strings you need to import not only the marker but all variables -everything used by the marker, which violates encapsulation. - -The reason for specifying the condition as a string was that ``pytest`` can -report a summary of skip conditions based purely on the condition string. -With conditions as booleans you are required to specify a ``reason`` string. - -Note that string conditions will remain fully supported and you are free -to use them if you have no need for cross-importing markers. - -The evaluation of a condition string in ``pytest.mark.skipif(conditionstring)`` -or ``pytest.mark.xfail(conditionstring)`` takes place in a namespace -dictionary which is constructed as follows: - -* the namespace is initialized by putting the ``sys`` and ``os`` modules - and the pytest ``config`` object into it. - -* updated with the module globals of the test function for which the - expression is applied. - -The pytest ``config`` object allows you to skip based on a test -configuration value which you might have added:: - - @pytest.mark.skipif("not config.getvalue('db')") - def test_function(...): - ... - -The equivalent with "boolean conditions" is:: - - @pytest.mark.skipif(not pytest.config.getvalue("db"), - reason="--db was not specified") - def test_function(...): - pass - -.. note:: - - You cannot use ``pytest.config.getvalue()`` in code - imported before py.test's argument parsing takes place. For example, - ``conftest.py`` files are imported before command line parsing and thus - ``config.getvalue()`` will not execute correctly. diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/status.rst b/tests/wpt/web-platform-tests/tools/pytest/doc/en/status.rst deleted file mode 100644 index 3c7bf70eaa4..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/status.rst +++ /dev/null @@ -1,5 +0,0 @@ -pytest development status -================================ - -https://travis-ci.org/pytest-dev/pytest - diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/genscript.rst b/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/genscript.rst deleted file mode 100644 index ee80f233fa0..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/genscript.rst +++ /dev/null @@ -1,28 +0,0 @@ - -(deprecated) generate standalone test script to be distributed along with an application. -============================================================================ - - -.. contents:: - :local: - - - -command line options --------------------- - - -``--genscript=path`` - create standalone ``pytest`` script at given target path. - -Start improving this plugin in 30 seconds -========================================= - - -1. Download `pytest_genscript.py`_ plugin source code -2. put it somewhere as ``pytest_genscript.py`` into your import path -3. a subsequent ``pytest`` run will use your local version - -Checkout customize_, other plugins_ or `get in contact`_. - -.. include:: links.txt diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/unittest.rst b/tests/wpt/web-platform-tests/tools/pytest/doc/en/unittest.rst deleted file mode 100644 index ce99bd11867..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/unittest.rst +++ /dev/null @@ -1,190 +0,0 @@ - -.. _`unittest.TestCase`: - -Support for unittest.TestCase / Integration of fixtures -===================================================================== - -.. _`unittest.py style`: http://docs.python.org/library/unittest.html - -``pytest`` has support for running Python `unittest.py style`_ tests. -It's meant for leveraging existing unittest-style projects -to use pytest features. Concretely, pytest will automatically -collect ``unittest.TestCase`` subclasses and their ``test`` methods in -test files. It will invoke typical setup/teardown methods and -generally try to make test suites written to run on unittest, to also -run using ``pytest``. We assume here that you are familiar with writing -``unittest.TestCase`` style tests and rather focus on -integration aspects. - -Usage -------------------------------------------------------------------- - -After :ref:`installation` type:: - - py.test - -and you should be able to run your unittest-style tests if they -are contained in ``test_*`` modules. If that works for you then -you can make use of most :ref:`pytest features `, for example -``--pdb`` debugging in failures, using :ref:`plain assert-statements `, -:ref:`more informative tracebacks `, stdout-capturing or -distributing tests to multiple CPUs via the ``-nNUM`` option if you -installed the ``pytest-xdist`` plugin. Please refer to -the general ``pytest`` documentation for many more examples. - -Mixing pytest fixtures into unittest.TestCase style tests ------------------------------------------------------------ - -Running your unittest with ``pytest`` allows you to use its -:ref:`fixture mechanism ` with ``unittest.TestCase`` style -tests. Assuming you have at least skimmed the pytest fixture features, -let's jump-start into an example that integrates a pytest ``db_class`` -fixture, setting up a class-cached database object, and then reference -it from a unittest-style test:: - - # content of conftest.py - - # we define a fixture function below and it will be "used" by - # referencing its name from tests - - import pytest - - @pytest.fixture(scope="class") - def db_class(request): - class DummyDB: - pass - # set a class attribute on the invoking test context - request.cls.db = DummyDB() - -This defines a fixture function ``db_class`` which - if used - is -called once for each test class and which sets the class-level -``db`` attribute to a ``DummyDB`` instance. The fixture function -achieves this by receiving a special ``request`` object which gives -access to :ref:`the requesting test context ` such -as the ``cls`` attribute, denoting the class from which the fixture -is used. This architecture de-couples fixture writing from actual test -code and allows re-use of the fixture by a minimal reference, the fixture -name. So let's write an actual ``unittest.TestCase`` class using our -fixture definition:: - - # content of test_unittest_db.py - - import unittest - import pytest - - @pytest.mark.usefixtures("db_class") - class MyTest(unittest.TestCase): - def test_method1(self): - assert hasattr(self, "db") - assert 0, self.db # fail for demo purposes - - def test_method2(self): - assert 0, self.db # fail for demo purposes - -The ``@pytest.mark.usefixtures("db_class")`` class-decorator makes sure that -the pytest fixture function ``db_class`` is called once per class. -Due to the deliberately failing assert statements, we can take a look at -the ``self.db`` values in the traceback:: - - $ py.test test_unittest_db.py - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: - collected 2 items - - test_unittest_db.py FF - - ======= FAILURES ======== - _______ MyTest.test_method1 ________ - - self = - - def test_method1(self): - assert hasattr(self, "db") - > assert 0, self.db # fail for demo purposes - E AssertionError: .DummyDB object at 0xdeadbeef> - E assert 0 - - test_unittest_db.py:9: AssertionError - _______ MyTest.test_method2 ________ - - self = - - def test_method2(self): - > assert 0, self.db # fail for demo purposes - E AssertionError: .DummyDB object at 0xdeadbeef> - E assert 0 - - test_unittest_db.py:12: AssertionError - ======= 2 failed in 0.12 seconds ======== - -This default pytest traceback shows that the two test methods -share the same ``self.db`` instance which was our intention -when writing the class-scoped fixture function above. - - -autouse fixtures and accessing other fixtures -------------------------------------------------------------------- - -Although it's usually better to explicitly declare use of fixtures you need -for a given test, you may sometimes want to have fixtures that are -automatically used in a given context. After all, the traditional -style of unittest-setup mandates the use of this implicit fixture writing -and chances are, you are used to it or like it. - -You can flag fixture functions with ``@pytest.fixture(autouse=True)`` -and define the fixture function in the context where you want it used. -Let's look at an ``initdir`` fixture which makes all test methods of a -``TestCase`` class execute in a temporary directory with a -pre-initialized ``samplefile.ini``. Our ``initdir`` fixture itself uses -the pytest builtin :ref:`tmpdir ` fixture to delegate the -creation of a per-test temporary directory:: - - # content of test_unittest_cleandir.py - import pytest - import unittest - - class MyTest(unittest.TestCase): - @pytest.fixture(autouse=True) - def initdir(self, tmpdir): - tmpdir.chdir() # change to pytest-provided temporary directory - tmpdir.join("samplefile.ini").write("# testdata") - - def test_method(self): - s = open("samplefile.ini").read() - assert "testdata" in s - -Due to the ``autouse`` flag the ``initdir`` fixture function will be -used for all methods of the class where it is defined. This is a -shortcut for using a ``@pytest.mark.usefixtures("initdir")`` marker -on the class like in the previous example. - -Running this test module ...:: - - $ py.test -q test_unittest_cleandir.py - . - 1 passed in 0.12 seconds - -... gives us one passed test because the ``initdir`` fixture function -was executed ahead of the ``test_method``. - -.. note:: - - While pytest supports receiving fixtures via :ref:`test function arguments ` for non-unittest test methods, ``unittest.TestCase`` methods cannot directly receive fixture - function arguments as implementing that is likely to inflict - on the ability to run general unittest.TestCase test suites. - Maybe optional support would be possible, though. If unittest finally - grows a plugin system that should help as well. In the meanwhile, the - above ``usefixtures`` and ``autouse`` examples should help to mix in - pytest fixtures into unittest suites. And of course you can also start - to selectively leave away the ``unittest.TestCase`` subclassing, use - plain asserts and get the unlimited pytest feature set. - - -Converting from unittest to pytest ---------------------------------------- - -If you want to convert your unittest testcases to pytest, there are -some helpers like `unittest2pytest -`__, which uses lib2to3 -and introspection for the transformation. diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/usage.rst b/tests/wpt/web-platform-tests/tools/pytest/doc/en/usage.rst deleted file mode 100644 index 4b92fd1e150..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/usage.rst +++ /dev/null @@ -1,275 +0,0 @@ - -.. _usage: - -Usage and Invocations -========================================== - - -.. _cmdline: - -Calling pytest through ``python -m pytest`` ------------------------------------------------------ - -.. versionadded:: 2.0 - -You can invoke testing through the Python interpreter from the command line:: - - python -m pytest [...] - -This is equivalent to invoking the command line script ``py.test [...]`` -directly. - -Getting help on version, option names, environment variables --------------------------------------------------------------- - -:: - - py.test --version # shows where pytest was imported from - py.test --fixtures # show available builtin function arguments - py.test -h | --help # show help on command line and config file options - - -Stopping after the first (or N) failures ---------------------------------------------------- - -To stop the testing process after the first (N) failures:: - - py.test -x # stop after first failure - py.test --maxfail=2 # stop after two failures - -Specifying tests / selecting tests ---------------------------------------------------- - -Several test run options:: - - py.test test_mod.py # run tests in module - py.test somepath # run all tests below somepath - py.test -k stringexpr # only run tests with names that match the - # "string expression", e.g. "MyClass and not method" - # will select TestMyClass.test_something - # but not TestMyClass.test_method_simple - py.test test_mod.py::test_func # only run tests that match the "node ID", - # e.g "test_mod.py::test_func" will select - # only test_func in test_mod.py - py.test test_mod.py::TestClass::test_method # run a single method in - # a single class - -Import 'pkg' and use its filesystem location to find and run tests:: - - py.test --pyargs pkg # run all tests found below directory of pypkg - -Modifying Python traceback printing ----------------------------------------------- - -Examples for modifying traceback printing:: - - py.test --showlocals # show local variables in tracebacks - py.test -l # show local variables (shortcut) - - py.test --tb=auto # (default) 'long' tracebacks for the first and last - # entry, but 'short' style for the other entries - py.test --tb=long # exhaustive, informative traceback formatting - py.test --tb=short # shorter traceback format - py.test --tb=line # only one line per failure - py.test --tb=native # Python standard library formatting - py.test --tb=no # no traceback at all - -Dropping to PDB_ (Python Debugger) on failures ------------------------------------------------ - -.. _PDB: http://docs.python.org/library/pdb.html - -Python comes with a builtin Python debugger called PDB_. ``pytest`` -allows one to drop into the PDB_ prompt via a command line option:: - - py.test --pdb - -This will invoke the Python debugger on every failure. Often you might -only want to do this for the first failing test to understand a certain -failure situation:: - - py.test -x --pdb # drop to PDB on first failure, then end test session - py.test --pdb --maxfail=3 # drop to PDB for first three failures - -Note that on any failure the exception information is stored on -``sys.last_value``, ``sys.last_type`` and ``sys.last_traceback``. In -interactive use, this allows one to drop into postmortem debugging with -any debug tool. One can also manually access the exception information, -for example:: - - >>> import sys - >>> sys.last_traceback.tb_lineno - 42 - >>> sys.last_value - AssertionError('assert result == "ok"',) - -Setting a breakpoint / aka ``set_trace()`` ----------------------------------------------------- - -If you want to set a breakpoint and enter the ``pdb.set_trace()`` you -can use a helper:: - - import pytest - def test_function(): - ... - pytest.set_trace() # invoke PDB debugger and tracing - -.. versionadded: 2.0.0 - -Prior to pytest version 2.0.0 you could only enter PDB_ tracing if you disabled -capturing on the command line via ``py.test -s``. In later versions, pytest -automatically disables its output capture when you enter PDB_ tracing: - -* Output capture in other tests is not affected. -* Any prior test output that has already been captured and will be processed as - such. -* Any later output produced within the same test will not be captured and will - instead get sent directly to ``sys.stdout``. Note that this holds true even - for test output occurring after you exit the interactive PDB_ tracing session - and continue with the regular test run. - -.. versionadded: 2.4.0 - -Since pytest version 2.4.0 you can also use the native Python -``import pdb;pdb.set_trace()`` call to enter PDB_ tracing without having to use -the ``pytest.set_trace()`` wrapper or explicitly disable pytest's output -capturing via ``py.test -s``. - -.. _durations: - -Profiling test execution duration -------------------------------------- - -.. versionadded: 2.2 - -To get a list of the slowest 10 test durations:: - - py.test --durations=10 - - -Creating JUnitXML format files ----------------------------------------------------- - -To create result files which can be read by Hudson_ or other Continuous -integration servers, use this invocation:: - - py.test --junitxml=path - -to create an XML file at ``path``. - -record_xml_property -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. versionadded:: 2.8 - -If you want to log additional information for a test, you can use the -``record_xml_property`` fixture: - -.. code-block:: python - - def test_function(record_xml_property): - record_xml_property("example_key", 1) - assert 0 - -This will add an extra property ``example_key="1"`` to the generated -``testcase`` tag: - -.. code-block:: xml - - - - - - - -.. warning:: - - This is an experimental feature, and its interface might be replaced - by something more powerful and general in future versions. The - functionality per-se will be kept, however. - - Currently it does not work when used with the ``pytest-xdist`` plugin. - - Also please note that using this feature will break any schema verification. - This might be a problem when used with some CI servers. - -Creating resultlog format files ----------------------------------------------------- - -To create plain-text machine-readable result files you can issue:: - - py.test --resultlog=path - -and look at the content at the ``path`` location. Such files are used e.g. -by the `PyPy-test`_ web page to show test results over several revisions. - -.. _`PyPy-test`: http://buildbot.pypy.org/summary - - -Sending test report to online pastebin service ------------------------------------------------------ - -**Creating a URL for each test failure**:: - - py.test --pastebin=failed - -This will submit test run information to a remote Paste service and -provide a URL for each failure. You may select tests as usual or add -for example ``-x`` if you only want to send one particular failure. - -**Creating a URL for a whole test session log**:: - - py.test --pastebin=all - -Currently only pasting to the http://bpaste.net service is implemented. - -Disabling plugins ------------------ - -To disable loading specific plugins at invocation time, use the ``-p`` option -together with the prefix ``no:``. - -Example: to disable loading the plugin ``doctest``, which is responsible for -executing doctest tests from text files, invoke py.test like this:: - - py.test -p no:doctest - -.. _`pytest.main-usage`: - -Calling pytest from Python code ----------------------------------------------------- - -.. versionadded:: 2.0 - -You can invoke ``pytest`` from Python code directly:: - - pytest.main() - -this acts as if you would call "py.test" from the command line. -It will not raise ``SystemExit`` but return the exitcode instead. -You can pass in options and arguments:: - - pytest.main(['-x', 'mytestdir']) - -or pass in a string:: - - pytest.main("-x mytestdir") - -You can specify additional plugins to ``pytest.main``:: - - # content of myinvoke.py - import pytest - class MyPlugin: - def pytest_sessionfinish(self): - print("*** test run reporting finishing") - - pytest.main("-qq", plugins=[MyPlugin()]) - -Running it will show that ``MyPlugin`` was added and its -hook was invoked:: - - $ python myinvoke.py - *** test run reporting finishing - - -.. include:: links.inc diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/xdist.rst b/tests/wpt/web-platform-tests/tools/pytest/doc/en/xdist.rst deleted file mode 100644 index ee1bd603283..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/xdist.rst +++ /dev/null @@ -1,197 +0,0 @@ - -.. _`xdist`: - -xdist: pytest distributed testing plugin -=============================================================== - -The `pytest-xdist`_ plugin extends ``pytest`` with some unique -test execution modes: - -* Looponfail: run your tests repeatedly in a subprocess. After each - run, ``pytest`` waits until a file in your project changes and then - re-runs the previously failing tests. This is repeated until all - tests pass. At this point a full run is again performed. - -* multiprocess Load-balancing: if you have multiple CPUs or hosts you can use - them for a combined test run. This allows to speed up - development or to use special resources of remote machines. - -* Multi-Platform coverage: you can specify different Python interpreters - or different platforms and run tests in parallel on all of them. - -Before running tests remotely, ``pytest`` efficiently "rsyncs" your -program source code to the remote place. All test results -are reported back and displayed to your local terminal. -You may specify different Python versions and interpreters. - - -Installation of xdist plugin ------------------------------- - -Install the plugin with:: - - easy_install pytest-xdist - - # or - - pip install pytest-xdist - -or use the package in develop/in-place mode with -a checkout of the `pytest-xdist repository`_ :: - - python setup.py develop - - -Usage examples ---------------------- - -.. _`xdistcpu`: - -Speed up test runs by sending tests to multiple CPUs -+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -To send tests to multiple CPUs, type:: - - py.test -n NUM - -Especially for longer running tests or tests requiring -a lot of I/O this can lead to considerable speed ups. - - -Running tests in a Python subprocess -+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -To instantiate a Python-2.7 subprocess and send tests to it, you may type:: - - py.test -d --tx popen//python=python2.7 - -This will start a subprocess which is run with the "python2.7" -Python interpreter, found in your system binary lookup path. - -If you prefix the --tx option value like this:: - - py.test -d --tx 3*popen//python=python2.7 - -then three subprocesses would be created and the tests -will be distributed to three subprocesses and run simultanously. - -.. _looponfailing: - - -Running tests in looponfailing mode -+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -For refactoring a project with a medium or large test suite -you can use the looponfailing mode. Simply add the ``--f`` option:: - - py.test -f - -and ``pytest`` will run your tests. Assuming you have failures it will then -wait for file changes and re-run the failing test set. File changes are detected by looking at ``looponfailingroots`` root directories and all of their contents (recursively). If the default for this value does not work for you you -can change it in your project by setting a configuration option:: - - # content of a pytest.ini, setup.cfg or tox.ini file - [pytest] - looponfailroots = mypkg testdir - -This would lead to only looking for file changes in the respective directories, specified relatively to the ini-file's directory. - -Sending tests to remote SSH accounts -+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -Suppose you have a package ``mypkg`` which contains some -tests that you can successfully run locally. And you also -have a ssh-reachable machine ``myhost``. Then -you can ad-hoc distribute your tests by typing:: - - py.test -d --tx ssh=myhostpopen --rsyncdir mypkg mypkg - -This will synchronize your ``mypkg`` package directory -with a remote ssh account and then collect and run your -tests at the remote side. - -You can specify multiple ``--rsyncdir`` directories -to be sent to the remote side. - -.. XXX CHECK - - **NOTE:** For ``pytest`` to collect and send tests correctly - you not only need to make sure all code and tests - directories are rsynced, but that any test (sub) directory - also has an ``__init__.py`` file because internally - ``pytest`` references tests as a fully qualified python - module path. **You will otherwise get strange errors** - during setup of the remote side. - -Sending tests to remote Socket Servers -+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -Download the single-module `socketserver.py`_ Python program -and run it like this:: - - python socketserver.py - -It will tell you that it starts listening on the default -port. You can now on your home machine specify this -new socket host with something like this:: - - py.test -d --tx socket=192.168.1.102:8888 --rsyncdir mypkg mypkg - - -.. _`atonce`: - -Running tests on many platforms at once -+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -The basic command to run tests on multiple platforms is:: - - py.test --dist=each --tx=spec1 --tx=spec2 - -If you specify a windows host, an OSX host and a Linux -environment this command will send each tests to all -platforms - and report back failures from all platforms -at once. The specifications strings use the `xspec syntax`_. - -.. _`xspec syntax`: http://codespeak.net/execnet/basics.html#xspec - -.. _`socketserver.py`: http://bitbucket.org/hpk42/execnet/raw/2af991418160/execnet/script/socketserver.py - -.. _`execnet`: http://codespeak.net/execnet - -Specifying test exec environments in an ini file -+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -pytest (since version 2.0) supports ini-style configuration. -For example, you could make running with three subprocesses your default:: - - [pytest] - addopts = -n3 - -You can also add default environments like this:: - - [pytest] - addopts = --tx ssh=myhost//python=python2.7 --tx ssh=myhost//python=python2.6 - -and then just type:: - - py.test --dist=each - -to run tests in each of the environments. - -Specifying "rsync" dirs in an ini-file -+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -In a ``tox.ini`` or ``setup.cfg`` file in your root project directory -you may specify directories to include or to exclude in synchronisation:: - - [pytest] - rsyncdirs = . mypkg helperpkg - rsyncignore = .hg - -These directory specifications are relative to the directory -where the configuration file was found. - -.. _`pytest-xdist`: http://pypi.python.org/pypi/pytest-xdist -.. _`pytest-xdist repository`: http://bitbucket.org/pytest-dev/pytest-xdist -.. _`pytest`: http://pytest.org - diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/yieldfixture.rst b/tests/wpt/web-platform-tests/tools/pytest/doc/en/yieldfixture.rst deleted file mode 100644 index ee88a27df59..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/yieldfixture.rst +++ /dev/null @@ -1,100 +0,0 @@ -.. _yieldfixture: - -Fixture functions using "yield" / context manager integration ---------------------------------------------------------------- - -.. versionadded:: 2.4 - -.. regendoc:wipe - -pytest-2.4 allows fixture functions to seamlessly use a ``yield`` instead -of a ``return`` statement to provide a fixture value while otherwise -fully supporting all other fixture features. - -Let's look at a simple standalone-example using the ``yield`` syntax:: - - # content of test_yield.py - - import pytest - - @pytest.yield_fixture - def passwd(): - print ("\nsetup before yield") - f = open("/etc/passwd") - yield f.readlines() - print ("teardown after yield") - f.close() - - def test_has_lines(passwd): - print ("test called") - assert passwd - -In contrast to :ref:`finalization through registering callbacks -`, our fixture function used a ``yield`` -statement to provide the lines of the ``/etc/passwd`` file. -The code after the ``yield`` statement serves as the teardown code, -avoiding the indirection of registering a teardown callback function. - -Let's run it with output capturing disabled:: - - $ py.test -q -s test_yield.py - - setup before yield - test called - .teardown after yield - - 1 passed in 0.12 seconds - -We can also seamlessly use the new syntax with ``with`` statements. -Let's simplify the above ``passwd`` fixture:: - - # content of test_yield2.py - - import pytest - - @pytest.yield_fixture - def passwd(): - with open("/etc/passwd") as f: - yield f.readlines() - - def test_has_lines(passwd): - assert len(passwd) >= 1 - -The file ``f`` will be closed after the test finished execution -because the Python ``file`` object supports finalization when -the ``with`` statement ends. - -Note that the yield fixture form supports all other fixture -features such as ``scope``, ``params``, etc., thus changing existing -fixture functions to use ``yield`` is straightforward. - -.. note:: - - While the ``yield`` syntax is similar to what - :py:func:`contextlib.contextmanager` decorated functions - provide, with pytest fixture functions the part after the - "yield" will always be invoked, independently from the - exception status of the test function which uses the fixture. - This behaviour makes sense if you consider that many different - test functions might use a module or session scoped fixture. - - -Discussion and future considerations / feedback -++++++++++++++++++++++++++++++++++++++++++++++++++++ - -There are some topics that are worth mentioning: - -- usually ``yield`` is used for producing multiple values. - But fixture functions can only yield exactly one value. - Yielding a second fixture value will get you an error. - It's possible we can evolve pytest to allow for producing - multiple values as an alternative to current parametrization. - For now, you can just use the normal - :ref:`fixture parametrization ` - mechanisms together with ``yield``-style fixtures. - -- lastly ``yield`` introduces more than one way to write - fixture functions, so what's the obvious way to a newcomer? - -If you want to feedback or participate in discussion of the above -topics, please join our :ref:`contact channels`, you are most welcome. diff --git a/tests/wpt/web-platform-tests/tools/pytest/extra/get_issues.py b/tests/wpt/web-platform-tests/tools/pytest/extra/get_issues.py deleted file mode 100644 index 6437ba4c34e..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/extra/get_issues.py +++ /dev/null @@ -1,74 +0,0 @@ -import json -import py -import textwrap - -issues_url = "http://bitbucket.org/api/1.0/repositories/pytest-dev/pytest/issues" - -import requests - -def get_issues(): - chunksize = 50 - start = 0 - issues = [] - while 1: - post_data = {"accountname": "pytest-dev", - "repo_slug": "pytest", - "start": start, - "limit": chunksize} - print ("getting from", start) - r = requests.get(issues_url, params=post_data) - data = r.json() - issues.extend(data["issues"]) - if start + chunksize >= data["count"]: - return issues - start += chunksize - -kind2num = "bug enhancement task proposal".split() - -status2num = "new open resolved duplicate invalid wontfix".split() - -def main(args): - cachefile = py.path.local(args.cache) - if not cachefile.exists() or args.refresh: - issues = get_issues() - cachefile.write(json.dumps(issues)) - else: - issues = json.loads(cachefile.read()) - - open_issues = [x for x in issues - if x["status"] in ("new", "open")] - - def kind_and_id(x): - kind = x["metadata"]["kind"] - return kind2num.index(kind), len(issues)-int(x["local_id"]) - open_issues.sort(key=kind_and_id) - report(open_issues) - -def report(issues): - for issue in issues: - metadata = issue["metadata"] - priority = issue["priority"] - title = issue["title"] - content = issue["content"] - kind = metadata["kind"] - status = issue["status"] - id = issue["local_id"] - link = "https://bitbucket.org/pytest-dev/pytest/issue/%s/" % id - print("----") - print(status, kind, link) - print(title) - #print() - #lines = content.split("\n") - #print ("\n".join(lines[:3])) - #if len(lines) > 3 or len(content) > 240: - # print ("...") - -if __name__ == "__main__": - import argparse - parser = argparse.ArgumentParser("process bitbucket issues") - parser.add_argument("--refresh", action="store_true", - help="invalidate cache, refresh issues") - parser.add_argument("--cache", action="store", default="issues.json", - help="cache file") - args = parser.parse_args() - main(args) diff --git a/tests/wpt/web-platform-tests/tools/pytest/plugin-test.sh b/tests/wpt/web-platform-tests/tools/pytest/plugin-test.sh deleted file mode 100644 index 9c61b50536e..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/plugin-test.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -# this assumes plugins are installed as sister directories - -set -e -cd ../pytest-pep8 -py.test -cd ../pytest-instafail -py.test -cd ../pytest-cache -py.test -cd ../pytest-xprocess -py.test -#cd ../pytest-cov -#py.test -cd ../pytest-capturelog -py.test -cd ../pytest-xdist -py.test - diff --git a/tests/wpt/web-platform-tests/tools/pytest/pytest.py b/tests/wpt/web-platform-tests/tools/pytest/pytest.py deleted file mode 100644 index e376e417e8a..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/pytest.py +++ /dev/null @@ -1,28 +0,0 @@ -# PYTHON_ARGCOMPLETE_OK -""" -pytest: unit and functional testing with Python. -""" -__all__ = [ - 'main', - 'UsageError', - 'cmdline', - 'hookspec', - 'hookimpl', - '__version__', -] - -if __name__ == '__main__': # if run as a script or by 'python -m pytest' - # we trigger the below "else" condition by the following import - import pytest - raise SystemExit(pytest.main()) - -# else we are imported - -from _pytest.config import ( - main, UsageError, _preloadplugins, cmdline, - hookspec, hookimpl -) -from _pytest import __version__ - -_preloadplugins() # to populate pytest.* namespace so help(pytest) works - diff --git a/tests/wpt/web-platform-tests/tools/pytest/requirements-docs.txt b/tests/wpt/web-platform-tests/tools/pytest/requirements-docs.txt deleted file mode 100644 index be3a232e57b..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/requirements-docs.txt +++ /dev/null @@ -1,3 +0,0 @@ -sphinx==1.2.3 -regendoc -pyyaml diff --git a/tests/wpt/web-platform-tests/tools/pytest/runtox.py b/tests/wpt/web-platform-tests/tools/pytest/runtox.py deleted file mode 100644 index 8c13c53e1c4..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/runtox.py +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env python - -if __name__ == "__main__": - import subprocess - import sys - subprocess.call([sys.executable, "-m", "tox", - "-i", "ALL=https://devpi.net/hpk/dev/", - "--develop"] + sys.argv[1:]) diff --git a/tests/wpt/web-platform-tests/tools/pytest/setup.py b/tests/wpt/web-platform-tests/tools/pytest/setup.py deleted file mode 100644 index 6660f21604d..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/setup.py +++ /dev/null @@ -1,122 +0,0 @@ -import os, sys -import setuptools -import pkg_resources -from setuptools import setup, Command - -classifiers = ['Development Status :: 6 - Mature', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Operating System :: POSIX', - 'Operating System :: Microsoft :: Windows', - 'Operating System :: MacOS :: MacOS X', - 'Topic :: Software Development :: Testing', - 'Topic :: Software Development :: Libraries', - 'Topic :: Utilities'] + [ - ('Programming Language :: Python :: %s' % x) for x in - '2 2.6 2.7 3 3.2 3.3 3.4 3.5'.split()] - -with open('README.rst') as fd: - long_description = fd.read() - -def get_version(): - p = os.path.join(os.path.dirname( - os.path.abspath(__file__)), "_pytest", "__init__.py") - with open(p) as f: - for line in f.readlines(): - if "__version__" in line: - return line.strip().split("=")[-1].strip(" '") - raise ValueError("could not read version") - - -def has_environment_marker_support(): - """ - Tests that setuptools has support for PEP-426 environment marker support. - - The first known release to support it is 0.7 (and the earliest on PyPI seems to be 0.7.2 - so we're using that), see: http://pythonhosted.org/setuptools/history.html#id142 - - References: - - * https://wheel.readthedocs.org/en/latest/index.html#defining-conditional-dependencies - * https://www.python.org/dev/peps/pep-0426/#environment-markers - """ - try: - return pkg_resources.parse_version(setuptools.__version__) >= pkg_resources.parse_version('0.7.2') - except Exception as exc: - sys.stderr.write("Could not test setuptool's version: %s\n" % exc) - return False - - -def main(): - install_requires = ['py>=1.4.29'] # pluggy is vendored in _pytest.vendored_packages - extras_require = {} - if has_environment_marker_support(): - extras_require[':python_version=="2.6" or python_version=="3.0" or python_version=="3.1"'] = ['argparse'] - extras_require[':sys_platform=="win32"'] = ['colorama'] - else: - if sys.version_info < (2, 7) or (3,) <= sys.version_info < (3, 2): - install_requires.append('argparse') - if sys.platform == 'win32': - install_requires.append('colorama') - - setup( - name='pytest', - description='pytest: simple powerful testing with Python', - long_description=long_description, - version=get_version(), - url='http://pytest.org', - license='MIT license', - platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], - author='Holger Krekel, Bruno Oliveira, Ronny Pfannschmidt, Floris Bruynooghe, Brianna Laugher, Florian Bruhin and others', - author_email='holger at merlinux.eu', - entry_points=make_entry_points(), - classifiers=classifiers, - cmdclass={'test': PyTest}, - # the following should be enabled for release - install_requires=install_requires, - extras_require=extras_require, - packages=['_pytest', '_pytest.assertion', '_pytest._code', '_pytest.vendored_packages'], - py_modules=['pytest'], - zip_safe=False, - ) - - -def cmdline_entrypoints(versioninfo, platform, basename): - target = 'pytest:main' - if platform.startswith('java'): - points = {'py.test-jython': target} - else: - if basename.startswith('pypy'): - points = {'py.test-%s' % basename: target} - else: # cpython - points = {'py.test-%s.%s' % versioninfo[:2] : target} - points['py.test'] = target - return points - - -def make_entry_points(): - basename = os.path.basename(sys.executable) - points = cmdline_entrypoints(sys.version_info, sys.platform, basename) - keys = list(points.keys()) - keys.sort() - l = ['%s = %s' % (x, points[x]) for x in keys] - return {'console_scripts': l} - - -class PyTest(Command): - user_options = [] - def initialize_options(self): - pass - def finalize_options(self): - pass - def run(self): - import subprocess - PPATH = [x for x in os.environ.get('PYTHONPATH', '').split(':') if x] - PPATH.insert(0, os.getcwd()) - os.environ['PYTHONPATH'] = ':'.join(PPATH) - errno = subprocess.call([sys.executable, 'pytest.py', '--ignore=doc']) - raise SystemExit(errno) - - -if __name__ == '__main__': - main() diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/cx_freeze/install_cx_freeze.py b/tests/wpt/web-platform-tests/tools/pytest/testing/cx_freeze/install_cx_freeze.py deleted file mode 100644 index 83dce87aa56..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/cx_freeze/install_cx_freeze.py +++ /dev/null @@ -1,64 +0,0 @@ -""" -Installs cx_freeze from source, but first patching -setup.py as described here: - -http://stackoverflow.com/questions/25107697/compiling-cx-freeze-under-ubuntu -""" -import glob -import tarfile -import os -import sys -import platform -import py - -if __name__ == '__main__': - if 'ubuntu' not in platform.version().lower(): - - print('Not Ubuntu, installing using pip. (platform.version() is %r)' % - platform.version()) - res = os.system('pip install cx_freeze') - if res != 0: - sys.exit(res) - sys.exit(0) - - rootdir = py.path.local.make_numbered_dir(prefix='cx_freeze') - - res = os.system('pip install --download %s --no-use-wheel ' - 'cx_freeze' % rootdir) - if res != 0: - sys.exit(res) - - packages = glob.glob('%s/*.tar.gz' % rootdir) - assert len(packages) == 1 - tar_filename = packages[0] - - tar_file = tarfile.open(tar_filename) - try: - tar_file.extractall(path=str(rootdir)) - finally: - tar_file.close() - - basename = os.path.basename(tar_filename).replace('.tar.gz', '') - setup_py_filename = '%s/%s/setup.py' % (rootdir, basename) - with open(setup_py_filename) as f: - lines = f.readlines() - - line_to_patch = 'if not vars.get("Py_ENABLE_SHARED", 0):' - for index, line in enumerate(lines): - if line_to_patch in line: - indent = line[:line.index(line_to_patch)] - lines[index] = indent + 'if True:\n' - print('Patched line %d' % (index + 1)) - break - else: - sys.exit('Could not find line in setup.py to patch!') - - with open(setup_py_filename, 'w') as f: - f.writelines(lines) - - os.chdir('%s/%s' % (rootdir, basename)) - res = os.system('python setup.py install') - if res != 0: - sys.exit(res) - - sys.exit(0) diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/cx_freeze/runtests_setup.py b/tests/wpt/web-platform-tests/tools/pytest/testing/cx_freeze/runtests_setup.py deleted file mode 100644 index a2874a655eb..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/cx_freeze/runtests_setup.py +++ /dev/null @@ -1,15 +0,0 @@ -""" -Sample setup.py script that generates an executable with pytest runner embedded. -""" -if __name__ == '__main__': - from cx_Freeze import setup, Executable - import pytest - - setup( - name="runtests", - version="0.1", - description="exemple of how embedding py.test into an executable using cx_freeze", - executables=[Executable("runtests_script.py")], - options={"build_exe": {'includes': pytest.freeze_includes()}}, - ) - diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/cx_freeze/tox_run.py b/tests/wpt/web-platform-tests/tools/pytest/testing/cx_freeze/tox_run.py deleted file mode 100644 index e8df2684bb1..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/cx_freeze/tox_run.py +++ /dev/null @@ -1,15 +0,0 @@ -""" -Called by tox.ini: uses the generated executable to run the tests in ./tests/ -directory. - -.. note:: somehow calling "build/runtests_script" directly from tox doesn't - seem to work (at least on Windows). -""" -if __name__ == '__main__': - import os - import sys - - executable = os.path.join(os.getcwd(), 'build', 'runtests_script') - if sys.platform.startswith('win'): - executable += '.exe' - sys.exit(os.system('%s tests' % executable)) \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_assertinterpret.py b/tests/wpt/web-platform-tests/tools/pytest/testing/test_assertinterpret.py deleted file mode 100644 index 67a352ce7f5..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_assertinterpret.py +++ /dev/null @@ -1,274 +0,0 @@ -"PYTEST_DONT_REWRITE" -import py -import pytest -from _pytest.assertion import util - - -def exvalue(): - return py.std.sys.exc_info()[1] - -def f(): - return 2 - -def test_not_being_rewritten(): - assert "@py_builtins" not in globals() - -def test_assert(): - try: - assert f() == 3 - except AssertionError: - e = exvalue() - s = str(e) - assert s.startswith('assert 2 == 3\n') - -def test_assert_with_explicit_message(): - try: - assert f() == 3, "hello" - except AssertionError: - e = exvalue() - assert e.msg == 'hello' - -def test_assert_within_finally(): - excinfo = pytest.raises(ZeroDivisionError, """ - try: - 1/0 - finally: - i = 42 - """) - s = excinfo.exconly() - assert py.std.re.search("division.+by zero", s) is not None - - #def g(): - # A.f() - #excinfo = getexcinfo(TypeError, g) - #msg = getmsg(excinfo) - #assert msg.find("must be called with A") != -1 - - -def test_assert_multiline_1(): - try: - assert (f() == - 3) - except AssertionError: - e = exvalue() - s = str(e) - assert s.startswith('assert 2 == 3\n') - -def test_assert_multiline_2(): - try: - assert (f() == (4, - 3)[-1]) - except AssertionError: - e = exvalue() - s = str(e) - assert s.startswith('assert 2 ==') - -def test_in(): - try: - assert "hi" in [1, 2] - except AssertionError: - e = exvalue() - s = str(e) - assert s.startswith("assert 'hi' in") - -def test_is(): - try: - assert 1 is 2 - except AssertionError: - e = exvalue() - s = str(e) - assert s.startswith("assert 1 is 2") - - -def test_attrib(): - class Foo(object): - b = 1 - i = Foo() - try: - assert i.b == 2 - except AssertionError: - e = exvalue() - s = str(e) - assert s.startswith("assert 1 == 2") - -def test_attrib_inst(): - class Foo(object): - b = 1 - try: - assert Foo().b == 2 - except AssertionError: - e = exvalue() - s = str(e) - assert s.startswith("assert 1 == 2") - -def test_len(): - l = list(range(42)) - try: - assert len(l) == 100 - except AssertionError: - e = exvalue() - s = str(e) - assert s.startswith("assert 42 == 100") - assert "where 42 = len([" in s - -def test_assert_non_string_message(): - class A: - def __str__(self): - return "hello" - try: - assert 0 == 1, A() - except AssertionError: - e = exvalue() - assert e.msg == "hello" - -def test_assert_keyword_arg(): - def f(x=3): - return False - try: - assert f(x=5) - except AssertionError: - e = exvalue() - assert "x=5" in e.msg - -def test_private_class_variable(): - class X: - def __init__(self): - self.__v = 41 - def m(self): - assert self.__v == 42 - try: - X().m() - except AssertionError: - e = exvalue() - assert "== 42" in e.msg - -# These tests should both fail, but should fail nicely... -class WeirdRepr: - def __repr__(self): - return '' - -def bug_test_assert_repr(): - v = WeirdRepr() - try: - assert v == 1 - except AssertionError: - e = exvalue() - assert e.msg.find('WeirdRepr') != -1 - assert e.msg.find('second line') != -1 - assert 0 - -def test_assert_non_string(): - try: - assert 0, ['list'] - except AssertionError: - e = exvalue() - assert e.msg.find("list") != -1 - -def test_assert_implicit_multiline(): - try: - x = [1,2,3] - assert x != [1, - 2, 3] - except AssertionError: - e = exvalue() - assert e.msg.find('assert [1, 2, 3] !=') != -1 - - -def test_assert_with_brokenrepr_arg(): - class BrokenRepr: - def __repr__(self): 0 / 0 - e = AssertionError(BrokenRepr()) - if e.msg.find("broken __repr__") == -1: - pytest.fail("broken __repr__ not handle correctly") - -def test_multiple_statements_per_line(): - try: - a = 1; assert a == 2 - except AssertionError: - e = exvalue() - assert "assert 1 == 2" in e.msg - -def test_power(): - try: - assert 2**3 == 7 - except AssertionError: - e = exvalue() - assert "assert (2 ** 3) == 7" in e.msg - - -def test_assert_customizable_reprcompare(monkeypatch): - monkeypatch.setattr(util, '_reprcompare', lambda *args: 'hello') - try: - assert 3 == 4 - except AssertionError: - e = exvalue() - s = str(e) - assert "hello" in s - -def test_assert_long_source_1(): - try: - assert len == [ - (None, ['somet text', 'more text']), - ] - except AssertionError: - e = exvalue() - s = str(e) - assert 're-run' not in s - assert 'somet text' in s - -def test_assert_long_source_2(): - try: - assert(len == [ - (None, ['somet text', 'more text']), - ]) - except AssertionError: - e = exvalue() - s = str(e) - assert 're-run' not in s - assert 'somet text' in s - -def test_assert_raise_alias(testdir): - testdir.makepyfile(""" - "PYTEST_DONT_REWRITE" - import sys - EX = AssertionError - def test_hello(): - raise EX("hello" - "multi" - "line") - """) - result = testdir.runpytest() - result.stdout.fnmatch_lines([ - "*def test_hello*", - "*raise EX*", - "*1 failed*", - ]) - - -def test_assert_raise_subclass(): - class SomeEx(AssertionError): - def __init__(self, *args): - super(SomeEx, self).__init__() - try: - raise SomeEx("hello") - except AssertionError: - s = str(exvalue()) - assert 're-run' not in s - assert 'could not determine' in s - -def test_assert_raises_in_nonzero_of_object_pytest_issue10(): - class A(object): - def __nonzero__(self): - raise ValueError(42) - def __lt__(self, other): - return A() - def __repr__(self): - return "" - def myany(x): - return True - try: - assert not(myany(A() < 0)) - except AssertionError: - e = exvalue() - s = str(e) - assert " < 0" in s diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_assertion.py b/tests/wpt/web-platform-tests/tools/pytest/testing/test_assertion.py deleted file mode 100644 index 347278e1904..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_assertion.py +++ /dev/null @@ -1,628 +0,0 @@ -# -*- coding: utf-8 -*- -import sys -import textwrap - -import _pytest.assertion as plugin -import _pytest._code -import py -import pytest -from _pytest.assertion import reinterpret -from _pytest.assertion import util - -PY3 = sys.version_info >= (3, 0) - - -@pytest.fixture -def mock_config(): - class Config(object): - verbose = False - def getoption(self, name): - if name == 'verbose': - return self.verbose - raise KeyError('Not mocked out: %s' % name) - return Config() - - -def interpret(expr): - return reinterpret.reinterpret(expr, _pytest._code.Frame(sys._getframe(1))) - -class TestBinReprIntegration: - - def test_pytest_assertrepr_compare_called(self, testdir): - testdir.makeconftest(""" - l = [] - def pytest_assertrepr_compare(op, left, right): - l.append((op, left, right)) - def pytest_funcarg__l(request): - return l - """) - testdir.makepyfile(""" - def test_hello(): - assert 0 == 1 - def test_check(l): - assert l == [("==", 0, 1)] - """) - result = testdir.runpytest("-v") - result.stdout.fnmatch_lines([ - "*test_hello*FAIL*", - "*test_check*PASS*", - ]) - -def callequal(left, right, verbose=False): - config = mock_config() - config.verbose = verbose - return plugin.pytest_assertrepr_compare(config, '==', left, right) - - -class TestAssert_reprcompare: - def test_different_types(self): - assert callequal([0, 1], 'foo') is None - - def test_summary(self): - summary = callequal([0, 1], [0, 2])[0] - assert len(summary) < 65 - - def test_text_diff(self): - diff = callequal('spam', 'eggs')[1:] - assert '- spam' in diff - assert '+ eggs' in diff - - def test_text_skipping(self): - lines = callequal('a'*50 + 'spam', 'a'*50 + 'eggs') - assert 'Skipping' in lines[1] - for line in lines: - assert 'a'*50 not in line - - def test_text_skipping_verbose(self): - lines = callequal('a'*50 + 'spam', 'a'*50 + 'eggs', verbose=True) - assert '- ' + 'a'*50 + 'spam' in lines - assert '+ ' + 'a'*50 + 'eggs' in lines - - def test_multiline_text_diff(self): - left = 'foo\nspam\nbar' - right = 'foo\neggs\nbar' - diff = callequal(left, right) - assert '- spam' in diff - assert '+ eggs' in diff - - def test_list(self): - expl = callequal([0, 1], [0, 2]) - assert len(expl) > 1 - - @pytest.mark.parametrize( - ['left', 'right', 'expected'], [ - ([0, 1], [0, 2], """ - Full diff: - - [0, 1] - ? ^ - + [0, 2] - ? ^ - """), - ({0: 1}, {0: 2}, """ - Full diff: - - {0: 1} - ? ^ - + {0: 2} - ? ^ - """), - (set([0, 1]), set([0, 2]), """ - Full diff: - - set([0, 1]) - ? ^ - + set([0, 2]) - ? ^ - """ if not PY3 else """ - Full diff: - - {0, 1} - ? ^ - + {0, 2} - ? ^ - """) - ] - ) - def test_iterable_full_diff(self, left, right, expected): - """Test the full diff assertion failure explanation. - - When verbose is False, then just a -v notice to get the diff is rendered, - when verbose is True, then ndiff of the pprint is returned. - """ - expl = callequal(left, right, verbose=False) - assert expl[-1] == 'Use -v to get the full diff' - expl = '\n'.join(callequal(left, right, verbose=True)) - assert expl.endswith(textwrap.dedent(expected).strip()) - - def test_list_different_lenghts(self): - expl = callequal([0, 1], [0, 1, 2]) - assert len(expl) > 1 - expl = callequal([0, 1, 2], [0, 1]) - assert len(expl) > 1 - - def test_dict(self): - expl = callequal({'a': 0}, {'a': 1}) - assert len(expl) > 1 - - def test_dict_omitting(self): - lines = callequal({'a': 0, 'b': 1}, {'a': 1, 'b': 1}) - assert lines[1].startswith('Omitting 1 identical item') - assert 'Common items' not in lines - for line in lines[1:]: - assert 'b' not in line - - def test_dict_omitting_verbose(self): - lines = callequal({'a': 0, 'b': 1}, {'a': 1, 'b': 1}, verbose=True) - assert lines[1].startswith('Common items:') - assert 'Omitting' not in lines[1] - assert lines[2] == "{'b': 1}" - - def test_set(self): - expl = callequal(set([0, 1]), set([0, 2])) - assert len(expl) > 1 - - def test_frozenzet(self): - expl = callequal(frozenset([0, 1]), set([0, 2])) - assert len(expl) > 1 - - def test_Sequence(self): - col = py.builtin._tryimport( - "collections.abc", - "collections", - "sys") - if not hasattr(col, "MutableSequence"): - pytest.skip("cannot import MutableSequence") - MutableSequence = col.MutableSequence - - class TestSequence(MutableSequence): # works with a Sequence subclass - def __init__(self, iterable): - self.elements = list(iterable) - - def __getitem__(self, item): - return self.elements[item] - - def __len__(self): - return len(self.elements) - - def __setitem__(self, item, value): - pass - - def __delitem__(self, item): - pass - - def insert(self, item, index): - pass - - expl = callequal(TestSequence([0, 1]), list([0, 2])) - assert len(expl) > 1 - - def test_list_tuples(self): - expl = callequal([], [(1,2)]) - assert len(expl) > 1 - expl = callequal([(1,2)], []) - assert len(expl) > 1 - - def test_list_bad_repr(self): - class A: - def __repr__(self): - raise ValueError(42) - expl = callequal([], [A()]) - assert 'ValueError' in "".join(expl) - expl = callequal({}, {'1': A()}) - assert 'faulty' in "".join(expl) - - def test_one_repr_empty(self): - """ - the faulty empty string repr did trigger - a unbound local error in _diff_text - """ - class A(str): - def __repr__(self): - return '' - expl = callequal(A(), '') - assert not expl - - def test_repr_no_exc(self): - expl = ' '.join(callequal('foo', 'bar')) - assert 'raised in repr()' not in expl - - def test_unicode(self): - left = py.builtin._totext('£€', 'utf-8') - right = py.builtin._totext('£', 'utf-8') - expl = callequal(left, right) - assert expl[0] == py.builtin._totext("'£€' == '£'", 'utf-8') - assert expl[1] == py.builtin._totext('- £€', 'utf-8') - assert expl[2] == py.builtin._totext('+ £', 'utf-8') - - def test_nonascii_text(self): - """ - :issue: 877 - non ascii python2 str caused a UnicodeDecodeError - """ - class A(str): - def __repr__(self): - return '\xff' - expl = callequal(A(), '1') - assert expl - - def test_format_nonascii_explanation(self): - assert util.format_explanation('λ') - - def test_mojibake(self): - # issue 429 - left = 'e' - right = '\xc3\xa9' - if not isinstance(left, py.builtin.bytes): - left = py.builtin.bytes(left, 'utf-8') - right = py.builtin.bytes(right, 'utf-8') - expl = callequal(left, right) - for line in expl: - assert isinstance(line, py.builtin.text) - msg = py.builtin._totext('\n').join(expl) - assert msg - - -class TestFormatExplanation: - - def test_special_chars_full(self, testdir): - # Issue 453, for the bug this would raise IndexError - testdir.makepyfile(""" - def test_foo(): - assert '\\n}' == '' - """) - result = testdir.runpytest() - assert result.ret == 1 - result.stdout.fnmatch_lines([ - "*AssertionError*", - ]) - - def test_fmt_simple(self): - expl = 'assert foo' - assert util.format_explanation(expl) == 'assert foo' - - def test_fmt_where(self): - expl = '\n'.join(['assert 1', - '{1 = foo', - '} == 2']) - res = '\n'.join(['assert 1 == 2', - ' + where 1 = foo']) - assert util.format_explanation(expl) == res - - def test_fmt_and(self): - expl = '\n'.join(['assert 1', - '{1 = foo', - '} == 2', - '{2 = bar', - '}']) - res = '\n'.join(['assert 1 == 2', - ' + where 1 = foo', - ' + and 2 = bar']) - assert util.format_explanation(expl) == res - - def test_fmt_where_nested(self): - expl = '\n'.join(['assert 1', - '{1 = foo', - '{foo = bar', - '}', - '} == 2']) - res = '\n'.join(['assert 1 == 2', - ' + where 1 = foo', - ' + where foo = bar']) - assert util.format_explanation(expl) == res - - def test_fmt_newline(self): - expl = '\n'.join(['assert "foo" == "bar"', - '~- foo', - '~+ bar']) - res = '\n'.join(['assert "foo" == "bar"', - ' - foo', - ' + bar']) - assert util.format_explanation(expl) == res - - def test_fmt_newline_escaped(self): - expl = '\n'.join(['assert foo == bar', - 'baz']) - res = 'assert foo == bar\\nbaz' - assert util.format_explanation(expl) == res - - def test_fmt_newline_before_where(self): - expl = '\n'.join(['the assertion message here', - '>assert 1', - '{1 = foo', - '} == 2', - '{2 = bar', - '}']) - res = '\n'.join(['the assertion message here', - 'assert 1 == 2', - ' + where 1 = foo', - ' + and 2 = bar']) - assert util.format_explanation(expl) == res - - def test_fmt_multi_newline_before_where(self): - expl = '\n'.join(['the assertion', - '~message here', - '>assert 1', - '{1 = foo', - '} == 2', - '{2 = bar', - '}']) - res = '\n'.join(['the assertion', - ' message here', - 'assert 1 == 2', - ' + where 1 = foo', - ' + and 2 = bar']) - assert util.format_explanation(expl) == res - - -def test_python25_compile_issue257(testdir): - testdir.makepyfile(""" - def test_rewritten(): - assert 1 == 2 - # some comment - """) - result = testdir.runpytest() - assert result.ret == 1 - result.stdout.fnmatch_lines(""" - *E*assert 1 == 2* - *1 failed* - """) - -def test_rewritten(testdir): - testdir.makepyfile(""" - def test_rewritten(): - assert "@py_builtins" in globals() - """) - assert testdir.runpytest().ret == 0 - -def test_reprcompare_notin(mock_config): - detail = plugin.pytest_assertrepr_compare( - mock_config, 'not in', 'foo', 'aaafoobbb')[1:] - assert detail == ["'foo' is contained here:", ' aaafoobbb', '? +++'] - -def test_pytest_assertrepr_compare_integration(testdir): - testdir.makepyfile(""" - def test_hello(): - x = set(range(100)) - y = x.copy() - y.remove(50) - assert x == y - """) - result = testdir.runpytest() - result.stdout.fnmatch_lines([ - "*def test_hello():*", - "*assert x == y*", - "*E*Extra items*left*", - "*E*50*", - ]) - -def test_sequence_comparison_uses_repr(testdir): - testdir.makepyfile(""" - def test_hello(): - x = set("hello x") - y = set("hello y") - assert x == y - """) - result = testdir.runpytest() - result.stdout.fnmatch_lines([ - "*def test_hello():*", - "*assert x == y*", - "*E*Extra items*left*", - "*E*'x'*", - "*E*Extra items*right*", - "*E*'y'*", - ]) - - -def test_assert_compare_truncate_longmessage(monkeypatch, testdir): - testdir.makepyfile(r""" - def test_long(): - a = list(range(200)) - b = a[::2] - a = '\n'.join(map(str, a)) - b = '\n'.join(map(str, b)) - assert a == b - """) - monkeypatch.delenv('CI', raising=False) - - result = testdir.runpytest() - # without -vv, truncate the message showing a few diff lines only - result.stdout.fnmatch_lines([ - "*- 1", - "*- 3", - "*- 5", - "*- 7", - "*truncated (191 more lines)*use*-vv*", - ]) - - - result = testdir.runpytest('-vv') - result.stdout.fnmatch_lines([ - "*- 197", - ]) - - monkeypatch.setenv('CI', '1') - result = testdir.runpytest() - result.stdout.fnmatch_lines([ - "*- 197", - ]) - - -def test_assertrepr_loaded_per_dir(testdir): - testdir.makepyfile(test_base=['def test_base(): assert 1 == 2']) - a = testdir.mkdir('a') - a_test = a.join('test_a.py') - a_test.write('def test_a(): assert 1 == 2') - a_conftest = a.join('conftest.py') - a_conftest.write('def pytest_assertrepr_compare(): return ["summary a"]') - b = testdir.mkdir('b') - b_test = b.join('test_b.py') - b_test.write('def test_b(): assert 1 == 2') - b_conftest = b.join('conftest.py') - b_conftest.write('def pytest_assertrepr_compare(): return ["summary b"]') - result = testdir.runpytest() - result.stdout.fnmatch_lines([ - '*def test_base():*', - '*E*assert 1 == 2*', - '*def test_a():*', - '*E*assert summary a*', - '*def test_b():*', - '*E*assert summary b*']) - - -def test_assertion_options(testdir): - testdir.makepyfile(""" - def test_hello(): - x = 3 - assert x == 4 - """) - result = testdir.runpytest() - assert "3 == 4" in result.stdout.str() - off_options = (("--no-assert",), - ("--nomagic",), - ("--no-assert", "--nomagic"), - ("--assert=plain",), - ("--assert=plain", "--no-assert"), - ("--assert=plain", "--nomagic"), - ("--assert=plain", "--no-assert", "--nomagic")) - for opt in off_options: - result = testdir.runpytest_subprocess(*opt) - assert "3 == 4" not in result.stdout.str() - -def test_old_assert_mode(testdir): - testdir.makepyfile(""" - def test_in_old_mode(): - assert "@py_builtins" not in globals() - """) - result = testdir.runpytest_subprocess("--assert=reinterp") - assert result.ret == 0 - -def test_triple_quoted_string_issue113(testdir): - testdir.makepyfile(""" - def test_hello(): - assert "" == ''' - '''""") - result = testdir.runpytest("--fulltrace") - result.stdout.fnmatch_lines([ - "*1 failed*", - ]) - assert 'SyntaxError' not in result.stdout.str() - -def test_traceback_failure(testdir): - p1 = testdir.makepyfile(""" - def g(): - return 2 - def f(x): - assert x == g() - def test_onefails(): - f(3) - """) - result = testdir.runpytest(p1, "--tb=long") - result.stdout.fnmatch_lines([ - "*test_traceback_failure.py F", - "====* FAILURES *====", - "____*____", - "", - " def test_onefails():", - "> f(3)", - "", - "*test_*.py:6: ", - "_ _ _ *", - #"", - " def f(x):", - "> assert x == g()", - "E assert 3 == 2", - "E + where 2 = g()", - "", - "*test_traceback_failure.py:4: AssertionError" - ]) - - result = testdir.runpytest(p1) # "auto" - result.stdout.fnmatch_lines([ - "*test_traceback_failure.py F", - "====* FAILURES *====", - "____*____", - "", - " def test_onefails():", - "> f(3)", - "", - "*test_*.py:6: ", - "", - " def f(x):", - "> assert x == g()", - "E assert 3 == 2", - "E + where 2 = g()", - "", - "*test_traceback_failure.py:4: AssertionError" - ]) - -@pytest.mark.skipif("'__pypy__' in sys.builtin_module_names or sys.platform.startswith('java')" ) -def test_warn_missing(testdir): - testdir.makepyfile("") - result = testdir.run(sys.executable, "-OO", "-m", "pytest", "-h") - result.stderr.fnmatch_lines([ - "*WARNING*assert statements are not executed*", - ]) - result = testdir.run(sys.executable, "-OO", "-m", "pytest", "--no-assert") - result.stderr.fnmatch_lines([ - "*WARNING*assert statements are not executed*", - ]) - -def test_recursion_source_decode(testdir): - testdir.makepyfile(""" - def test_something(): - pass - """) - testdir.makeini(""" - [pytest] - python_files = *.py - """) - result = testdir.runpytest("--collect-only") - result.stdout.fnmatch_lines(""" - - """) - -def test_AssertionError_message(testdir): - testdir.makepyfile(""" - def test_hello(): - x,y = 1,2 - assert 0, (x,y) - """) - result = testdir.runpytest() - result.stdout.fnmatch_lines(""" - *def test_hello* - *assert 0, (x,y)* - *AssertionError: (1, 2)* - """) - -@pytest.mark.skipif(PY3, reason='This bug does not exist on PY3') -def test_set_with_unsortable_elements(): - # issue #718 - class UnsortableKey(object): - def __init__(self, name): - self.name = name - - def __lt__(self, other): - raise RuntimeError() - - def __repr__(self): - return 'repr({0})'.format(self.name) - - def __eq__(self, other): - return self.name == other.name - - def __hash__(self): - return hash(self.name) - - left_set = set(UnsortableKey(str(i)) for i in range(1, 3)) - right_set = set(UnsortableKey(str(i)) for i in range(2, 4)) - expl = callequal(left_set, right_set, verbose=True) - # skip first line because it contains the "construction" of the set, which does not have a guaranteed order - expl = expl[1:] - dedent = textwrap.dedent(""" - Extra items in the left set: - repr(1) - Extra items in the right set: - repr(3) - Full diff (fallback to calling repr on each item): - - repr(1) - repr(2) - + repr(3) - """).strip() - assert '\n'.join(expl) == dedent diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_genscript.py b/tests/wpt/web-platform-tests/tools/pytest/testing/test_genscript.py deleted file mode 100644 index 1260a5a6b26..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_genscript.py +++ /dev/null @@ -1,51 +0,0 @@ -import pytest -import sys - - -@pytest.fixture(scope="module") -def standalone(request): - return Standalone(request) - -class Standalone: - def __init__(self, request): - self.testdir = request.getfuncargvalue("testdir") - script = "mypytest" - result = self.testdir.runpytest("--genscript=%s" % script) - assert result.ret == 0 - self.script = self.testdir.tmpdir.join(script) - assert self.script.check() - - def run(self, anypython, testdir, *args): - return testdir._run(anypython, self.script, *args) - -def test_gen(testdir, anypython, standalone): - if sys.version_info >= (2,7): - result = testdir._run(anypython, "-c", - "import sys;print (sys.version_info >=(2,7))") - assert result.ret == 0 - if result.stdout.str() == "False": - pytest.skip("genscript called from python2.7 cannot work " - "earlier python versions") - result = standalone.run(anypython, testdir, '--version') - if result.ret == 2: - result.stderr.fnmatch_lines(["*ERROR: setuptools not installed*"]) - elif result.ret == 0: - result.stderr.fnmatch_lines([ - "*imported from*mypytest*" - ]) - p = testdir.makepyfile("def test_func(): assert 0") - result = standalone.run(anypython, testdir, p) - assert result.ret != 0 - else: - pytest.fail("Unexpected return code") - - -def test_freeze_includes(): - """ - Smoke test for freeze_includes(), to ensure that it works across all - supported python versions. - """ - includes = pytest.freeze_includes() - assert len(includes) > 1 - assert '_pytest.genscript' in includes - diff --git a/tests/wpt/web-platform-tests/tools/pytest/tox.ini b/tests/wpt/web-platform-tests/tools/pytest/tox.ini deleted file mode 100644 index 5f65446e42b..00000000000 --- a/tests/wpt/web-platform-tests/tools/pytest/tox.ini +++ /dev/null @@ -1,160 +0,0 @@ -[tox] -minversion=2.0 -distshare={homedir}/.tox/distshare -envlist= - linting,py26,py27,py33,py34,py35,pypy, - {py27,py35}-{pexpect,xdist,trial}, - py27-nobyte,doctesting,py27-cxfreeze - -[testenv] -commands= py.test --lsof -rfsxX {posargs:testing} -passenv = USER USERNAME -deps= - nose - mock - requests - -[testenv:py26] -commands= py.test --lsof -rfsxX {posargs:testing} -deps= - nose - mock<1.1 # last supported version for py26 - -[testenv:py27-subprocess] -changedir=. -basepython=python2.7 -deps=pytest-xdist>=1.13 - mock - nose -commands= - py.test -n3 -rfsxX --runpytest=subprocess {posargs:testing} - -[testenv:genscript] -commands= py.test --genscript=pytest1 - -[testenv:linting] -basepython = python2.7 -deps = flake8 - restructuredtext_lint -commands = flake8 pytest.py _pytest testing - rst-lint CHANGELOG.rst - -[testenv:py27-xdist] -deps=pytest-xdist>=1.13 - mock - nose -commands= - py.test -n1 -rfsxX {posargs:testing} - -[testenv:py35-xdist] -deps={[testenv:py27-xdist]deps} -commands= - py.test -n3 -rfsxX {posargs:testing} - -[testenv:py27-pexpect] -changedir=testing -platform=linux|darwin -deps=pexpect -commands= - py.test -rfsxX test_pdb.py test_terminal.py test_unittest.py - -[testenv:py35-pexpect] -changedir=testing -platform=linux|darwin -deps={[testenv:py27-pexpect]deps} -commands= - py.test -rfsxX test_pdb.py test_terminal.py test_unittest.py - -[testenv:py27-nobyte] -deps=pytest-xdist>=1.13 -distribute=true -setenv= - PYTHONDONTWRITEBYTECODE=1 -commands= - py.test -n3 -rfsxX {posargs:testing} - -[testenv:py27-trial] -deps=twisted -commands= - py.test -rsxf {posargs:testing/test_unittest.py} - -[testenv:py35-trial] -platform=linux|darwin -deps={[testenv:py27-trial]deps} -commands= - py.test -rsxf {posargs:testing/test_unittest.py} - -[testenv:doctest] -commands=py.test --doctest-modules _pytest -deps= - -[testenv:doc] -basepython=python -changedir=doc/en -deps=sphinx - PyYAML - -commands= - make clean - make html - -[testenv:doctesting] -basepython = python3.4 -changedir=doc/en -deps=PyYAML -commands= py.test -rfsxX {posargs} - -[testenv:regen] -changedir=doc/en -basepython = python3.4 -deps=sphinx - PyYAML - regendoc>=0.6.1 -whitelist_externals= - rm - make -commands= - rm -rf /tmp/doc-exec* - make regen - -[testenv:jython] -changedir=testing -commands= - {envpython} {envbindir}/py.test-jython -rfsxX {posargs} - -[testenv:py27-cxfreeze] -changedir=testing/cx_freeze -platform=linux|darwin -commands= - {envpython} install_cx_freeze.py - {envpython} runtests_setup.py build --build-exe build - {envpython} tox_run.py - - -[testenv:coveralls] -passenv = TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH COVERALLS_REPO_TOKEN -usedevelop=True -basepython=python3.4 -changedir=. -deps = - {[testenv]deps} - coveralls -commands= - coverage run --source=_pytest -m pytest testing - coverage report -m - coveralls - -[pytest] -minversion=2.0 -plugins=pytester -#--pyargs --doctest-modules --ignore=.tox -addopts= -rxsX -p pytester --ignore=testing/cx_freeze -rsyncdirs=tox.ini pytest.py _pytest testing -python_files=test_*.py *_test.py testing/*/*.py -python_classes=Test Acceptance -python_functions=test -norecursedirs = .tox ja .hg cx_freeze_source - - -[flake8] -ignore =E401,E225,E261,E128,E124,E301,E302,E121,E303,W391,E501,E231,E126,E701,E265,E241,E251,E226,E101,W191,E131,E203,E122,E123,E271,E712,E222,E127,E125,E221,W292,E111,E113,E293,E262,W293,E129,E702,E201,E272,E202,E704,E731,E402 diff --git a/tests/wpt/web-platform-tests/tools/serve/serve.py b/tests/wpt/web-platform-tests/tools/serve/serve.py index 74b9b7e55b7..c77badc2682 100644 --- a/tests/wpt/web-platform-tests/tools/serve/serve.py +++ b/tests/wpt/web-platform-tests/tools/serve/serve.py @@ -383,19 +383,19 @@ class ServerProc(object): self.daemon = None self.stop = Event() - def start(self, init_func, host, port, paths, routes, bind_hostname, external_config, + def start(self, init_func, host, port, paths, routes, bind_hostname, config, ssl_config, **kwargs): self.proc = Process(target=self.create_daemon, args=(init_func, host, port, paths, routes, bind_hostname, - external_config, ssl_config), + config, ssl_config), kwargs=kwargs) self.proc.daemon = True self.proc.start() def create_daemon(self, init_func, host, port, paths, routes, bind_hostname, - external_config, ssl_config, **kwargs): + config, ssl_config, **kwargs): try: - self.daemon = init_func(host, port, paths, routes, bind_hostname, external_config, + self.daemon = init_func(host, port, paths, routes, bind_hostname, config, ssl_config, **kwargs) except socket.error: print("Socket error on port %s" % port, file=sys.stderr) @@ -446,7 +446,8 @@ def check_subdomains(host, paths, bind_hostname, ssl_config, aliases): time.sleep(1) if not connected: - logger.critical("Failed to connect to test server on http://%s:%s You may need to edit /etc/hosts or similar" % (host, port)) + logger.critical("Failed to connect to test server on http://%s:%s. " + "You may need to edit /etc/hosts or similar, see README.md." % (host, port)) sys.exit(1) for subdomain, (punycode, host) in subdomains.iteritems(): @@ -454,7 +455,8 @@ def check_subdomains(host, paths, bind_hostname, ssl_config, aliases): try: urllib2.urlopen("http://%s:%d/" % (domain, port)) except Exception as e: - logger.critical("Failed probing domain %s. You may need to edit /etc/hosts or similar." % domain) + logger.critical("Failed probing domain %s. " + "You may need to edit /etc/hosts or similar, see README.md." % domain) sys.exit(1) wrapper.wait() @@ -466,7 +468,7 @@ def get_subdomains(host): for subdomain in subdomains} -def start_servers(host, ports, paths, routes, bind_hostname, external_config, ssl_config, +def start_servers(host, ports, paths, routes, bind_hostname, config, ssl_config, **kwargs): servers = defaultdict(list) for scheme, ports in ports.iteritems(): @@ -482,13 +484,13 @@ def start_servers(host, ports, paths, routes, bind_hostname, external_config, ss server_proc = ServerProc() server_proc.start(init_func, host, port, paths, routes, bind_hostname, - external_config, ssl_config, **kwargs) + config, ssl_config, **kwargs) servers[scheme].append((port, server_proc)) return servers -def start_http_server(host, port, paths, routes, bind_hostname, external_config, ssl_config, +def start_http_server(host, port, paths, routes, bind_hostname, config, ssl_config, **kwargs): return wptserve.WebTestHttpd(host=host, port=port, @@ -496,14 +498,14 @@ def start_http_server(host, port, paths, routes, bind_hostname, external_config, routes=routes, rewrites=rewrites, bind_hostname=bind_hostname, - config=external_config, + config=config, use_ssl=False, key_file=None, certificate=None, latency=kwargs.get("latency")) -def start_https_server(host, port, paths, routes, bind_hostname, external_config, ssl_config, +def start_https_server(host, port, paths, routes, bind_hostname, config, ssl_config, **kwargs): return wptserve.WebTestHttpd(host=host, port=port, @@ -511,7 +513,7 @@ def start_https_server(host, port, paths, routes, bind_hostname, external_config routes=routes, rewrites=rewrites, bind_hostname=bind_hostname, - config=external_config, + config=config, use_ssl=True, key_file=ssl_config["key_path"], certificate=ssl_config["cert_path"], @@ -584,7 +586,7 @@ class WebSocketDaemon(object): self.server = None -def start_ws_server(host, port, paths, routes, bind_hostname, external_config, ssl_config, +def start_ws_server(host, port, paths, routes, bind_hostname, config, ssl_config, **kwargs): return WebSocketDaemon(host, str(port), @@ -595,7 +597,7 @@ def start_ws_server(host, port, paths, routes, bind_hostname, external_config, s ssl_config = None) -def start_wss_server(host, port, paths, routes, bind_hostname, external_config, ssl_config, +def start_wss_server(host, port, paths, routes, bind_hostname, config, ssl_config, **kwargs): return WebSocketDaemon(host, str(port), @@ -637,12 +639,22 @@ def normalise_config(config, ports): for scheme, ports_used in ports.iteritems(): ports_[scheme] = ports_used - return {"host": host, - "domains": domains, - "ports": ports_} + # make a (shallow) copy of the config and update that, so that the + # normalized config can be used in place of the original one. + config_ = config.copy() + config_["host"] = host + config_["domains"] = domains + config_["ports"] = ports_ + return config_ -def get_ssl_config(config, external_domains, ssl_environment): +def get_paths(config): + return {"doc_root": config["doc_root"], + "ws_doc_root": config["ws_doc_root"]} + + +def get_ssl_config(config, ssl_environment): + external_domains = config["domains"].values() key_path, cert_path = ssl_environment.host_cert_path(external_domains) return {"key_path": key_path, "cert_path": cert_path, @@ -650,24 +662,15 @@ def get_ssl_config(config, external_domains, ssl_environment): def start(config, ssl_environment, routes, **kwargs): host = config["host"] - domains = get_subdomains(host) ports = get_ports(config, ssl_environment) + paths = get_paths(config) bind_hostname = config["bind_hostname"] + ssl_config = get_ssl_config(config, ssl_environment) - paths = {"doc_root": config["doc_root"], - "ws_doc_root": config["ws_doc_root"]} - - external_config = normalise_config(config, ports) - - ssl_config = get_ssl_config(config, external_config["domains"].values(), ssl_environment) - - if config["check_subdomains"]: - check_subdomains(host, paths, bind_hostname, ssl_config, config["aliases"]) - - servers = start_servers(host, ports, paths, routes, bind_hostname, external_config, + servers = start_servers(host, ports, paths, routes, bind_hostname, config, ssl_config, **kwargs) - return external_config, servers + return servers def iter_procs(servers): @@ -778,13 +781,23 @@ def run(**kwargs): setup_logger(config["log_level"]) - stash_address = None - if config["bind_hostname"]: - stash_address = (config["host"], get_port()) + with get_ssl_environment(config) as ssl_env: + ports = get_ports(config, ssl_env) + config = normalise_config(config, ports) + host = config["host"] + bind_hostname = config["bind_hostname"] - with stash.StashServer(stash_address, authkey=str(uuid.uuid4())): - with get_ssl_environment(config) as ssl_env: - config_, servers = start(config, ssl_env, build_routes(config["aliases"]), **kwargs) + if config["check_subdomains"]: + paths = get_paths(config) + ssl_config = get_ssl_config(config, ssl_env) + check_subdomains(host, paths, bind_hostname, ssl_config, config["aliases"]) + + stash_address = None + if bind_hostname: + stash_address = (host, get_port()) + + with stash.StashServer(stash_address, authkey=str(uuid.uuid4())): + servers = start(config, ssl_env, build_routes(config["aliases"]), **kwargs) try: while any(item.is_alive() for item in iter_procs(servers)): diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/.gitignore b/tests/wpt/web-platform-tests/tools/third_party/attrs/.gitignore new file mode 100644 index 00000000000..a4ca3f8cef7 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/.gitignore @@ -0,0 +1,9 @@ +.tox +.coverage* +*.pyc +*.egg-info +docs/_build/ +htmlcov +dist +.cache +.hypothesis \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/.travis.yml b/tests/wpt/web-platform-tests/tools/third_party/attrs/.travis.yml new file mode 100644 index 00000000000..4f1cf2f60b0 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/.travis.yml @@ -0,0 +1,56 @@ +dist: trusty +sudo: false +cache: + directories: + - $HOME/.cache/pip + +language: python + + +matrix: + include: + - python: "2.7" + env: TOXENV=py27 + - python: "3.4" + env: TOXENV=py34 + - python: "3.5" + env: TOXENV=py35 + - python: "3.6" + env: TOXENV=py36 + - python: "pypy2.7-5.8.0" + env: TOXENV=pypy + - python: "pypy3.5-5.8.0" + env: TOXENV=pypy3 + + # Meta + - python: "3.6" + env: TOXENV=flake8 + - python: "3.6" + env: TOXENV=manifest + - python: "3.6" + env: TOXENV=docs + - python: "3.6" + env: TOXENV=readme + - python: "3.6" + env: TOXENV=changelog + + +install: + - pip install tox + + +script: + - tox + + +before_install: + - pip install codecov + + +after_success: + - tox -e coverage-report + - codecov + + +notifications: + email: false diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/AUTHORS.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/AUTHORS.rst new file mode 100644 index 00000000000..73eae2154d5 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/AUTHORS.rst @@ -0,0 +1,11 @@ +Credits +======= + +``attrs`` is written and maintained by `Hynek Schlawack `_. + +The development is kindly supported by `Variomedia AG `_. + +A full list of contributors can be found in `GitHub's overview `_. + +It’s the spiritual successor of `characteristic `_ and aspires to fix some of it clunkiness and unfortunate decisions. +Both were inspired by Twisted’s `FancyEqMixin `_ but both are implemented using class decorators because `sub-classing is bad for you `_, m’kay? diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/CHANGELOG.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/CHANGELOG.rst new file mode 100644 index 00000000000..55cd4591357 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/CHANGELOG.rst @@ -0,0 +1,326 @@ +Changelog +========= + +Versions follow `CalVer `_ with a strict backwards compatibility policy. +The third digit is only for regressions. + +Changes for the upcoming release can be found in the `"changelog.d" directory `_ in our repository. + +.. + Do *NOT* add changelog entries here! + + This changelog is managed by towncrier and is compiled at release time. + + See http://www.attrs.org/en/latest/contributing.html#changelog for details.""" # noqa + +.. towncrier release notes start + + +17.3.0 (2017-11-08) +------------------- + +Backward-incompatible Changes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Attributes are not defined on the class body anymore. + + This means that if you define a class ``C`` with an attribute ``x``, the class will *not* have an attribute ``x`` for introspection anymore. + Instead of ``C.x``, use ``attr.fields(C).x`` or look at ``C.__attrs_attrs__``. + The old behavior has been deprecated since version 16.1. + (`#253 `_) + + +Changes +^^^^^^^ + +- ``super()`` and ``__class__`` now work on Python 3 when ``slots=True``. + (`#102 `_, `#226 `_, `#269 `_, `#270 `_, `#272 `_) +- Added ``type`` argument to ``attr.ib()`` and corresponding ``type`` attribute to ``attr.Attribute``. + + This change paves the way for automatic type checking and serialization (though as of this release ``attrs`` does not make use of it). + In Python 3.6 or higher, the value of ``attr.Attribute.type`` can alternately be set using variable type annotations + (see `PEP 526 `_). (`#151 `_, `#214 `_, `#215 `_, `#239 `_) +- The combination of ``str=True`` and ``slots=True`` now works on Python 2. + (`#198 `_) +- ``attr.Factory`` is hashable again. (`#204 + `_) +- Subclasses now can overwrite attribute definitions of their superclass. + + That means that you can -- for example -- change the default value for an attribute by redefining it. + (`#221 `_, `#229 `_) +- Added new option ``auto_attribs`` to ``@attr.s`` that allows to collect annotated fields without setting them to ``attr.ib()``. + + Setting a field to an ``attr.ib()`` is still possible to supply options like validators. + Setting it to any other value is treated like it was passed as ``attr.ib(default=value)`` -- passing an instance of ``attr.Factory`` also works as expected. + (`#262 `_, `#277 `_) +- Instances of classes created using ``attr.make_class()`` can now be pickled. + (`#282 `_) + + +---- + + +17.2.0 (2017-05-24) +------------------- + + +Changes: +^^^^^^^^ + +- Validators are hashable again. + Note that validators may become frozen in the future, pending availability of no-overhead frozen classes. + `#192 `_ + + +---- + + +17.1.0 (2017-05-16) +------------------- + +To encourage more participation, the project has also been moved into a `dedicated GitHub organization `_ and everyone is most welcome to join! + +``attrs`` also has a logo now! + +.. image:: http://www.attrs.org/en/latest/_static/attrs_logo.png + :alt: attrs logo + + +Backward-incompatible Changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- ``attrs`` will set the ``__hash__()`` method to ``None`` by default now. + The way hashes were handled before was in conflict with `Python's specification `_. + This *may* break some software although this breakage is most likely just surfacing of latent bugs. + You can always make ``attrs`` create the ``__hash__()`` method using ``@attr.s(hash=True)``. + See `#136`_ for the rationale of this change. + + .. warning:: + + Please *do not* upgrade blindly and *do* test your software! + *Especially* if you use instances as dict keys or put them into sets! + +- Correspondingly, ``attr.ib``'s ``hash`` argument is ``None`` by default too and mirrors the ``cmp`` argument as it should. + + +Deprecations: +^^^^^^^^^^^^^ + +- ``attr.assoc()`` is now deprecated in favor of ``attr.evolve()`` and will stop working in 2018. + + +Changes: +^^^^^^^^ + +- Fix default hashing behavior. + Now *hash* mirrors the value of *cmp* and classes are unhashable by default. + `#136`_ + `#142 `_ +- Added ``attr.evolve()`` that, given an instance of an ``attrs`` class and field changes as keyword arguments, will instantiate a copy of the given instance with the changes applied. + ``evolve()`` replaces ``assoc()``, which is now deprecated. + ``evolve()`` is significantly faster than ``assoc()``, and requires the class have an initializer that can take the field values as keyword arguments (like ``attrs`` itself can generate). + `#116 `_ + `#124 `_ + `#135 `_ +- ``FrozenInstanceError`` is now raised when trying to delete an attribute from a frozen class. + `#118 `_ +- Frozen-ness of classes is now inherited. + `#128 `_ +- ``__attrs_post_init__()`` is now run if validation is disabled. + `#130 `_ +- Added ``attr.validators.in_(options)`` that, given the allowed `options`, checks whether the attribute value is in it. + This can be used to check constants, enums, mappings, etc. + `#181 `_ +- Added ``attr.validators.and_()`` that composes multiple validators into one. + `#161 `_ +- For convenience, the ``validator`` argument of ``@attr.s`` now can take a ``list`` of validators that are wrapped using ``and_()``. + `#138 `_ +- Accordingly, ``attr.validators.optional()`` now can take a ``list`` of validators too. + `#161 `_ +- Validators can now be defined conveniently inline by using the attribute as a decorator. + Check out the `examples `_ to see it in action! + `#143 `_ +- ``attr.Factory()`` now has a ``takes_self`` argument that makes the initializer to pass the partially initialized instance into the factory. + In other words you can define attribute defaults based on other attributes. + `#165`_ + `#189 `_ +- Default factories can now also be defined inline using decorators. + They are *always* passed the partially initialized instance. + `#165`_ +- Conversion can now be made optional using ``attr.converters.optional()``. + `#105 `_ + `#173 `_ +- ``attr.make_class()`` now accepts the keyword argument ``bases`` which allows for subclassing. + `#152 `_ +- Metaclasses are now preserved with ``slots=True``. + `#155 `_ + +.. _`#136`: https://github.com/python-attrs/attrs/issues/136 +.. _`#165`: https://github.com/python-attrs/attrs/issues/165 + + +---- + + +16.3.0 (2016-11-24) +------------------- + +Changes: +^^^^^^^^ + +- Attributes now can have user-defined metadata which greatly improves ``attrs``'s extensibility. + `#96 `_ +- Allow for a ``__attrs_post_init__()`` method that -- if defined -- will get called at the end of the ``attrs``-generated ``__init__()`` method. + `#111 `_ +- Added ``@attr.s(str=True)`` that will optionally create a ``__str__()`` method that is identical to ``__repr__()``. + This is mainly useful with ``Exception``\ s and other classes that rely on a useful ``__str__()`` implementation but overwrite the default one through a poor own one. + Default Python class behavior is to use ``__repr__()`` as ``__str__()`` anyways. + + If you tried using ``attrs`` with ``Exception``\ s and were puzzled by the tracebacks: this option is for you. +- ``__name__`` is not overwritten with ``__qualname__`` for ``attr.s(slots=True)`` classes anymore. + `#99 `_ + + +---- + + +16.2.0 (2016-09-17) +------------------- + +Changes: +^^^^^^^^ + +- Added ``attr.astuple()`` that -- similarly to ``attr.asdict()`` -- returns the instance as a tuple. + `#77 `_ +- Converts now work with frozen classes. + `#76 `_ +- Instantiation of ``attrs`` classes with converters is now significantly faster. + `#80 `_ +- Pickling now works with ``__slots__`` classes. + `#81 `_ +- ``attr.assoc()`` now works with ``__slots__`` classes. + `#84 `_ +- The tuple returned by ``attr.fields()`` now also allows to access the ``Attribute`` instances by name. + Yes, we've subclassed ``tuple`` so you don't have to! + Therefore ``attr.fields(C).x`` is equivalent to the deprecated ``C.x`` and works with ``__slots__`` classes. + `#88 `_ + + +---- + + +16.1.0 (2016-08-30) +------------------- + +Backward-incompatible Changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- All instances where function arguments were called ``cl`` have been changed to the more Pythonic ``cls``. + Since it was always the first argument, it's doubtful anyone ever called those function with in the keyword form. + If so, sorry for any breakage but there's no practical deprecation path to solve this ugly wart. + + +Deprecations: +^^^^^^^^^^^^^ + +- Accessing ``Attribute`` instances on class objects is now deprecated and will stop working in 2017. + If you need introspection please use the ``__attrs_attrs__`` attribute or the ``attr.fields()`` function that carry them too. + In the future, the attributes that are defined on the class body and are usually overwritten in your ``__init__`` method are simply removed after ``@attr.s`` has been applied. + + This will remove the confusing error message if you write your own ``__init__`` and forget to initialize some attribute. + Instead you will get a straightforward ``AttributeError``. + In other words: decorated classes will work more like plain Python classes which was always ``attrs``'s goal. +- The serious business aliases ``attr.attributes`` and ``attr.attr`` have been deprecated in favor of ``attr.attrs`` and ``attr.attrib`` which are much more consistent and frankly obvious in hindsight. + They will be purged from documentation immediately but there are no plans to actually remove them. + + +Changes: +^^^^^^^^ + +- ``attr.asdict()``\ 's ``dict_factory`` arguments is now propagated on recursion. + `#45 `_ +- ``attr.asdict()``, ``attr.has()`` and ``attr.fields()`` are significantly faster. + `#48 `_ + `#51 `_ +- Add ``attr.attrs`` and ``attr.attrib`` as a more consistent aliases for ``attr.s`` and ``attr.ib``. +- Add ``frozen`` option to ``attr.s`` that will make instances best-effort immutable. + `#60 `_ +- ``attr.asdict()`` now takes ``retain_collection_types`` as an argument. + If ``True``, it does not convert attributes of type ``tuple`` or ``set`` to ``list``. + `#69 `_ + + +---- + + +16.0.0 (2016-05-23) +------------------- + +Backward-incompatible Changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Python 3.3 and 2.6 aren't supported anymore. + They may work by chance but any effort to keep them working has ceased. + + The last Python 2.6 release was on October 29, 2013 and isn't supported by the CPython core team anymore. + Major Python packages like Django and Twisted dropped Python 2.6 a while ago already. + + Python 3.3 never had a significant user base and wasn't part of any distribution's LTS release. + +Changes: +^^^^^^^^ + +- ``__slots__`` have arrived! + Classes now can automatically be `slots `_-style (and save your precious memory) just by passing ``slots=True``. + `#35 `_ +- Allow the case of initializing attributes that are set to ``init=False``. + This allows for clean initializer parameter lists while being able to initialize attributes to default values. + `#32 `_ +- ``attr.asdict()`` can now produce arbitrary mappings instead of Python ``dict``\ s when provided with a ``dict_factory`` argument. + `#40 `_ +- Multiple performance improvements. + + +---- + + +15.2.0 (2015-12-08) +------------------- + +Changes: +^^^^^^^^ + +- Added a ``convert`` argument to ``attr.ib``, which allows specifying a function to run on arguments. + This allows for simple type conversions, e.g. with ``attr.ib(convert=int)``. + `#26 `_ +- Speed up object creation when attribute validators are used. + `#28 `_ + + +---- + + +15.1.0 (2015-08-20) +------------------- + +Changes: +^^^^^^^^ + +- Added ``attr.validators.optional()`` that wraps other validators allowing attributes to be ``None``. + `#16 `_ +- Multi-level inheritance now works. + `#24 `_ +- ``__repr__()`` now works with non-redecorated subclasses. + `#20 `_ + + +---- + + +15.0.0 (2015-04-15) +------------------- + +Changes: +^^^^^^^^ + +Initial release. diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/CODE_OF_CONDUCT.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/CODE_OF_CONDUCT.rst new file mode 100644 index 00000000000..4f4b8ee9cd9 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/CODE_OF_CONDUCT.rst @@ -0,0 +1,55 @@ +Contributor Covenant Code of Conduct +==================================== + +Our Pledge +---------- + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +Our Standards +------------- + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +Our Responsibilities +-------------------- + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +Scope +----- + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. +Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. +Representation of a project may be further defined and clarified by project maintainers. + +Enforcement +----------- + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hs@ox.cx. +All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. +The project team is obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +Attribution +----------- + +This Code of Conduct is adapted from the `Contributor Covenant `_, version 1.4, available at http://contributor-covenant.org/version/1/4. diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/CONTRIBUTING.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/CONTRIBUTING.rst new file mode 100644 index 00000000000..9822f8926a8 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/CONTRIBUTING.rst @@ -0,0 +1,220 @@ +How To Contribute +================= + +First off, thank you for considering contributing to ``attrs``! +It's people like *you* who make it is such a great tool for everyone. + +This document is mainly to help you to get started by codifying tribal knowledge and expectations and make it more accessible to everyone. +But don't be afraid to open half-finished PRs and ask questions if something is unclear! + + +Support +------- + +In case you'd like to help out but don't want to deal with GitHub, there's a great opportunity: +help your fellow developers on `StackOverflow `_! + +The offical tag is ``python-attrs`` and helping out in support frees us up for improving ``attrs`` instead! + + +Workflow +-------- + +- No contribution is too small! + Please submit as many fixes for typos and grammar bloopers as you can! +- Try to limit each pull request to *one* change only. +- *Always* add tests and docs for your code. + This is a hard rule; patches with missing tests or documentation can't be merged. +- Make sure your changes pass our CI_. + You won't get any feedback until it's green unless you ask for it. +- Once you've addressed review feedback, make sure to bump the pull request with a short note, so we know you're done. +- Don’t break `backward compatibility`_. + + +Code +---- + +- Obey `PEP 8`_ and `PEP 257`_. + We use the ``"""``\ -on-separate-lines style for docstrings: + + .. code-block:: python + + def func(x): + """ + Do something. + + :param str x: A very important parameter. + + :rtype: str + """ +- If you add or change public APIs, tag the docstring using ``.. versionadded:: 16.0.0 WHAT`` or ``.. versionchanged:: 16.2.0 WHAT``. +- Prefer double quotes (``"``) over single quotes (``'``) unless the string contains double quotes itself. + + +Tests +----- + +- Write your asserts as ``expected == actual`` to line them up nicely: + + .. code-block:: python + + x = f() + + assert 42 == x.some_attribute + assert "foo" == x._a_private_attribute + +- To run the test suite, all you need is a recent tox_. + It will ensure the test suite runs with all dependencies against all Python versions just as it will on Travis CI. + If you lack some Python versions, you can can always limit the environments like ``tox -e py27,py35`` (in that case you may want to look into pyenv_, which makes it very easy to install many different Python versions in parallel). +- Write `good test docstrings`_. +- To ensure new features work well with the rest of the system, they should be also added to our `Hypothesis`_ testing strategy which you find in ``tests/util.py``. + + +Documentation +------------- + +- Use `semantic newlines`_ in reStructuredText_ files (files ending in ``.rst``): + + .. code-block:: rst + + This is a sentence. + This is another sentence. + +- If you start a new section, add two blank lines before and one blank line after the header except if two headers follow immediately after each other: + + .. code-block:: rst + + Last line of previous section. + + + Header of New Top Section + ------------------------- + + Header of New Section + ^^^^^^^^^^^^^^^^^^^^^ + + First line of new section. +- If you add a new feature, demonstrate its awesomeness in the `examples page`_! + + +Changelog +^^^^^^^^^ + +If your change is noteworthy, there needs to be a changelog entry, so our users can learn about it! + +To avoid merge conflicts, we use the towncrier_ package to manage our changelog. +``towncrier`` uses independent files for each pull request -- so called *news fragments* -- instead of one monolithic changelog file. +On release those news fragments are compiled into our ``CHANGELOG.rst``. + +You don't need to install ``towncrier`` yourself, you just have to abide to a few simple rules: + +- For each pull request, add a new file into ``changelog.d`` with a filename adhering to the ``pr#.(change|deprecation|breaking).rst`` schema: + For example ``changelog.d/42.change.rst`` for a non-breaking change, that is proposed in pull request number 42. +- As with other docs, please use `semantic newlines`_ within news fragments. +- Wrap symbols like modules, functions, or classes into double backticks so they are rendered in a monospaced font. +- If you mention functions or other callables, add parantheses at the end of their names: ``attr.func()`` or ``attr.Class.method()``. + This makes the changelog a lot more readable. +- Prefer simple past or constructions with "now". + For example: + + + Added ``attr.validators.func()``. + + ``attr.func()`` now doesn't crash the Large Hadron Collider anymore. +- If you want to reference multiple issues, copy the news fragment to another filename. + ``towncrier`` will merge all news fragments with identical contents into one entry with multiple links to the respective pull requests. + +Example entries: + + .. code-block:: rst + + Added ``attr.validators.func()``. + The feature really *is* awesome. + +or: + + .. code-block:: rst + + ``attr.func()`` now doesn't crash the Large Hadron Collider anymore. + The bug really *was* nasty. + +---- + +``tox -e changelog`` will render the current changelog to the terminal if you have any doubts. + + +Local Development Environment +----------------------------- + +You can (and should) run our test suite using tox_. +However you’ll probably want a more traditional environment too. +We highly recommend to develop using the latest Python 3 release because ``attrs`` tries to take advantage of modern features whenever possible. + +First create a `virtual environment `_. +It’s out of scope for this document to list all the ways to manage virtual environments in Python but if you don’t have already a pet way, take some time to look at tools like `pew `_, `virtualfish `_, and `virtualenvwrapper `_. + +Next get an up to date checkout of the ``attrs`` repository: + +.. code-block:: bash + + git checkout git@github.com:python-attrs/attrs.git + +Change into the newly created directory and **after activating your virtual environment** install an editable version of ``attrs``: + +.. code-block:: bash + + cd attrs + pip install -e . + +If you run the virtual environment’s Python and try to ``import attr`` it should work! + +To run the test suite, you'll need our development dependencies which can be installed using + +.. code-block:: bash + + pip install -r dev-requirements.txt + +At this point + +.. code-block:: bash + + python -m pytest + +should work and pass! + + +Governance +---------- + +``attrs`` is maintained by `team of volunteers`_ that is always open for new members that share our vision of a fast, lean, and magic-free library that empowers programmers to write better code with less effort. +If you'd like to join, just get a pull request merged and ask to be added in the very same pull request! + +**The simple rule is that everyone is welcome to review/merge pull requests of others but nobody is allowed to merge their own code.** + +`Hynek Schlawack`_ acts reluctantly as the BDFL_ and has the final say over design decisions. + + +**** + +Please note that this project is released with a Contributor `Code of Conduct`_. +By participating in this project you agree to abide by its terms. +Please report any harm to `Hynek Schlawack`_ in any way you find appropriate. + +Thank you for considering contributing to ``attrs``! + + +.. _`Hynek Schlawack`: https://hynek.me/about/ +.. _`PEP 8`: https://www.python.org/dev/peps/pep-0008/ +.. _`PEP 257`: https://www.python.org/dev/peps/pep-0257/ +.. _`good test docstrings`: https://jml.io/pages/test-docstrings.html +.. _`Code of Conduct`: https://github.com/python-attrs/attrs/blob/master/CODE_OF_CONDUCT.rst +.. _changelog: https://github.com/python-attrs/attrs/blob/master/CHANGELOG.rst +.. _`backward compatibility`: http://www.attrs.org/en/latest/backward-compatibility.html +.. _tox: https://tox.readthedocs.io/ +.. _pyenv: https://github.com/pyenv/pyenv +.. _reStructuredText: http://www.sphinx-doc.org/en/stable/rest.html +.. _semantic newlines: http://rhodesmill.org/brandon/2012/one-sentence-per-line/ +.. _examples page: https://github.com/python-attrs/attrs/blob/master/docs/examples.rst +.. _Hypothesis: https://hypothesis.readthedocs.io/ +.. _CI: https://travis-ci.org/python-attrs/attrs/ +.. _`team of volunteers`: https://github.com/python-attrs +.. _BDFL: https://en.wikipedia.org/wiki/Benevolent_dictator_for_life +.. _towncrier: https://pypi.org/project/towncrier diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/LICENSE b/tests/wpt/web-platform-tests/tools/third_party/attrs/LICENSE new file mode 100644 index 00000000000..7ae3df93097 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Hynek Schlawack + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/MANIFEST.in b/tests/wpt/web-platform-tests/tools/third_party/attrs/MANIFEST.in new file mode 100644 index 00000000000..03a948ef2c4 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/MANIFEST.in @@ -0,0 +1,19 @@ +include LICENSE *.rst *.toml + +# Don't package GitHub-specific files. +exclude *.md .travis.yml + +# Tests +include tox.ini .coveragerc conftest.py dev-requirements.txt docs-requirements.txt +recursive-include tests *.py + +# Documentation +include docs/Makefile docs/docutils.conf +recursive-include docs *.png +recursive-include docs *.svg +recursive-include docs *.py +recursive-include docs *.rst +prune docs/_build + +# Changelog news fragments -- is empty on releases. +prune changelog.d diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/PULL_REQUEST_TEMPLATE.md b/tests/wpt/web-platform-tests/tools/third_party/attrs/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000000..34c468e6ae5 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,12 @@ +# Pull Request Check List + +This is just a reminder about the most common mistakes. Please make sure that you tick all *appropriate* boxes. But please read our [contribution guide](http://www.attrs.org/en/latest/contributing.html) at least once, it will save you unnecessary review cycles! + +- [ ] Added **tests** for changed code. +- [ ] New features have been added to our [Hypothesis testing strategy](https://github.com/python-attrs/attrs/blob/master/tests/utils.py). +- [ ] Updated **documentation** for changed code. +- [ ] Documentation in `.rst` files is written using [semantic newlines](http://rhodesmill.org/brandon/2012/one-sentence-per-line/). +- [ ] Changed/added classes/methods/functions have appropriate `versionadded`, `versionchanged`, or `deprecated` [directives](http://www.sphinx-doc.org/en/stable/markup/para.html#directive-versionadded). +- [ ] Changes (and possible deprecations) have news fragments in [`changelog.d`](https://github.com/python-attrs/attrs/blob/master/changelog.d). + +If you have *any* questions to *any* of the points above, just **submit and ask**! This checklist is here to *help* you, not to deter you from contributing! diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/README.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/README.rst new file mode 100644 index 00000000000..84d6aa76531 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/README.rst @@ -0,0 +1,129 @@ +.. image:: http://www.attrs.org/en/latest/_static/attrs_logo.png + :alt: attrs Logo + +====================================== +``attrs``: Classes Without Boilerplate +====================================== + +.. image:: https://readthedocs.org/projects/attrs/badge/?version=stable + :target: http://www.attrs.org/en/stable/?badge=stable + :alt: Documentation Status + +.. image:: https://travis-ci.org/python-attrs/attrs.svg?branch=master + :target: https://travis-ci.org/python-attrs/attrs + :alt: CI Status + +.. image:: https://codecov.io/github/python-attrs/attrs/branch/master/graph/badge.svg + :target: https://codecov.io/github/python-attrs/attrs + :alt: Test Coverage + +.. teaser-begin + +``attrs`` is the Python package that will bring back the **joy** of **writing classes** by relieving you from the drudgery of implementing object protocols (aka `dunder `_ methods). + +Its main goal is to help you to write **concise** and **correct** software without slowing down your code. + +.. -spiel-end- + +For that, it gives you a class decorator and a way to declaratively define the attributes on that class: + +.. -code-begin- + +.. code-block:: pycon + + >>> import attr + + >>> @attr.s + ... class SomeClass(object): + ... a_number = attr.ib(default=42) + ... list_of_numbers = attr.ib(default=attr.Factory(list)) + ... + ... def hard_math(self, another_number): + ... return self.a_number + sum(self.list_of_numbers) * another_number + + + >>> sc = SomeClass(1, [1, 2, 3]) + >>> sc + SomeClass(a_number=1, list_of_numbers=[1, 2, 3]) + + >>> sc.hard_math(3) + 19 + >>> sc == SomeClass(1, [1, 2, 3]) + True + >>> sc != SomeClass(2, [3, 2, 1]) + True + + >>> attr.asdict(sc) + {'a_number': 1, 'list_of_numbers': [1, 2, 3]} + + >>> SomeClass() + SomeClass(a_number=42, list_of_numbers=[]) + + >>> C = attr.make_class("C", ["a", "b"]) + >>> C("foo", "bar") + C(a='foo', b='bar') + + +After *declaring* your attributes ``attrs`` gives you: + +- a concise and explicit overview of the class's attributes, +- a nice human-readable ``__repr__``, +- a complete set of comparison methods, +- an initializer, +- and much more, + +*without* writing dull boilerplate code again and again and *without* runtime performance penalties. + +This gives you the power to use actual classes with actual types in your code instead of confusing ``tuple``\ s or `confusingly behaving `_ ``namedtuple``\ s. +Which in turn encourages you to write *small classes* that do `one thing well `_. +Never again violate the `single responsibility principle `_ just because implementing ``__init__`` et al is a painful drag. + + +.. -testimonials- + +Testimonials +============ + +**Amber Hawkie Brown**, Twisted Release Manager and Computer Owl: + + Writing a fully-functional class using attrs takes me less time than writing this testimonial. + + +**Glyph Lefkowitz**, creator of `Twisted `_, `Automat `_, and other open source software, in `The One Python Library Everyone Needs `_: + + I’m looking forward to is being able to program in Python-with-attrs everywhere. + It exerts a subtle, but positive, design influence in all the codebases I’ve see it used in. + + +**Kenneth Reitz**, author of `requests `_, Python Overlord at Heroku, `on paper no less `_: + + attrs—classes for humans. I like it. + + +**Łukasz Langa**, prolific CPython core developer and Production Engineer at Facebook: + + I'm increasingly digging your attr.ocity. Good job! + + +.. -end- + +.. -project-information- + +Getting Help +============ + +Please use the ``python-attrs`` tag on `StackOverflow `_ to get help. + +Answering questions of your fellow developers is also great way to help the project! + + +Project Information +=================== + +``attrs`` is released under the `MIT `_ license, +its documentation lives at `Read the Docs `_, +the code on `GitHub `_, +and the latest release on `PyPI `_. +It’s rigorously tested on Python 2.7, 3.4+, and PyPy. + +If you'd like to contribute you're most welcome and we've written `a little guide `_ to get you started! diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/nonpython/__init__.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/.gitignore similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/nonpython/__init__.py rename to tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/.gitignore diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/261.change.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/261.change.rst new file mode 100644 index 00000000000..6867f66dd23 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/261.change.rst @@ -0,0 +1,4 @@ +Generated ``__hash__`` methods now hash the class type along with the attribute values. +Until now the hashes of two classes with the same values were identical which was a bug. + +The generated method is also *much* faster now. diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/284.change.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/284.change.rst new file mode 100644 index 00000000000..266599daabe --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/284.change.rst @@ -0,0 +1,2 @@ +``ctypes`` is optional now however if it's missing, a bare ``super()`` will not work in slots classes. +This should only happen in special environments like Google App Engine. diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/285.change.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/285.change.rst new file mode 100644 index 00000000000..c3fbb797d4f --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/285.change.rst @@ -0,0 +1,2 @@ +The attribute redefinition feature introduced in 17.3.0 now takes into account if an attribute is redefined via multiple inheritance. +In that case, the definition that is closer to the base of the class hierarchy wins. diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/286.change.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/286.change.rst new file mode 100644 index 00000000000..266599daabe --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/286.change.rst @@ -0,0 +1,2 @@ +``ctypes`` is optional now however if it's missing, a bare ``super()`` will not work in slots classes. +This should only happen in special environments like Google App Engine. diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/287.change.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/287.change.rst new file mode 100644 index 00000000000..c3fbb797d4f --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/287.change.rst @@ -0,0 +1,2 @@ +The attribute redefinition feature introduced in 17.3.0 now takes into account if an attribute is redefined via multiple inheritance. +In that case, the definition that is closer to the base of the class hierarchy wins. diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/291.change.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/291.change.rst new file mode 100644 index 00000000000..0d5438f1dbe --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/291.change.rst @@ -0,0 +1 @@ +Subclasses of ``auto_attribs=True`` can be empty now. diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/292.change.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/292.change.rst new file mode 100644 index 00000000000..0d5438f1dbe --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/292.change.rst @@ -0,0 +1 @@ +Subclasses of ``auto_attribs=True`` can be empty now. diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/295.change.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/295.change.rst new file mode 100644 index 00000000000..6867f66dd23 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/295.change.rst @@ -0,0 +1,4 @@ +Generated ``__hash__`` methods now hash the class type along with the attribute values. +Until now the hashes of two classes with the same values were identical which was a bug. + +The generated method is also *much* faster now. diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/296.change.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/296.change.rst new file mode 100644 index 00000000000..6867f66dd23 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/changelog.d/296.change.rst @@ -0,0 +1,4 @@ +Generated ``__hash__`` methods now hash the class type along with the attribute values. +Until now the hashes of two classes with the same values were identical which was a bug. + +The generated method is also *much* faster now. diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/conftest.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/conftest.py new file mode 100644 index 00000000000..ed4d6525b45 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/conftest.py @@ -0,0 +1,28 @@ +from __future__ import absolute_import, division, print_function + +import sys + +import pytest + + +@pytest.fixture(scope="session") +def C(): + """ + Return a simple but fully featured attrs class with an x and a y attribute. + """ + import attr + + @attr.s + class C(object): + x = attr.ib() + y = attr.ib() + + return C + + +collect_ignore = [] +if sys.version_info[:2] < (3, 6): + collect_ignore.extend([ + "tests/test_annotations.py", + "tests/test_init_subclass.py", + ]) diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/dev-requirements.txt b/tests/wpt/web-platform-tests/tools/third_party/attrs/dev-requirements.txt new file mode 100644 index 00000000000..bbd6b9201e0 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/dev-requirements.txt @@ -0,0 +1,6 @@ +coverage +hypothesis +pympler +pytest +six +zope.interface diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/docs-requirements.txt b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs-requirements.txt new file mode 100644 index 00000000000..c473e1e4324 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs-requirements.txt @@ -0,0 +1,3 @@ +-e . +sphinx +zope.interface diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/Makefile b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/Makefile new file mode 100644 index 00000000000..3143891daf8 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/Makefile @@ -0,0 +1,177 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/attrs.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/attrs.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/attrs" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/attrs" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/_static/attrs_logo.png b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/_static/attrs_logo.png new file mode 100644 index 00000000000..11b6e6fe3f9 Binary files /dev/null and b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/_static/attrs_logo.png differ diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/_static/attrs_logo.svg b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/_static/attrs_logo.svg new file mode 100644 index 00000000000..1bb3e4b7273 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/_static/attrs_logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/api.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/api.rst new file mode 100644 index 00000000000..e2acb7400f4 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/api.rst @@ -0,0 +1,428 @@ +.. _api: + +API Reference +============= + +.. currentmodule:: attr + +``attrs`` works by decorating a class using :func:`attr.s` and then optionally defining attributes on the class using :func:`attr.ib`. + +.. note:: + + When this documentation speaks about "``attrs`` attributes" it means those attributes that are defined using :func:`attr.ib` in the class body. + +What follows is the API explanation, if you'd like a more hands-on introduction, have a look at :doc:`examples`. + + + +Core +---- + +.. autofunction:: attr.s(these=None, repr_ns=None, repr=True, cmp=True, hash=None, init=True, slots=False, frozen=False, str=False) + + .. note:: + + ``attrs`` also comes with a serious business alias ``attr.attrs``. + + For example: + + .. doctest:: + + >>> import attr + >>> @attr.s + ... class C(object): + ... _private = attr.ib() + >>> C(private=42) + C(_private=42) + >>> class D(object): + ... def __init__(self, x): + ... self.x = x + >>> D(1) + + >>> D = attr.s(these={"x": attr.ib()}, init=False)(D) + >>> D(1) + D(x=1) + + +.. autofunction:: attr.ib + + .. note:: + + ``attrs`` also comes with a serious business alias ``attr.attrib``. + + The object returned by :func:`attr.ib` also allows for setting the default and the validator using decorators: + + .. doctest:: + + >>> @attr.s + ... class C(object): + ... x = attr.ib() + ... y = attr.ib() + ... @x.validator + ... def name_can_be_anything(self, attribute, value): + ... if value < 0: + ... raise ValueError("x must be positive") + ... @y.default + ... def name_does_not_matter(self): + ... return self.x + 1 + >>> C(1) + C(x=1, y=2) + >>> C(-1) + Traceback (most recent call last): + ... + ValueError: x must be positive + +.. autoclass:: attr.Attribute + + Instances of this class are frequently used for introspection purposes like: + + - :func:`fields` returns a tuple of them. + - Validators get them passed as the first argument. + + .. warning:: + + You should never instantiate this class yourself! + + .. doctest:: + + >>> import attr + >>> @attr.s + ... class C(object): + ... x = attr.ib() + >>> attr.fields(C).x + Attribute(name='x', default=NOTHING, validator=None, repr=True, cmp=True, hash=None, init=True, convert=None, metadata=mappingproxy({}), type=None) + + +.. autofunction:: attr.make_class + + This is handy if you want to programmatically create classes. + + For example: + + .. doctest:: + + >>> C1 = attr.make_class("C1", ["x", "y"]) + >>> C1(1, 2) + C1(x=1, y=2) + >>> C2 = attr.make_class("C2", {"x": attr.ib(default=42), + ... "y": attr.ib(default=attr.Factory(list))}) + >>> C2() + C2(x=42, y=[]) + + +.. autoclass:: attr.Factory + + For example: + + .. doctest:: + + >>> @attr.s + ... class C(object): + ... x = attr.ib(default=attr.Factory(list)) + ... y = attr.ib(default=attr.Factory( + ... lambda self: set(self.x), + ... takes_self=True) + ... ) + >>> C() + C(x=[], y=set()) + >>> C([1, 2, 3]) + C(x=[1, 2, 3], y={1, 2, 3}) + + +.. autoexception:: attr.exceptions.FrozenInstanceError +.. autoexception:: attr.exceptions.AttrsAttributeNotFoundError +.. autoexception:: attr.exceptions.NotAnAttrsClassError +.. autoexception:: attr.exceptions.DefaultAlreadySetError +.. autoexception:: attr.exceptions.UnannotatedAttributeError + + For example:: + + @attr.s(auto_attribs=True) + class C: + x: int + y = attr.ib() + + +Influencing Initialization +++++++++++++++++++++++++++ + +Generally speaking, it's best to keep logic out of your ``__init__``. +The moment you need a finer control over how your class is instantiated, it's usually best to use a classmethod factory or to apply the `builder pattern `_. + +However, sometimes you need to do that one quick thing after your class is initialized. +And for that ``attrs`` offers the ``__attrs_post_init__`` hook that is automatically detected and run after ``attrs`` is done initializing your instance: + +.. doctest:: + + >>> @attr.s + ... class C(object): + ... x = attr.ib() + ... y = attr.ib(init=False) + ... def __attrs_post_init__(self): + ... self.y = self.x + 1 + >>> C(1) + C(x=1, y=2) + +Please note that you can't directly set attributes on frozen classes: + +.. doctest:: + + >>> @attr.s(frozen=True) + ... class FrozenBroken(object): + ... x = attr.ib() + ... y = attr.ib(init=False) + ... def __attrs_post_init__(self): + ... self.y = self.x + 1 + >>> FrozenBroken(1) + Traceback (most recent call last): + ... + attr.exceptions.FrozenInstanceError: can't set attribute + +If you need to set attributes on a frozen class, you'll have to resort to the :ref:`same trick ` as ``attrs`` and use :meth:`object.__setattr__`: + +.. doctest:: + + >>> @attr.s(frozen=True) + ... class Frozen(object): + ... x = attr.ib() + ... y = attr.ib(init=False) + ... def __attrs_post_init__(self): + ... object.__setattr__(self, "y", self.x + 1) + >>> Frozen(1) + Frozen(x=1, y=2) + + +.. _helpers: + +Helpers +------- + +``attrs`` comes with a bunch of helper methods that make working with it easier: + +.. autofunction:: attr.fields + + For example: + + .. doctest:: + + >>> @attr.s + ... class C(object): + ... x = attr.ib() + ... y = attr.ib() + >>> attr.fields(C) + (Attribute(name='x', default=NOTHING, validator=None, repr=True, cmp=True, hash=None, init=True, convert=None, metadata=mappingproxy({}), type=None), Attribute(name='y', default=NOTHING, validator=None, repr=True, cmp=True, hash=None, init=True, convert=None, metadata=mappingproxy({}), type=None)) + >>> attr.fields(C)[1] + Attribute(name='y', default=NOTHING, validator=None, repr=True, cmp=True, hash=None, init=True, convert=None, metadata=mappingproxy({}), type=None) + >>> attr.fields(C).y is attr.fields(C)[1] + True + + +.. autofunction:: attr.has + + For example: + + .. doctest:: + + >>> @attr.s + ... class C(object): + ... pass + >>> attr.has(C) + True + >>> attr.has(object) + False + + +.. autofunction:: attr.asdict + + For example: + + .. doctest:: + + >>> @attr.s + ... class C(object): + ... x = attr.ib() + ... y = attr.ib() + >>> attr.asdict(C(1, C(2, 3))) + {'x': 1, 'y': {'x': 2, 'y': 3}} + + +.. autofunction:: attr.astuple + + For example: + + .. doctest:: + + >>> @attr.s + ... class C(object): + ... x = attr.ib() + ... y = attr.ib() + >>> attr.astuple(C(1,2)) + (1, 2) + +``attrs`` includes some handy helpers for filtering: + +.. autofunction:: attr.filters.include + +.. autofunction:: attr.filters.exclude + +See :ref:`asdict` for examples. + +.. autofunction:: attr.evolve + + For example: + + .. doctest:: + + >>> @attr.s + ... class C(object): + ... x = attr.ib() + ... y = attr.ib() + >>> i1 = C(1, 2) + >>> i1 + C(x=1, y=2) + >>> i2 = attr.evolve(i1, y=3) + >>> i2 + C(x=1, y=3) + >>> i1 == i2 + False + + ``evolve`` creates a new instance using ``__init__``. + This fact has several implications: + + * private attributes should be specified without the leading underscore, just like in ``__init__``. + * attributes with ``init=False`` can't be set with ``evolve``. + * the usual ``__init__`` validators will validate the new values. + +.. autofunction:: validate + + For example: + + .. doctest:: + + >>> @attr.s + ... class C(object): + ... x = attr.ib(validator=attr.validators.instance_of(int)) + >>> i = C(1) + >>> i.x = "1" + >>> attr.validate(i) + Traceback (most recent call last): + ... + TypeError: ("'x' must be (got '1' that is a ).", Attribute(name='x', default=NOTHING, validator=>, repr=True, cmp=True, hash=None, init=True, type=None), , '1') + + +Validators can be globally disabled if you want to run them only in development and tests but not in production because you fear their performance impact: + +.. autofunction:: set_run_validators + +.. autofunction:: get_run_validators + + +.. _api_validators: + +Validators +---------- + +``attrs`` comes with some common validators in the ``attrs.validators`` module: + + +.. autofunction:: attr.validators.instance_of + + + For example: + + .. doctest:: + + >>> @attr.s + ... class C(object): + ... x = attr.ib(validator=attr.validators.instance_of(int)) + >>> C(42) + C(x=42) + >>> C("42") + Traceback (most recent call last): + ... + TypeError: ("'x' must be (got '42' that is a ).", Attribute(name='x', default=NOTHING, validator=>, type=None), , '42') + >>> C(None) + Traceback (most recent call last): + ... + TypeError: ("'x' must be (got None that is a ).", Attribute(name='x', default=NOTHING, validator=>, repr=True, cmp=True, hash=None, init=True, type=None), , None) + +.. autofunction:: attr.validators.in_ + + For example: + + .. doctest:: + + >>> import enum + >>> class State(enum.Enum): + ... ON = "on" + ... OFF = "off" + >>> @attr.s + ... class C(object): + ... state = attr.ib(validator=attr.validators.in_(State)) + ... val = attr.ib(validator=attr.validators.in_([1, 2, 3])) + >>> C(State.ON, 1) + C(state=, val=1) + >>> C("on", 1) + Traceback (most recent call last): + ... + ValueError: 'state' must be in (got 'on') + >>> C(State.ON, 4) + Traceback (most recent call last): + ... + ValueError: 'val' must be in [1, 2, 3] (got 4) + +.. autofunction:: attr.validators.provides + +.. autofunction:: attr.validators.and_ + + For convenience, it's also possible to pass a list to :func:`attr.ib`'s validator argument. + + Thus the following two statements are equivalent:: + + x = attr.ib(validator=attr.validators.and_(v1, v2, v3)) + x = attr.ib(validator=[v1, v2, v3]) + +.. autofunction:: attr.validators.optional + + For example: + + .. doctest:: + + >>> @attr.s + ... class C(object): + ... x = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(int))) + >>> C(42) + C(x=42) + >>> C("42") + Traceback (most recent call last): + ... + TypeError: ("'x' must be (got '42' that is a ).", Attribute(name='x', default=NOTHING, validator=>, type=None), , '42') + >>> C(None) + C(x=None) + + +Converters +---------- + +.. autofunction:: attr.converters.optional + + For example: + + .. doctest:: + + >>> @attr.s + ... class C(object): + ... x = attr.ib(convert=attr.converters.optional(int)) + >>> C(None) + C(x=None) + >>> C(42) + C(x=42) + + +Deprecated APIs +--------------- + +The serious business aliases used to be called ``attr.attributes`` and ``attr.attr``. +There are no plans to remove them but they shouldn't be used in new code. + +.. autofunction:: assoc diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/backward-compatibility.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/backward-compatibility.rst new file mode 100644 index 00000000000..52559f8d450 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/backward-compatibility.rst @@ -0,0 +1,19 @@ +Backward Compatibility +====================== + +.. currentmodule:: attr + +``attrs`` has a very strong backward compatibility policy that is inspired by the policy of the `Twisted framework `_. + +Put simply, you shouldn't ever be afraid to upgrade ``attrs`` if you're only using its public APIs. +If there will ever be a need to break compatibility, it will be announced in the :doc:`changelog` and raise a ``DeprecationWarning`` for a year (if possible) before it's finally really broken. + + +.. _exemption: + +.. warning:: + + The structure of the :class:`attr.Attribute` class is exempt from this rule. + It *will* change in the future, but since it should be considered read-only, that shouldn't matter. + + However if you intend to build extensions on top of ``attrs`` you have to anticipate that. diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/changelog.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/changelog.rst new file mode 100644 index 00000000000..565b0521d0c --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/changelog.rst @@ -0,0 +1 @@ +.. include:: ../CHANGELOG.rst diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/conf.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/conf.py new file mode 100644 index 00000000000..1cdb07c1f79 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/conf.py @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- + +import codecs +import os +import re + + +def read(*parts): + """ + Build an absolute path from *parts* and and return the contents of the + resulting file. Assume UTF-8 encoding. + """ + here = os.path.abspath(os.path.dirname(__file__)) + with codecs.open(os.path.join(here, *parts), "rb", "utf-8") as f: + return f.read() + + +def find_version(*file_paths): + """ + Build a path from *file_paths* and search for a ``__version__`` + string inside. + """ + version_file = read(*file_paths) + version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", + version_file, re.M) + if version_match: + return version_match.group(1) + raise RuntimeError("Unable to find version string.") + + +# -- General configuration ------------------------------------------------ + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.doctest', + 'sphinx.ext.intersphinx', + 'sphinx.ext.todo', +] + + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'attrs' +copyright = u'2015, Hynek Schlawack' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +release = find_version("../src/attr/__init__.py") +version = release.rsplit(u".", 1)[0] +# The full version, including alpha/beta/rc tags. + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# If true, '()' will be appended to :func: etc. cross-reference text. +add_function_parentheses = True + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. + +html_theme = "alabaster" +html_theme_options = { + "font_family": '"Avenir Next", Calibri, "PT Sans", sans-serif', + "head_font_family": '"Avenir Next", Calibri, "PT Sans", sans-serif', + "font_size": "18px", + "page_width": "980px", +} + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +html_logo = "_static/attrs_logo.svg" + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If false, no module index is generated. +html_domain_indices = True + +# If false, no index is generated. +html_use_index = True + +# If true, the index is split into individual pages for each letter. +html_split_index = False + +# If true, links to the reST sources are added to the pages. +html_show_sourcelink = False + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# html_use_opensearch = '' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'attrsdoc' + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'attrs', u'attrs Documentation', + [u'Hynek Schlawack'], 1) +] + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'attrs', u'attrs Documentation', + u'Hynek Schlawack', 'attrs', 'One line description of project.', + 'Miscellaneous'), +] + +intersphinx_mapping = { + "https://docs.python.org/3": None, +} + +# Allow non-local URIs so we can have images in CHANGELOG etc. +suppress_warnings = ['image.nonlocal_uri'] diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/contributing.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/contributing.rst new file mode 100644 index 00000000000..1d519c38151 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/contributing.rst @@ -0,0 +1,5 @@ +.. _contributing: + +.. include:: ../CONTRIBUTING.rst + +.. include:: ../CODE_OF_CONDUCT.rst diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/docutils.conf b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/docutils.conf new file mode 100644 index 00000000000..db8ca82c747 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/docutils.conf @@ -0,0 +1,3 @@ +[parsers] +[restructuredtext parser] +smart_quotes=yes diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/examples.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/examples.rst new file mode 100644 index 00000000000..4432e8fcb53 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/examples.rst @@ -0,0 +1,705 @@ +.. _examples: + +``attrs`` by Example +==================== + + +Basics +------ + +The simplest possible usage is: + +.. doctest:: + + >>> import attr + >>> @attr.s + ... class Empty(object): + ... pass + >>> Empty() + Empty() + >>> Empty() == Empty() + True + >>> Empty() is Empty() + False + +So in other words: ``attrs`` is useful even without actual attributes! + +But you'll usually want some data on your classes, so let's add some: + +.. doctest:: + + >>> @attr.s + ... class Coordinates(object): + ... x = attr.ib() + ... y = attr.ib() + +By default, all features are added, so you immediately have a fully functional data class with a nice ``repr`` string and comparison methods. + +.. doctest:: + + >>> c1 = Coordinates(1, 2) + >>> c1 + Coordinates(x=1, y=2) + >>> c2 = Coordinates(x=2, y=1) + >>> c2 + Coordinates(x=2, y=1) + >>> c1 == c2 + False + +As shown, the generated ``__init__`` method allows for both positional and keyword arguments. + +If playful naming turns you off, ``attrs`` comes with serious business aliases: + +.. doctest:: + + >>> from attr import attrs, attrib + >>> @attrs + ... class SeriousCoordinates(object): + ... x = attrib() + ... y = attrib() + >>> SeriousCoordinates(1, 2) + SeriousCoordinates(x=1, y=2) + >>> attr.fields(Coordinates) == attr.fields(SeriousCoordinates) + True + +For private attributes, ``attrs`` will strip the leading underscores for keyword arguments: + +.. doctest:: + + >>> @attr.s + ... class C(object): + ... _x = attr.ib() + >>> C(x=1) + C(_x=1) + +If you want to initialize your private attributes yourself, you can do that too: + +.. doctest:: + + >>> @attr.s + ... class C(object): + ... _x = attr.ib(init=False, default=42) + >>> C() + C(_x=42) + >>> C(23) + Traceback (most recent call last): + ... + TypeError: __init__() takes exactly 1 argument (2 given) + +An additional way of defining attributes is supported too. +This is useful in times when you want to enhance classes that are not yours (nice ``__repr__`` for Django models anyone?): + +.. doctest:: + + >>> class SomethingFromSomeoneElse(object): + ... def __init__(self, x): + ... self.x = x + >>> SomethingFromSomeoneElse = attr.s( + ... these={ + ... "x": attr.ib() + ... }, init=False)(SomethingFromSomeoneElse) + >>> SomethingFromSomeoneElse(1) + SomethingFromSomeoneElse(x=1) + + +`Subclassing is bad for you `_, but ``attrs`` will still do what you'd hope for: + +.. doctest:: + + >>> @attr.s + ... class A(object): + ... a = attr.ib() + ... def get_a(self): + ... return self.a + >>> @attr.s + ... class B(object): + ... b = attr.ib() + >>> @attr.s + ... class C(B, A): + ... c = attr.ib() + >>> i = C(1, 2, 3) + >>> i + C(a=1, b=2, c=3) + >>> i == C(1, 2, 3) + True + >>> i.get_a() + 1 + +The order of the attributes is defined by the `MRO `_. + +In Python 3, classes defined within other classes are `detected `_ and reflected in the ``__repr__``. +In Python 2 though, it's impossible. +Therefore ``@attr.s`` comes with the ``repr_ns`` option to set it manually: + +.. doctest:: + + >>> @attr.s + ... class C(object): + ... @attr.s(repr_ns="C") + ... class D(object): + ... pass + >>> C.D() + C.D() + +``repr_ns`` works on both Python 2 and 3. +On Python 3 it overrides the implicit detection. + + +.. _asdict: + +Converting to Collections Types +------------------------------- + +When you have a class with data, it often is very convenient to transform that class into a :class:`dict` (for example if you want to serialize it to JSON): + +.. doctest:: + + >>> attr.asdict(Coordinates(x=1, y=2)) + {'x': 1, 'y': 2} + +Some fields cannot or should not be transformed. +For that, :func:`attr.asdict` offers a callback that decides whether an attribute should be included: + +.. doctest:: + + >>> @attr.s + ... class UserList(object): + ... users = attr.ib() + >>> @attr.s + ... class User(object): + ... email = attr.ib() + ... password = attr.ib() + >>> attr.asdict(UserList([User("jane@doe.invalid", "s33kred"), + ... User("joe@doe.invalid", "p4ssw0rd")]), + ... filter=lambda attr, value: attr.name != "password") + {'users': [{'email': 'jane@doe.invalid'}, {'email': 'joe@doe.invalid'}]} + +For the common case where you want to :func:`include ` or :func:`exclude ` certain types or attributes, ``attrs`` ships with a few helpers: + +.. doctest:: + + >>> @attr.s + ... class User(object): + ... login = attr.ib() + ... password = attr.ib() + ... id = attr.ib() + >>> attr.asdict( + ... User("jane", "s33kred", 42), + ... filter=attr.filters.exclude(attr.fields(User).password, int)) + {'login': 'jane'} + >>> @attr.s + ... class C(object): + ... x = attr.ib() + ... y = attr.ib() + ... z = attr.ib() + >>> attr.asdict(C("foo", "2", 3), + ... filter=attr.filters.include(int, attr.fields(C).x)) + {'x': 'foo', 'z': 3} + +Other times, all you want is a tuple and ``attrs`` won't let you down: + +.. doctest:: + + >>> import sqlite3 + >>> import attr + >>> @attr.s + ... class Foo: + ... a = attr.ib() + ... b = attr.ib() + >>> foo = Foo(2, 3) + >>> with sqlite3.connect(":memory:") as conn: + ... c = conn.cursor() + ... c.execute("CREATE TABLE foo (x INTEGER PRIMARY KEY ASC, y)") #doctest: +ELLIPSIS + ... c.execute("INSERT INTO foo VALUES (?, ?)", attr.astuple(foo)) #doctest: +ELLIPSIS + ... foo2 = Foo(*c.execute("SELECT x, y FROM foo").fetchone()) + + + >>> foo == foo2 + True + + + + +Defaults +-------- + +Sometimes you want to have default values for your initializer. +And sometimes you even want mutable objects as default values (ever used accidentally ``def f(arg=[])``?). +``attrs`` has you covered in both cases: + +.. doctest:: + + >>> import collections + >>> @attr.s + ... class Connection(object): + ... socket = attr.ib() + ... @classmethod + ... def connect(cls, db_string): + ... # ... connect somehow to db_string ... + ... return cls(socket=42) + >>> @attr.s + ... class ConnectionPool(object): + ... db_string = attr.ib() + ... pool = attr.ib(default=attr.Factory(collections.deque)) + ... debug = attr.ib(default=False) + ... def get_connection(self): + ... try: + ... return self.pool.pop() + ... except IndexError: + ... if self.debug: + ... print("New connection!") + ... return Connection.connect(self.db_string) + ... def free_connection(self, conn): + ... if self.debug: + ... print("Connection returned!") + ... self.pool.appendleft(conn) + ... + >>> cp = ConnectionPool("postgres://localhost") + >>> cp + ConnectionPool(db_string='postgres://localhost', pool=deque([]), debug=False) + >>> conn = cp.get_connection() + >>> conn + Connection(socket=42) + >>> cp.free_connection(conn) + >>> cp + ConnectionPool(db_string='postgres://localhost', pool=deque([Connection(socket=42)]), debug=False) + +More information on why class methods for constructing objects are awesome can be found in this insightful `blog post `_. + +Default factories can also be set using a decorator. +The method receives the partially initialized instance which enables you to base a default value on other attributes: + +.. doctest:: + + >>> @attr.s + ... class C(object): + ... x = attr.ib(default=1) + ... y = attr.ib() + ... @y.default + ... def name_does_not_matter(self): + ... return self.x + 1 + >>> C() + C(x=1, y=2) + + +.. _examples_validators: + +Validators +---------- + +Although your initializers should do as little as possible (ideally: just initialize your instance according to the arguments!), it can come in handy to do some kind of validation on the arguments. + +``attrs`` offers two ways to define validators for each attribute and it's up to you to choose which one suites better your style and project. + + +Decorator +~~~~~~~~~ + +The more straightforward way is by using the attribute's ``validator`` method as a decorator. +The method has to accept three arguments: + +#. the *instance* that's being validated (aka ``self``), +#. the *attribute* that it's validating, and finally +#. the *value* that is passed for it. + +If the value does not pass the validator's standards, it just raises an appropriate exception. + +.. doctest:: + + >>> @attr.s + ... class C(object): + ... x = attr.ib() + ... @x.validator + ... def check(self, attribute, value): + ... if value > 42: + ... raise ValueError("x must be smaller or equal to 42") + >>> C(42) + C(x=42) + >>> C(43) + Traceback (most recent call last): + ... + ValueError: x must be smaller or equal to 42 + + +Callables +~~~~~~~~~ + +If you want to re-use your validators, you should have a look at the ``validator`` argument to :func:`attr.ib()`. + +It takes either a callable or a list of callables (usually functions) and treats them as validators that receive the same arguments as with the decorator approach. + +Since the validators runs *after* the instance is initialized, you can refer to other attributes while validating: + +.. doctest:: + + >>> def x_smaller_than_y(instance, attribute, value): + ... if value >= instance.y: + ... raise ValueError("'x' has to be smaller than 'y'!") + >>> @attr.s + ... class C(object): + ... x = attr.ib(validator=[attr.validators.instance_of(int), + ... x_smaller_than_y]) + ... y = attr.ib() + >>> C(x=3, y=4) + C(x=3, y=4) + >>> C(x=4, y=3) + Traceback (most recent call last): + ... + ValueError: 'x' has to be smaller than 'y'! + +This example also shows of some syntactic sugar for using the :func:`attr.validators.and_` validator: if you pass a list, all validators have to pass. + +``attrs`` won't intercept your changes to those attributes but you can always call :func:`attr.validate` on any instance to verify that it's still valid: + +.. doctest:: + + >>> i = C(4, 5) + >>> i.x = 5 # works, no magic here + >>> attr.validate(i) + Traceback (most recent call last): + ... + ValueError: 'x' has to be smaller than 'y'! + +``attrs`` ships with a bunch of validators, make sure to :ref:`check them out ` before writing your own: + +.. doctest:: + + >>> @attr.s + ... class C(object): + ... x = attr.ib(validator=attr.validators.instance_of(int)) + >>> C(42) + C(x=42) + >>> C("42") + Traceback (most recent call last): + ... + TypeError: ("'x' must be (got '42' that is a ).", Attribute(name='x', default=NOTHING, factory=NOTHING, validator=>, type=None), , '42') + +Of course you can mix and match the two approaches at your convenience: + +.. doctest:: + + >>> @attr.s + ... class C(object): + ... x = attr.ib(validator=attr.validators.instance_of(int)) + ... @x.validator + ... def fits_byte(self, attribute, value): + ... if not 0 < value < 256: + ... raise ValueError("value out of bounds") + >>> C(128) + C(x=128) + >>> C("128") + Traceback (most recent call last): + ... + TypeError: ("'x' must be (got '128' that is a ).", Attribute(name='x', default=NOTHING, validator=[>, ], repr=True, cmp=True, hash=True, init=True, convert=None, metadata=mappingproxy({}), type=None), , '128') + >>> C(256) + Traceback (most recent call last): + ... + ValueError: value out of bounds + +And finally you can disable validators globally: + + >>> attr.set_run_validators(False) + >>> C("128") + C(x='128') + >>> attr.set_run_validators(True) + >>> C("128") + Traceback (most recent call last): + ... + TypeError: ("'x' must be (got '128' that is a ).", Attribute(name='x', default=NOTHING, validator=[>, ], repr=True, cmp=True, hash=True, init=True, convert=None, metadata=mappingproxy({}), type=None), , '128') + + +Conversion +---------- + +Attributes can have a ``convert`` function specified, which will be called with the attribute's passed-in value to get a new value to use. +This can be useful for doing type-conversions on values that you don't want to force your callers to do. + +.. doctest:: + + >>> @attr.s + ... class C(object): + ... x = attr.ib(convert=int) + >>> o = C("1") + >>> o.x + 1 + +Converters are run *before* validators, so you can use validators to check the final form of the value. + +.. doctest:: + + >>> def validate_x(instance, attribute, value): + ... if value < 0: + ... raise ValueError("x must be be at least 0.") + >>> @attr.s + ... class C(object): + ... x = attr.ib(convert=int, validator=validate_x) + >>> o = C("0") + >>> o.x + 0 + >>> C("-1") + Traceback (most recent call last): + ... + ValueError: x must be be at least 0. + + +.. _metadata: + +Metadata +-------- + +All ``attrs`` attributes may include arbitrary metadata in the form of a read-only dictionary. + +.. doctest:: + + >>> @attr.s + ... class C(object): + ... x = attr.ib(metadata={'my_metadata': 1}) + >>> attr.fields(C).x.metadata + mappingproxy({'my_metadata': 1}) + >>> attr.fields(C).x.metadata['my_metadata'] + 1 + +Metadata is not used by ``attrs``, and is meant to enable rich functionality in third-party libraries. +The metadata dictionary follows the normal dictionary rules: keys need to be hashable, and both keys and values are recommended to be immutable. + +If you're the author of a third-party library with ``attrs`` integration, please see :ref:`Extending Metadata `. + + +Types +----- + +``attrs`` also allows you to associate a type with an attribute using either the *type* argument to :func:`attr.ib` or -- as of Python 3.6 -- using `PEP 526 `_-annotations: + + +.. doctest:: + + >>> @attr.s + ... class C: + ... x = attr.ib(type=int) + ... y: int = attr.ib() + >>> attr.fields(C).x.type + + >>> attr.fields(C).y.type + + +If you don't mind annotating *all* attributes, you can even drop the :func:`attr.ib` and assign default values instead: + +.. doctest:: + + >>> import typing + >>> @attr.s(auto_attribs=True) + ... class AutoC: + ... cls_var: typing.ClassVar[int] = 5 # this one is ignored + ... l: typing.List[int] = attr.Factory(list) + ... x: int = 1 + ... foo: str = attr.ib( + ... default="every attrib needs a type if auto_attribs=True" + ... ) + ... bar: typing.Any = None + >>> attr.fields(AutoC).l.type + typing.List[int] + >>> attr.fields(AutoC).x.type + + >>> attr.fields(AutoC).foo.type + + >>> attr.fields(AutoC).bar.type + typing.Any + >>> AutoC() + AutoC(l=[], x=1, foo='every attrib needs a type if auto_attribs=True', bar=None) + >>> AutoC.cls_var + 5 + + +.. warning:: + + ``attrs`` itself doesn't have any features that work on top of type metadata *yet*. + However it's useful for writing your own validators or serialization frameworks. + + +.. _slots: + +Slots +----- + +By default, instances of classes have a dictionary for attribute storage. +This wastes space for objects having very few data attributes. +The space consumption can become significant when creating large numbers of instances. + +Normal Python classes can avoid using a separate dictionary for each instance of a class by `defining `_ ``__slots__``. +For ``attrs`` classes it's enough to set ``slots=True``: + +.. doctest:: + + >>> @attr.s(slots=True) + ... class Coordinates(object): + ... x = attr.ib() + ... y = attr.ib() + + +.. note:: + + ``attrs`` slot classes can inherit from other classes just like non-slot classes, but some of the benefits of slot classes are lost if you do that. + If you must inherit from other classes, try to inherit only from other slot classes. + +Slot classes are a little different than ordinary, dictionary-backed classes: + +- Assigning to a non-existent attribute of an instance will result in an ``AttributeError`` being raised. + Depending on your needs, this might be a good thing since it will let you catch typos early. + This is not the case if your class inherits from any non-slot classes. + + .. doctest:: + + >>> @attr.s(slots=True) + ... class Coordinates(object): + ... x = attr.ib() + ... y = attr.ib() + ... + >>> c = Coordinates(x=1, y=2) + >>> c.z = 3 + Traceback (most recent call last): + ... + AttributeError: 'Coordinates' object has no attribute 'z' + +- Since non-slot classes cannot be turned into slot classes after they have been created, ``attr.s(slots=True)`` will *replace* the class it is applied to with a copy. + In almost all cases this isn't a problem, but we mention it for the sake of completeness. + + * One notable problem is that certain metaclass features like ``__init_subclass__`` do not work with slot classes. + +- Using :mod:`pickle` with slot classes requires pickle protocol 2 or greater. + Python 2 uses protocol 0 by default so the protocol needs to be specified. + Python 3 uses protocol 3 by default. + You can support protocol 0 and 1 by implementing :meth:`__getstate__ ` and :meth:`__setstate__ ` methods yourself. + Those methods are created for frozen slot classes because they won't pickle otherwise. + `Think twice `_ before using :mod:`pickle` though. + +- As always with slot classes, you must specify a ``__weakref__`` slot if you wish for the class to be weak-referenceable. + Here's how it looks using ``attrs``: + + .. doctest:: + + >>> import weakref + >>> @attr.s(slots=True) + ... class C(object): + ... __weakref__ = attr.ib(init=False, hash=False, repr=False, cmp=False) + ... x = attr.ib() + >>> c = C(1) + >>> weakref.ref(c) + + +All in all, setting ``slots=True`` is usually a very good idea. + + +Immutability +------------ + +Sometimes you have instances that shouldn't be changed after instantiation. +Immutability is especially popular in functional programming and is generally a very good thing. +If you'd like to enforce it, ``attrs`` will try to help: + +.. doctest:: + + >>> @attr.s(frozen=True) + ... class C(object): + ... x = attr.ib() + >>> i = C(1) + >>> i.x = 2 + Traceback (most recent call last): + ... + attr.exceptions.FrozenInstanceError: can't set attribute + >>> i.x + 1 + +Please note that true immutability is impossible in Python but it will :ref:`get ` you 99% there. +By themselves, immutable classes are useful for long-lived objects that should never change; like configurations for example. + +In order to use them in regular program flow, you'll need a way to easily create new instances with changed attributes. +In Clojure that function is called `assoc `_ and ``attrs`` shamelessly imitates it: :func:`attr.evolve`: + +.. doctest:: + + >>> @attr.s(frozen=True) + ... class C(object): + ... x = attr.ib() + ... y = attr.ib() + >>> i1 = C(1, 2) + >>> i1 + C(x=1, y=2) + >>> i2 = attr.evolve(i1, y=3) + >>> i2 + C(x=1, y=3) + >>> i1 == i2 + False + + +Other Goodies +------------- + +Sometimes you may want to create a class programmatically. +``attrs`` won't let you down and gives you :func:`attr.make_class` : + +.. doctest:: + + >>> @attr.s + ... class C1(object): + ... x = attr.ib() + ... y = attr.ib() + >>> C2 = attr.make_class("C2", ["x", "y"]) + >>> attr.fields(C1) == attr.fields(C2) + True + +You can still have power over the attributes if you pass a dictionary of name: ``attr.ib`` mappings and can pass arguments to ``@attr.s``: + +.. doctest:: + + >>> C = attr.make_class("C", {"x": attr.ib(default=42), + ... "y": attr.ib(default=attr.Factory(list))}, + ... repr=False) + >>> i = C() + >>> i # no repr added! + <__main__.C object at ...> + >>> i.x + 42 + >>> i.y + [] + +If you need to dynamically make a class with :func:`attr.make_class` and it needs to be a subclass of something else than ``object``, use the ``bases`` argument: + +.. doctest:: + + >>> class D(object): + ... def __eq__(self, other): + ... return True # arbitrary example + >>> C = attr.make_class("C", {}, bases=(D,), cmp=False) + >>> isinstance(C(), D) + True + +Sometimes, you want to have your class's ``__init__`` method do more than just +the initialization, validation, etc. that gets done for you automatically when +using ``@attr.s``. +To do this, just define a ``__attrs_post_init__`` method in your class. +It will get called at the end of the generated ``__init__`` method. + +.. doctest:: + + >>> @attr.s + ... class C(object): + ... x = attr.ib() + ... y = attr.ib() + ... z = attr.ib(init=False) + ... + ... def __attrs_post_init__(self): + ... self.z = self.x + self.y + >>> obj = C(x=1, y=2) + >>> obj + C(x=1, y=2, z=3) + +Finally, you can exclude single attributes from certain methods: + +.. doctest:: + + >>> @attr.s + ... class C(object): + ... user = attr.ib() + ... password = attr.ib(repr=False) + >>> C("me", "s3kr3t") + C(user='me') diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/extending.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/extending.rst new file mode 100644 index 00000000000..d460ee9b8c0 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/extending.rst @@ -0,0 +1,112 @@ +.. _extending: + +Extending +========= + +Each ``attrs``-decorated class has a ``__attrs_attrs__`` class attribute. +It is a tuple of :class:`attr.Attribute` carrying meta-data about each attribute. + +So it is fairly simple to build your own decorators on top of ``attrs``: + +.. doctest:: + + >>> import attr + >>> def print_attrs(cls): + ... print(cls.__attrs_attrs__) + >>> @print_attrs + ... @attr.s + ... class C(object): + ... a = attr.ib() + (Attribute(name='a', default=NOTHING, validator=None, repr=True, cmp=True, hash=None, init=True, convert=None, metadata=mappingproxy({}), type=None),) + + +.. warning:: + + The :func:`attr.s` decorator **must** be applied first because it puts ``__attrs_attrs__`` in place! + That means that is has to come *after* your decorator because:: + + @a + @b + def f(): + pass + + is just `syntactic sugar `_ for:: + + def original_f(): + pass + + f = a(b(original_f)) + + +Wrapping the Decorator +---------------------- + +A more elegant way can be to wrap ``attrs`` altogether and build a class `DSL `_ on top of it. + +An example for that is the package `environ_config `_ that uses ``attrs`` under the hood to define environment-based configurations declaratively without exposing ``attrs`` APIs at all. + + +Types +----- + +``attrs`` offers two ways of attaching type information to attributes: + +- `PEP 526 `_ annotations on Python 3.6 and later, +- and the *type* argument to :func:`attr.ib`. + +This information is available to you: + +.. doctest:: + + >>> import attr + >>> @attr.s + ... class C(object): + ... x: int = attr.ib() + ... y = attr.ib(type=str) + >>> attr.fields(C).x.type + + >>> attr.fields(C).y.type + + +Currently, ``attrs`` doesn't do anything with this information but it's very useful if you'd like to write your own validators or serializers! + + +.. _extending_metadata: + +Metadata +-------- + +If you're the author of a third-party library with ``attrs`` integration, you may want to take advantage of attribute metadata. + +Here are some tips for effective use of metadata: + +- Try making your metadata keys and values immutable. + This keeps the entire ``Attribute`` instances immutable too. + +- To avoid metadata key collisions, consider exposing your metadata keys from your modules.:: + + from mylib import MY_METADATA_KEY + + @attr.s + class C(object): + x = attr.ib(metadata={MY_METADATA_KEY: 1}) + + Metadata should be composable, so consider supporting this approach even if you decide implementing your metadata in one of the following ways. + +- Expose ``attr.ib`` wrappers for your specific metadata. + This is a more graceful approach if your users don't require metadata from other libraries. + + .. doctest:: + + >>> MY_TYPE_METADATA = '__my_type_metadata' + >>> + >>> def typed(cls, default=attr.NOTHING, validator=None, repr=True, cmp=True, hash=None, init=True, convert=None, metadata={}): + ... metadata = dict() if not metadata else metadata + ... metadata[MY_TYPE_METADATA] = cls + ... return attr.ib(default, validator, repr, cmp, hash, init, convert, metadata) + >>> + >>> @attr.s + ... class C(object): + ... x = typed(int, default=1, init=False) + >>> attr.fields(C).x.metadata[MY_TYPE_METADATA] + diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/how-does-it-work.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/how-does-it-work.rst new file mode 100644 index 00000000000..c20becd1f78 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/how-does-it-work.rst @@ -0,0 +1,79 @@ +.. _how: + +How Does It Work? +================= + + +Boilerplate +----------- + +``attrs`` certainly isn't the first library that aims to simplify class definition in Python. +But its **declarative** approach combined with **no runtime overhead** lets it stand out. + +Once you apply the ``@attr.s`` decorator to a class, ``attrs`` searches the class object for instances of ``attr.ib``\ s. +Internally they're a representation of the data passed into ``attr.ib`` along with a counter to preserve the order of the attributes. + +In order to ensure that sub-classing works as you'd expect it to work, ``attrs`` also walks the class hierarchy and collects the attributes of all super-classes. +Please note that ``attrs`` does *not* call ``super()`` *ever*. +It will write dunder methods to work on *all* of those attributes which also has performance benefits due to fewer function calls. + +Once ``attrs`` knows what attributes it has to work on, it writes the requested dunder methods and -- depending on whether you wish to have ``__slots__`` -- creates a new class for you (``slots=True``) or attaches them to the original class (``slots=False``). +While creating new classes is more elegant, we've run into several edge cases surrounding metaclasses that make it impossible to go this route unconditionally. + +To be very clear: if you define a class with a single attribute without a default value, the generated ``__init__`` will look *exactly* how you'd expect: + +.. doctest:: + + >>> import attr, inspect + >>> @attr.s + ... class C(object): + ... x = attr.ib() + >>> print(inspect.getsource(C.__init__)) + def __init__(self, x): + self.x = x + + +No magic, no meta programming, no expensive introspection at runtime. + +**** + +Everything until this point happens exactly *once* when the class is defined. +As soon as a class is done, it's done. +And it's just a regular Python class like any other, except for a single ``__attrs_attrs__`` attribute that can be used for introspection or for writing your own tools and decorators on top of ``attrs`` (like :func:`attr.asdict`). + +And once you start instantiating your classes, ``attrs`` is out of your way completely. + +This **static** approach was very much a design goal of ``attrs`` and what I strongly believe makes it distinct. + + +.. _how-frozen: + +Immutability +------------ + +In order to give you immutability, ``attrs`` will attach a ``__setattr__`` method to your class that raises a :exc:`attr.exceptions.FrozenInstanceError` whenever anyone tries to set an attribute. + +To circumvent that ourselves in ``__init__``, ``attrs`` uses (an aggressively cached) :meth:`object.__setattr__` to set your attributes. +This is (still) slower than a plain assignment: + +.. code-block:: none + + $ pyperf timeit --rigorous \ + -s "import attr; C = attr.make_class('C', ['x', 'y', 'z'], slots=True)" \ + "C(1, 2, 3)" + ........................................ + Median +- std dev: 378 ns +- 12 ns + + $ pyperf timeit --rigorous \ + -s "import attr; C = attr.make_class('C', ['x', 'y', 'z'], slots=True, frozen=True)" \ + "C(1, 2, 3)" + ........................................ + Median +- std dev: 676 ns +- 16 ns + +So on a standard notebook the difference is about 300 nanoseconds (1 second is 1,000,000,000 nanoseconds). +It's certainly something you'll feel in a hot loop but shouldn't matter in normal code. +Pick what's more important to you. + +**** + +Once constructed, frozen instances don't differ in any way from regular ones except that you cannot change its attributes. diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/index.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/index.rst new file mode 100644 index 00000000000..bb24cd773fb --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/index.rst @@ -0,0 +1,80 @@ +====================================== +``attrs``: Classes Without Boilerplate +====================================== + +Release v\ |release| (:doc:`What's new? `). + +.. include:: ../README.rst + :start-after: teaser-begin + :end-before: -spiel-end- + + +Getting Started +=============== + +``attrs`` is a Python-only package `hosted on PyPI `_. +The recommended installation method is `pip `_-installing into a `virtualenv `_: + +.. code-block:: console + + $ pip install attrs + +The next three steps should bring you up and running in no time: + +- :doc:`overview` will show you a simple example of ``attrs`` in action and introduce you to its philosophy. + Afterwards, you can start writing your own classes, understand what drives ``attrs``'s design, and know what ``@attr.s`` and ``attr.ib()`` stand for. +- :doc:`examples` will give you a comprehensive tour of ``attrs``'s features. + After reading, you will know about our advanced features and how to use them. +- Finally :doc:`why` gives you a rundown of potential alternatives and why we think ``attrs`` is superior. + Yes, we've heard about ``namedtuple``\ s! + + +If you need any help while getting started, feel free to use the ``python-attrs`` tag on `StackOverflow `_ and someone will surely help you out! + + +Day-to-Day Usage +================ + +- Once you're comfortable with the concepts, our :doc:`api` contains all information you need to use ``attrs`` to its fullest. +- ``attrs`` is built for extension from the ground up. + :doc:`extending` will show you the affordances it offers and how to make it a building block of your own projects. + + +.. include:: ../README.rst + :start-after: -testimonials- + :end-before: -end- + +.. include:: ../README.rst + :start-after: -project-information- + +.. toctree:: + :maxdepth: 1 + + license + backward-compatibility + contributing + changelog + + +---- + + +Full Table of Contents +====================== + +.. toctree:: + :maxdepth: 2 + + overview + why + examples + api + extending + how-does-it-work + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`search` diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/license.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/license.rst new file mode 100644 index 00000000000..cef5f393993 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/license.rst @@ -0,0 +1,8 @@ +=================== +License and Credits +=================== + +``attrs`` is licensed under the `MIT `_ license. +The full license text can be also found in the `source code repository `_. + +.. include:: ../AUTHORS.rst diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/overview.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/overview.rst new file mode 100644 index 00000000000..47b022ff32e --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/overview.rst @@ -0,0 +1,87 @@ +======== +Overview +======== + +In order to fulfill its ambitious goal of bringing back the joy to writing classes, it gives you a class decorator and a way to declaratively define the attributes on that class: + +.. include:: ../README.rst + :start-after: -code-begin- + :end-before: -testimonials- + + +.. _philosophy: + +Philosophy +========== + +**It's about regular classes.** + ``attrs`` is for creating well-behaved classes with a type, attributes, methods, and everything that comes with a class. + It can be used for data-only containers like ``namedtuple``\ s or ``types.SimpleNamespace`` but they're just a sub-genre of what ``attrs`` is good for. + +**The class belongs to the users.** + You define a class and ``attrs`` adds static methods to that class based on the attributes you declare. + The end. + It doesn't add metaclasses. + It doesn't add classes you've never heard of to your inheritance tree. + An ``attrs`` class in runtime is indistiguishable from a regular class: because it *is* a regular class with a few boilerplate-y methods attached. + +**Be light on API impact.** + As convenient as it seems at first, ``attrs`` will *not* tack on any methods to your classes save the dunder ones. + Hence all the useful :ref:`tools ` that come with ``attrs`` live in functions that operate on top of instances. + Since they take an ``attrs`` instance as their first argument, you can attach them to your classes with one line of code. + +**Performance matters.** + ``attrs`` runtime impact is very close to zero because all the work is done when the class is defined. + Once you're instantiating it, ``attrs`` is out of the picture completely. + +**No surprises.** + ``attrs`` creates classes that arguably work the way a Python beginner would reasonably expect them to work. + It doesn't try to guess what you mean because explicit is better than implicit. + It doesn't try to be clever because software shouldn't be clever. + +Check out :doc:`how-does-it-work` if you'd like to know how it achieves all of the above. + + +What ``attrs`` Is Not +===================== + +``attrs`` does *not* invent some kind of magic system that pulls classes out of its hat using meta classes, runtime introspection, and shaky interdependencies. + +All ``attrs`` does is: + +1. take your declaration, +2. write dunder methods based on that information, +3. and attach them to your class. + +It does *nothing* dynamic at runtime, hence zero runtime overhead. +It's still *your* class. +Do with it as you please. + + +On the ``attr.s`` and ``attr.ib`` Names +======================================= + +The ``attr.s`` decorator and the ``attr.ib`` function aren't any obscure abbreviations. +They are a *concise* and highly *readable* way to write ``attrs`` and ``attrib`` with an *explicit namespace*. + +At first, some people have a negative gut reaction to that; resembling the reactions to Python's significant whitespace. +And as with that, once one gets used to it, the readability and explicitness of that API prevails and delights. + +For those who can't swallow that API at all, ``attrs`` comes with serious business aliases: ``attr.attrs`` and ``attr.attrib``. + +Therefore, the following class definition is identical to the previous one: + +.. doctest:: + + >>> from attr import attrs, attrib, Factory + >>> @attrs + ... class SomeClass(object): + ... a_number = attrib(default=42) + ... list_of_numbers = attrib(default=Factory(list)) + ... + ... def hard_math(self, another_number): + ... return self.a_number + sum(self.list_of_numbers) * another_number + >>> SomeClass(1, [1, 2, 3]) + SomeClass(a_number=1, list_of_numbers=[1, 2, 3]) + +Use whichever variant fits your taste better. diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/why.rst b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/why.rst new file mode 100644 index 00000000000..9c64cb93c57 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/docs/why.rst @@ -0,0 +1,251 @@ +.. _why: + +Why not… +======== + + +If you'd like third party's account why ``attrs`` is great, have a look at Glyph's `The One Python Library Everyone Needs `_! + + +…tuples? +-------- + + +Readability +^^^^^^^^^^^ + +What makes more sense while debugging:: + + Point(x=1, y=2) + +or:: + + (1, 2) + +? + +Let's add even more ambiguity:: + + Customer(id=42, reseller=23, first_name="Jane", last_name="John") + +or:: + + (42, 23, "Jane", "John") + +? + +Why would you want to write ``customer[2]`` instead of ``customer.first_name``? + +Don't get me started when you add nesting. +If you've never run into mysterious tuples you had no idea what the hell they meant while debugging, you're much smarter than yours truly. + +Using proper classes with names and types makes program code much more readable and comprehensible_. +Especially when trying to grok a new piece of software or returning to old code after several months. + +.. _comprehensible: https://arxiv.org/pdf/1304.5257.pdf + + +Extendability +^^^^^^^^^^^^^ + +Imagine you have a function that takes or returns a tuple. +Especially if you use tuple unpacking (eg. ``x, y = get_point()``), adding additional data means that you have to change the invocation of that function *everywhere*. + +Adding an attribute to a class concerns only those who actually care about that attribute. + + +…namedtuples? +------------- + +:func:`collections.namedtuple`\ s are tuples with names, not classes. [#history]_ +Since writing classes is tiresome in Python, every now and then someone discovers all the typing they could save and gets really excited. +However that convenience comes at a price. + +The most obvious difference between ``namedtuple``\ s and ``attrs``-based classes is that the latter are type-sensitive: + +.. doctest:: + + >>> import attr + >>> C1 = attr.make_class("C1", ["a"]) + >>> C2 = attr.make_class("C2", ["a"]) + >>> i1 = C1(1) + >>> i2 = C2(1) + >>> i1.a == i2.a + True + >>> i1 == i2 + False + +…while a ``namedtuple`` is *intentionally* `behaving like a tuple`_ which means the type of a tuple is *ignored*: + +.. doctest:: + + >>> from collections import namedtuple + >>> NT1 = namedtuple("NT1", "a") + >>> NT2 = namedtuple("NT2", "b") + >>> t1 = NT1(1) + >>> t2 = NT2(1) + >>> t1 == t2 == (1,) + True + +Other often surprising behaviors include: + +- Since they are a subclass of tuples, ``namedtuple``\ s have a length and are both iterable and indexable. + That's not what you'd expect from a class and is likely to shadow subtle typo bugs. +- Iterability also implies that it's easy to accidentally unpack a ``namedtuple`` which leads to hard-to-find bugs. [#iter]_ +- ``namedtuple``\ s have their methods *on your instances* whether you like it or not. [#pollution]_ +- ``namedtuple``\ s are *always* immutable. + Not only does that mean that you can't decide for yourself whether your instances should be immutable or not, it also means that if you want to influence your class' initialization (validation? default values?), you have to implement :meth:`__new__() ` which is a particularly hacky and error-prone requirement for a very common problem. [#immutable]_ +- To attach methods to a ``namedtuple`` you have to subclass it. + And if you follow the standard library documentation's recommendation of:: + + class Point(namedtuple('Point', ['x', 'y'])): + # ... + + you end up with a class that has *two* ``Point``\ s in its :attr:`__mro__ `: ``[, , , ]``. + + That's not only confusing, it also has very practical consequences: + for example if you create documentation that includes class hierarchies like `Sphinx's autodoc `_ with ``show-inheritance``. + Again: common problem, hacky solution with confusing fallout. + +All these things make ``namedtuple``\ s a particularly poor choice for public APIs because all your objects are irrevocably tainted. +With ``attrs`` your users won't notice a difference because it creates regular, well-behaved classes. + +.. admonition:: Summary + + If you want a *tuple with names*, by all means: go for a ``namedtuple``. [#perf]_ + But if you want a class with methods, you're doing yourself a disservice by relying on a pile of hacks that requires you to employ even more hacks as your requirements expand. + + Other than that, ``attrs`` also adds nifty features like validators, converters, and (mutable!) default values. + + +.. rubric:: Footnotes + +.. [#history] The word is that ``namedtuple``\ s were added to the Python standard library as a way to make tuples in return values more readable. + And indeed that is something you see throughout the standard library. + + Looking at what the makers of ``namedtuple``\ s use it for themselves is a good guideline for deciding on your own use cases. +.. [#pollution] ``attrs`` only adds a single attribute: ``__attrs_attrs__`` for introspection. + All helpers are functions in the ``attr`` package. + Since they take the instance as first argument, you can easily attach them to your classes under a name of your own choice. +.. [#iter] :func:`attr.astuple` can be used to get that behavior in ``attrs`` on *explicit demand*. +.. [#immutable] ``attrs`` offers *optional* immutability through the ``frozen`` keyword. +.. [#perf] Although ``attrs`` would serve you just as well! + Since both employ the same method of writing and compiling Python code for you, the performance penalty is negligible at worst and in some cases ``attrs`` is even faster if you use ``slots=True`` (which is generally a good idea anyway). + +.. _behaving like a tuple: https://docs.python.org/3/tutorial/datastructures.html#tuples-and-sequences + + +…dicts? +------- + +Dictionaries are not for fixed fields. + +If you have a dict, it maps something to something else. +You should be able to add and remove values. + + + +``attrs`` lets you be specific about those expectations; a dictionary does not. +It gives you a named entity (the class) in your code, which lets you explain in other places whether you take a parameter of that class or return a value of that class. + +In other words: if your dict has a fixed and known set of keys, it is an object, not a hash. +So if you never iterate over the keys of a dict, you should use a proper class. + + +…hand-written classes? +---------------------- + +While we're fans of all things artisanal, writing the same nine methods all over again doesn't qualify for me. +I usually manage to get some typos inside and there's simply more code that can break and thus has to be tested. + +To bring it into perspective, the equivalent of + +.. doctest:: + + >>> @attr.s + ... class SmartClass(object): + ... a = attr.ib() + ... b = attr.ib() + >>> SmartClass(1, 2) + SmartClass(a=1, b=2) + +is + +.. doctest:: + + >>> class ArtisanalClass(object): + ... def __init__(self, a, b): + ... self.a = a + ... self.b = b + ... + ... def __repr__(self): + ... return "ArtisanalClass(a={}, b={})".format(self.a, self.b) + ... + ... def __eq__(self, other): + ... if other.__class__ is self.__class__: + ... return (self.a, self.b) == (other.a, other.b) + ... else: + ... return NotImplemented + ... + ... def __ne__(self, other): + ... result = self.__eq__(other) + ... if result is NotImplemented: + ... return NotImplemented + ... else: + ... return not result + ... + ... def __lt__(self, other): + ... if other.__class__ is self.__class__: + ... return (self.a, self.b) < (other.a, other.b) + ... else: + ... return NotImplemented + ... + ... def __le__(self, other): + ... if other.__class__ is self.__class__: + ... return (self.a, self.b) <= (other.a, other.b) + ... else: + ... return NotImplemented + ... + ... def __gt__(self, other): + ... if other.__class__ is self.__class__: + ... return (self.a, self.b) > (other.a, other.b) + ... else: + ... return NotImplemented + ... + ... def __ge__(self, other): + ... if other.__class__ is self.__class__: + ... return (self.a, self.b) >= (other.a, other.b) + ... else: + ... return NotImplemented + ... + ... def __hash__(self): + ... return hash((self.a, self.b)) + >>> ArtisanalClass(a=1, b=2) + ArtisanalClass(a=1, b=2) + +which is quite a mouthful and it doesn't even use any of ``attrs``'s more advanced features like validators or defaults values. +Also: no tests whatsoever. +And who will guarantee you, that you don't accidentally flip the ``<`` in your tenth implementation of ``__gt__``? + +It also should be noted that ``attrs`` is not an all-or-nothing solution. +You can freely choose which features you want and disable those that you want more control over: + +.. doctest:: + + >>> @attr.s(repr=False) + ... class SmartClass(object): + ... a = attr.ib() + ... b = attr.ib() + ... + ... def __repr__(self): + ... return "" % (self.a,) + >>> SmartClass(1, 2) + + +.. admonition:: Summary + + If you don't care and like typing, we're not gonna stop you. + + However it takes a lot of bias and determined rationalization to claim that ``attrs`` raises the mental burden on a project given how difficult it is to find the important bits in a hand-written class and how annoying it is to ensure you've copy-pasted your code correctly over all your classes. + + In any case, if you ever get sick of the repetitiveness and drowning important code in a sea of boilerplate, ``attrs`` will be waiting for you. diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/pyproject.toml b/tests/wpt/web-platform-tests/tools/third_party/attrs/pyproject.toml new file mode 100644 index 00000000000..0f68a7cb0fc --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/pyproject.toml @@ -0,0 +1,26 @@ +[tool.towncrier] + package = "attr" + package_dir = "src" + filename = "CHANGELOG.rst" + issue_format = "`#{issue} `_" + directory = "changelog.d" + title_format = "{version} ({project_date})" + underlines = ["-", "^"] + + [[tool.towncrier.section]] + path = "" + + [[tool.towncrier.type]] + directory = "breaking" + name = "Backward-incompatible Changes" + showcontent = true + + [[tool.towncrier.type]] + directory = "deprecation" + name = "Deprecations" + showcontent = true + + [[tool.towncrier.type]] + directory = "change" + name = "Changes" + showcontent = true diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/setup.cfg b/tests/wpt/web-platform-tests/tools/third_party/attrs/setup.cfg new file mode 100644 index 00000000000..8ddbbabc3cd --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/setup.cfg @@ -0,0 +1,26 @@ +[bdist_wheel] +universal = 1 + + +[metadata] +# ensure LICENSE is included in wheel metadata +license_file = LICENSE + + +[tool:pytest] +minversion = 3.0 +strict = true +addopts = -ra +testpaths = tests +filterwarnings = + once::Warning + + +[isort] +atomic=true +lines_after_imports=2 +lines_between_types=1 +multi_line_output=5 +not_skip=__init__.py + +known_first_party=attr diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/setup.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/setup.py new file mode 100644 index 00000000000..232d3f5eaaa --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/setup.py @@ -0,0 +1,95 @@ +import codecs +import os +import re + +from setuptools import find_packages, setup + + +############################################################################### + +NAME = "attrs" +PACKAGES = find_packages(where="src") +META_PATH = os.path.join("src", "attr", "__init__.py") +KEYWORDS = ["class", "attribute", "boilerplate"] +CLASSIFIERS = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Natural Language :: English", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Software Development :: Libraries :: Python Modules", +] +INSTALL_REQUIRES = [] + +############################################################################### + +HERE = os.path.abspath(os.path.dirname(__file__)) + + +def read(*parts): + """ + Build an absolute path from *parts* and and return the contents of the + resulting file. Assume UTF-8 encoding. + """ + with codecs.open(os.path.join(HERE, *parts), "rb", "utf-8") as f: + return f.read() + + +META_FILE = read(META_PATH) + + +def find_meta(meta): + """ + Extract __*meta*__ from META_FILE. + """ + meta_match = re.search( + r"^__{meta}__ = ['\"]([^'\"]*)['\"]".format(meta=meta), + META_FILE, re.M + ) + if meta_match: + return meta_match.group(1) + raise RuntimeError("Unable to find __{meta}__ string.".format(meta=meta)) + + +VERSION = find_meta("version") +URI = find_meta("uri") +LONG = ( + read("README.rst") + "\n\n" + + "Release Information\n" + + "===================\n\n" + + re.search("(\d+.\d.\d \(.*?\)\n.*?)\n\n\n----\n\n\n", + read("CHANGELOG.rst"), re.S).group(1) + + "\n\n`Full changelog " + + "<{uri}en/stable/changelog.html>`_.\n\n".format(uri=URI) + + read("AUTHORS.rst") +) + + +if __name__ == "__main__": + setup( + name=NAME, + description=find_meta("description"), + license=find_meta("license"), + url=URI, + version=VERSION, + author=find_meta("author"), + author_email=find_meta("email"), + maintainer=find_meta("author"), + maintainer_email=find_meta("email"), + keywords=KEYWORDS, + long_description=LONG, + packages=PACKAGES, + package_dir={"": "src"}, + zip_safe=False, + classifiers=CLASSIFIERS, + install_requires=INSTALL_REQUIRES, + ) diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/__init__.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/__init__.py new file mode 100644 index 00000000000..929b1721ff1 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/__init__.py @@ -0,0 +1,55 @@ +from __future__ import absolute_import, division, print_function + +from functools import partial + +from . import converters, exceptions, filters, validators +from ._config import get_run_validators, set_run_validators +from ._funcs import asdict, assoc, astuple, evolve, has +from ._make import ( + NOTHING, Attribute, Factory, attrib, attrs, fields, make_class, validate +) + + +__version__ = "17.4.0.dev0" + +__title__ = "attrs" +__description__ = "Classes Without Boilerplate" +__uri__ = "http://www.attrs.org/" +__doc__ = __description__ + " <" + __uri__ + ">" + +__author__ = "Hynek Schlawack" +__email__ = "hs@ox.cx" + +__license__ = "MIT" +__copyright__ = "Copyright (c) 2015 Hynek Schlawack" + + +s = attributes = attrs +ib = attr = attrib +dataclass = partial(attrs, auto_attribs=True) # happy Easter ;) + +__all__ = [ + "Attribute", + "Factory", + "NOTHING", + "asdict", + "assoc", + "astuple", + "attr", + "attrib", + "attributes", + "attrs", + "converters", + "evolve", + "exceptions", + "fields", + "filters", + "get_run_validators", + "has", + "ib", + "make_class", + "s", + "set_run_validators", + "validate", + "validators", +] diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/_compat.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/_compat.py new file mode 100644 index 00000000000..8a49341b25f --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/_compat.py @@ -0,0 +1,139 @@ +from __future__ import absolute_import, division, print_function + +import platform +import sys +import types +import warnings + + +PY2 = sys.version_info[0] == 2 +PYPY = platform.python_implementation() == "PyPy" + + +if PY2: + from UserDict import IterableUserDict + + # We 'bundle' isclass instead of using inspect as importing inspect is + # fairly expensive (order of 10-15 ms for a modern machine in 2016) + def isclass(klass): + return isinstance(klass, (type, types.ClassType)) + + # TYPE is used in exceptions, repr(int) is different on Python 2 and 3. + TYPE = "type" + + def iteritems(d): + return d.iteritems() + + # Python 2 is bereft of a read-only dict proxy, so we make one! + class ReadOnlyDict(IterableUserDict): + """ + Best-effort read-only dict wrapper. + """ + + def __setitem__(self, key, val): + # We gently pretend we're a Python 3 mappingproxy. + raise TypeError("'mappingproxy' object does not support item " + "assignment") + + def update(self, _): + # We gently pretend we're a Python 3 mappingproxy. + raise AttributeError("'mappingproxy' object has no attribute " + "'update'") + + def __delitem__(self, _): + # We gently pretend we're a Python 3 mappingproxy. + raise TypeError("'mappingproxy' object does not support item " + "deletion") + + def clear(self): + # We gently pretend we're a Python 3 mappingproxy. + raise AttributeError("'mappingproxy' object has no attribute " + "'clear'") + + def pop(self, key, default=None): + # We gently pretend we're a Python 3 mappingproxy. + raise AttributeError("'mappingproxy' object has no attribute " + "'pop'") + + def popitem(self): + # We gently pretend we're a Python 3 mappingproxy. + raise AttributeError("'mappingproxy' object has no attribute " + "'popitem'") + + def setdefault(self, key, default=None): + # We gently pretend we're a Python 3 mappingproxy. + raise AttributeError("'mappingproxy' object has no attribute " + "'setdefault'") + + def __repr__(self): + # Override to be identical to the Python 3 version. + return "mappingproxy(" + repr(self.data) + ")" + + def metadata_proxy(d): + res = ReadOnlyDict() + res.data.update(d) # We blocked update, so we have to do it like this. + return res + +else: + def isclass(klass): + return isinstance(klass, type) + + TYPE = "class" + + def iteritems(d): + return d.items() + + def metadata_proxy(d): + return types.MappingProxyType(dict(d)) + + +def import_ctypes(): # pragma: nocover + """ + Moved into a function for testability. + """ + try: + import ctypes + return ctypes + except ImportError: + return None + + +if not PY2: + def just_warn(*args, **kw): + """ + We only warn on Python 3 because we are not aware of any concrete + consequences of not setting the cell on Python 2. + """ + warnings.warn( + "Missing ctypes. Some features like bare super() or accessing " + "__class__ will not work with slots classes.", + RuntimeWarning, + stacklevel=2, + ) +else: + def just_warn(*args, **kw): # pragma: nocover + """ + We only warn on Python 3 because we are not aware of any concrete + consequences of not setting the cell on Python 2. + """ + + +def make_set_closure_cell(): + """ + Moved into a function for testability. + """ + if PYPY: # pragma: no cover + def set_closure_cell(cell, value): + cell.__setstate__((value,)) + else: + ctypes = import_ctypes() + if ctypes is not None: + set_closure_cell = ctypes.pythonapi.PyCell_Set + set_closure_cell.argtypes = (ctypes.py_object, ctypes.py_object) + set_closure_cell.restype = ctypes.c_int + else: + set_closure_cell = just_warn + return set_closure_cell + + +set_closure_cell = make_set_closure_cell() diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/_config.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/_config.py new file mode 100644 index 00000000000..8ec920962d1 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/_config.py @@ -0,0 +1,23 @@ +from __future__ import absolute_import, division, print_function + + +__all__ = ["set_run_validators", "get_run_validators"] + +_run_validators = True + + +def set_run_validators(run): + """ + Set whether or not validators are run. By default, they are run. + """ + if not isinstance(run, bool): + raise TypeError("'run' must be bool.") + global _run_validators + _run_validators = run + + +def get_run_validators(): + """ + Return whether or not validators are run. + """ + return _run_validators diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/_funcs.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/_funcs.py new file mode 100644 index 00000000000..798043af3f8 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/_funcs.py @@ -0,0 +1,212 @@ +from __future__ import absolute_import, division, print_function + +import copy + +from ._compat import iteritems +from ._make import NOTHING, _obj_setattr, fields +from .exceptions import AttrsAttributeNotFoundError + + +def asdict(inst, recurse=True, filter=None, dict_factory=dict, + retain_collection_types=False): + """ + Return the ``attrs`` attribute values of *inst* as a dict. + + Optionally recurse into other ``attrs``-decorated classes. + + :param inst: Instance of an ``attrs``-decorated class. + :param bool recurse: Recurse into classes that are also + ``attrs``-decorated. + :param callable filter: A callable whose return code determines whether an + attribute or element is included (``True``) or dropped (``False``). Is + called with the :class:`attr.Attribute` as the first argument and the + value as the second argument. + :param callable dict_factory: A callable to produce dictionaries from. For + example, to produce ordered dictionaries instead of normal Python + dictionaries, pass in ``collections.OrderedDict``. + :param bool retain_collection_types: Do not convert to ``list`` when + encountering an attribute whose type is ``tuple`` or ``set``. Only + meaningful if ``recurse`` is ``True``. + + :rtype: return type of *dict_factory* + + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class. + + .. versionadded:: 16.0.0 *dict_factory* + .. versionadded:: 16.1.0 *retain_collection_types* + """ + attrs = fields(inst.__class__) + rv = dict_factory() + for a in attrs: + v = getattr(inst, a.name) + if filter is not None and not filter(a, v): + continue + if recurse is True: + if has(v.__class__): + rv[a.name] = asdict(v, recurse=True, filter=filter, + dict_factory=dict_factory) + elif isinstance(v, (tuple, list, set)): + cf = v.__class__ if retain_collection_types is True else list + rv[a.name] = cf([ + asdict(i, recurse=True, filter=filter, + dict_factory=dict_factory) + if has(i.__class__) else i + for i in v + ]) + elif isinstance(v, dict): + df = dict_factory + rv[a.name] = df(( + asdict(kk, dict_factory=df) if has(kk.__class__) else kk, + asdict(vv, dict_factory=df) if has(vv.__class__) else vv) + for kk, vv in iteritems(v)) + else: + rv[a.name] = v + else: + rv[a.name] = v + return rv + + +def astuple(inst, recurse=True, filter=None, tuple_factory=tuple, + retain_collection_types=False): + """ + Return the ``attrs`` attribute values of *inst* as a tuple. + + Optionally recurse into other ``attrs``-decorated classes. + + :param inst: Instance of an ``attrs``-decorated class. + :param bool recurse: Recurse into classes that are also + ``attrs``-decorated. + :param callable filter: A callable whose return code determines whether an + attribute or element is included (``True``) or dropped (``False``). Is + called with the :class:`attr.Attribute` as the first argument and the + value as the second argument. + :param callable tuple_factory: A callable to produce tuples from. For + example, to produce lists instead of tuples. + :param bool retain_collection_types: Do not convert to ``list`` + or ``dict`` when encountering an attribute which type is + ``tuple``, ``dict`` or ``set``. Only meaningful if ``recurse`` is + ``True``. + + :rtype: return type of *tuple_factory* + + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class. + + .. versionadded:: 16.2.0 + """ + attrs = fields(inst.__class__) + rv = [] + retain = retain_collection_types # Very long. :/ + for a in attrs: + v = getattr(inst, a.name) + if filter is not None and not filter(a, v): + continue + if recurse is True: + if has(v.__class__): + rv.append(astuple(v, recurse=True, filter=filter, + tuple_factory=tuple_factory, + retain_collection_types=retain)) + elif isinstance(v, (tuple, list, set)): + cf = v.__class__ if retain is True else list + rv.append(cf([ + astuple(j, recurse=True, filter=filter, + tuple_factory=tuple_factory, + retain_collection_types=retain) + if has(j.__class__) else j + for j in v + ])) + elif isinstance(v, dict): + df = v.__class__ if retain is True else dict + rv.append(df( + ( + astuple( + kk, + tuple_factory=tuple_factory, + retain_collection_types=retain + ) if has(kk.__class__) else kk, + astuple( + vv, + tuple_factory=tuple_factory, + retain_collection_types=retain + ) if has(vv.__class__) else vv + ) + for kk, vv in iteritems(v))) + else: + rv.append(v) + else: + rv.append(v) + return rv if tuple_factory is list else tuple_factory(rv) + + +def has(cls): + """ + Check whether *cls* is a class with ``attrs`` attributes. + + :param type cls: Class to introspect. + :raise TypeError: If *cls* is not a class. + + :rtype: :class:`bool` + """ + return getattr(cls, "__attrs_attrs__", None) is not None + + +def assoc(inst, **changes): + """ + Copy *inst* and apply *changes*. + + :param inst: Instance of a class with ``attrs`` attributes. + :param changes: Keyword changes in the new copy. + + :return: A copy of inst with *changes* incorporated. + + :raise attr.exceptions.AttrsAttributeNotFoundError: If *attr_name* couldn't + be found on *cls*. + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class. + + .. deprecated:: 17.1.0 + Use :func:`evolve` instead. + """ + import warnings + warnings.warn("assoc is deprecated and will be removed after 2018/01.", + DeprecationWarning, stacklevel=2) + new = copy.copy(inst) + attrs = fields(inst.__class__) + for k, v in iteritems(changes): + a = getattr(attrs, k, NOTHING) + if a is NOTHING: + raise AttrsAttributeNotFoundError( + "{k} is not an attrs attribute on {cl}." + .format(k=k, cl=new.__class__) + ) + _obj_setattr(new, k, v) + return new + + +def evolve(inst, **changes): + """ + Create a new instance, based on *inst* with *changes* applied. + + :param inst: Instance of a class with ``attrs`` attributes. + :param changes: Keyword changes in the new copy. + + :return: A copy of inst with *changes* incorporated. + + :raise TypeError: If *attr_name* couldn't be found in the class + ``__init__``. + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class. + + .. versionadded:: 17.1.0 + """ + cls = inst.__class__ + attrs = fields(cls) + for a in attrs: + if not a.init: + continue + attr_name = a.name # To deal with private attributes. + init_name = attr_name if attr_name[0] != "_" else attr_name[1:] + if init_name not in changes: + changes[init_name] = getattr(inst, attr_name) + return cls(**changes) diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/_make.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/_make.py new file mode 100644 index 00000000000..31c5f94ce38 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/_make.py @@ -0,0 +1,1395 @@ +from __future__ import absolute_import, division, print_function + +import hashlib +import linecache +import sys + +from operator import itemgetter + +from . import _config +from ._compat import PY2, isclass, iteritems, metadata_proxy, set_closure_cell +from .exceptions import ( + DefaultAlreadySetError, FrozenInstanceError, NotAnAttrsClassError, + UnannotatedAttributeError +) + + +# This is used at least twice, so cache it here. +_obj_setattr = object.__setattr__ +_init_convert_pat = "__attr_convert_{}" +_init_factory_pat = "__attr_factory_{}" +_tuple_property_pat = " {attr_name} = property(itemgetter({index}))" +_empty_metadata_singleton = metadata_proxy({}) + + +class _Nothing(object): + """ + Sentinel class to indicate the lack of a value when ``None`` is ambiguous. + + All instances of `_Nothing` are equal. + """ + def __copy__(self): + return self + + def __deepcopy__(self, _): + return self + + def __eq__(self, other): + return other.__class__ == _Nothing + + def __ne__(self, other): + return not self == other + + def __repr__(self): + return "NOTHING" + + def __hash__(self): + return 0xdeadbeef + + +NOTHING = _Nothing() +""" +Sentinel to indicate the lack of a value when ``None`` is ambiguous. +""" + + +def attrib(default=NOTHING, validator=None, + repr=True, cmp=True, hash=None, init=True, + convert=None, metadata={}, type=None): + """ + Create a new attribute on a class. + + .. warning:: + + Does *not* do anything unless the class is also decorated with + :func:`attr.s`! + + :param default: A value that is used if an ``attrs``-generated ``__init__`` + is used and no value is passed while instantiating or the attribute is + excluded using ``init=False``. + + If the value is an instance of :class:`Factory`, its callable will be + used to construct a new value (useful for mutable data types like lists + or dicts). + + If a default is not set (or set manually to ``attr.NOTHING``), a value + *must* be supplied when instantiating; otherwise a :exc:`TypeError` + will be raised. + + The default can also be set using decorator notation as shown below. + + :type default: Any value. + + :param validator: :func:`callable` that is called by ``attrs``-generated + ``__init__`` methods after the instance has been initialized. They + receive the initialized instance, the :class:`Attribute`, and the + passed value. + + The return value is *not* inspected so the validator has to throw an + exception itself. + + If a ``list`` is passed, its items are treated as validators and must + all pass. + + Validators can be globally disabled and re-enabled using + :func:`get_run_validators`. + + The validator can also be set using decorator notation as shown below. + + :type validator: ``callable`` or a ``list`` of ``callable``\ s. + + :param bool repr: Include this attribute in the generated ``__repr__`` + method. + :param bool cmp: Include this attribute in the generated comparison methods + (``__eq__`` et al). + :param hash: Include this attribute in the generated ``__hash__`` + method. If ``None`` (default), mirror *cmp*'s value. This is the + correct behavior according the Python spec. Setting this value to + anything else than ``None`` is *discouraged*. + :type hash: ``bool`` or ``None`` + :param bool init: Include this attribute in the generated ``__init__`` + method. It is possible to set this to ``False`` and set a default + value. In that case this attributed is unconditionally initialized + with the specified default value or factory. + :param callable convert: :func:`callable` that is called by + ``attrs``-generated ``__init__`` methods to convert attribute's value + to the desired format. It is given the passed-in value, and the + returned value will be used as the new value of the attribute. The + value is converted before being passed to the validator, if any. + :param metadata: An arbitrary mapping, to be used by third-party + components. See :ref:`extending_metadata`. + :param type: The type of the attribute. In Python 3.6 or greater, the + preferred method to specify the type is using a variable annotation + (see `PEP 526 `_). + This argument is provided for backward compatibility. + Regardless of the approach used, the type will be stored on + ``Attribute.type``. + + .. versionchanged:: 17.1.0 *validator* can be a ``list`` now. + .. versionchanged:: 17.1.0 + *hash* is ``None`` and therefore mirrors *cmp* by default. + .. versionadded:: 17.3.0 *type* + """ + if hash is not None and hash is not True and hash is not False: + raise TypeError( + "Invalid value for hash. Must be True, False, or None." + ) + return _CountingAttr( + default=default, + validator=validator, + repr=repr, + cmp=cmp, + hash=hash, + init=init, + convert=convert, + metadata=metadata, + type=type, + ) + + +def _make_attr_tuple_class(cls_name, attr_names): + """ + Create a tuple subclass to hold `Attribute`s for an `attrs` class. + + The subclass is a bare tuple with properties for names. + + class MyClassAttributes(tuple): + __slots__ = () + x = property(itemgetter(0)) + """ + attr_class_name = "{}Attributes".format(cls_name) + attr_class_template = [ + "class {}(tuple):".format(attr_class_name), + " __slots__ = ()", + ] + if attr_names: + for i, attr_name in enumerate(attr_names): + attr_class_template.append(_tuple_property_pat.format( + index=i, + attr_name=attr_name, + )) + else: + attr_class_template.append(" pass") + globs = {"itemgetter": itemgetter} + eval(compile("\n".join(attr_class_template), "", "exec"), globs) + return globs[attr_class_name] + + +# Tuple class for extracted attributes from a class definition. +# `super_attrs` is a subset of `attrs`. +_Attributes = _make_attr_tuple_class("_Attributes", [ + "attrs", # all attributes to build dunder methods for + "super_attrs", # attributes that have been inherited from super classes +]) + + +def _is_class_var(annot): + """ + Check whether *annot* is a typing.ClassVar. + + The implementation is gross but importing `typing` is slow and there are + discussions to remove it from the stdlib alltogether. + """ + return str(annot).startswith("typing.ClassVar") + + +def _get_annotations(cls): + """ + Get annotations for *cls*. + """ + anns = getattr(cls, "__annotations__", None) + if anns is None: + return {} + + # Verify that the annotations aren't merely inherited. + for super_cls in cls.__mro__[1:]: + if anns is getattr(super_cls, "__annotations__", None): + return {} + + return anns + + +def _transform_attrs(cls, these, auto_attribs): + """ + Transform all `_CountingAttr`s on a class into `Attribute`s. + + If *these* is passed, use that and don't look for them on the class. + + Return an `_Attributes`. + """ + cd = cls.__dict__ + anns = _get_annotations(cls) + + if these is not None: + ca_list = sorted(( + (name, ca) + for name, ca + in iteritems(these) + ), key=lambda e: e[1].counter) + elif auto_attribs is True: + ca_names = { + name + for name, attr + in cd.items() + if isinstance(attr, _CountingAttr) + } + ca_list = [] + annot_names = set() + for attr_name, type in anns.items(): + if _is_class_var(type): + continue + annot_names.add(attr_name) + a = cd.get(attr_name, NOTHING) + if not isinstance(a, _CountingAttr): + if a is NOTHING: + a = attrib() + else: + a = attrib(default=a) + ca_list.append((attr_name, a)) + + unannotated = ca_names - annot_names + if len(unannotated) > 0: + raise UnannotatedAttributeError( + "The following `attr.ib`s lack a type annotation: " + + ", ".join(sorted( + unannotated, + key=lambda n: cd.get(n).counter + )) + "." + ) + else: + ca_list = sorted(( + (name, attr) + for name, attr + in cd.items() + if isinstance(attr, _CountingAttr) + ), key=lambda e: e[1].counter) + + non_super_attrs = [ + Attribute.from_counting_attr( + name=attr_name, + ca=ca, + type=anns.get(attr_name), + ) + for attr_name, ca + in ca_list + ] + + # Walk *down* the MRO for attributes. While doing so, we collect the names + # of attributes we've seen in `take_attr_names` and ignore their + # redefinitions deeper in the hierarchy. + super_attrs = [] + taken_attr_names = {a.name: a for a in non_super_attrs} + for super_cls in cls.__mro__[1:-1]: + sub_attrs = getattr(super_cls, "__attrs_attrs__", None) + if sub_attrs is not None: + # We iterate over sub_attrs backwards so we can reverse the whole + # list in the end and get all attributes in the order they have + # been defined. + for a in reversed(sub_attrs): + prev_a = taken_attr_names.get(a.name) + if prev_a is None: + super_attrs.append(a) + taken_attr_names[a.name] = a + elif prev_a == a: + # This happens thru multiple inheritance. We don't want + # to favor attributes that are further down in the tree + # so we move them to the back. + super_attrs.remove(a) + super_attrs.append(a) + + # Now reverse the list, such that the attributes are sorted by *descending* + # age. IOW: the oldest attribute definition is at the head of the list. + super_attrs.reverse() + + attr_names = [a.name for a in super_attrs + non_super_attrs] + + AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names) + + attrs = AttrsClass( + super_attrs + [ + Attribute.from_counting_attr( + name=attr_name, + ca=ca, + type=anns.get(attr_name) + ) + for attr_name, ca + in ca_list + ] + ) + + had_default = False + for a in attrs: + if had_default is True and a.default is NOTHING and a.init is True: + raise ValueError( + "No mandatory attributes allowed after an attribute with a " + "default value or factory. Attribute in question: {a!r}" + .format(a=a) + ) + elif had_default is False and \ + a.default is not NOTHING and \ + a.init is not False: + had_default = True + + return _Attributes((attrs, super_attrs)) + + +def _frozen_setattrs(self, name, value): + """ + Attached to frozen classes as __setattr__. + """ + raise FrozenInstanceError() + + +def _frozen_delattrs(self, name): + """ + Attached to frozen classes as __delattr__. + """ + raise FrozenInstanceError() + + +class _ClassBuilder(object): + """ + Iteratively build *one* class. + """ + __slots__ = ( + "_cls", "_cls_dict", "_attrs", "_super_names", "_attr_names", "_slots", + "_frozen", "_has_post_init", + ) + + def __init__(self, cls, these, slots, frozen, auto_attribs): + attrs, super_attrs = _transform_attrs(cls, these, auto_attribs) + + self._cls = cls + self._cls_dict = dict(cls.__dict__) if slots else {} + self._attrs = attrs + self._super_names = set(a.name for a in super_attrs) + self._attr_names = tuple(a.name for a in attrs) + self._slots = slots + self._frozen = frozen or _has_frozen_superclass(cls) + self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False)) + + self._cls_dict["__attrs_attrs__"] = self._attrs + + if frozen: + self._cls_dict["__setattr__"] = _frozen_setattrs + self._cls_dict["__delattr__"] = _frozen_delattrs + + def __repr__(self): + return "<_ClassBuilder(cls={cls})>".format(cls=self._cls.__name__) + + def build_class(self): + """ + Finalize class based on the accumulated configuration. + + Builder cannot be used anymore after calling this method. + """ + if self._slots is True: + return self._create_slots_class() + else: + return self._patch_original_class() + + def _patch_original_class(self): + """ + Apply accumulated methods and return the class. + """ + cls = self._cls + super_names = self._super_names + + # Clean class of attribute definitions (`attr.ib()`s). + for name in self._attr_names: + if name not in super_names and \ + getattr(cls, name, None) is not None: + delattr(cls, name) + + # Attach our dunder methods. + for name, value in self._cls_dict.items(): + setattr(cls, name, value) + + return cls + + def _create_slots_class(self): + """ + Build and return a new class with a `__slots__` attribute. + """ + super_names = self._super_names + cd = { + k: v + for k, v in iteritems(self._cls_dict) + if k not in tuple(self._attr_names) + ("__dict__",) + } + + # We only add the names of attributes that aren't inherited. + # Settings __slots__ to inherited attributes wastes memory. + cd["__slots__"] = tuple( + name + for name in self._attr_names + if name not in super_names + ) + + qualname = getattr(self._cls, "__qualname__", None) + if qualname is not None: + cd["__qualname__"] = qualname + + attr_names = tuple(self._attr_names) + + def slots_getstate(self): + """ + Automatically created by attrs. + """ + return tuple(getattr(self, name) for name in attr_names) + + def slots_setstate(self, state): + """ + Automatically created by attrs. + """ + __bound_setattr = _obj_setattr.__get__(self, Attribute) + for name, value in zip(attr_names, state): + __bound_setattr(name, value) + + # slots and frozen require __getstate__/__setstate__ to work + cd["__getstate__"] = slots_getstate + cd["__setstate__"] = slots_setstate + + # Create new class based on old class and our methods. + cls = type(self._cls)( + self._cls.__name__, + self._cls.__bases__, + cd, + ) + + # The following is a fix for + # https://github.com/python-attrs/attrs/issues/102. On Python 3, + # if a method mentions `__class__` or uses the no-arg super(), the + # compiler will bake a reference to the class in the method itself + # as `method.__closure__`. Since we replace the class with a + # clone, we rewrite these references so it keeps working. + for item in cls.__dict__.values(): + if isinstance(item, (classmethod, staticmethod)): + # Class- and staticmethods hide their functions inside. + # These might need to be rewritten as well. + closure_cells = getattr(item.__func__, "__closure__", None) + else: + closure_cells = getattr(item, "__closure__", None) + + if not closure_cells: # Catch None or the empty list. + continue + for cell in closure_cells: + if cell.cell_contents is self._cls: + set_closure_cell(cell, cls) + + return cls + + def add_repr(self, ns): + self._cls_dict["__repr__"] = _make_repr(self._attrs, ns=ns) + return self + + def add_str(self): + repr_ = self._cls_dict.get("__repr__") + if repr_ is None: + raise ValueError( + "__str__ can only be generated if a __repr__ exists." + ) + + self._cls_dict["__str__"] = repr_ + return self + + def make_unhashable(self): + self._cls_dict["__hash__"] = None + return self + + def add_hash(self): + self._cls_dict["__hash__"] = _make_hash(self._attrs) + return self + + def add_init(self): + self._cls_dict["__init__"] = _make_init( + self._attrs, + self._has_post_init, + self._frozen, + ) + return self + + def add_cmp(self): + cd = self._cls_dict + + cd["__eq__"], cd["__ne__"], cd["__lt__"], cd["__le__"], cd["__gt__"], \ + cd["__ge__"] = _make_cmp(self._attrs) + + return self + + +def attrs(maybe_cls=None, these=None, repr_ns=None, + repr=True, cmp=True, hash=None, init=True, + slots=False, frozen=False, str=False, auto_attribs=False): + r""" + A class decorator that adds `dunder + `_\ -methods according to the + specified attributes using :func:`attr.ib` or the *these* argument. + + :param these: A dictionary of name to :func:`attr.ib` mappings. This is + useful to avoid the definition of your attributes within the class body + because you can't (e.g. if you want to add ``__repr__`` methods to + Django models) or don't want to. + + If *these* is not ``None``, ``attrs`` will *not* search the class body + for attributes. + + :type these: :class:`dict` of :class:`str` to :func:`attr.ib` + + :param str repr_ns: When using nested classes, there's no way in Python 2 + to automatically detect that. Therefore it's possible to set the + namespace explicitly for a more meaningful ``repr`` output. + :param bool repr: Create a ``__repr__`` method with a human readable + representation of ``attrs`` attributes.. + :param bool str: Create a ``__str__`` method that is identical to + ``__repr__``. This is usually not necessary except for + :class:`Exception`\ s. + :param bool cmp: Create ``__eq__``, ``__ne__``, ``__lt__``, ``__le__``, + ``__gt__``, and ``__ge__`` methods that compare the class as if it were + a tuple of its ``attrs`` attributes. But the attributes are *only* + compared, if the type of both classes is *identical*! + :param hash: If ``None`` (default), the ``__hash__`` method is generated + according how *cmp* and *frozen* are set. + + 1. If *both* are True, ``attrs`` will generate a ``__hash__`` for you. + 2. If *cmp* is True and *frozen* is False, ``__hash__`` will be set to + None, marking it unhashable (which it is). + 3. If *cmp* is False, ``__hash__`` will be left untouched meaning the + ``__hash__`` method of the superclass will be used (if superclass is + ``object``, this means it will fall back to id-based hashing.). + + Although not recommended, you can decide for yourself and force + ``attrs`` to create one (e.g. if the class is immutable even though you + didn't freeze it programmatically) by passing ``True`` or not. Both of + these cases are rather special and should be used carefully. + + See the `Python documentation \ + `_ + and the `GitHub issue that led to the default behavior \ + `_ for more details. + :type hash: ``bool`` or ``None`` + :param bool init: Create a ``__init__`` method that initializes the + ``attrs`` attributes. Leading underscores are stripped for the + argument name. If a ``__attrs_post_init__`` method exists on the + class, it will be called after the class is fully initialized. + :param bool slots: Create a slots_-style class that's more + memory-efficient. See :ref:`slots` for further ramifications. + :param bool frozen: Make instances immutable after initialization. If + someone attempts to modify a frozen instance, + :exc:`attr.exceptions.FrozenInstanceError` is raised. + + Please note: + + 1. This is achieved by installing a custom ``__setattr__`` method + on your class so you can't implement an own one. + + 2. True immutability is impossible in Python. + + 3. This *does* have a minor a runtime performance :ref:`impact + ` when initializing new instances. In other words: + ``__init__`` is slightly slower with ``frozen=True``. + + 4. If a class is frozen, you cannot modify ``self`` in + ``__attrs_post_init__`` or a self-written ``__init__``. You can + circumvent that limitation by using + ``object.__setattr__(self, "attribute_name", value)``. + + .. _slots: https://docs.python.org/3/reference/datamodel.html#slots + :param bool auto_attribs: If True, collect `PEP 526`_-annotated attributes + (Python 3.6 and later only) from the class body. + + In this case, you **must** annotate every field. If ``attrs`` + encounters a field that is set to an :func:`attr.ib` but lacks a type + annotation, an :exc:`attr.exceptions.UnannotatedAttributeError` is + raised. Use ``field_name: typing.Any = attr.ib(...)`` if you don't + want to set a type. + + If you assign a value to those attributes (e.g. ``x: int = 42``), that + value becomes the default value like if it were passed using + ``attr.ib(default=42)``. Passing an instance of :class:`Factory` also + works as expected. + + Attributes annotated as :data:`typing.ClassVar` are **ignored**. + + .. _`PEP 526`: https://www.python.org/dev/peps/pep-0526/ + + .. versionadded:: 16.0.0 *slots* + .. versionadded:: 16.1.0 *frozen* + .. versionadded:: 16.3.0 *str*, and support for ``__attrs_post_init__``. + .. versionchanged:: + 17.1.0 *hash* supports ``None`` as value which is also the default + now. + .. versionadded:: 17.3.0 *auto_attribs* + """ + def wrap(cls): + if getattr(cls, "__class__", None) is None: + raise TypeError("attrs only works with new-style classes.") + + builder = _ClassBuilder(cls, these, slots, frozen, auto_attribs) + + if repr is True: + builder.add_repr(repr_ns) + if str is True: + builder.add_str() + if cmp is True: + builder.add_cmp() + + if hash is not True and hash is not False and hash is not None: + # Can't use `hash in` because 1 == True for example. + raise TypeError( + "Invalid value for hash. Must be True, False, or None." + ) + elif hash is False or (hash is None and cmp is False): + pass + elif hash is True or (hash is None and cmp is True and frozen is True): + builder.add_hash() + else: + builder.make_unhashable() + + if init is True: + builder.add_init() + + return builder.build_class() + + # maybe_cls's type depends on the usage of the decorator. It's a class + # if it's used as `@attrs` but ``None`` if used as `@attrs()`. + if maybe_cls is None: + return wrap + else: + return wrap(maybe_cls) + + +_attrs = attrs +""" +Internal alias so we can use it in functions that take an argument called +*attrs*. +""" + + +if PY2: + def _has_frozen_superclass(cls): + """ + Check whether *cls* has a frozen ancestor by looking at its + __setattr__. + """ + return ( + getattr( + cls.__setattr__, "__module__", None + ) == _frozen_setattrs.__module__ and + cls.__setattr__.__name__ == _frozen_setattrs.__name__ + ) +else: + def _has_frozen_superclass(cls): + """ + Check whether *cls* has a frozen ancestor by looking at its + __setattr__. + """ + return cls.__setattr__ == _frozen_setattrs + + +def _attrs_to_tuple(obj, attrs): + """ + Create a tuple of all values of *obj*'s *attrs*. + """ + return tuple(getattr(obj, a.name) for a in attrs) + + +def _make_hash(attrs): + attrs = tuple( + a + for a in attrs + if a.hash is True or (a.hash is None and a.cmp is True) + ) + + # We cache the generated init methods for the same kinds of attributes. + sha1 = hashlib.sha1() + sha1.update(repr(attrs).encode("utf-8")) + unique_filename = "" % (sha1.hexdigest(),) + type_hash = hash(unique_filename) + lines = [ + "def __hash__(self):", + " return hash((", + " %d," % (type_hash,), + ] + for a in attrs: + lines.append(" self.%s," % (a.name)) + + lines.append(" ))") + + script = "\n".join(lines) + globs = {} + locs = {} + bytecode = compile(script, unique_filename, "exec") + eval(bytecode, globs, locs) + + # In order of debuggers like PDB being able to step through the code, + # we add a fake linecache entry. + linecache.cache[unique_filename] = ( + len(script), + None, + script.splitlines(True), + unique_filename, + ) + + return locs["__hash__"] + + +def _add_hash(cls, attrs): + """ + Add a hash method to *cls*. + """ + cls.__hash__ = _make_hash(attrs) + return cls + + +def _make_cmp(attrs): + attrs = [a for a in attrs if a.cmp] + + def attrs_to_tuple(obj): + """ + Save us some typing. + """ + return _attrs_to_tuple(obj, attrs) + + def eq(self, other): + """ + Automatically created by attrs. + """ + if other.__class__ is self.__class__: + return attrs_to_tuple(self) == attrs_to_tuple(other) + else: + return NotImplemented + + def ne(self, other): + """ + Automatically created by attrs. + """ + result = eq(self, other) + if result is NotImplemented: + return NotImplemented + else: + return not result + + def lt(self, other): + """ + Automatically created by attrs. + """ + if isinstance(other, self.__class__): + return attrs_to_tuple(self) < attrs_to_tuple(other) + else: + return NotImplemented + + def le(self, other): + """ + Automatically created by attrs. + """ + if isinstance(other, self.__class__): + return attrs_to_tuple(self) <= attrs_to_tuple(other) + else: + return NotImplemented + + def gt(self, other): + """ + Automatically created by attrs. + """ + if isinstance(other, self.__class__): + return attrs_to_tuple(self) > attrs_to_tuple(other) + else: + return NotImplemented + + def ge(self, other): + """ + Automatically created by attrs. + """ + if isinstance(other, self.__class__): + return attrs_to_tuple(self) >= attrs_to_tuple(other) + else: + return NotImplemented + + return eq, ne, lt, le, gt, ge + + +def _add_cmp(cls, attrs=None): + """ + Add comparison methods to *cls*. + """ + if attrs is None: + attrs = cls.__attrs_attrs__ + + cls.__eq__, cls.__ne__, cls.__lt__, cls.__le__, cls.__gt__, cls.__ge__ = \ + _make_cmp(attrs) + + return cls + + +def _make_repr(attrs, ns): + """ + Make a repr method for *attr_names* adding *ns* to the full name. + """ + attr_names = tuple( + a.name + for a in attrs + if a.repr + ) + + def repr_(self): + """ + Automatically created by attrs. + """ + real_cls = self.__class__ + if ns is None: + qualname = getattr(real_cls, "__qualname__", None) + if qualname is not None: + class_name = qualname.rsplit(">.", 1)[-1] + else: + class_name = real_cls.__name__ + else: + class_name = ns + "." + real_cls.__name__ + + return "{0}({1})".format( + class_name, + ", ".join( + name + "=" + repr(getattr(self, name)) + for name in attr_names + ) + ) + return repr_ + + +def _add_repr(cls, ns=None, attrs=None): + """ + Add a repr method to *cls*. + """ + if attrs is None: + attrs = cls.__attrs_attrs__ + + repr_ = _make_repr(attrs, ns) + cls.__repr__ = repr_ + return cls + + +def _make_init(attrs, post_init, frozen): + attrs = [ + a + for a in attrs + if a.init or a.default is not NOTHING + ] + + # We cache the generated init methods for the same kinds of attributes. + sha1 = hashlib.sha1() + sha1.update(repr(attrs).encode("utf-8")) + unique_filename = "".format( + sha1.hexdigest() + ) + + script, globs = _attrs_to_init_script( + attrs, + frozen, + post_init, + ) + locs = {} + bytecode = compile(script, unique_filename, "exec") + attr_dict = dict((a.name, a) for a in attrs) + globs.update({ + "NOTHING": NOTHING, + "attr_dict": attr_dict, + }) + if frozen is True: + # Save the lookup overhead in __init__ if we need to circumvent + # immutability. + globs["_cached_setattr"] = _obj_setattr + eval(bytecode, globs, locs) + + # In order of debuggers like PDB being able to step through the code, + # we add a fake linecache entry. + linecache.cache[unique_filename] = ( + len(script), + None, + script.splitlines(True), + unique_filename, + ) + + return locs["__init__"] + + +def _add_init(cls, frozen): + """ + Add a __init__ method to *cls*. If *frozen* is True, make it immutable. + """ + cls.__init__ = _make_init( + cls.__attrs_attrs__, + getattr(cls, "__attrs_post_init__", False), + frozen, + ) + return cls + + +def fields(cls): + """ + Returns the tuple of ``attrs`` attributes for a class. + + The tuple also allows accessing the fields by their names (see below for + examples). + + :param type cls: Class to introspect. + + :raise TypeError: If *cls* is not a class. + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class. + + :rtype: tuple (with name accessors) of :class:`attr.Attribute` + + .. versionchanged:: 16.2.0 Returned tuple allows accessing the fields + by name. + """ + if not isclass(cls): + raise TypeError("Passed object must be a class.") + attrs = getattr(cls, "__attrs_attrs__", None) + if attrs is None: + raise NotAnAttrsClassError( + "{cls!r} is not an attrs-decorated class.".format(cls=cls) + ) + return attrs + + +def validate(inst): + """ + Validate all attributes on *inst* that have a validator. + + Leaves all exceptions through. + + :param inst: Instance of a class with ``attrs`` attributes. + """ + if _config._run_validators is False: + return + + for a in fields(inst.__class__): + v = a.validator + if v is not None: + v(inst, a, getattr(inst, a.name)) + + +def _attrs_to_init_script(attrs, frozen, post_init): + """ + Return a script of an initializer for *attrs* and a dict of globals. + + The globals are expected by the generated script. + + If *frozen* is True, we cannot set the attributes directly so we use + a cached ``object.__setattr__``. + """ + lines = [] + if frozen is True: + lines.append( + # Circumvent the __setattr__ descriptor to save one lookup per + # assignment. + "_setattr = _cached_setattr.__get__(self, self.__class__)" + ) + + def fmt_setter(attr_name, value_var): + return "_setattr('%(attr_name)s', %(value_var)s)" % { + "attr_name": attr_name, + "value_var": value_var, + } + + def fmt_setter_with_converter(attr_name, value_var): + conv_name = _init_convert_pat.format(attr_name) + return "_setattr('%(attr_name)s', %(conv)s(%(value_var)s))" % { + "attr_name": attr_name, + "value_var": value_var, + "conv": conv_name, + } + else: + def fmt_setter(attr_name, value): + return "self.%(attr_name)s = %(value)s" % { + "attr_name": attr_name, + "value": value, + } + + def fmt_setter_with_converter(attr_name, value_var): + conv_name = _init_convert_pat.format(attr_name) + return "self.%(attr_name)s = %(conv)s(%(value_var)s)" % { + "attr_name": attr_name, + "value_var": value_var, + "conv": conv_name, + } + + args = [] + attrs_to_validate = [] + + # This is a dictionary of names to validator and converter callables. + # Injecting this into __init__ globals lets us avoid lookups. + names_for_globals = {} + + for a in attrs: + if a.validator: + attrs_to_validate.append(a) + attr_name = a.name + arg_name = a.name.lstrip("_") + has_factory = isinstance(a.default, Factory) + if has_factory and a.default.takes_self: + maybe_self = "self" + else: + maybe_self = "" + if a.init is False: + if has_factory: + init_factory_name = _init_factory_pat.format(a.name) + if a.convert is not None: + lines.append(fmt_setter_with_converter( + attr_name, + init_factory_name + "({0})".format(maybe_self))) + conv_name = _init_convert_pat.format(a.name) + names_for_globals[conv_name] = a.convert + else: + lines.append(fmt_setter( + attr_name, + init_factory_name + "({0})".format(maybe_self) + )) + names_for_globals[init_factory_name] = a.default.factory + else: + if a.convert is not None: + lines.append(fmt_setter_with_converter( + attr_name, + "attr_dict['{attr_name}'].default" + .format(attr_name=attr_name) + )) + conv_name = _init_convert_pat.format(a.name) + names_for_globals[conv_name] = a.convert + else: + lines.append(fmt_setter( + attr_name, + "attr_dict['{attr_name}'].default" + .format(attr_name=attr_name) + )) + elif a.default is not NOTHING and not has_factory: + args.append( + "{arg_name}=attr_dict['{attr_name}'].default".format( + arg_name=arg_name, + attr_name=attr_name, + ) + ) + if a.convert is not None: + lines.append(fmt_setter_with_converter(attr_name, arg_name)) + names_for_globals[_init_convert_pat.format(a.name)] = a.convert + else: + lines.append(fmt_setter(attr_name, arg_name)) + elif has_factory: + args.append("{arg_name}=NOTHING".format(arg_name=arg_name)) + lines.append("if {arg_name} is not NOTHING:" + .format(arg_name=arg_name)) + init_factory_name = _init_factory_pat.format(a.name) + if a.convert is not None: + lines.append(" " + fmt_setter_with_converter(attr_name, + arg_name)) + lines.append("else:") + lines.append(" " + fmt_setter_with_converter( + attr_name, + init_factory_name + "({0})".format(maybe_self) + )) + names_for_globals[_init_convert_pat.format(a.name)] = a.convert + else: + lines.append(" " + fmt_setter(attr_name, arg_name)) + lines.append("else:") + lines.append(" " + fmt_setter( + attr_name, + init_factory_name + "({0})".format(maybe_self) + )) + names_for_globals[init_factory_name] = a.default.factory + else: + args.append(arg_name) + if a.convert is not None: + lines.append(fmt_setter_with_converter(attr_name, arg_name)) + names_for_globals[_init_convert_pat.format(a.name)] = a.convert + else: + lines.append(fmt_setter(attr_name, arg_name)) + + if attrs_to_validate: # we can skip this if there are no validators. + names_for_globals["_config"] = _config + lines.append("if _config._run_validators is True:") + for a in attrs_to_validate: + val_name = "__attr_validator_{}".format(a.name) + attr_name = "__attr_{}".format(a.name) + lines.append(" {}(self, {}, self.{})".format( + val_name, attr_name, a.name)) + names_for_globals[val_name] = a.validator + names_for_globals[attr_name] = a + if post_init: + lines.append("self.__attrs_post_init__()") + + return """\ +def __init__(self, {args}): + {lines} +""".format( + args=", ".join(args), + lines="\n ".join(lines) if lines else "pass", + ), names_for_globals + + +class Attribute(object): + """ + *Read-only* representation of an attribute. + + :attribute name: The name of the attribute. + + Plus *all* arguments of :func:`attr.ib`. + """ + __slots__ = ( + "name", "default", "validator", "repr", "cmp", "hash", "init", + "convert", "metadata", "type" + ) + + def __init__(self, name, default, validator, repr, cmp, hash, init, + convert=None, metadata=None, type=None): + # Cache this descriptor here to speed things up later. + bound_setattr = _obj_setattr.__get__(self, Attribute) + + bound_setattr("name", name) + bound_setattr("default", default) + bound_setattr("validator", validator) + bound_setattr("repr", repr) + bound_setattr("cmp", cmp) + bound_setattr("hash", hash) + bound_setattr("init", init) + bound_setattr("convert", convert) + bound_setattr("metadata", (metadata_proxy(metadata) if metadata + else _empty_metadata_singleton)) + bound_setattr("type", type) + + def __setattr__(self, name, value): + raise FrozenInstanceError() + + @classmethod + def from_counting_attr(cls, name, ca, type=None): + # type holds the annotated value. deal with conflicts: + if type is None: + type = ca.type + elif ca.type is not None: + raise ValueError( + "Type annotation and type argument cannot both be present" + ) + inst_dict = { + k: getattr(ca, k) + for k + in Attribute.__slots__ + if k not in ( + "name", "validator", "default", "type" + ) # exclude methods + } + return cls(name=name, validator=ca._validator, default=ca._default, + type=type, **inst_dict) + + # Don't use _add_pickle since fields(Attribute) doesn't work + def __getstate__(self): + """ + Play nice with pickle. + """ + return tuple(getattr(self, name) if name != "metadata" + else dict(self.metadata) + for name in self.__slots__) + + def __setstate__(self, state): + """ + Play nice with pickle. + """ + bound_setattr = _obj_setattr.__get__(self, Attribute) + for name, value in zip(self.__slots__, state): + if name != "metadata": + bound_setattr(name, value) + else: + bound_setattr(name, metadata_proxy(value) if value else + _empty_metadata_singleton) + + +_a = [Attribute(name=name, default=NOTHING, validator=None, + repr=True, cmp=True, hash=(name != "metadata"), init=True) + for name in Attribute.__slots__] + +Attribute = _add_hash( + _add_cmp(_add_repr(Attribute, attrs=_a), attrs=_a), + attrs=[a for a in _a if a.hash] +) + + +class _CountingAttr(object): + """ + Intermediate representation of attributes that uses a counter to preserve + the order in which the attributes have been defined. + + *Internal* data structure of the attrs library. Running into is most + likely the result of a bug like a forgotten `@attr.s` decorator. + """ + __slots__ = ("counter", "_default", "repr", "cmp", "hash", "init", + "metadata", "_validator", "convert", "type") + __attrs_attrs__ = tuple( + Attribute(name=name, default=NOTHING, validator=None, + repr=True, cmp=True, hash=True, init=True) + for name + in ("counter", "_default", "repr", "cmp", "hash", "init",) + ) + ( + Attribute(name="metadata", default=None, validator=None, + repr=True, cmp=True, hash=False, init=True), + ) + cls_counter = 0 + + def __init__(self, default, validator, repr, cmp, hash, init, convert, + metadata, type): + _CountingAttr.cls_counter += 1 + self.counter = _CountingAttr.cls_counter + self._default = default + # If validator is a list/tuple, wrap it using helper validator. + if validator and isinstance(validator, (list, tuple)): + self._validator = and_(*validator) + else: + self._validator = validator + self.repr = repr + self.cmp = cmp + self.hash = hash + self.init = init + self.convert = convert + self.metadata = metadata + self.type = type + + def validator(self, meth): + """ + Decorator that adds *meth* to the list of validators. + + Returns *meth* unchanged. + + .. versionadded:: 17.1.0 + """ + if self._validator is None: + self._validator = meth + else: + self._validator = and_(self._validator, meth) + return meth + + def default(self, meth): + """ + Decorator that allows to set the default for an attribute. + + Returns *meth* unchanged. + + :raises DefaultAlreadySetError: If default has been set before. + + .. versionadded:: 17.1.0 + """ + if self._default is not NOTHING: + raise DefaultAlreadySetError() + + self._default = Factory(meth, takes_self=True) + + return meth + + +_CountingAttr = _add_cmp(_add_repr(_CountingAttr)) + + +@attrs(slots=True, init=False, hash=True) +class Factory(object): + """ + Stores a factory callable. + + If passed as the default value to :func:`attr.ib`, the factory is used to + generate a new value. + + :param callable factory: A callable that takes either none or exactly one + mandatory positional argument depending on *takes_self*. + :param bool takes_self: Pass the partially initialized instance that is + being initialized as a positional argument. + + .. versionadded:: 17.1.0 *takes_self* + """ + factory = attrib() + takes_self = attrib() + + def __init__(self, factory, takes_self=False): + """ + `Factory` is part of the default machinery so if we want a default + value here, we have to implement it ourselves. + """ + self.factory = factory + self.takes_self = takes_self + + +def make_class(name, attrs, bases=(object,), **attributes_arguments): + """ + A quick way to create a new class called *name* with *attrs*. + + :param name: The name for the new class. + :type name: str + + :param attrs: A list of names or a dictionary of mappings of names to + attributes. + :type attrs: :class:`list` or :class:`dict` + + :param tuple bases: Classes that the new class will subclass. + + :param attributes_arguments: Passed unmodified to :func:`attr.s`. + + :return: A new class with *attrs*. + :rtype: type + + .. versionadded:: 17.1.0 *bases* + """ + if isinstance(attrs, dict): + cls_dict = attrs + elif isinstance(attrs, (list, tuple)): + cls_dict = dict((a, attrib()) for a in attrs) + else: + raise TypeError("attrs argument must be a dict or a list.") + + post_init = cls_dict.pop("__attrs_post_init__", None) + type_ = type( + name, + bases, + {} if post_init is None else {"__attrs_post_init__": post_init} + ) + # For pickling to work, the __module__ variable needs to be set to the + # frame where the class is created. Bypass this step in environments where + # sys._getframe is not defined (Jython for example) or sys._getframe is not + # defined for arguments greater than 0 (IronPython). + try: + type_.__module__ = sys._getframe(1).f_globals.get( + "__name__", "__main__", + ) + except (AttributeError, ValueError): + pass + + return _attrs(these=cls_dict, **attributes_arguments)(type_) + + +# These are required by within this module so we define them here and merely +# import into .validators. + + +@attrs(slots=True, hash=True) +class _AndValidator(object): + """ + Compose many validators to a single one. + """ + _validators = attrib() + + def __call__(self, inst, attr, value): + for v in self._validators: + v(inst, attr, value) + + +def and_(*validators): + """ + A validator that composes multiple validators into one. + + When called on a value, it runs all wrapped validators. + + :param validators: Arbitrary number of validators. + :type validators: callables + + .. versionadded:: 17.1.0 + """ + vals = [] + for validator in validators: + vals.extend( + validator._validators if isinstance(validator, _AndValidator) + else [validator] + ) + + return _AndValidator(tuple(vals)) diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/converters.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/converters.py new file mode 100644 index 00000000000..3b3bac92be5 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/converters.py @@ -0,0 +1,24 @@ +""" +Commonly useful converters. +""" + +from __future__ import absolute_import, division, print_function + + +def optional(converter): + """ + A converter that allows an attribute to be optional. An optional attribute + is one which can be set to ``None``. + + :param callable converter: the converter that is used for non-``None`` + values. + + .. versionadded:: 17.1.0 + """ + + def optional_converter(val): + if val is None: + return None + return converter(val) + + return optional_converter diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/exceptions.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/exceptions.py new file mode 100644 index 00000000000..f949f3c9c01 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/exceptions.py @@ -0,0 +1,48 @@ +from __future__ import absolute_import, division, print_function + + +class FrozenInstanceError(AttributeError): + """ + A frozen/immutable instance has been attempted to be modified. + + It mirrors the behavior of ``namedtuples`` by using the same error message + and subclassing :exc:`AttributeError`. + + .. versionadded:: 16.1.0 + """ + msg = "can't set attribute" + args = [msg] + + +class AttrsAttributeNotFoundError(ValueError): + """ + An ``attrs`` function couldn't find an attribute that the user asked for. + + .. versionadded:: 16.2.0 + """ + + +class NotAnAttrsClassError(ValueError): + """ + A non-``attrs`` class has been passed into an ``attrs`` function. + + .. versionadded:: 16.2.0 + """ + + +class DefaultAlreadySetError(RuntimeError): + """ + A default has been set using ``attr.ib()`` and is attempted to be reset + using the decorator. + + .. versionadded:: 17.1.0 + """ + + +class UnannotatedAttributeError(RuntimeError): + """ + A class with ``auto_attribs=True`` has an ``attr.ib()`` without a type + annotation. + + .. versionadded:: 17.3.0 + """ diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/filters.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/filters.py new file mode 100644 index 00000000000..d1bad35e363 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/filters.py @@ -0,0 +1,52 @@ +""" +Commonly useful filters for :func:`attr.asdict`. +""" + +from __future__ import absolute_import, division, print_function + +from ._compat import isclass +from ._make import Attribute + + +def _split_what(what): + """ + Returns a tuple of `frozenset`s of classes and attributes. + """ + return ( + frozenset(cls for cls in what if isclass(cls)), + frozenset(cls for cls in what if isinstance(cls, Attribute)), + ) + + +def include(*what): + """ + Whitelist *what*. + + :param what: What to whitelist. + :type what: :class:`list` of :class:`type` or :class:`attr.Attribute`\ s + + :rtype: :class:`callable` + """ + cls, attrs = _split_what(what) + + def include_(attribute, value): + return value.__class__ in cls or attribute in attrs + + return include_ + + +def exclude(*what): + """ + Blacklist *what*. + + :param what: What to blacklist. + :type what: :class:`list` of classes or :class:`attr.Attribute`\ s. + + :rtype: :class:`callable` + """ + cls, attrs = _split_what(what) + + def exclude_(attribute, value): + return value.__class__ not in cls and attribute not in attrs + + return exclude_ diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/validators.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/validators.py new file mode 100644 index 00000000000..f8892fcdfe4 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/src/attr/validators.py @@ -0,0 +1,166 @@ +""" +Commonly useful validators. +""" + +from __future__ import absolute_import, division, print_function + +from ._make import _AndValidator, and_, attrib, attrs + + +__all__ = [ + "and_", + "in_", + "instance_of", + "optional", + "provides", +] + + +@attrs(repr=False, slots=True, hash=True) +class _InstanceOfValidator(object): + type = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not isinstance(value, self.type): + raise TypeError( + "'{name}' must be {type!r} (got {value!r} that is a " + "{actual!r})." + .format(name=attr.name, type=self.type, + actual=value.__class__, value=value), + attr, self.type, value, + ) + + def __repr__(self): + return ( + "" + .format(type=self.type) + ) + + +def instance_of(type): + """ + A validator that raises a :exc:`TypeError` if the initializer is called + with a wrong type for this particular attribute (checks are performed using + :func:`isinstance` therefore it's also valid to pass a tuple of types). + + :param type: The type to check for. + :type type: type or tuple of types + + :raises TypeError: With a human readable error message, the attribute + (of type :class:`attr.Attribute`), the expected type, and the value it + got. + """ + return _InstanceOfValidator(type) + + +@attrs(repr=False, slots=True, hash=True) +class _ProvidesValidator(object): + interface = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not self.interface.providedBy(value): + raise TypeError( + "'{name}' must provide {interface!r} which {value!r} " + "doesn't." + .format(name=attr.name, interface=self.interface, value=value), + attr, self.interface, value, + ) + + def __repr__(self): + return ( + "" + .format(interface=self.interface) + ) + + +def provides(interface): + """ + A validator that raises a :exc:`TypeError` if the initializer is called + with an object that does not provide the requested *interface* (checks are + performed using ``interface.providedBy(value)`` (see `zope.interface + `_). + + :param zope.interface.Interface interface: The interface to check for. + + :raises TypeError: With a human readable error message, the attribute + (of type :class:`attr.Attribute`), the expected interface, and the + value it got. + """ + return _ProvidesValidator(interface) + + +@attrs(repr=False, slots=True, hash=True) +class _OptionalValidator(object): + validator = attrib() + + def __call__(self, inst, attr, value): + if value is None: + return + + self.validator(inst, attr, value) + + def __repr__(self): + return ( + "" + .format(what=repr(self.validator)) + ) + + +def optional(validator): + """ + A validator that makes an attribute optional. An optional attribute is one + which can be set to ``None`` in addition to satisfying the requirements of + the sub-validator. + + :param validator: A validator (or a list of validators) that is used for + non-``None`` values. + :type validator: callable or :class:`list` of callables. + + .. versionadded:: 15.1.0 + .. versionchanged:: 17.1.0 *validator* can be a list of validators. + """ + if isinstance(validator, list): + return _OptionalValidator(_AndValidator(validator)) + return _OptionalValidator(validator) + + +@attrs(repr=False, slots=True, hash=True) +class _InValidator(object): + options = attrib() + + def __call__(self, inst, attr, value): + if value not in self.options: + raise ValueError( + "'{name}' must be in {options!r} (got {value!r})" + .format(name=attr.name, options=self.options, value=value) + ) + + def __repr__(self): + return ( + "" + .format(options=self.options) + ) + + +def in_(options): + """ + A validator that raises a :exc:`ValueError` if the initializer is called + with a value that does not belong in the options provided. The check is + performed using ``value in options``. + + :param options: Allowed options. + :type options: list, tuple, :class:`enum.Enum`, ... + + :raises ValueError: With a human readable error message, the attribute (of + type :class:`attr.Attribute`), the expected options, and the value it + got. + + .. versionadded:: 17.1.0 + """ + return _InValidator(options) diff --git a/tests/wpt/web-platform-tests/webdriver/tests/retrieval/__init__.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/__init__.py similarity index 100% rename from tests/wpt/web-platform-tests/webdriver/tests/retrieval/__init__.py rename to tests/wpt/web-platform-tests/tools/third_party/attrs/tests/__init__.py diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_annotations.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_annotations.py new file mode 100644 index 00000000000..602f21bd5e6 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_annotations.py @@ -0,0 +1,156 @@ +""" +Tests for PEP-526 type annotations. + +Python 3.6+ only. +""" + +import types +import typing + +import pytest + +import attr + +from attr.exceptions import UnannotatedAttributeError + + +class TestAnnotations: + """ + Tests for types derived from variable annotations (PEP-526). + """ + + def test_basic_annotations(self): + """ + Sets the `Attribute.type` attr from basic type annotations. + """ + @attr.s + class C: + x: int = attr.ib() + y = attr.ib(type=str) + z = attr.ib() + + assert int is attr.fields(C).x.type + assert str is attr.fields(C).y.type + assert None is attr.fields(C).z.type + + def test_catches_basic_type_conflict(self): + """ + Raises ValueError if type is specified both ways. + """ + with pytest.raises(ValueError) as e: + @attr.s + class C: + x: int = attr.ib(type=int) + + assert ( + "Type annotation and type argument cannot both be present", + ) == e.value.args + + def test_typing_annotations(self): + """ + Sets the `Attribute.type` attr from typing annotations. + """ + @attr.s + class C: + x: typing.List[int] = attr.ib() + y = attr.ib(type=typing.Optional[str]) + + assert typing.List[int] is attr.fields(C).x.type + assert typing.Optional[str] is attr.fields(C).y.type + + def test_only_attrs_annotations_collected(self): + """ + Annotations that aren't set to an attr.ib are ignored. + """ + @attr.s + class C: + x: typing.List[int] = attr.ib() + y: int + + assert 1 == len(attr.fields(C)) + + @pytest.mark.parametrize("slots", [True, False]) + def test_auto_attribs(self, slots): + """ + If *auto_attribs* is True, bare annotations are collected too. + Defaults work and class variables are ignored. + """ + @attr.s(auto_attribs=True, slots=slots) + class C: + cls_var: typing.ClassVar[int] = 23 + a: int + x: typing.List[int] = attr.Factory(list) + y: int = 2 + z: int = attr.ib(default=3) + foo: typing.Any = None + + i = C(42) + assert "C(a=42, x=[], y=2, z=3, foo=None)" == repr(i) + + attr_names = set(a.name for a in C.__attrs_attrs__) + assert "a" in attr_names # just double check that the set works + assert "cls_var" not in attr_names + + assert int == attr.fields(C).a.type + + assert attr.Factory(list) == attr.fields(C).x.default + assert typing.List[int] == attr.fields(C).x.type + + assert int == attr.fields(C).y.type + assert 2 == attr.fields(C).y.default + + assert int == attr.fields(C).z.type + + assert typing.Any == attr.fields(C).foo.type + + # Class body is clean. + if slots is False: + with pytest.raises(AttributeError): + C.y + + assert 2 == i.y + else: + assert isinstance(C.y, types.MemberDescriptorType) + + i.y = 23 + assert 23 == i.y + + @pytest.mark.parametrize("slots", [True, False]) + def test_auto_attribs_unannotated(self, slots): + """ + Unannotated `attr.ib`s raise an error. + """ + with pytest.raises(UnannotatedAttributeError) as e: + @attr.s(slots=slots, auto_attribs=True) + class C: + v = attr.ib() + x: int + y = attr.ib() + z: str + + assert ( + "The following `attr.ib`s lack a type annotation: v, y.", + ) == e.value.args + + @pytest.mark.parametrize("slots", [True, False]) + def test_auto_attribs_subclassing(self, slots): + """ + Attributes from super classes are inherited, it doesn't matter if the + subclass has annotations or not. + + Ref #291 + """ + @attr.s(slots=slots, auto_attribs=True) + class A: + a: int = 1 + + @attr.s(slots=slots, auto_attribs=True) + class B(A): + b: int = 2 + + @attr.s(slots=slots, auto_attribs=True) + class C(A): + pass + + assert "B(a=1, b=2)" == repr(B()) + assert "C(a=1)" == repr(C()) diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_config.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_config.py new file mode 100644 index 00000000000..287be03a597 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_config.py @@ -0,0 +1,43 @@ +""" +Tests for `attr._config`. +""" + +from __future__ import absolute_import, division, print_function + +import pytest + +from attr import _config + + +class TestConfig(object): + def test_default(self): + """ + Run validators by default. + """ + assert True is _config._run_validators + + def test_set_run_validators(self): + """ + Sets `_run_validators`. + """ + _config.set_run_validators(False) + assert False is _config._run_validators + _config.set_run_validators(True) + assert True is _config._run_validators + + def test_get_run_validators(self): + """ + Returns `_run_validators`. + """ + _config._run_validators = False + assert _config._run_validators is _config.get_run_validators() + _config._run_validators = True + assert _config._run_validators is _config.get_run_validators() + + def test_wrong_type(self): + """ + Passing anything else than a boolean raises TypeError. + """ + with pytest.raises(TypeError) as e: + _config.set_run_validators("False") + assert "'run' must be bool." == e.value.args[0] diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_converters.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_converters.py new file mode 100644 index 00000000000..daf39d8ace0 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_converters.py @@ -0,0 +1,36 @@ +""" +Tests for `attr.converters`. +""" + +from __future__ import absolute_import + +import pytest + +from attr.converters import optional + + +class TestOptional(object): + """ + Tests for `optional`. + """ + def test_success_with_type(self): + """ + Wrapped converter is used as usual if value is not None. + """ + c = optional(int) + assert c("42") == 42 + + def test_success_with_none(self): + """ + Nothing happens if None. + """ + c = optional(int) + assert c(None) is None + + def test_fail(self): + """ + Propagates the underlying conversion error when conversion fails. + """ + c = optional(int) + with pytest.raises(ValueError): + c("not_an_int") diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_dark_magic.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_dark_magic.py new file mode 100644 index 00000000000..bc6665cf5fe --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_dark_magic.py @@ -0,0 +1,382 @@ +""" +End-to-end tests. +""" + +from __future__ import absolute_import, division, print_function + +import pickle + +import pytest +import six + +from hypothesis import given +from hypothesis.strategies import booleans + +import attr + +from attr._compat import TYPE +from attr._make import NOTHING, Attribute +from attr.exceptions import FrozenInstanceError + + +@attr.s +class C1(object): + x = attr.ib(validator=attr.validators.instance_of(int)) + y = attr.ib() + + +@attr.s(slots=True) +class C1Slots(object): + x = attr.ib(validator=attr.validators.instance_of(int)) + y = attr.ib() + + +foo = None + + +@attr.s() +class C2(object): + x = attr.ib(default=foo) + y = attr.ib(default=attr.Factory(list)) + + +@attr.s(slots=True) +class C2Slots(object): + x = attr.ib(default=foo) + y = attr.ib(default=attr.Factory(list)) + + +@attr.s +class Super(object): + x = attr.ib() + + def meth(self): + return self.x + + +@attr.s(slots=True) +class SuperSlots(object): + x = attr.ib() + + def meth(self): + return self.x + + +@attr.s +class Sub(Super): + y = attr.ib() + + +@attr.s(slots=True) +class SubSlots(SuperSlots): + y = attr.ib() + + +@attr.s(frozen=True, slots=True) +class Frozen(object): + x = attr.ib() + + +@attr.s +class SubFrozen(Frozen): + y = attr.ib() + + +@attr.s(frozen=True, slots=False) +class FrozenNoSlots(object): + x = attr.ib() + + +class Meta(type): + pass + + +@attr.s +@six.add_metaclass(Meta) +class WithMeta(object): + pass + + +@attr.s(slots=True) +@six.add_metaclass(Meta) +class WithMetaSlots(object): + pass + + +FromMakeClass = attr.make_class("FromMakeClass", ["x"]) + + +class TestDarkMagic(object): + """ + Integration tests. + """ + @pytest.mark.parametrize("cls", [C2, C2Slots]) + def test_fields(self, cls): + """ + `attr.fields` works. + """ + assert ( + Attribute(name="x", default=foo, validator=None, + repr=True, cmp=True, hash=None, init=True), + Attribute(name="y", default=attr.Factory(list), validator=None, + repr=True, cmp=True, hash=None, init=True), + ) == attr.fields(cls) + + @pytest.mark.parametrize("cls", [C1, C1Slots]) + def test_asdict(self, cls): + """ + `attr.asdict` works. + """ + assert { + "x": 1, + "y": 2, + } == attr.asdict(cls(x=1, y=2)) + + @pytest.mark.parametrize("cls", [C1, C1Slots]) + def test_validator(self, cls): + """ + `instance_of` raises `TypeError` on type mismatch. + """ + with pytest.raises(TypeError) as e: + cls("1", 2) + + # Using C1 explicitly, since slot classes don't support this. + assert ( + "'x' must be <{type} 'int'> (got '1' that is a <{type} " + "'str'>).".format(type=TYPE), + attr.fields(C1).x, int, "1", + ) == e.value.args + + @given(booleans()) + def test_renaming(self, slots): + """ + Private members are renamed but only in `__init__`. + """ + @attr.s(slots=slots) + class C3(object): + _x = attr.ib() + + assert "C3(_x=1)" == repr(C3(x=1)) + + @given(booleans(), booleans()) + def test_programmatic(self, slots, frozen): + """ + `attr.make_class` works. + """ + PC = attr.make_class("PC", ["a", "b"], slots=slots, frozen=frozen) + assert ( + Attribute(name="a", default=NOTHING, validator=None, + repr=True, cmp=True, hash=None, init=True), + Attribute(name="b", default=NOTHING, validator=None, + repr=True, cmp=True, hash=None, init=True), + ) == attr.fields(PC) + + @pytest.mark.parametrize("cls", [Sub, SubSlots]) + def test_subclassing_with_extra_attrs(self, cls): + """ + Sub-classing (where the subclass has extra attrs) does what you'd hope + for. + """ + obj = object() + i = cls(x=obj, y=2) + assert i.x is i.meth() is obj + assert i.y == 2 + if cls is Sub: + assert "Sub(x={obj}, y=2)".format(obj=obj) == repr(i) + else: + assert "SubSlots(x={obj}, y=2)".format(obj=obj) == repr(i) + + @pytest.mark.parametrize("base", [Super, SuperSlots]) + def test_subclass_without_extra_attrs(self, base): + """ + Sub-classing (where the subclass does not have extra attrs) still + behaves the same as a subclass with extra attrs. + """ + class Sub2(base): + pass + + obj = object() + i = Sub2(x=obj) + assert i.x is i.meth() is obj + assert "Sub2(x={obj})".format(obj=obj) == repr(i) + + @pytest.mark.parametrize("frozen_class", [ + Frozen, # has slots=True + attr.make_class("FrozenToo", ["x"], slots=False, frozen=True), + ]) + def test_frozen_instance(self, frozen_class): + """ + Frozen instances can't be modified (easily). + """ + frozen = frozen_class(1) + + with pytest.raises(FrozenInstanceError) as e: + frozen.x = 2 + + with pytest.raises(FrozenInstanceError) as e: + del frozen.x + + assert e.value.args[0] == "can't set attribute" + assert 1 == frozen.x + + @pytest.mark.parametrize("cls", + [C1, C1Slots, C2, C2Slots, Super, SuperSlots, + Sub, SubSlots, Frozen, FrozenNoSlots, + FromMakeClass]) + @pytest.mark.parametrize("protocol", + range(2, pickle.HIGHEST_PROTOCOL + 1)) + def test_pickle_attributes(self, cls, protocol): + """ + Pickling/un-pickling of Attribute instances works. + """ + for attribute in attr.fields(cls): + assert attribute == pickle.loads(pickle.dumps(attribute, protocol)) + + @pytest.mark.parametrize("cls", + [C1, C1Slots, C2, C2Slots, Super, SuperSlots, + Sub, SubSlots, Frozen, FrozenNoSlots, + FromMakeClass]) + @pytest.mark.parametrize("protocol", + range(2, pickle.HIGHEST_PROTOCOL + 1)) + def test_pickle_object(self, cls, protocol): + """ + Pickle object serialization works on all kinds of attrs classes. + """ + if len(attr.fields(cls)) == 2: + obj = cls(123, 456) + else: + obj = cls(123) + assert repr(obj) == repr(pickle.loads(pickle.dumps(obj, protocol))) + + def test_subclassing_frozen_gives_frozen(self): + """ + The frozen-ness of classes is inherited. Subclasses of frozen classes + are also frozen and can be instantiated. + """ + i = SubFrozen("foo", "bar") + + assert i.x == "foo" + assert i.y == "bar" + + @pytest.mark.parametrize("cls", [WithMeta, WithMetaSlots]) + def test_metaclass_preserved(self, cls): + """ + Metaclass data is preserved. + """ + assert Meta == type(cls) + + def test_default_decorator(self): + """ + Default decorator sets the default and the respective method gets + called. + """ + @attr.s + class C(object): + x = attr.ib(default=1) + y = attr.ib() + + @y.default + def compute(self): + return self.x + 1 + + assert C(1, 2) == C() + + @pytest.mark.parametrize("slots", [True, False]) + @pytest.mark.parametrize("frozen", [True, False]) + def test_attrib_overwrite(self, slots, frozen): + """ + Subclasses can overwrite attributes of their superclass. + """ + @attr.s(slots=slots, frozen=frozen) + class SubOverwrite(Super): + x = attr.ib(default=attr.Factory(list)) + + assert SubOverwrite([]) == SubOverwrite() + + def test_dict_patch_class(self): + """ + dict-classes are never replaced. + """ + class C(object): + x = attr.ib() + + C_new = attr.s(C) + + assert C_new is C + + def test_hash_by_id(self): + """ + With dict classes, hashing by ID is active for hash=False even on + Python 3. This is incorrect behavior but we have to retain it for + backward compatibility. + """ + @attr.s(hash=False) + class HashByIDBackwardCompat(object): + x = attr.ib() + + assert ( + hash(HashByIDBackwardCompat(1)) != hash(HashByIDBackwardCompat(1)) + ) + + @attr.s(hash=False, cmp=False) + class HashByID(object): + x = attr.ib() + + assert hash(HashByID(1)) != hash(HashByID(1)) + + @attr.s(hash=True) + class HashByValues(object): + x = attr.ib() + + assert hash(HashByValues(1)) == hash(HashByValues(1)) + + def test_handles_different_defaults(self): + """ + Unhashable defaults + subclassing values work. + """ + @attr.s + class Unhashable(object): + pass + + @attr.s + class C(object): + x = attr.ib(default=Unhashable()) + + @attr.s + class D(C): + pass + + @pytest.mark.parametrize("slots", [True, False]) + def test_hash_false_cmp_false(self, slots): + """ + hash=False and cmp=False make a class hashable by ID. + """ + @attr.s(hash=False, cmp=False, slots=slots) + class C(object): + pass + + assert hash(C()) != hash(C()) + + def test_overwrite_super(self): + """ + Super classes can overwrite each other and the attributes are added + in the order they are defined. + """ + @attr.s + class C(object): + c = attr.ib(default=100) + x = attr.ib(default=1) + b = attr.ib(default=23) + + @attr.s + class D(C): + a = attr.ib(default=42) + x = attr.ib(default=2) + d = attr.ib(default=3.14) + + @attr.s + class E(D): + y = attr.ib(default=3) + z = attr.ib(default=4) + + assert "E(c=100, b=23, a=42, x=2, d=3.14, y=3, z=4)" == repr(E()) diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_dunders.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_dunders.py new file mode 100644 index 00000000000..951faba2ffc --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_dunders.py @@ -0,0 +1,502 @@ +""" +Tests for dunder methods from `attrib._make`. +""" + +from __future__ import absolute_import, division, print_function + +import copy + +import pytest + +from hypothesis import given +from hypothesis.strategies import booleans + +import attr + +from attr._make import ( + NOTHING, Factory, _add_init, _add_repr, _Nothing, fields, make_class +) +from attr.validators import instance_of + +from .utils import simple_attr, simple_class + + +CmpC = simple_class(cmp=True) +CmpCSlots = simple_class(cmp=True, slots=True) +ReprC = simple_class(repr=True) +ReprCSlots = simple_class(repr=True, slots=True) + +# HashC is hashable by explicit definition while HashCSlots is hashable +# implicitly. +HashC = simple_class(hash=True) +HashCSlots = simple_class(hash=None, cmp=True, frozen=True, slots=True) + + +class InitC(object): + __attrs_attrs__ = [simple_attr("a"), simple_attr("b")] + + +InitC = _add_init(InitC, False) + + +class TestAddCmp(object): + """ + Tests for `_add_cmp`. + """ + @given(booleans()) + def test_cmp(self, slots): + """ + If `cmp` is False, ignore that attribute. + """ + C = make_class("C", { + "a": attr.ib(cmp=False), + "b": attr.ib() + }, slots=slots) + + assert C(1, 2) == C(2, 2) + + @pytest.mark.parametrize("cls", [CmpC, CmpCSlots]) + def test_equal(self, cls): + """ + Equal objects are detected as equal. + """ + assert cls(1, 2) == cls(1, 2) + assert not (cls(1, 2) != cls(1, 2)) + + @pytest.mark.parametrize("cls", [CmpC, CmpCSlots]) + def test_unequal_same_class(self, cls): + """ + Unequal objects of correct type are detected as unequal. + """ + assert cls(1, 2) != cls(2, 1) + assert not (cls(1, 2) == cls(2, 1)) + + @pytest.mark.parametrize("cls", [CmpC, CmpCSlots]) + def test_unequal_different_class(self, cls): + """ + Unequal objects of different type are detected even if their attributes + match. + """ + class NotCmpC(object): + a = 1 + b = 2 + assert cls(1, 2) != NotCmpC() + assert not (cls(1, 2) == NotCmpC()) + + @pytest.mark.parametrize("cls", [CmpC, CmpCSlots]) + def test_lt(self, cls): + """ + __lt__ compares objects as tuples of attribute values. + """ + for a, b in [ + ((1, 2), (2, 1)), + ((1, 2), (1, 3)), + (("a", "b"), ("b", "a")), + ]: + assert cls(*a) < cls(*b) + + @pytest.mark.parametrize("cls", [CmpC, CmpCSlots]) + def test_lt_unordable(self, cls): + """ + __lt__ returns NotImplemented if classes differ. + """ + assert NotImplemented == (cls(1, 2).__lt__(42)) + + @pytest.mark.parametrize("cls", [CmpC, CmpCSlots]) + def test_le(self, cls): + """ + __le__ compares objects as tuples of attribute values. + """ + for a, b in [ + ((1, 2), (2, 1)), + ((1, 2), (1, 3)), + ((1, 1), (1, 1)), + (("a", "b"), ("b", "a")), + (("a", "b"), ("a", "b")), + ]: + assert cls(*a) <= cls(*b) + + @pytest.mark.parametrize("cls", [CmpC, CmpCSlots]) + def test_le_unordable(self, cls): + """ + __le__ returns NotImplemented if classes differ. + """ + assert NotImplemented == (cls(1, 2).__le__(42)) + + @pytest.mark.parametrize("cls", [CmpC, CmpCSlots]) + def test_gt(self, cls): + """ + __gt__ compares objects as tuples of attribute values. + """ + for a, b in [ + ((2, 1), (1, 2)), + ((1, 3), (1, 2)), + (("b", "a"), ("a", "b")), + ]: + assert cls(*a) > cls(*b) + + @pytest.mark.parametrize("cls", [CmpC, CmpCSlots]) + def test_gt_unordable(self, cls): + """ + __gt__ returns NotImplemented if classes differ. + """ + assert NotImplemented == (cls(1, 2).__gt__(42)) + + @pytest.mark.parametrize("cls", [CmpC, CmpCSlots]) + def test_ge(self, cls): + """ + __ge__ compares objects as tuples of attribute values. + """ + for a, b in [ + ((2, 1), (1, 2)), + ((1, 3), (1, 2)), + ((1, 1), (1, 1)), + (("b", "a"), ("a", "b")), + (("a", "b"), ("a", "b")), + ]: + assert cls(*a) >= cls(*b) + + @pytest.mark.parametrize("cls", [CmpC, CmpCSlots]) + def test_ge_unordable(self, cls): + """ + __ge__ returns NotImplemented if classes differ. + """ + assert NotImplemented == (cls(1, 2).__ge__(42)) + + +class TestAddRepr(object): + """ + Tests for `_add_repr`. + """ + @pytest.mark.parametrize("slots", [True, False]) + def test_repr(self, slots): + """ + If `repr` is False, ignore that attribute. + """ + C = make_class("C", { + "a": attr.ib(repr=False), + "b": attr.ib() + }, slots=slots) + + assert "C(b=2)" == repr(C(1, 2)) + + @pytest.mark.parametrize("cls", [ReprC, ReprCSlots]) + def test_repr_works(self, cls): + """ + repr returns a sensible value. + """ + assert "C(a=1, b=2)" == repr(cls(1, 2)) + + def test_underscores(self): + """ + repr does not strip underscores. + """ + class C(object): + __attrs_attrs__ = [simple_attr("_x")] + + C = _add_repr(C) + i = C() + i._x = 42 + + assert "C(_x=42)" == repr(i) + + @given(add_str=booleans(), slots=booleans()) + def test_str(self, add_str, slots): + """ + If str is True, it returns the same as repr. + + This only makes sense when subclassing a class with an poor __str__ + (like Exceptions). + """ + @attr.s(str=add_str, slots=slots) + class Error(Exception): + x = attr.ib() + + e = Error(42) + + assert (str(e) == repr(e)) is add_str + + def test_str_no_repr(self): + """ + Raises a ValueError if repr=False and str=True. + """ + with pytest.raises(ValueError) as e: + simple_class(repr=False, str=True) + + assert ( + "__str__ can only be generated if a __repr__ exists." + ) == e.value.args[0] + + +class TestAddHash(object): + """ + Tests for `_add_hash`. + """ + def test_enforces_type(self): + """ + The `hash` argument to both attrs and attrib must be None, True, or + False. + """ + exc_args = ("Invalid value for hash. Must be True, False, or None.",) + + with pytest.raises(TypeError) as e: + make_class("C", {}, hash=1), + + assert exc_args == e.value.args + + with pytest.raises(TypeError) as e: + make_class("C", {"a": attr.ib(hash=1)}), + + assert exc_args == e.value.args + + @given(booleans()) + def test_hash_attribute(self, slots): + """ + If `hash` is False on an attribute, ignore that attribute. + """ + C = make_class("C", {"a": attr.ib(hash=False), "b": attr.ib()}, + slots=slots, hash=True) + + assert hash(C(1, 2)) == hash(C(2, 2)) + + @given(booleans()) + def test_hash_attribute_mirrors_cmp(self, cmp): + """ + If `hash` is None, the hash generation mirrors `cmp`. + """ + C = make_class("C", {"a": attr.ib(cmp=cmp)}, cmp=True, frozen=True) + + if cmp: + assert C(1) != C(2) + assert hash(C(1)) != hash(C(2)) + assert hash(C(1)) == hash(C(1)) + else: + assert C(1) == C(2) + assert hash(C(1)) == hash(C(2)) + + @given(booleans()) + def test_hash_mirrors_cmp(self, cmp): + """ + If `hash` is None, the hash generation mirrors `cmp`. + """ + C = make_class("C", {"a": attr.ib()}, cmp=cmp, frozen=True) + + i = C(1) + + assert i == i + assert hash(i) == hash(i) + + if cmp: + assert C(1) == C(1) + assert hash(C(1)) == hash(C(1)) + else: + assert C(1) != C(1) + assert hash(C(1)) != hash(C(1)) + + @pytest.mark.parametrize("cls", [HashC, HashCSlots]) + def test_hash_works(self, cls): + """ + __hash__ returns different hashes for different values. + """ + assert hash(cls(1, 2)) != hash(cls(1, 1)) + + def test_hash_default(self): + """ + Classes are not hashable by default. + """ + C = make_class("C", {}) + + with pytest.raises(TypeError) as e: + hash(C()) + + assert e.value.args[0] in ( + "'C' objects are unhashable", # PyPy + "unhashable type: 'C'", # CPython + ) + + +class TestAddInit(object): + """ + Tests for `_add_init`. + """ + @given(booleans(), booleans()) + def test_init(self, slots, frozen): + """ + If `init` is False, ignore that attribute. + """ + C = make_class("C", {"a": attr.ib(init=False), "b": attr.ib()}, + slots=slots, frozen=frozen) + with pytest.raises(TypeError) as e: + C(a=1, b=2) + + assert ( + "__init__() got an unexpected keyword argument 'a'" == + e.value.args[0] + ) + + @given(booleans(), booleans()) + def test_no_init_default(self, slots, frozen): + """ + If `init` is False but a Factory is specified, don't allow passing that + argument but initialize it anyway. + """ + C = make_class("C", { + "_a": attr.ib(init=False, default=42), + "_b": attr.ib(init=False, default=Factory(list)), + "c": attr.ib() + }, slots=slots, frozen=frozen) + with pytest.raises(TypeError): + C(a=1, c=2) + with pytest.raises(TypeError): + C(b=1, c=2) + + i = C(23) + assert (42, [], 23) == (i._a, i._b, i.c) + + @given(booleans(), booleans()) + def test_no_init_order(self, slots, frozen): + """ + If an attribute is `init=False`, it's legal to come after a mandatory + attribute. + """ + make_class("C", { + "a": attr.ib(default=Factory(list)), + "b": attr.ib(init=False), + }, slots=slots, frozen=frozen) + + def test_sets_attributes(self): + """ + The attributes are initialized using the passed keywords. + """ + obj = InitC(a=1, b=2) + assert 1 == obj.a + assert 2 == obj.b + + def test_default(self): + """ + If a default value is present, it's used as fallback. + """ + class C(object): + __attrs_attrs__ = [ + simple_attr(name="a", default=2), + simple_attr(name="b", default="hallo"), + simple_attr(name="c", default=None), + ] + + C = _add_init(C, False) + i = C() + assert 2 == i.a + assert "hallo" == i.b + assert None is i.c + + def test_factory(self): + """ + If a default factory is present, it's used as fallback. + """ + class D(object): + pass + + class C(object): + __attrs_attrs__ = [ + simple_attr(name="a", default=Factory(list)), + simple_attr(name="b", default=Factory(D)), + ] + C = _add_init(C, False) + i = C() + + assert [] == i.a + assert isinstance(i.b, D) + + def test_validator(self): + """ + If a validator is passed, call it with the preliminary instance, the + Attribute, and the argument. + """ + class VException(Exception): + pass + + def raiser(*args): + raise VException(*args) + + C = make_class("C", {"a": attr.ib("a", validator=raiser)}) + with pytest.raises(VException) as e: + C(42) + + assert (fields(C).a, 42,) == e.value.args[1:] + assert isinstance(e.value.args[0], C) + + def test_validator_slots(self): + """ + If a validator is passed, call it with the preliminary instance, the + Attribute, and the argument. + """ + class VException(Exception): + pass + + def raiser(*args): + raise VException(*args) + + C = make_class("C", {"a": attr.ib("a", validator=raiser)}, slots=True) + with pytest.raises(VException) as e: + C(42) + + assert (fields(C)[0], 42,) == e.value.args[1:] + assert isinstance(e.value.args[0], C) + + @given(booleans()) + def test_validator_others(self, slots): + """ + Does not interfere when setting non-attrs attributes. + """ + C = make_class("C", { + "a": attr.ib("a", validator=instance_of(int)) + }, slots=slots) + i = C(1) + + assert 1 == i.a + + if not slots: + i.b = "foo" + assert "foo" == i.b + else: + with pytest.raises(AttributeError): + i.b = "foo" + + def test_underscores(self): + """ + The argument names in `__init__` are without leading and trailing + underscores. + """ + class C(object): + __attrs_attrs__ = [simple_attr("_private")] + + C = _add_init(C, False) + i = C(private=42) + assert 42 == i._private + + +class TestNothing(object): + """ + Tests for `_Nothing`. + """ + def test_copy(self): + """ + __copy__ returns the same object. + """ + n = _Nothing() + assert n is copy.copy(n) + + def test_deepcopy(self): + """ + __deepcopy__ returns the same object. + """ + n = _Nothing() + assert n is copy.deepcopy(n) + + def test_eq(self): + """ + All instances are equal. + """ + assert _Nothing() == _Nothing() == NOTHING + assert not (_Nothing() != _Nothing()) + assert 1 != _Nothing() diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_filters.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_filters.py new file mode 100644 index 00000000000..8f7dd694925 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_filters.py @@ -0,0 +1,94 @@ +""" +Tests for `attr.filters`. +""" + +from __future__ import absolute_import, division, print_function + +import pytest + +import attr + +from attr import fields +from attr.filters import _split_what, exclude, include + + +@attr.s +class C(object): + a = attr.ib() + b = attr.ib() + + +class TestSplitWhat(object): + """ + Tests for `_split_what`. + """ + def test_splits(self): + """ + Splits correctly. + """ + assert ( + frozenset((int, str)), + frozenset((fields(C).a,)), + ) == _split_what((str, fields(C).a, int,)) + + +class TestInclude(object): + """ + Tests for `include`. + """ + @pytest.mark.parametrize("incl,value", [ + ((int,), 42), + ((str,), "hello"), + ((str, fields(C).a), 42), + ((str, fields(C).b), "hello"), + ]) + def test_allow(self, incl, value): + """ + Return True if a class or attribute is whitelisted. + """ + i = include(*incl) + assert i(fields(C).a, value) is True + + @pytest.mark.parametrize("incl,value", [ + ((str,), 42), + ((int,), "hello"), + ((str, fields(C).b), 42), + ((int, fields(C).b), "hello"), + ]) + def test_drop_class(self, incl, value): + """ + Return False on non-whitelisted classes and attributes. + """ + i = include(*incl) + assert i(fields(C).a, value) is False + + +class TestExclude(object): + """ + Tests for `exclude`. + """ + @pytest.mark.parametrize("excl,value", [ + ((str,), 42), + ((int,), "hello"), + ((str, fields(C).b), 42), + ((int, fields(C).b), "hello"), + ]) + def test_allow(self, excl, value): + """ + Return True if class or attribute is not blacklisted. + """ + e = exclude(*excl) + assert e(fields(C).a, value) is True + + @pytest.mark.parametrize("excl,value", [ + ((int,), 42), + ((str,), "hello"), + ((str, fields(C).a), 42), + ((str, fields(C).b), "hello"), + ]) + def test_drop_class(self, excl, value): + """ + Return True on non-blacklisted classes and attributes. + """ + e = exclude(*excl) + assert e(fields(C).a, value) is False diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_funcs.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_funcs.py new file mode 100644 index 00000000000..0167823818e --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_funcs.py @@ -0,0 +1,527 @@ +""" +Tests for `attr._funcs`. +""" + +from __future__ import absolute_import, division, print_function + +from collections import Mapping, OrderedDict, Sequence + +import pytest + +from hypothesis import strategies as st +from hypothesis import HealthCheck, assume, given, settings + +import attr + +from attr import asdict, assoc, astuple, evolve, fields, has +from attr._compat import TYPE +from attr.exceptions import AttrsAttributeNotFoundError +from attr.validators import instance_of + +from .utils import nested_classes, simple_classes + + +MAPPING_TYPES = (dict, OrderedDict) +SEQUENCE_TYPES = (list, tuple) + + +class TestAsDict(object): + """ + Tests for `asdict`. + """ + @given(st.sampled_from(MAPPING_TYPES)) + def test_shallow(self, C, dict_factory): + """ + Shallow asdict returns correct dict. + """ + assert { + "x": 1, + "y": 2, + } == asdict(C(x=1, y=2), False, dict_factory=dict_factory) + + @given(st.sampled_from(MAPPING_TYPES)) + def test_recurse(self, C, dict_class): + """ + Deep asdict returns correct dict. + """ + assert { + "x": {"x": 1, "y": 2}, + "y": {"x": 3, "y": 4}, + } == asdict(C( + C(1, 2), + C(3, 4), + ), dict_factory=dict_class) + + @given(nested_classes, st.sampled_from(MAPPING_TYPES)) + @settings(suppress_health_check=[HealthCheck.too_slow]) + def test_recurse_property(self, cls, dict_class): + """ + Property tests for recursive asdict. + """ + obj = cls() + obj_dict = asdict(obj, dict_factory=dict_class) + + def assert_proper_dict_class(obj, obj_dict): + assert isinstance(obj_dict, dict_class) + + for field in fields(obj.__class__): + field_val = getattr(obj, field.name) + if has(field_val.__class__): + # This field holds a class, recurse the assertions. + assert_proper_dict_class(field_val, obj_dict[field.name]) + elif isinstance(field_val, Sequence): + dict_val = obj_dict[field.name] + for item, item_dict in zip(field_val, dict_val): + if has(item.__class__): + assert_proper_dict_class(item, item_dict) + elif isinstance(field_val, Mapping): + # This field holds a dictionary. + assert isinstance(obj_dict[field.name], dict_class) + + for key, val in field_val.items(): + if has(val.__class__): + assert_proper_dict_class(val, + obj_dict[field.name][key]) + + assert_proper_dict_class(obj, obj_dict) + + @given(st.sampled_from(MAPPING_TYPES)) + def test_filter(self, C, dict_factory): + """ + Attributes that are supposed to be skipped are skipped. + """ + assert { + "x": {"x": 1}, + } == asdict(C( + C(1, 2), + C(3, 4), + ), filter=lambda a, v: a.name != "y", dict_factory=dict_factory) + + @given(container=st.sampled_from(SEQUENCE_TYPES)) + def test_lists_tuples(self, container, C): + """ + If recurse is True, also recurse into lists. + """ + assert { + "x": 1, + "y": [{"x": 2, "y": 3}, {"x": 4, "y": 5}, "a"], + } == asdict(C(1, container([C(2, 3), C(4, 5), "a"]))) + + @given(container=st.sampled_from(SEQUENCE_TYPES)) + def test_lists_tuples_retain_type(self, container, C): + """ + If recurse and retain_collection_types are True, also recurse + into lists and do not convert them into list. + """ + assert { + "x": 1, + "y": container([{"x": 2, "y": 3}, {"x": 4, "y": 5}, "a"]), + } == asdict(C(1, container([C(2, 3), C(4, 5), "a"])), + retain_collection_types=True) + + @given(st.sampled_from(MAPPING_TYPES)) + def test_dicts(self, C, dict_factory): + """ + If recurse is True, also recurse into dicts. + """ + res = asdict(C(1, {"a": C(4, 5)}), dict_factory=dict_factory) + assert { + "x": 1, + "y": {"a": {"x": 4, "y": 5}}, + } == res + assert isinstance(res, dict_factory) + + @given(simple_classes(private_attrs=False), st.sampled_from(MAPPING_TYPES)) + def test_roundtrip(self, cls, dict_class): + """ + Test dumping to dicts and back for Hypothesis-generated classes. + + Private attributes don't round-trip (the attribute name is different + than the initializer argument). + """ + instance = cls() + dict_instance = asdict(instance, dict_factory=dict_class) + + assert isinstance(dict_instance, dict_class) + + roundtrip_instance = cls(**dict_instance) + + assert instance == roundtrip_instance + + @given(simple_classes()) + def test_asdict_preserve_order(self, cls): + """ + Field order should be preserved when dumping to OrderedDicts. + """ + instance = cls() + dict_instance = asdict(instance, dict_factory=OrderedDict) + + assert [a.name for a in fields(cls)] == list(dict_instance.keys()) + + +class TestAsTuple(object): + """ + Tests for `astuple`. + """ + @given(st.sampled_from(SEQUENCE_TYPES)) + def test_shallow(self, C, tuple_factory): + """ + Shallow astuple returns correct dict. + """ + assert (tuple_factory([1, 2]) == + astuple(C(x=1, y=2), False, tuple_factory=tuple_factory)) + + @given(st.sampled_from(SEQUENCE_TYPES)) + def test_recurse(self, C, tuple_factory): + """ + Deep astuple returns correct tuple. + """ + assert (tuple_factory([tuple_factory([1, 2]), + tuple_factory([3, 4])]) + == astuple(C( + C(1, 2), + C(3, 4), + ), + tuple_factory=tuple_factory)) + + @given(nested_classes, st.sampled_from(SEQUENCE_TYPES)) + @settings(suppress_health_check=[HealthCheck.too_slow]) + def test_recurse_property(self, cls, tuple_class): + """ + Property tests for recursive astuple. + """ + obj = cls() + obj_tuple = astuple(obj, tuple_factory=tuple_class) + + def assert_proper_tuple_class(obj, obj_tuple): + assert isinstance(obj_tuple, tuple_class) + for index, field in enumerate(fields(obj.__class__)): + field_val = getattr(obj, field.name) + if has(field_val.__class__): + # This field holds a class, recurse the assertions. + assert_proper_tuple_class(field_val, obj_tuple[index]) + + assert_proper_tuple_class(obj, obj_tuple) + + @given(nested_classes, st.sampled_from(SEQUENCE_TYPES)) + @settings(suppress_health_check=[HealthCheck.too_slow]) + def test_recurse_retain(self, cls, tuple_class): + """ + Property tests for asserting collection types are retained. + """ + obj = cls() + obj_tuple = astuple(obj, tuple_factory=tuple_class, + retain_collection_types=True) + + def assert_proper_col_class(obj, obj_tuple): + # Iterate over all attributes, and if they are lists or mappings + # in the original, assert they are the same class in the dumped. + for index, field in enumerate(fields(obj.__class__)): + field_val = getattr(obj, field.name) + if has(field_val.__class__): + # This field holds a class, recurse the assertions. + assert_proper_col_class(field_val, obj_tuple[index]) + elif isinstance(field_val, (list, tuple)): + # This field holds a sequence of something. + expected_type = type(obj_tuple[index]) + assert type(field_val) is expected_type # noqa: E721 + for obj_e, obj_tuple_e in zip(field_val, obj_tuple[index]): + if has(obj_e.__class__): + assert_proper_col_class(obj_e, obj_tuple_e) + elif isinstance(field_val, dict): + orig = field_val + tupled = obj_tuple[index] + assert type(orig) is type(tupled) # noqa: E721 + for obj_e, obj_tuple_e in zip(orig.items(), + tupled.items()): + if has(obj_e[0].__class__): # Dict key + assert_proper_col_class(obj_e[0], obj_tuple_e[0]) + if has(obj_e[1].__class__): # Dict value + assert_proper_col_class(obj_e[1], obj_tuple_e[1]) + + assert_proper_col_class(obj, obj_tuple) + + @given(st.sampled_from(SEQUENCE_TYPES)) + def test_filter(self, C, tuple_factory): + """ + Attributes that are supposed to be skipped are skipped. + """ + assert tuple_factory([tuple_factory([1, ]), ]) == astuple(C( + C(1, 2), + C(3, 4), + ), filter=lambda a, v: a.name != "y", tuple_factory=tuple_factory) + + @given(container=st.sampled_from(SEQUENCE_TYPES)) + def test_lists_tuples(self, container, C): + """ + If recurse is True, also recurse into lists. + """ + assert ((1, [(2, 3), (4, 5), "a"]) + == astuple(C(1, container([C(2, 3), C(4, 5), "a"]))) + ) + + @given(st.sampled_from(SEQUENCE_TYPES)) + def test_dicts(self, C, tuple_factory): + """ + If recurse is True, also recurse into dicts. + """ + res = astuple(C(1, {"a": C(4, 5)}), tuple_factory=tuple_factory) + assert tuple_factory([1, {"a": tuple_factory([4, 5])}]) == res + assert isinstance(res, tuple_factory) + + @given(container=st.sampled_from(SEQUENCE_TYPES)) + def test_lists_tuples_retain_type(self, container, C): + """ + If recurse and retain_collection_types are True, also recurse + into lists and do not convert them into list. + """ + assert ( + (1, container([(2, 3), (4, 5), "a"])) + == astuple(C(1, container([C(2, 3), C(4, 5), "a"])), + retain_collection_types=True)) + + @given(container=st.sampled_from(MAPPING_TYPES)) + def test_dicts_retain_type(self, container, C): + """ + If recurse and retain_collection_types are True, also recurse + into lists and do not convert them into list. + """ + assert ( + (1, container({"a": (4, 5)})) + == astuple(C(1, container({"a": C(4, 5)})), + retain_collection_types=True)) + + @given(simple_classes(), st.sampled_from(SEQUENCE_TYPES)) + def test_roundtrip(self, cls, tuple_class): + """ + Test dumping to tuple and back for Hypothesis-generated classes. + """ + instance = cls() + tuple_instance = astuple(instance, tuple_factory=tuple_class) + + assert isinstance(tuple_instance, tuple_class) + + roundtrip_instance = cls(*tuple_instance) + + assert instance == roundtrip_instance + + +class TestHas(object): + """ + Tests for `has`. + """ + def test_positive(self, C): + """ + Returns `True` on decorated classes. + """ + assert has(C) + + def test_positive_empty(self): + """ + Returns `True` on decorated classes even if there are no attributes. + """ + @attr.s + class D(object): + pass + + assert has(D) + + def test_negative(self): + """ + Returns `False` on non-decorated classes. + """ + assert not has(object) + + +class TestAssoc(object): + """ + Tests for `assoc`. + """ + @given(slots=st.booleans(), frozen=st.booleans()) + def test_empty(self, slots, frozen): + """ + Empty classes without changes get copied. + """ + @attr.s(slots=slots, frozen=frozen) + class C(object): + pass + + i1 = C() + with pytest.deprecated_call(): + i2 = assoc(i1) + + assert i1 is not i2 + assert i1 == i2 + + @given(simple_classes()) + def test_no_changes(self, C): + """ + No changes means a verbatim copy. + """ + i1 = C() + with pytest.deprecated_call(): + i2 = assoc(i1) + + assert i1 is not i2 + assert i1 == i2 + + @given(simple_classes(), st.data()) + def test_change(self, C, data): + """ + Changes work. + """ + # Take the first attribute, and change it. + assume(fields(C)) # Skip classes with no attributes. + field_names = [a.name for a in fields(C)] + original = C() + chosen_names = data.draw(st.sets(st.sampled_from(field_names))) + change_dict = {name: data.draw(st.integers()) + for name in chosen_names} + + with pytest.deprecated_call(): + changed = assoc(original, **change_dict) + + for k, v in change_dict.items(): + assert getattr(changed, k) == v + + @given(simple_classes()) + def test_unknown(self, C): + """ + Wanting to change an unknown attribute raises an + AttrsAttributeNotFoundError. + """ + # No generated class will have a four letter attribute. + with pytest.raises(AttrsAttributeNotFoundError) as e, \ + pytest.deprecated_call(): + assoc(C(), aaaa=2) + + assert ( + "aaaa is not an attrs attribute on {cls!r}.".format(cls=C), + ) == e.value.args + + def test_frozen(self): + """ + Works on frozen classes. + """ + @attr.s(frozen=True) + class C(object): + x = attr.ib() + y = attr.ib() + + with pytest.deprecated_call(): + assert C(3, 2) == assoc(C(1, 2), x=3) + + def test_warning(self): + """ + DeprecationWarning points to the correct file. + """ + @attr.s + class C(object): + x = attr.ib() + + with pytest.warns(DeprecationWarning) as wi: + assert C(2) == assoc(C(1), x=2) + + assert __file__ == wi.list[0].filename + + +class TestEvolve(object): + """ + Tests for `evolve`. + """ + @given(slots=st.booleans(), frozen=st.booleans()) + def test_empty(self, slots, frozen): + """ + Empty classes without changes get copied. + """ + @attr.s(slots=slots, frozen=frozen) + class C(object): + pass + + i1 = C() + i2 = evolve(i1) + + assert i1 is not i2 + assert i1 == i2 + + @given(simple_classes()) + def test_no_changes(self, C): + """ + No changes means a verbatim copy. + """ + i1 = C() + i2 = evolve(i1) + + assert i1 is not i2 + assert i1 == i2 + + @given(simple_classes(), st.data()) + def test_change(self, C, data): + """ + Changes work. + """ + # Take the first attribute, and change it. + assume(fields(C)) # Skip classes with no attributes. + field_names = [a.name for a in fields(C)] + original = C() + chosen_names = data.draw(st.sets(st.sampled_from(field_names))) + # We pay special attention to private attributes, they should behave + # like in `__init__`. + change_dict = {name.replace('_', ''): data.draw(st.integers()) + for name in chosen_names} + changed = evolve(original, **change_dict) + for name in chosen_names: + assert getattr(changed, name) == change_dict[name.replace('_', '')] + + @given(simple_classes()) + def test_unknown(self, C): + """ + Wanting to change an unknown attribute raises an + AttrsAttributeNotFoundError. + """ + # No generated class will have a four letter attribute. + with pytest.raises(TypeError) as e: + evolve(C(), aaaa=2) + expected = "__init__() got an unexpected keyword argument 'aaaa'" + assert (expected,) == e.value.args + + def test_validator_failure(self): + """ + TypeError isn't swallowed when validation fails within evolve. + """ + @attr.s + class C(object): + a = attr.ib(validator=instance_of(int)) + + with pytest.raises(TypeError) as e: + evolve(C(a=1), a="some string") + m = e.value.args[0] + + assert m.startswith("'a' must be <{type} 'int'>".format(type=TYPE)) + + def test_private(self): + """ + evolve() acts as `__init__` with regards to private attributes. + """ + @attr.s + class C(object): + _a = attr.ib() + + assert evolve(C(1), a=2)._a == 2 + + with pytest.raises(TypeError): + evolve(C(1), _a=2) + + with pytest.raises(TypeError): + evolve(C(1), a=3, _a=2) + + def test_non_init_attrs(self): + """ + evolve() handles `init=False` attributes. + """ + @attr.s + class C(object): + a = attr.ib() + b = attr.ib(init=False, default=0) + + assert evolve(C(1), a=2).a == 2 diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_init_subclass.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_init_subclass.py new file mode 100644 index 00000000000..b66130ede47 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_init_subclass.py @@ -0,0 +1,44 @@ +""" +Tests for `__init_subclass__` related tests. + +Python 3.6+ only. +""" + +import pytest + +import attr + + +@pytest.mark.parametrize("slots", [True, False]) +def test_init_subclass_vanilla(slots): + """ + `super().__init_subclass__` can be used if the subclass is not an attrs + class both with dict and slots classes. + """ + @attr.s(slots=slots) + class Base: + def __init_subclass__(cls, param, **kw): + super().__init_subclass__(**kw) + cls.param = param + + class Vanilla(Base, param="foo"): + pass + + assert "foo" == Vanilla().param + + +def test_init_subclass_attrs(): + """ + `__init_subclass__` works with attrs classes as long as slots=False. + """ + @attr.s(slots=False) + class Base: + def __init_subclass__(cls, param, **kw): + super().__init_subclass__(**kw) + cls.param = param + + @attr.s + class Attrs(Base, param="foo"): + pass + + assert "foo" == Attrs().param diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_make.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_make.py new file mode 100644 index 00000000000..f8c80228ae8 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_make.py @@ -0,0 +1,866 @@ +""" +Tests for `attr._make`. +""" + +from __future__ import absolute_import, division, print_function + +import inspect +import sys + +from operator import attrgetter + +import pytest + +from hypothesis import given +from hypothesis.strategies import booleans, integers, lists, sampled_from, text + +import attr + +from attr import _config +from attr._compat import PY2 +from attr._make import ( + Attribute, Factory, _AndValidator, _Attributes, _ClassBuilder, + _CountingAttr, _transform_attrs, and_, fields, make_class, validate +) +from attr.exceptions import DefaultAlreadySetError, NotAnAttrsClassError + +from .utils import ( + gen_attr_names, list_of_attrs, simple_attr, simple_attrs, + simple_attrs_without_metadata, simple_classes +) + + +attrs_st = simple_attrs.map(lambda c: Attribute.from_counting_attr("name", c)) + + +class TestCountingAttr(object): + """ + Tests for `attr`. + """ + def test_returns_Attr(self): + """ + Returns an instance of _CountingAttr. + """ + a = attr.ib() + + assert isinstance(a, _CountingAttr) + + def test_validators_lists_to_wrapped_tuples(self): + """ + If a list is passed as validator, it's just converted to a tuple. + """ + def v1(_, __): + pass + + def v2(_, __): + pass + + a = attr.ib(validator=[v1, v2]) + + assert _AndValidator((v1, v2,)) == a._validator + + def test_validator_decorator_single(self): + """ + If _CountingAttr.validator is used as a decorator and there is no + decorator set, the decorated method is used as the validator. + """ + a = attr.ib() + + @a.validator + def v(): + pass + + assert v == a._validator + + @pytest.mark.parametrize("wrap", [ + lambda v: v, + lambda v: [v], + lambda v: and_(v) + + ]) + def test_validator_decorator(self, wrap): + """ + If _CountingAttr.validator is used as a decorator and there is already + a decorator set, the decorators are composed using `and_`. + """ + def v(_, __): + pass + + a = attr.ib(validator=wrap(v)) + + @a.validator + def v2(self, _, __): + pass + + assert _AndValidator((v, v2,)) == a._validator + + def test_default_decorator_already_set(self): + """ + Raise DefaultAlreadySetError if the decorator is used after a default + has been set. + """ + a = attr.ib(default=42) + + with pytest.raises(DefaultAlreadySetError): + @a.default + def f(self): + pass + + def test_default_decorator_sets(self): + """ + Decorator wraps the method in a Factory with pass_self=True and sets + the default. + """ + a = attr.ib() + + @a.default + def f(self): + pass + + assert Factory(f, True) == a._default + + +def make_tc(): + class TransformC(object): + z = attr.ib() + y = attr.ib() + x = attr.ib() + a = 42 + return TransformC + + +class TestTransformAttrs(object): + """ + Tests for `_transform_attrs`. + """ + def test_no_modifications(self): + """ + Doesn't attach __attrs_attrs__ to the class anymore. + """ + C = make_tc() + _transform_attrs(C, None, False) + + assert None is getattr(C, "__attrs_attrs__", None) + + def test_normal(self): + """ + Transforms every `_CountingAttr` and leaves others (a) be. + """ + C = make_tc() + attrs, _, = _transform_attrs(C, None, False) + + assert ["z", "y", "x"] == [a.name for a in attrs] + + def test_empty(self): + """ + No attributes works as expected. + """ + @attr.s + class C(object): + pass + + assert _Attributes(((), [])) == _transform_attrs(C, None, False) + + def test_transforms_to_attribute(self): + """ + All `_CountingAttr`s are transformed into `Attribute`s. + """ + C = make_tc() + attrs, super_attrs = _transform_attrs(C, None, False) + + assert [] == super_attrs + assert 3 == len(attrs) + assert all(isinstance(a, Attribute) for a in attrs) + + def test_conflicting_defaults(self): + """ + Raises `ValueError` if attributes with defaults are followed by + mandatory attributes. + """ + class C(object): + x = attr.ib(default=None) + y = attr.ib() + + with pytest.raises(ValueError) as e: + _transform_attrs(C, None, False) + assert ( + "No mandatory attributes allowed after an attribute with a " + "default value or factory. Attribute in question: Attribute" + "(name='y', default=NOTHING, validator=None, repr=True, " + "cmp=True, hash=None, init=True, convert=None, " + "metadata=mappingproxy({}), type=None)", + ) == e.value.args + + def test_these(self): + """ + If these is passed, use it and ignore body and super classes. + """ + class Base(object): + z = attr.ib() + + class C(Base): + y = attr.ib() + + attrs, super_attrs = _transform_attrs(C, {"x": attr.ib()}, False) + + assert [] == super_attrs + assert ( + simple_attr("x"), + ) == attrs + + def test_multiple_inheritance(self): + """ + Order of attributes doesn't get mixed up by multiple inheritance. + + See #285 + """ + @attr.s + class A(object): + a1 = attr.ib(default="a1") + a2 = attr.ib(default="a2") + + @attr.s + class B(A): + b1 = attr.ib(default="b1") + b2 = attr.ib(default="b2") + + @attr.s + class C(B, A): + c1 = attr.ib(default="c1") + c2 = attr.ib(default="c2") + + @attr.s + class D(A): + d1 = attr.ib(default="d1") + d2 = attr.ib(default="d2") + + @attr.s + class E(D, C): + e1 = attr.ib(default="e1") + e2 = attr.ib(default="e2") + + assert ( + "E(a1='a1', a2='a2', b1='b1', b2='b2', c1='c1', c2='c2', d1='d1', " + "d2='d2', e1='e1', e2='e2')" + ) == repr(E()) + + +class TestAttributes(object): + """ + Tests for the `attrs`/`attr.s` class decorator. + """ + @pytest.mark.skipif(not PY2, reason="No old-style classes in Py3") + def test_catches_old_style(self): + """ + Raises TypeError on old-style classes. + """ + with pytest.raises(TypeError) as e: + @attr.s + class C: + pass + + assert ("attrs only works with new-style classes.",) == e.value.args + + def test_sets_attrs(self): + """ + Sets the `__attrs_attrs__` class attribute with a list of `Attribute`s. + """ + @attr.s + class C(object): + x = attr.ib() + + assert "x" == C.__attrs_attrs__[0].name + assert all(isinstance(a, Attribute) for a in C.__attrs_attrs__) + + def test_empty(self): + """ + No attributes, no problems. + """ + @attr.s + class C3(object): + pass + + assert "C3()" == repr(C3()) + assert C3() == C3() + + @given(attr=attrs_st, attr_name=sampled_from(Attribute.__slots__)) + def test_immutable(self, attr, attr_name): + """ + Attribute instances are immutable. + """ + with pytest.raises(AttributeError): + setattr(attr, attr_name, 1) + + @pytest.mark.parametrize("method_name", [ + "__repr__", + "__eq__", + "__hash__", + "__init__", + ]) + def test_adds_all_by_default(self, method_name): + """ + If no further arguments are supplied, all add_XXX functions except + add_hash are applied. __hash__ is set to None. + """ + # Set the method name to a sentinel and check whether it has been + # overwritten afterwards. + sentinel = object() + + class C(object): + x = attr.ib() + + setattr(C, method_name, sentinel) + + C = attr.s(C) + meth = getattr(C, method_name) + + assert sentinel != meth + if method_name == "__hash__": + assert meth is None + + @pytest.mark.parametrize("arg_name, method_name", [ + ("repr", "__repr__"), + ("cmp", "__eq__"), + ("hash", "__hash__"), + ("init", "__init__"), + ]) + def test_respects_add_arguments(self, arg_name, method_name): + """ + If a certain `add_XXX` is `False`, `__XXX__` is not added to the class. + """ + # Set the method name to a sentinel and check whether it has been + # overwritten afterwards. + sentinel = object() + + am_args = { + "repr": True, + "cmp": True, + "hash": True, + "init": True + } + am_args[arg_name] = False + + class C(object): + x = attr.ib() + + setattr(C, method_name, sentinel) + + C = attr.s(**am_args)(C) + + assert sentinel == getattr(C, method_name) + + @pytest.mark.skipif(PY2, reason="__qualname__ is PY3-only.") + @given(slots_outer=booleans(), slots_inner=booleans()) + def test_repr_qualname(self, slots_outer, slots_inner): + """ + On Python 3, the name in repr is the __qualname__. + """ + @attr.s(slots=slots_outer) + class C(object): + @attr.s(slots=slots_inner) + class D(object): + pass + + assert "C.D()" == repr(C.D()) + assert "GC.D()" == repr(GC.D()) + + @given(slots_outer=booleans(), slots_inner=booleans()) + def test_repr_fake_qualname(self, slots_outer, slots_inner): + """ + Setting repr_ns overrides a potentially guessed namespace. + """ + @attr.s(slots=slots_outer) + class C(object): + @attr.s(repr_ns="C", slots=slots_inner) + class D(object): + pass + assert "C.D()" == repr(C.D()) + + @pytest.mark.skipif(PY2, reason="__qualname__ is PY3-only.") + @given(slots_outer=booleans(), slots_inner=booleans()) + def test_name_not_overridden(self, slots_outer, slots_inner): + """ + On Python 3, __name__ is different from __qualname__. + """ + @attr.s(slots=slots_outer) + class C(object): + @attr.s(slots=slots_inner) + class D(object): + pass + + assert C.D.__name__ == "D" + assert C.D.__qualname__ == C.__qualname__ + ".D" + + @given(with_validation=booleans()) + def test_post_init(self, with_validation, monkeypatch): + """ + Verify that __attrs_post_init__ gets called if defined. + """ + monkeypatch.setattr(_config, "_run_validators", with_validation) + + @attr.s + class C(object): + x = attr.ib() + y = attr.ib() + + def __attrs_post_init__(self2): + self2.z = self2.x + self2.y + + c = C(x=10, y=20) + + assert 30 == getattr(c, 'z', None) + + def test_types(self): + """ + Sets the `Attribute.type` attr from type argument. + """ + @attr.s + class C(object): + x = attr.ib(type=int) + y = attr.ib(type=str) + z = attr.ib() + + assert int is fields(C).x.type + assert str is fields(C).y.type + assert None is fields(C).z.type + + @pytest.mark.parametrize("slots", [True, False]) + def test_clean_class(self, slots): + """ + Attribute definitions do not appear on the class body after @attr.s. + """ + @attr.s(slots=slots) + class C(object): + x = attr.ib() + + x = getattr(C, "x", None) + + assert not isinstance(x, _CountingAttr) + + +@attr.s +class GC(object): + @attr.s + class D(object): + pass + + +class TestMakeClass(object): + """ + Tests for `make_class`. + """ + @pytest.mark.parametrize("ls", [ + list, + tuple + ]) + def test_simple(self, ls): + """ + Passing a list of strings creates attributes with default args. + """ + C1 = make_class("C1", ls(["a", "b"])) + + @attr.s + class C2(object): + a = attr.ib() + b = attr.ib() + + assert C1.__attrs_attrs__ == C2.__attrs_attrs__ + + def test_dict(self): + """ + Passing a dict of name: _CountingAttr creates an equivalent class. + """ + C1 = make_class("C1", { + "a": attr.ib(default=42), + "b": attr.ib(default=None), + }) + + @attr.s + class C2(object): + a = attr.ib(default=42) + b = attr.ib(default=None) + + assert C1.__attrs_attrs__ == C2.__attrs_attrs__ + + def test_attr_args(self): + """ + attributes_arguments are passed to attributes + """ + C = make_class("C", ["x"], repr=False) + + assert repr(C(1)).startswith("" == repr(b) + + def test_returns_self(self): + """ + All methods return the builder for chaining. + """ + class C(object): + x = attr.ib() + + b = _ClassBuilder(C, None, True, True, False) + + cls = b.add_cmp().add_hash().add_init().add_repr("ns").add_str() \ + .build_class() + + assert "ns.C(x=1)" == repr(cls(1)) diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_slots.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_slots.py new file mode 100644 index 00000000000..516a797b757 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_slots.py @@ -0,0 +1,423 @@ +""" +Unit tests for slot-related functionality. +""" + +import pytest + +import attr + +from attr._compat import PY2, PYPY, just_warn, make_set_closure_cell + + +# Pympler doesn't work on PyPy. +try: + from pympler.asizeof import asizeof + has_pympler = True +except BaseException: # Won't be an import error. + has_pympler = False + + +@attr.s +class C1(object): + x = attr.ib(validator=attr.validators.instance_of(int)) + y = attr.ib() + + def method(self): + return self.x + + @classmethod + def classmethod(cls): + return "clsmethod" + + @staticmethod + def staticmethod(): + return "staticmethod" + + if not PY2: + def my_class(self): + return __class__ # NOQA: F821 + + def my_super(self): + """Just to test out the no-arg super.""" + return super().__repr__() + + +@attr.s(slots=True, hash=True) +class C1Slots(object): + x = attr.ib(validator=attr.validators.instance_of(int)) + y = attr.ib() + + def method(self): + return self.x + + @classmethod + def classmethod(cls): + return "clsmethod" + + @staticmethod + def staticmethod(): + return "staticmethod" + + if not PY2: + def my_class(self): + return __class__ # NOQA: F821 + + def my_super(self): + """Just to test out the no-arg super.""" + return super().__repr__() + + +def test_slots_being_used(): + """ + The class is really using __slots__. + """ + non_slot_instance = C1(x=1, y="test") + slot_instance = C1Slots(x=1, y="test") + + assert "__dict__" not in dir(slot_instance) + assert "__slots__" in dir(slot_instance) + + assert "__dict__" in dir(non_slot_instance) + assert "__slots__" not in dir(non_slot_instance) + + assert set(["x", "y"]) == set(slot_instance.__slots__) + + if has_pympler: + assert asizeof(slot_instance) < asizeof(non_slot_instance) + + non_slot_instance.t = "test" + with pytest.raises(AttributeError): + slot_instance.t = "test" + + assert 1 == non_slot_instance.method() + assert 1 == slot_instance.method() + + assert attr.fields(C1Slots) == attr.fields(C1) + assert attr.asdict(slot_instance) == attr.asdict(non_slot_instance) + + +def test_basic_attr_funcs(): + """ + Comparison, `__eq__`, `__hash__`, `__repr__`, `attrs.asdict` work. + """ + a = C1Slots(x=1, y=2) + b = C1Slots(x=1, y=3) + a_ = C1Slots(x=1, y=2) + + # Comparison. + assert b > a + + assert a_ == a + + # Hashing. + hash(b) # Just to assert it doesn't raise. + + # Repr. + assert "C1Slots(x=1, y=2)" == repr(a) + + assert {"x": 1, "y": 2} == attr.asdict(a) + + +def test_inheritance_from_nonslots(): + """ + Inheritance from a non-slot class works. + + Note that a slots class inheriting from an ordinary class loses most of the + benefits of slots classes, but it should still work. + """ + @attr.s(slots=True, hash=True) + class C2Slots(C1): + z = attr.ib() + + c2 = C2Slots(x=1, y=2, z="test") + + assert 1 == c2.x + assert 2 == c2.y + assert "test" == c2.z + + c2.t = "test" # This will work, using the base class. + + assert "test" == c2.t + + assert 1 == c2.method() + assert "clsmethod" == c2.classmethod() + assert "staticmethod" == c2.staticmethod() + + assert set(["z"]) == set(C2Slots.__slots__) + + c3 = C2Slots(x=1, y=3, z="test") + + assert c3 > c2 + + c2_ = C2Slots(x=1, y=2, z="test") + + assert c2 == c2_ + + assert "C2Slots(x=1, y=2, z='test')" == repr(c2) + + hash(c2) # Just to assert it doesn't raise. + + assert {"x": 1, "y": 2, "z": "test"} == attr.asdict(c2) + + +def test_nonslots_these(): + """ + Enhancing a non-slots class using 'these' works. + + This will actually *replace* the class with another one, using slots. + """ + class SimpleOrdinaryClass(object): + def __init__(self, x, y, z): + self.x = x + self.y = y + self.z = z + + def method(self): + return self.x + + @classmethod + def classmethod(cls): + return "clsmethod" + + @staticmethod + def staticmethod(): + return "staticmethod" + + C2Slots = attr.s(these={"x": attr.ib(), "y": attr.ib(), "z": attr.ib()}, + init=False, slots=True, hash=True)(SimpleOrdinaryClass) + + c2 = C2Slots(x=1, y=2, z="test") + assert 1 == c2.x + assert 2 == c2.y + assert "test" == c2.z + with pytest.raises(AttributeError): + c2.t = "test" # We have slots now. + + assert 1 == c2.method() + assert "clsmethod" == c2.classmethod() + assert "staticmethod" == c2.staticmethod() + + assert set(["x", "y", "z"]) == set(C2Slots.__slots__) + + c3 = C2Slots(x=1, y=3, z="test") + assert c3 > c2 + c2_ = C2Slots(x=1, y=2, z="test") + assert c2 == c2_ + + assert "SimpleOrdinaryClass(x=1, y=2, z='test')" == repr(c2) + + hash(c2) # Just to assert it doesn't raise. + + assert {"x": 1, "y": 2, "z": "test"} == attr.asdict(c2) + + +def test_inheritance_from_slots(): + """ + Inheriting from an attr slot class works. + """ + @attr.s(slots=True, hash=True) + class C2Slots(C1Slots): + z = attr.ib() + + @attr.s(slots=True, hash=True) + class C2(C1): + z = attr.ib() + + c2 = C2Slots(x=1, y=2, z="test") + assert 1 == c2.x + assert 2 == c2.y + assert "test" == c2.z + + assert set(["z"]) == set(C2Slots.__slots__) + + assert 1 == c2.method() + assert "clsmethod" == c2.classmethod() + assert "staticmethod" == c2.staticmethod() + + with pytest.raises(AttributeError): + c2.t = "test" + + non_slot_instance = C2(x=1, y=2, z="test") + if has_pympler: + assert asizeof(c2) < asizeof(non_slot_instance) + + c3 = C2Slots(x=1, y=3, z="test") + assert c3 > c2 + c2_ = C2Slots(x=1, y=2, z="test") + assert c2 == c2_ + + assert "C2Slots(x=1, y=2, z='test')" == repr(c2) + + hash(c2) # Just to assert it doesn't raise. + + assert {"x": 1, "y": 2, "z": "test"} == attr.asdict(c2) + + +def test_bare_inheritance_from_slots(): + """ + Inheriting from a bare attr slot class works. + """ + @attr.s(init=False, cmp=False, hash=False, repr=False, slots=True) + class C1BareSlots(object): + x = attr.ib(validator=attr.validators.instance_of(int)) + y = attr.ib() + + def method(self): + return self.x + + @classmethod + def classmethod(cls): + return "clsmethod" + + @staticmethod + def staticmethod(): + return "staticmethod" + + @attr.s(init=False, cmp=False, hash=False, repr=False) + class C1Bare(object): + x = attr.ib(validator=attr.validators.instance_of(int)) + y = attr.ib() + + def method(self): + return self.x + + @classmethod + def classmethod(cls): + return "clsmethod" + + @staticmethod + def staticmethod(): + return "staticmethod" + + @attr.s(slots=True, hash=True) + class C2Slots(C1BareSlots): + z = attr.ib() + + @attr.s(slots=True, hash=True) + class C2(C1Bare): + z = attr.ib() + + c2 = C2Slots(x=1, y=2, z="test") + assert 1 == c2.x + assert 2 == c2.y + assert "test" == c2.z + + assert 1 == c2.method() + assert "clsmethod" == c2.classmethod() + assert "staticmethod" == c2.staticmethod() + + with pytest.raises(AttributeError): + c2.t = "test" + + non_slot_instance = C2(x=1, y=2, z="test") + if has_pympler: + assert asizeof(c2) < asizeof(non_slot_instance) + + c3 = C2Slots(x=1, y=3, z="test") + assert c3 > c2 + c2_ = C2Slots(x=1, y=2, z="test") + assert c2 == c2_ + + assert "C2Slots(x=1, y=2, z='test')" == repr(c2) + + hash(c2) # Just to assert it doesn't raise. + + assert {"x": 1, "y": 2, "z": "test"} == attr.asdict(c2) + + +@pytest.mark.skipif(PY2, reason="closure cell rewriting is PY3-only.") +class TestClosureCellRewriting(object): + def test_closure_cell_rewriting(self): + """ + Slot classes support proper closure cell rewriting. + + This affects features like `__class__` and the no-arg super(). + """ + non_slot_instance = C1(x=1, y="test") + slot_instance = C1Slots(x=1, y="test") + + assert non_slot_instance.my_class() is C1 + assert slot_instance.my_class() is C1Slots + + # Just assert they return something, and not an exception. + assert non_slot_instance.my_super() + assert slot_instance.my_super() + + def test_inheritance(self): + """ + Slot classes support proper closure cell rewriting when inheriting. + + This affects features like `__class__` and the no-arg super(). + """ + @attr.s + class C2(C1): + def my_subclass(self): + return __class__ # NOQA: F821 + + @attr.s + class C2Slots(C1Slots): + def my_subclass(self): + return __class__ # NOQA: F821 + + non_slot_instance = C2(x=1, y="test") + slot_instance = C2Slots(x=1, y="test") + + assert non_slot_instance.my_class() is C1 + assert slot_instance.my_class() is C1Slots + + # Just assert they return something, and not an exception. + assert non_slot_instance.my_super() + assert slot_instance.my_super() + + assert non_slot_instance.my_subclass() is C2 + assert slot_instance.my_subclass() is C2Slots + + @pytest.mark.parametrize("slots", [True, False]) + def test_cls_static(self, slots): + """ + Slot classes support proper closure cell rewriting for class- and + static methods. + """ + # Python can reuse closure cells, so we create new classes just for + # this test. + + @attr.s(slots=slots) + class C: + @classmethod + def clsmethod(cls): + return __class__ # noqa: F821 + + assert C.clsmethod() is C + + @attr.s(slots=slots) + class D: + @staticmethod + def statmethod(): + return __class__ # noqa: F821 + + assert D.statmethod() is D + + @pytest.mark.skipif( + PYPY, + reason="ctypes are used only on CPython" + ) + def test_missing_ctypes(self, monkeypatch): + """ + Keeps working if ctypes is missing. + + A warning is emitted that points to the actual code. + """ + monkeypatch.setattr(attr._compat, "import_ctypes", lambda: None) + func = make_set_closure_cell() + + with pytest.warns(RuntimeWarning) as wr: + func() + + w = wr.pop() + assert __file__ == w.filename + assert ( + "Missing ctypes. Some features like bare super() or accessing " + "__class__ will not work with slots classes.", + ) == w.message.args + + assert just_warn is func diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_validators.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_validators.py new file mode 100644 index 00000000000..9722da27fdb --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/test_validators.py @@ -0,0 +1,266 @@ +""" +Tests for `attr.validators`. +""" + +from __future__ import absolute_import, division, print_function + +import pytest +import zope.interface + +import attr + +from attr import validators as validator_module +from attr import has +from attr._compat import TYPE +from attr.validators import and_, in_, instance_of, optional, provides + +from .utils import simple_attr + + +class TestInstanceOf(object): + """ + Tests for `instance_of`. + """ + def test_success(self): + """ + Nothing happens if types match. + """ + v = instance_of(int) + v(None, simple_attr("test"), 42) + + def test_subclass(self): + """ + Subclasses are accepted too. + """ + v = instance_of(int) + # yep, bools are a subclass of int :( + v(None, simple_attr("test"), True) + + def test_fail(self): + """ + Raises `TypeError` on wrong types. + """ + v = instance_of(int) + a = simple_attr("test") + with pytest.raises(TypeError) as e: + v(None, a, "42") + assert ( + "'test' must be <{type} 'int'> (got '42' that is a <{type} " + "'str'>).".format(type=TYPE), + a, int, "42", + + ) == e.value.args + + def test_repr(self): + """ + Returned validator has a useful `__repr__`. + """ + v = instance_of(int) + assert ( + ">" + .format(type=TYPE) + ) == repr(v) + + +def always_pass(_, __, ___): + """ + Toy validator that always passses. + """ + + +def always_fail(_, __, ___): + """ + Toy validator that always fails. + """ + 0/0 + + +class TestAnd(object): + def test_success(self): + """ + Succeeds if all wrapped validators succeed. + """ + v = and_(instance_of(int), always_pass) + + v(None, simple_attr("test"), 42) + + def test_fail(self): + """ + Fails if any wrapped validator fails. + """ + v = and_(instance_of(int), always_fail) + + with pytest.raises(ZeroDivisionError): + v(None, simple_attr("test"), 42) + + def test_sugar(self): + """ + `and_(v1, v2, v3)` and `[v1, v2, v3]` are equivalent. + """ + @attr.s + class C(object): + a1 = attr.ib("a1", validator=and_( + instance_of(int), + )) + a2 = attr.ib("a2", validator=[ + instance_of(int), + ]) + + assert C.__attrs_attrs__[0].validator == C.__attrs_attrs__[1].validator + + +class IFoo(zope.interface.Interface): + """ + An interface. + """ + def f(): + """ + A function called f. + """ + + +class TestProvides(object): + """ + Tests for `provides`. + """ + def test_success(self): + """ + Nothing happens if value provides requested interface. + """ + @zope.interface.implementer(IFoo) + class C(object): + def f(self): + pass + + v = provides(IFoo) + v(None, simple_attr("x"), C()) + + def test_fail(self): + """ + Raises `TypeError` if interfaces isn't provided by value. + """ + value = object() + a = simple_attr("x") + + v = provides(IFoo) + with pytest.raises(TypeError) as e: + v(None, a, value) + assert ( + "'x' must provide {interface!r} which {value!r} doesn't." + .format(interface=IFoo, value=value), + a, IFoo, value, + ) == e.value.args + + def test_repr(self): + """ + Returned validator has a useful `__repr__`. + """ + v = provides(IFoo) + assert ( + "" + .format(interface=IFoo) + ) == repr(v) + + +@pytest.mark.parametrize("validator", [ + instance_of(int), + [always_pass, instance_of(int)], +]) +class TestOptional(object): + """ + Tests for `optional`. + """ + def test_success(self, validator): + """ + Nothing happens if validator succeeds. + """ + v = optional(validator) + v(None, simple_attr("test"), 42) + + def test_success_with_none(self, validator): + """ + Nothing happens if None. + """ + v = optional(validator) + v(None, simple_attr("test"), None) + + def test_fail(self, validator): + """ + Raises `TypeError` on wrong types. + """ + v = optional(validator) + a = simple_attr("test") + with pytest.raises(TypeError) as e: + v(None, a, "42") + assert ( + "'test' must be <{type} 'int'> (got '42' that is a <{type} " + "'str'>).".format(type=TYPE), + a, int, "42", + + ) == e.value.args + + def test_repr(self, validator): + """ + Returned validator has a useful `__repr__`. + """ + v = optional(validator) + + if isinstance(validator, list): + assert ( + (">]) or None>") + .format(func=repr(always_pass), type=TYPE) + ) == repr(v) + else: + assert ( + ("> or None>") + .format(type=TYPE) + ) == repr(v) + + +class TestIn_(object): + """ + Tests for `in_`. + """ + def test_success_with_value(self): + """ + If the value is in our options, nothing happens. + """ + v = in_([1, 2, 3]) + a = simple_attr("test") + v(1, a, 3) + + def test_fail(self): + """ + Raise ValueError if the value is outside our options. + """ + v = in_([1, 2, 3]) + a = simple_attr("test") + with pytest.raises(ValueError) as e: + v(None, a, None) + assert ( + "'test' must be in [1, 2, 3] (got None)", + ) == e.value.args + + def test_repr(self): + """ + Returned validator has a useful `__repr__`. + """ + v = in_([3, 4, 5]) + assert( + ("") + ) == repr(v) + + +def test_hashability(): + """ + Validator classes are hashable. + """ + for obj_name in dir(validator_module): + obj = getattr(validator_module, obj_name) + if not has(obj): + continue + hash_func = getattr(obj, '__hash__', None) + assert hash_func is not None + assert hash_func is not object.__hash__ diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/utils.py b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/utils.py new file mode 100644 index 00000000000..36b624981e9 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/tests/utils.py @@ -0,0 +1,237 @@ +""" +Common helper functions for tests. +""" + +from __future__ import absolute_import, division, print_function + +import keyword +import string + +from collections import OrderedDict + +from hypothesis import strategies as st + +import attr + +from attr import Attribute +from attr._make import NOTHING, make_class + + +def simple_class(cmp=False, repr=False, hash=False, str=False, slots=False, + frozen=False): + """ + Return a new simple class. + """ + return make_class( + "C", ["a", "b"], + cmp=cmp, repr=repr, hash=hash, init=True, slots=slots, str=str, + frozen=frozen, + ) + + +def simple_attr(name, default=NOTHING, validator=None, repr=True, + cmp=True, hash=None, init=True): + """ + Return an attribute with a name and no other bells and whistles. + """ + return Attribute( + name=name, default=default, validator=validator, repr=repr, + cmp=cmp, hash=hash, init=init + ) + + +class TestSimpleClass(object): + """ + Tests for the testing helper function `make_class`. + """ + def test_returns_class(self): + """ + Returns a class object. + """ + assert type is simple_class().__class__ + + def returns_distinct_classes(self): + """ + Each call returns a completely new class. + """ + assert simple_class() is not simple_class() + + +def gen_attr_names(): + """ + Generate names for attributes, 'a'...'z', then 'aa'...'zz'. + + ~702 different attribute names should be enough in practice. + + Some short strings (such as 'as') are keywords, so we skip them. + """ + lc = string.ascii_lowercase + for c in lc: + yield c + for outer in lc: + for inner in lc: + res = outer + inner + if keyword.iskeyword(res): + continue + yield outer + inner + + +def maybe_underscore_prefix(source): + """ + A generator to sometimes prepend an underscore. + """ + to_underscore = False + for val in source: + yield val if not to_underscore else '_' + val + to_underscore = not to_underscore + + +def _create_hyp_class(attrs): + """ + A helper function for Hypothesis to generate attrs classes. + """ + return make_class( + "HypClass", dict(zip(gen_attr_names(), attrs)) + ) + + +def _create_hyp_nested_strategy(simple_class_strategy): + """ + Create a recursive attrs class. + + Given a strategy for building (simpler) classes, create and return + a strategy for building classes that have as an attribute: either just + the simpler class, a list of simpler classes, a tuple of simpler classes, + an ordered dict or a dict mapping the string "cls" to a simpler class. + """ + # Use a tuple strategy to combine simple attributes and an attr class. + def just_class(tup): + combined_attrs = list(tup[0]) + combined_attrs.append(attr.ib(default=attr.Factory(tup[1]))) + return _create_hyp_class(combined_attrs) + + def list_of_class(tup): + default = attr.Factory(lambda: [tup[1]()]) + combined_attrs = list(tup[0]) + combined_attrs.append(attr.ib(default=default)) + return _create_hyp_class(combined_attrs) + + def tuple_of_class(tup): + default = attr.Factory(lambda: (tup[1](),)) + combined_attrs = list(tup[0]) + combined_attrs.append(attr.ib(default=default)) + return _create_hyp_class(combined_attrs) + + def dict_of_class(tup): + default = attr.Factory(lambda: {"cls": tup[1]()}) + combined_attrs = list(tup[0]) + combined_attrs.append(attr.ib(default=default)) + return _create_hyp_class(combined_attrs) + + def ordereddict_of_class(tup): + default = attr.Factory(lambda: OrderedDict([("cls", tup[1]())])) + combined_attrs = list(tup[0]) + combined_attrs.append(attr.ib(default=default)) + return _create_hyp_class(combined_attrs) + + # A strategy producing tuples of the form ([list of attributes], ). + attrs_and_classes = st.tuples(list_of_attrs, simple_class_strategy) + + return st.one_of(attrs_and_classes.map(just_class), + attrs_and_classes.map(list_of_class), + attrs_and_classes.map(tuple_of_class), + attrs_and_classes.map(dict_of_class), + attrs_and_classes.map(ordereddict_of_class)) + + +bare_attrs = st.just(attr.ib(default=None)) +int_attrs = st.integers().map(lambda i: attr.ib(default=i)) +str_attrs = st.text().map(lambda s: attr.ib(default=s)) +float_attrs = st.floats().map(lambda f: attr.ib(default=f)) +dict_attrs = (st.dictionaries(keys=st.text(), values=st.integers()) + .map(lambda d: attr.ib(default=d))) + +simple_attrs_without_metadata = (bare_attrs | int_attrs | str_attrs | + float_attrs | dict_attrs) + + +@st.composite +def simple_attrs_with_metadata(draw): + """ + Create a simple attribute with arbitrary metadata. + """ + c_attr = draw(simple_attrs) + keys = st.booleans() | st.binary() | st.integers() | st.text() + vals = st.booleans() | st.binary() | st.integers() | st.text() + metadata = draw(st.dictionaries(keys=keys, values=vals)) + + return attr.ib(c_attr._default, c_attr._validator, c_attr.repr, + c_attr.cmp, c_attr.hash, c_attr.init, c_attr.convert, + metadata) + + +simple_attrs = simple_attrs_without_metadata | simple_attrs_with_metadata() + +# Python functions support up to 255 arguments. +list_of_attrs = st.lists(simple_attrs, average_size=3, max_size=9) + + +@st.composite +def simple_classes(draw, slots=None, frozen=None, private_attrs=None): + """ + A strategy that generates classes with default non-attr attributes. + + For example, this strategy might generate a class such as: + + @attr.s(slots=True, frozen=True) + class HypClass: + a = attr.ib(default=1) + _b = attr.ib(default=None) + c = attr.ib(default='text') + _d = attr.ib(default=1.0) + c = attr.ib(default={'t': 1}) + + By default, all combinations of slots and frozen classes will be generated. + If `slots=True` is passed in, only slots classes will be generated, and + if `slots=False` is passed in, no slot classes will be generated. The same + applies to `frozen`. + + By default, some attributes will be private (i.e. prefixed with an + underscore). If `private_attrs=True` is passed in, all attributes will be + private, and if `private_attrs=False`, no attributes will be private. + """ + attrs = draw(list_of_attrs) + frozen_flag = draw(st.booleans()) if frozen is None else frozen + slots_flag = draw(st.booleans()) if slots is None else slots + + if private_attrs is None: + attr_names = maybe_underscore_prefix(gen_attr_names()) + elif private_attrs is True: + attr_names = ('_' + n for n in gen_attr_names()) + elif private_attrs is False: + attr_names = gen_attr_names() + + cls_dict = dict(zip(attr_names, attrs)) + post_init_flag = draw(st.booleans()) + if post_init_flag: + def post_init(self): + pass + cls_dict["__attrs_post_init__"] = post_init + + return make_class( + "HypClass", + cls_dict, + slots=slots_flag, + frozen=frozen_flag, + ) + + +# st.recursive works by taking a base strategy (in this case, simple_classes) +# and a special function. This function receives a strategy, and returns +# another strategy (building on top of the base strategy). +nested_classes = st.recursive( + simple_classes(), + _create_hyp_nested_strategy, + max_leaves=10 +) diff --git a/tests/wpt/web-platform-tests/tools/third_party/attrs/tox.ini b/tests/wpt/web-platform-tests/tools/third_party/attrs/tox.ini new file mode 100644 index 00000000000..e02c3301025 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/attrs/tox.ini @@ -0,0 +1,83 @@ +[tox] +envlist = isort,py27,py34,py35,py36,pypy,pypy3,flake8,manifest,docs,readme,changelog,coverage-report + + +[testenv] +# Prevent random setuptools/pip breakages like +# https://github.com/pypa/setuptools/issues/1042 from breaking our builds. +setenv = + VIRTUALENV_NO_DOWNLOAD=1 +deps = -rdev-requirements.txt +commands = python -m pytest {posargs} + + +[testenv:py27] +deps = -rdev-requirements.txt +commands = coverage run --parallel -m pytest {posargs} + + +[testenv:py36] +deps = -rdev-requirements.txt +commands = coverage run --parallel -m pytest {posargs} + + +# Uses default basepython otherwise reporting doesn't work on Travis where +# Python 3.6 is only available in 3.6 jobs. +[testenv:coverage-report] +deps = coverage +skip_install = true +commands = + coverage combine + coverage report + + +[testenv:flake8] +basepython = python3.6 +# Needs a full install so isort can determine own/foreign imports. +deps = + -rdev-requirements.txt + flake8 + flake8-isort +commands = flake8 src tests setup.py conftest.py docs/conf.py + + +[testenv:isort] +basepython = python3.6 +# Needs a full install so isort can determine own/foreign imports. +deps = + -rdev-requirements.txt + isort +commands = + isort --recursive setup.py conftest.py src tests + + +[testenv:docs] +basepython = python3.6 +setenv = + PYTHONHASHSEED = 0 +deps = -rdocs-requirements.txt +commands = + sphinx-build -W -b html -d {envtmpdir}/doctrees docs docs/_build/html + sphinx-build -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html + python -m doctest README.rst + + +[testenv:manifest] +basepython = python3.6 +deps = check-manifest +skip_install = true +commands = check-manifest + + +[testenv:readme] +basepython = python3.6 +deps = readme_renderer +skip_install = true +commands = python setup.py check -r -s + + +[testenv:changelog] +basepython = python3.6 +deps = towncrier +skip_install = true +commands = towncrier --draft diff --git a/tests/wpt/web-platform-tests/tools/third_party/funcsigs/.travis.yml b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/.travis.yml new file mode 100644 index 00000000000..d2a7ab3051a --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/.travis.yml @@ -0,0 +1,17 @@ +language: python +python: + - 2.6 + - 2.7 + - 3.2 + - 3.3 + - pypy +install: + - pip install -r requirements/development.txt -r requirements/production.txt + - python setup.py install +script: + - coverage run setup.py test + - coverage report --show-missing +after_success: + - coveralls +notifications: + email: aaron.iles+travis-ci@gmail.com diff --git a/tests/wpt/web-platform-tests/tools/third_party/funcsigs/CHANGELOG b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/CHANGELOG new file mode 100644 index 00000000000..602eec5e7c2 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/CHANGELOG @@ -0,0 +1,19 @@ +Changelog +--------- + +0.4 (2013-12-20) +```````````````` +* Fix unbound methods getting their first parameter curried +* Publish Python wheel packages + +0.3 (2013-05-29) +```````````````` +* Fix annotation formatting of builtin types on Python 2.x + +0.2 (2012-01-07) +```````````````` +* PyPy compatability + +0.1 (2012-01-06) +```````````````` +* Initial release diff --git a/tests/wpt/web-platform-tests/tools/third_party/funcsigs/LICENSE b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/LICENSE new file mode 100644 index 00000000000..3e563d6fbd4 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/LICENSE @@ -0,0 +1,13 @@ +Copyright 2013 Aaron Iles + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/tests/wpt/web-platform-tests/tools/third_party/funcsigs/MANIFEST.in b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/MANIFEST.in new file mode 100644 index 00000000000..f0abb42f04a --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/MANIFEST.in @@ -0,0 +1,7 @@ +recursive-include docs * +recursive-include tests *.py +include *.py +include CHANGELOG +include LICENSE +include MANIFEST.in +include README.rst diff --git a/tests/wpt/web-platform-tests/tools/third_party/funcsigs/Makefile b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/Makefile new file mode 100644 index 00000000000..e2329231b56 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/Makefile @@ -0,0 +1,39 @@ +SHELL := /bin/bash + +deps: + pip install --upgrade \ + -r requirements/development.txt \ + -r requirements/production.txt + +sdist: + python setup.py sdist + python setup.py bdist_wheel + +register: + python setup.py register + python setup.py sdist upload + python setup.py bdist_wheel upload + +site: + cd docs; make html + +test: + coverage run setup.py test + +unittest: + coverage run -m unittest discover + +lint: + flake8 --exit-zero funcsigs tests + +coverage: + coverage report --show-missing + +clean: + python setup.py clean --all + find . -type f -name "*.pyc" -exec rm '{}' + + find . -type d -name "__pycache__" -exec rmdir '{}' + + rm -rf *.egg-info .coverage + cd docs; make clean + +docs: site diff --git a/tests/wpt/web-platform-tests/tools/third_party/funcsigs/README.rst b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/README.rst new file mode 100644 index 00000000000..f04b7b422cf --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/README.rst @@ -0,0 +1,83 @@ +funcsigs +======== + +``funcsigs`` is a backport of the `PEP 362`_ function signature features from +Python 3.3's `inspect`_ module. The backport is compatible with Python 2.6, 2.7 +as well as 3.2 and up. + +|pypi_version| + +Documentation +------------- + +The reference documentation is standard library documentation for the +`inspect`_ module in Python3. This documentation has been included in the +``funcsigs`` package documentation hosted on `Read The Docs`_. + +Example +------- + +To obtain a signature object, pass the target function to the +``funcsigs.signature`` function. :: + + >>> from funcsigs import signature + >>> def foo(a, b=None, *args, **kwargs): + ... pass + + >>> sig = signature(foo) + +For the details of the signature object, refer to the either the package of +standard library documentation. + +Compatability +------------- + +The ``funcsigs`` backport has been tested against: + +* CPython 2.6 +* CPython 2.7 +* CPython 3.2 +* PyPy 1.9 + +Continuous integration testing is provided by `Travis CI`_. + +Under Python 2.x there is a compatability issue when a function is assigned to +the ``__wrapped__`` property of a class after it has been constructed. +Similiarily there under PyPy directly passing the ``__call__`` method of a +builtin is also a compatability issues. Otherwise the functionality is +believed to be uniform between both Python2 and Python3. + +Issues +------ + +Source code for ``funcsigs`` is hosted on `GitHub`_. Any bug reports or feature +requests can be made using GitHub's `issues system`_. |build_status| |coverage| + +Copyright +--------- + +This is a derived work of CPython under the terms of the `PSF License +Agreement`_. The original CPython inspect module, its unit tests and +documentation are the copyright of the Python Software Foundation. The derived +work is distributed under the `Apache License Version 2.0`_. + +.. _Apache License Version 2.0: http://opensource.org/licenses/Apache-2.0 +.. _GitHub: https://github.com/aliles/funcsigs +.. _PSF License Agreement: http://docs.python.org/3/license.html#terms-and-conditions-for-accessing-or-otherwise-using-python +.. _Travis CI: http://travis-ci.org/ +.. _Read The Docs: http://funcsigs.readthedocs.org/ +.. _PEP 362: http://www.python.org/dev/peps/pep-0362/ +.. _inspect: http://docs.python.org/3/library/inspect.html#introspecting-callables-with-the-signature-object +.. _issues system: https://github.com/alies/funcsigs/issues + +.. |build_status| image:: https://secure.travis-ci.org/aliles/funcsigs.png?branch=master + :target: http://travis-ci.org/#!/aliles/funcsigs + :alt: Current build status + +.. |coverage| image:: https://coveralls.io/repos/aliles/funcsigs/badge.png?branch=master + :target: https://coveralls.io/r/aliles/funcsigs?branch=master + :alt: Coverage status + +.. |pypi_version| image:: https://pypip.in/v/funcsigs/badge.png + :target: https://crate.io/packages/funcsigs/ + :alt: Latest PyPI version diff --git a/tests/wpt/web-platform-tests/tools/third_party/funcsigs/docs/Makefile b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/docs/Makefile new file mode 100644 index 00000000000..f7ab3d16b40 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/docs/Makefile @@ -0,0 +1,153 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR) + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/funcsigs.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/funcsigs.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/funcsigs" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/funcsigs" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff --git a/tests/wpt/web-platform-tests/tools/third_party/funcsigs/docs/_templates/page.html b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/docs/_templates/page.html new file mode 100644 index 00000000000..5e1e00bcafa --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/docs/_templates/page.html @@ -0,0 +1,9 @@ +{% extends "!page.html" %} +{% block extrahead %} + + Fork me on GitHub + + {{ super() }} +{% endblock %} diff --git a/tests/wpt/web-platform-tests/tools/third_party/funcsigs/docs/conf.py b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/docs/conf.py new file mode 100644 index 00000000000..c6e4194cc05 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/docs/conf.py @@ -0,0 +1,251 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# funcsigs documentation build configuration file, created by +# sphinx-quickstart on Fri Apr 20 20:27:52 2012. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('..')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.viewcode'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'funcsigs' +copyright = '2013, Aaron Iles' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +from funcsigs import __version__ +version = '.'.join(__version__.split('.')[:2]) +# The full version, including alpha/beta/rc tags. +release = __version__ + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'agogo' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'funcsigsdoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'funcsigs.tex', 'funcsigs Documentation', + 'Aaron Iles', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'funcsigs', 'funcsigs Documentation', + ['Aaron Iles'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'funcsigs', 'funcsigs Documentation', + 'Aaron Iles', 'funcsigs', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = { + 'python3': ('http://docs.python.org/py3k', None), + 'python': ('http://docs.python.org/', None) +} diff --git a/tests/wpt/web-platform-tests/tools/third_party/funcsigs/docs/index.rst b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/docs/index.rst new file mode 100644 index 00000000000..5d0f42f9368 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/docs/index.rst @@ -0,0 +1,315 @@ +.. funcsigs documentation master file, created by + sphinx-quickstart on Fri Apr 20 20:27:52 2012. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Introducing funcsigs +==================== + +The Funcsigs Package +-------------------- + +*funcsigs* is a backport of the `PEP 362`_ function signature features from +Python 3.3's `inspect`_ module. The backport is compatible with Python 2.6, 2.7 +as well as 3.2 and up. + +.. _PEP 362: http://www.python.org/dev/peps/pep-0362/ +.. _inspect: http://docs.python.org/3/library/inspect.html#introspecting-callables-with-the-signature-object + +Compatability +````````````` + +The *funcsigs* backport has been tested against: + +* CPython 2.6 +* CPython 2.7 +* CPython 3.2 +* PyPy 1.9 + +Continuous integration testing is provided by `Travis CI`_. + +Under Python 2.x there is a compatability issue when a function is assigned to +the ``__wrapped__`` property of a class after it has been constructed. +Similiarily there under PyPy directly passing the ``__call__`` method of a +builtin is also a compatability issues. Otherwise the functionality is +believed to be uniform between both Python2 and Python3. + +.. _Travis CI: http://travis-ci.org/ + +Issues +`````` + +Source code for *funcsigs* is hosted on `GitHub`_. Any bug reports or feature +requests can be made using GitHub's `issues system`_. + +.. _GitHub: https://github.com/aliles/funcsigs +.. _issues system: https://github.com/alies/funcsigs/issues + +Introspecting callables with the Signature object +------------------------------------------------- + +.. note:: + + This section of documentation is a direct repoduction of the Python + standard library documentation for the inspect module. + +The Signature object represents the call signature of a callable object and its +return annotation. To retrieve a Signature object, use the :func:`signature` +function. + +.. function:: signature(callable) + + Return a :class:`Signature` object for the given ``callable``:: + + >>> from inspect import signature + >>> def foo(a, *, b:int, **kwargs): + ... pass + + >>> sig = signature(foo) + + >>> str(sig) + '(a, *, b:int, **kwargs)' + + >>> str(sig.parameters['b']) + 'b:int' + + >>> sig.parameters['b'].annotation + + + Accepts a wide range of python callables, from plain functions and classes to + :func:`functools.partial` objects. + + .. note:: + + Some callables may not be introspectable in certain implementations of + Python. For example, in CPython, built-in functions defined in C provide + no metadata about their arguments. + + +.. class:: Signature + + A Signature object represents the call signature of a function and its return + annotation. For each parameter accepted by the function it stores a + :class:`Parameter` object in its :attr:`parameters` collection. + + Signature objects are *immutable*. Use :meth:`Signature.replace` to make a + modified copy. + + .. attribute:: Signature.empty + + A special class-level marker to specify absence of a return annotation. + + .. attribute:: Signature.parameters + + An ordered mapping of parameters' names to the corresponding + :class:`Parameter` objects. + + .. attribute:: Signature.return_annotation + + The "return" annotation for the callable. If the callable has no "return" + annotation, this attribute is set to :attr:`Signature.empty`. + + .. method:: Signature.bind(*args, **kwargs) + + Create a mapping from positional and keyword arguments to parameters. + Returns :class:`BoundArguments` if ``*args`` and ``**kwargs`` match the + signature, or raises a :exc:`TypeError`. + + .. method:: Signature.bind_partial(*args, **kwargs) + + Works the same way as :meth:`Signature.bind`, but allows the omission of + some required arguments (mimics :func:`functools.partial` behavior.) + Returns :class:`BoundArguments`, or raises a :exc:`TypeError` if the + passed arguments do not match the signature. + + .. method:: Signature.replace(*[, parameters][, return_annotation]) + + Create a new Signature instance based on the instance replace was invoked + on. It is possible to pass different ``parameters`` and/or + ``return_annotation`` to override the corresponding properties of the base + signature. To remove return_annotation from the copied Signature, pass in + :attr:`Signature.empty`. + + :: + + >>> def test(a, b): + ... pass + >>> sig = signature(test) + >>> new_sig = sig.replace(return_annotation="new return anno") + >>> str(new_sig) + "(a, b) -> 'new return anno'" + + +.. class:: Parameter + + Parameter objects are *immutable*. Instead of modifying a Parameter object, + you can use :meth:`Parameter.replace` to create a modified copy. + + .. attribute:: Parameter.empty + + A special class-level marker to specify absence of default values and + annotations. + + .. attribute:: Parameter.name + + The name of the parameter as a string. Must be a valid python identifier + name (with the exception of ``POSITIONAL_ONLY`` parameters, which can have + it set to ``None``). + + .. attribute:: Parameter.default + + The default value for the parameter. If the parameter has no default + value, this attribute is set to :attr:`Parameter.empty`. + + .. attribute:: Parameter.annotation + + The annotation for the parameter. If the parameter has no annotation, + this attribute is set to :attr:`Parameter.empty`. + + .. attribute:: Parameter.kind + + Describes how argument values are bound to the parameter. Possible values + (accessible via :class:`Parameter`, like ``Parameter.KEYWORD_ONLY``): + + +------------------------+----------------------------------------------+ + | Name | Meaning | + +========================+==============================================+ + | *POSITIONAL_ONLY* | Value must be supplied as a positional | + | | argument. | + | | | + | | Python has no explicit syntax for defining | + | | positional-only parameters, but many built-in| + | | and extension module functions (especially | + | | those that accept only one or two parameters)| + | | accept them. | + +------------------------+----------------------------------------------+ + | *POSITIONAL_OR_KEYWORD*| Value may be supplied as either a keyword or | + | | positional argument (this is the standard | + | | binding behaviour for functions implemented | + | | in Python.) | + +------------------------+----------------------------------------------+ + | *VAR_POSITIONAL* | A tuple of positional arguments that aren't | + | | bound to any other parameter. This | + | | corresponds to a ``*args`` parameter in a | + | | Python function definition. | + +------------------------+----------------------------------------------+ + | *KEYWORD_ONLY* | Value must be supplied as a keyword argument.| + | | Keyword only parameters are those which | + | | appear after a ``*`` or ``*args`` entry in a | + | | Python function definition. | + +------------------------+----------------------------------------------+ + | *VAR_KEYWORD* | A dict of keyword arguments that aren't bound| + | | to any other parameter. This corresponds to a| + | | ``**kwargs`` parameter in a Python function | + | | definition. | + +------------------------+----------------------------------------------+ + + Example: print all keyword-only arguments without default values:: + + >>> def foo(a, b, *, c, d=10): + ... pass + + >>> sig = signature(foo) + >>> for param in sig.parameters.values(): + ... if (param.kind == param.KEYWORD_ONLY and + ... param.default is param.empty): + ... print('Parameter:', param) + Parameter: c + + .. method:: Parameter.replace(*[, name][, kind][, default][, annotation]) + + Create a new Parameter instance based on the instance replaced was invoked + on. To override a :class:`Parameter` attribute, pass the corresponding + argument. To remove a default value or/and an annotation from a + Parameter, pass :attr:`Parameter.empty`. + + :: + + >>> from inspect import Parameter + >>> param = Parameter('foo', Parameter.KEYWORD_ONLY, default=42) + >>> str(param) + 'foo=42' + + >>> str(param.replace()) # Will create a shallow copy of 'param' + 'foo=42' + + >>> str(param.replace(default=Parameter.empty, annotation='spam')) + "foo:'spam'" + + +.. class:: BoundArguments + + Result of a :meth:`Signature.bind` or :meth:`Signature.bind_partial` call. + Holds the mapping of arguments to the function's parameters. + + .. attribute:: BoundArguments.arguments + + An ordered, mutable mapping (:class:`collections.OrderedDict`) of + parameters' names to arguments' values. Contains only explicitly bound + arguments. Changes in :attr:`arguments` will reflect in :attr:`args` and + :attr:`kwargs`. + + Should be used in conjunction with :attr:`Signature.parameters` for any + argument processing purposes. + + .. note:: + + Arguments for which :meth:`Signature.bind` or + :meth:`Signature.bind_partial` relied on a default value are skipped. + However, if needed, it is easy to include them. + + :: + + >>> def foo(a, b=10): + ... pass + + >>> sig = signature(foo) + >>> ba = sig.bind(5) + + >>> ba.args, ba.kwargs + ((5,), {}) + + >>> for param in sig.parameters.values(): + ... if param.name not in ba.arguments: + ... ba.arguments[param.name] = param.default + + >>> ba.args, ba.kwargs + ((5, 10), {}) + + + .. attribute:: BoundArguments.args + + A tuple of positional arguments values. Dynamically computed from the + :attr:`arguments` attribute. + + .. attribute:: BoundArguments.kwargs + + A dict of keyword arguments values. Dynamically computed from the + :attr:`arguments` attribute. + + The :attr:`args` and :attr:`kwargs` properties can be used to invoke + functions:: + + def test(a, *, b): + ... + + sig = signature(test) + ba = sig.bind(10, b=20) + test(*ba.args, **ba.kwargs) + + +.. seealso:: + + :pep:`362` - Function Signature Object. + The detailed specification, implementation details and examples. + +Copyright +--------- + +*funcsigs* is a derived work of CPython under the terms of the `PSF License +Agreement`_. The original CPython inspect module, its unit tests and +documentation are the copyright of the Python Software Foundation. The derived +work is distributed under the `Apache License Version 2.0`_. + +.. _PSF License Agreement: http://docs.python.org/3/license.html#terms-and-conditions-for-accessing-or-otherwise-using-python +.. _Apache License Version 2.0: http://opensource.org/licenses/Apache-2.0 diff --git a/tests/wpt/web-platform-tests/tools/third_party/funcsigs/funcsigs/__init__.py b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/funcsigs/__init__.py new file mode 100644 index 00000000000..fd2f47b1d4d --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/funcsigs/__init__.py @@ -0,0 +1,818 @@ +# Copyright 2001-2013 Python Software Foundation; All Rights Reserved +"""Function signature objects for callables + +Back port of Python 3.3's function signature tools from the inspect module, +modified to be compatible with Python 2.6, 2.7 and 3.2+. +""" +from __future__ import absolute_import, division, print_function +import itertools +import functools +import re +import types + +try: + from collections import OrderedDict +except ImportError: + from funcsigs.odict import OrderedDict + +from funcsigs.version import __version__ + +__all__ = ['BoundArguments', 'Parameter', 'Signature', 'signature'] + + +_WrapperDescriptor = type(type.__call__) +_MethodWrapper = type(all.__call__) + +_NonUserDefinedCallables = (_WrapperDescriptor, + _MethodWrapper, + types.BuiltinFunctionType) + + +def formatannotation(annotation, base_module=None): + if isinstance(annotation, type): + if annotation.__module__ in ('builtins', '__builtin__', base_module): + return annotation.__name__ + return annotation.__module__+'.'+annotation.__name__ + return repr(annotation) + + +def _get_user_defined_method(cls, method_name, *nested): + try: + if cls is type: + return + meth = getattr(cls, method_name) + for name in nested: + meth = getattr(meth, name, meth) + except AttributeError: + return + else: + if not isinstance(meth, _NonUserDefinedCallables): + # Once '__signature__' will be added to 'C'-level + # callables, this check won't be necessary + return meth + + +def signature(obj): + '''Get a signature object for the passed callable.''' + + if not callable(obj): + raise TypeError('{0!r} is not a callable object'.format(obj)) + + if isinstance(obj, types.MethodType): + sig = signature(obj.__func__) + if obj.__self__ is None: + # Unbound method: the first parameter becomes positional-only + if sig.parameters: + first = sig.parameters.values()[0].replace( + kind=_POSITIONAL_ONLY) + return sig.replace( + parameters=(first,) + tuple(sig.parameters.values())[1:]) + else: + return sig + else: + # In this case we skip the first parameter of the underlying + # function (usually `self` or `cls`). + return sig.replace(parameters=tuple(sig.parameters.values())[1:]) + + try: + sig = obj.__signature__ + except AttributeError: + pass + else: + if sig is not None: + return sig + + try: + # Was this function wrapped by a decorator? + wrapped = obj.__wrapped__ + except AttributeError: + pass + else: + return signature(wrapped) + + if isinstance(obj, types.FunctionType): + return Signature.from_function(obj) + + if isinstance(obj, functools.partial): + sig = signature(obj.func) + + new_params = OrderedDict(sig.parameters.items()) + + partial_args = obj.args or () + partial_keywords = obj.keywords or {} + try: + ba = sig.bind_partial(*partial_args, **partial_keywords) + except TypeError as ex: + msg = 'partial object {0!r} has incorrect arguments'.format(obj) + raise ValueError(msg) + + for arg_name, arg_value in ba.arguments.items(): + param = new_params[arg_name] + if arg_name in partial_keywords: + # We set a new default value, because the following code + # is correct: + # + # >>> def foo(a): print(a) + # >>> print(partial(partial(foo, a=10), a=20)()) + # 20 + # >>> print(partial(partial(foo, a=10), a=20)(a=30)) + # 30 + # + # So, with 'partial' objects, passing a keyword argument is + # like setting a new default value for the corresponding + # parameter + # + # We also mark this parameter with '_partial_kwarg' + # flag. Later, in '_bind', the 'default' value of this + # parameter will be added to 'kwargs', to simulate + # the 'functools.partial' real call. + new_params[arg_name] = param.replace(default=arg_value, + _partial_kwarg=True) + + elif (param.kind not in (_VAR_KEYWORD, _VAR_POSITIONAL) and + not param._partial_kwarg): + new_params.pop(arg_name) + + return sig.replace(parameters=new_params.values()) + + sig = None + if isinstance(obj, type): + # obj is a class or a metaclass + + # First, let's see if it has an overloaded __call__ defined + # in its metaclass + call = _get_user_defined_method(type(obj), '__call__') + if call is not None: + sig = signature(call) + else: + # Now we check if the 'obj' class has a '__new__' method + new = _get_user_defined_method(obj, '__new__') + if new is not None: + sig = signature(new) + else: + # Finally, we should have at least __init__ implemented + init = _get_user_defined_method(obj, '__init__') + if init is not None: + sig = signature(init) + elif not isinstance(obj, _NonUserDefinedCallables): + # An object with __call__ + # We also check that the 'obj' is not an instance of + # _WrapperDescriptor or _MethodWrapper to avoid + # infinite recursion (and even potential segfault) + call = _get_user_defined_method(type(obj), '__call__', 'im_func') + if call is not None: + sig = signature(call) + + if sig is not None: + # For classes and objects we skip the first parameter of their + # __call__, __new__, or __init__ methods + return sig.replace(parameters=tuple(sig.parameters.values())[1:]) + + if isinstance(obj, types.BuiltinFunctionType): + # Raise a nicer error message for builtins + msg = 'no signature found for builtin function {0!r}'.format(obj) + raise ValueError(msg) + + raise ValueError('callable {0!r} is not supported by signature'.format(obj)) + + +class _void(object): + '''A private marker - used in Parameter & Signature''' + + +class _empty(object): + pass + + +class _ParameterKind(int): + def __new__(self, *args, **kwargs): + obj = int.__new__(self, *args) + obj._name = kwargs['name'] + return obj + + def __str__(self): + return self._name + + def __repr__(self): + return '<_ParameterKind: {0!r}>'.format(self._name) + + +_POSITIONAL_ONLY = _ParameterKind(0, name='POSITIONAL_ONLY') +_POSITIONAL_OR_KEYWORD = _ParameterKind(1, name='POSITIONAL_OR_KEYWORD') +_VAR_POSITIONAL = _ParameterKind(2, name='VAR_POSITIONAL') +_KEYWORD_ONLY = _ParameterKind(3, name='KEYWORD_ONLY') +_VAR_KEYWORD = _ParameterKind(4, name='VAR_KEYWORD') + + +class Parameter(object): + '''Represents a parameter in a function signature. + + Has the following public attributes: + + * name : str + The name of the parameter as a string. + * default : object + The default value for the parameter if specified. If the + parameter has no default value, this attribute is not set. + * annotation + The annotation for the parameter if specified. If the + parameter has no annotation, this attribute is not set. + * kind : str + Describes how argument values are bound to the parameter. + Possible values: `Parameter.POSITIONAL_ONLY`, + `Parameter.POSITIONAL_OR_KEYWORD`, `Parameter.VAR_POSITIONAL`, + `Parameter.KEYWORD_ONLY`, `Parameter.VAR_KEYWORD`. + ''' + + __slots__ = ('_name', '_kind', '_default', '_annotation', '_partial_kwarg') + + POSITIONAL_ONLY = _POSITIONAL_ONLY + POSITIONAL_OR_KEYWORD = _POSITIONAL_OR_KEYWORD + VAR_POSITIONAL = _VAR_POSITIONAL + KEYWORD_ONLY = _KEYWORD_ONLY + VAR_KEYWORD = _VAR_KEYWORD + + empty = _empty + + def __init__(self, name, kind, default=_empty, annotation=_empty, + _partial_kwarg=False): + + if kind not in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD, + _VAR_POSITIONAL, _KEYWORD_ONLY, _VAR_KEYWORD): + raise ValueError("invalid value for 'Parameter.kind' attribute") + self._kind = kind + + if default is not _empty: + if kind in (_VAR_POSITIONAL, _VAR_KEYWORD): + msg = '{0} parameters cannot have default values'.format(kind) + raise ValueError(msg) + self._default = default + self._annotation = annotation + + if name is None: + if kind != _POSITIONAL_ONLY: + raise ValueError("None is not a valid name for a " + "non-positional-only parameter") + self._name = name + else: + name = str(name) + if kind != _POSITIONAL_ONLY and not re.match(r'[a-z_]\w*$', name, re.I): + msg = '{0!r} is not a valid parameter name'.format(name) + raise ValueError(msg) + self._name = name + + self._partial_kwarg = _partial_kwarg + + @property + def name(self): + return self._name + + @property + def default(self): + return self._default + + @property + def annotation(self): + return self._annotation + + @property + def kind(self): + return self._kind + + def replace(self, name=_void, kind=_void, annotation=_void, + default=_void, _partial_kwarg=_void): + '''Creates a customized copy of the Parameter.''' + + if name is _void: + name = self._name + + if kind is _void: + kind = self._kind + + if annotation is _void: + annotation = self._annotation + + if default is _void: + default = self._default + + if _partial_kwarg is _void: + _partial_kwarg = self._partial_kwarg + + return type(self)(name, kind, default=default, annotation=annotation, + _partial_kwarg=_partial_kwarg) + + def __str__(self): + kind = self.kind + + formatted = self._name + if kind == _POSITIONAL_ONLY: + if formatted is None: + formatted = '' + formatted = '<{0}>'.format(formatted) + + # Add annotation and default value + if self._annotation is not _empty: + formatted = '{0}:{1}'.format(formatted, + formatannotation(self._annotation)) + + if self._default is not _empty: + formatted = '{0}={1}'.format(formatted, repr(self._default)) + + if kind == _VAR_POSITIONAL: + formatted = '*' + formatted + elif kind == _VAR_KEYWORD: + formatted = '**' + formatted + + return formatted + + def __repr__(self): + return '<{0} at {1:#x} {2!r}>'.format(self.__class__.__name__, + id(self), self.name) + + def __hash__(self): + msg = "unhashable type: '{0}'".format(self.__class__.__name__) + raise TypeError(msg) + + def __eq__(self, other): + return (issubclass(other.__class__, Parameter) and + self._name == other._name and + self._kind == other._kind and + self._default == other._default and + self._annotation == other._annotation) + + def __ne__(self, other): + return not self.__eq__(other) + + +class BoundArguments(object): + '''Result of `Signature.bind` call. Holds the mapping of arguments + to the function's parameters. + + Has the following public attributes: + + * arguments : OrderedDict + An ordered mutable mapping of parameters' names to arguments' values. + Does not contain arguments' default values. + * signature : Signature + The Signature object that created this instance. + * args : tuple + Tuple of positional arguments values. + * kwargs : dict + Dict of keyword arguments values. + ''' + + def __init__(self, signature, arguments): + self.arguments = arguments + self._signature = signature + + @property + def signature(self): + return self._signature + + @property + def args(self): + args = [] + for param_name, param in self._signature.parameters.items(): + if (param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY) or + param._partial_kwarg): + # Keyword arguments mapped by 'functools.partial' + # (Parameter._partial_kwarg is True) are mapped + # in 'BoundArguments.kwargs', along with VAR_KEYWORD & + # KEYWORD_ONLY + break + + try: + arg = self.arguments[param_name] + except KeyError: + # We're done here. Other arguments + # will be mapped in 'BoundArguments.kwargs' + break + else: + if param.kind == _VAR_POSITIONAL: + # *args + args.extend(arg) + else: + # plain argument + args.append(arg) + + return tuple(args) + + @property + def kwargs(self): + kwargs = {} + kwargs_started = False + for param_name, param in self._signature.parameters.items(): + if not kwargs_started: + if (param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY) or + param._partial_kwarg): + kwargs_started = True + else: + if param_name not in self.arguments: + kwargs_started = True + continue + + if not kwargs_started: + continue + + try: + arg = self.arguments[param_name] + except KeyError: + pass + else: + if param.kind == _VAR_KEYWORD: + # **kwargs + kwargs.update(arg) + else: + # plain keyword argument + kwargs[param_name] = arg + + return kwargs + + def __hash__(self): + msg = "unhashable type: '{0}'".format(self.__class__.__name__) + raise TypeError(msg) + + def __eq__(self, other): + return (issubclass(other.__class__, BoundArguments) and + self.signature == other.signature and + self.arguments == other.arguments) + + def __ne__(self, other): + return not self.__eq__(other) + + +class Signature(object): + '''A Signature object represents the overall signature of a function. + It stores a Parameter object for each parameter accepted by the + function, as well as information specific to the function itself. + + A Signature object has the following public attributes and methods: + + * parameters : OrderedDict + An ordered mapping of parameters' names to the corresponding + Parameter objects (keyword-only arguments are in the same order + as listed in `code.co_varnames`). + * return_annotation : object + The annotation for the return type of the function if specified. + If the function has no annotation for its return type, this + attribute is not set. + * bind(*args, **kwargs) -> BoundArguments + Creates a mapping from positional and keyword arguments to + parameters. + * bind_partial(*args, **kwargs) -> BoundArguments + Creates a partial mapping from positional and keyword arguments + to parameters (simulating 'functools.partial' behavior.) + ''' + + __slots__ = ('_return_annotation', '_parameters') + + _parameter_cls = Parameter + _bound_arguments_cls = BoundArguments + + empty = _empty + + def __init__(self, parameters=None, return_annotation=_empty, + __validate_parameters__=True): + '''Constructs Signature from the given list of Parameter + objects and 'return_annotation'. All arguments are optional. + ''' + + if parameters is None: + params = OrderedDict() + else: + if __validate_parameters__: + params = OrderedDict() + top_kind = _POSITIONAL_ONLY + + for idx, param in enumerate(parameters): + kind = param.kind + if kind < top_kind: + msg = 'wrong parameter order: {0} before {1}' + msg = msg.format(top_kind, param.kind) + raise ValueError(msg) + else: + top_kind = kind + + name = param.name + if name is None: + name = str(idx) + param = param.replace(name=name) + + if name in params: + msg = 'duplicate parameter name: {0!r}'.format(name) + raise ValueError(msg) + params[name] = param + else: + params = OrderedDict(((param.name, param) + for param in parameters)) + + self._parameters = params + self._return_annotation = return_annotation + + @classmethod + def from_function(cls, func): + '''Constructs Signature for the given python function''' + + if not isinstance(func, types.FunctionType): + raise TypeError('{0!r} is not a Python function'.format(func)) + + Parameter = cls._parameter_cls + + # Parameter information. + func_code = func.__code__ + pos_count = func_code.co_argcount + arg_names = func_code.co_varnames + positional = tuple(arg_names[:pos_count]) + keyword_only_count = getattr(func_code, 'co_kwonlyargcount', 0) + keyword_only = arg_names[pos_count:(pos_count + keyword_only_count)] + annotations = getattr(func, '__annotations__', {}) + defaults = func.__defaults__ + kwdefaults = getattr(func, '__kwdefaults__', None) + + if defaults: + pos_default_count = len(defaults) + else: + pos_default_count = 0 + + parameters = [] + + # Non-keyword-only parameters w/o defaults. + non_default_count = pos_count - pos_default_count + for name in positional[:non_default_count]: + annotation = annotations.get(name, _empty) + parameters.append(Parameter(name, annotation=annotation, + kind=_POSITIONAL_OR_KEYWORD)) + + # ... w/ defaults. + for offset, name in enumerate(positional[non_default_count:]): + annotation = annotations.get(name, _empty) + parameters.append(Parameter(name, annotation=annotation, + kind=_POSITIONAL_OR_KEYWORD, + default=defaults[offset])) + + # *args + if func_code.co_flags & 0x04: + name = arg_names[pos_count + keyword_only_count] + annotation = annotations.get(name, _empty) + parameters.append(Parameter(name, annotation=annotation, + kind=_VAR_POSITIONAL)) + + # Keyword-only parameters. + for name in keyword_only: + default = _empty + if kwdefaults is not None: + default = kwdefaults.get(name, _empty) + + annotation = annotations.get(name, _empty) + parameters.append(Parameter(name, annotation=annotation, + kind=_KEYWORD_ONLY, + default=default)) + # **kwargs + if func_code.co_flags & 0x08: + index = pos_count + keyword_only_count + if func_code.co_flags & 0x04: + index += 1 + + name = arg_names[index] + annotation = annotations.get(name, _empty) + parameters.append(Parameter(name, annotation=annotation, + kind=_VAR_KEYWORD)) + + return cls(parameters, + return_annotation=annotations.get('return', _empty), + __validate_parameters__=False) + + @property + def parameters(self): + try: + return types.MappingProxyType(self._parameters) + except AttributeError: + return OrderedDict(self._parameters.items()) + + @property + def return_annotation(self): + return self._return_annotation + + def replace(self, parameters=_void, return_annotation=_void): + '''Creates a customized copy of the Signature. + Pass 'parameters' and/or 'return_annotation' arguments + to override them in the new copy. + ''' + + if parameters is _void: + parameters = self.parameters.values() + + if return_annotation is _void: + return_annotation = self._return_annotation + + return type(self)(parameters, + return_annotation=return_annotation) + + def __hash__(self): + msg = "unhashable type: '{0}'".format(self.__class__.__name__) + raise TypeError(msg) + + def __eq__(self, other): + if (not issubclass(type(other), Signature) or + self.return_annotation != other.return_annotation or + len(self.parameters) != len(other.parameters)): + return False + + other_positions = dict((param, idx) + for idx, param in enumerate(other.parameters.keys())) + + for idx, (param_name, param) in enumerate(self.parameters.items()): + if param.kind == _KEYWORD_ONLY: + try: + other_param = other.parameters[param_name] + except KeyError: + return False + else: + if param != other_param: + return False + else: + try: + other_idx = other_positions[param_name] + except KeyError: + return False + else: + if (idx != other_idx or + param != other.parameters[param_name]): + return False + + return True + + def __ne__(self, other): + return not self.__eq__(other) + + def _bind(self, args, kwargs, partial=False): + '''Private method. Don't use directly.''' + + arguments = OrderedDict() + + parameters = iter(self.parameters.values()) + parameters_ex = () + arg_vals = iter(args) + + if partial: + # Support for binding arguments to 'functools.partial' objects. + # See 'functools.partial' case in 'signature()' implementation + # for details. + for param_name, param in self.parameters.items(): + if (param._partial_kwarg and param_name not in kwargs): + # Simulating 'functools.partial' behavior + kwargs[param_name] = param.default + + while True: + # Let's iterate through the positional arguments and corresponding + # parameters + try: + arg_val = next(arg_vals) + except StopIteration: + # No more positional arguments + try: + param = next(parameters) + except StopIteration: + # No more parameters. That's it. Just need to check that + # we have no `kwargs` after this while loop + break + else: + if param.kind == _VAR_POSITIONAL: + # That's OK, just empty *args. Let's start parsing + # kwargs + break + elif param.name in kwargs: + if param.kind == _POSITIONAL_ONLY: + msg = '{arg!r} parameter is positional only, ' \ + 'but was passed as a keyword' + msg = msg.format(arg=param.name) + raise TypeError(msg) + parameters_ex = (param,) + break + elif (param.kind == _VAR_KEYWORD or + param.default is not _empty): + # That's fine too - we have a default value for this + # parameter. So, lets start parsing `kwargs`, starting + # with the current parameter + parameters_ex = (param,) + break + else: + if partial: + parameters_ex = (param,) + break + else: + msg = '{arg!r} parameter lacking default value' + msg = msg.format(arg=param.name) + raise TypeError(msg) + else: + # We have a positional argument to process + try: + param = next(parameters) + except StopIteration: + raise TypeError('too many positional arguments') + else: + if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY): + # Looks like we have no parameter for this positional + # argument + raise TypeError('too many positional arguments') + + if param.kind == _VAR_POSITIONAL: + # We have an '*args'-like argument, let's fill it with + # all positional arguments we have left and move on to + # the next phase + values = [arg_val] + values.extend(arg_vals) + arguments[param.name] = tuple(values) + break + + if param.name in kwargs: + raise TypeError('multiple values for argument ' + '{arg!r}'.format(arg=param.name)) + + arguments[param.name] = arg_val + + # Now, we iterate through the remaining parameters to process + # keyword arguments + kwargs_param = None + for param in itertools.chain(parameters_ex, parameters): + if param.kind == _POSITIONAL_ONLY: + # This should never happen in case of a properly built + # Signature object (but let's have this check here + # to ensure correct behaviour just in case) + raise TypeError('{arg!r} parameter is positional only, ' + 'but was passed as a keyword'. \ + format(arg=param.name)) + + if param.kind == _VAR_KEYWORD: + # Memorize that we have a '**kwargs'-like parameter + kwargs_param = param + continue + + param_name = param.name + try: + arg_val = kwargs.pop(param_name) + except KeyError: + # We have no value for this parameter. It's fine though, + # if it has a default value, or it is an '*args'-like + # parameter, left alone by the processing of positional + # arguments. + if (not partial and param.kind != _VAR_POSITIONAL and + param.default is _empty): + raise TypeError('{arg!r} parameter lacking default value'. \ + format(arg=param_name)) + + else: + arguments[param_name] = arg_val + + if kwargs: + if kwargs_param is not None: + # Process our '**kwargs'-like parameter + arguments[kwargs_param.name] = kwargs + else: + raise TypeError('too many keyword arguments') + + return self._bound_arguments_cls(self, arguments) + + def bind(self, *args, **kwargs): + '''Get a BoundArguments object, that maps the passed `args` + and `kwargs` to the function's signature. Raises `TypeError` + if the passed arguments can not be bound. + ''' + return self._bind(args, kwargs) + + def bind_partial(self, *args, **kwargs): + '''Get a BoundArguments object, that partially maps the + passed `args` and `kwargs` to the function's signature. + Raises `TypeError` if the passed arguments can not be bound. + ''' + return self._bind(args, kwargs, partial=True) + + def __str__(self): + result = [] + render_kw_only_separator = True + for idx, param in enumerate(self.parameters.values()): + formatted = str(param) + + kind = param.kind + if kind == _VAR_POSITIONAL: + # OK, we have an '*args'-like parameter, so we won't need + # a '*' to separate keyword-only arguments + render_kw_only_separator = False + elif kind == _KEYWORD_ONLY and render_kw_only_separator: + # We have a keyword-only parameter to render and we haven't + # rendered an '*args'-like parameter before, so add a '*' + # separator to the parameters list ("foo(arg1, *, arg2)" case) + result.append('*') + # This condition should be only triggered once, so + # reset the flag + render_kw_only_separator = False + + result.append(formatted) + + rendered = '({0})'.format(', '.join(result)) + + if self.return_annotation is not _empty: + anno = formatannotation(self.return_annotation) + rendered += ' -> {0}'.format(anno) + + return rendered diff --git a/tests/wpt/web-platform-tests/tools/third_party/funcsigs/funcsigs/odict.py b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/funcsigs/odict.py new file mode 100644 index 00000000000..6221e971b37 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/funcsigs/odict.py @@ -0,0 +1,261 @@ +# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy. +# Passes Python2.7's test suite and incorporates all the latest updates. +# Copyright 2009 Raymond Hettinger +# http://code.activestate.com/recipes/576693/ +"Ordered dictionary" + +try: + from thread import get_ident as _get_ident +except ImportError: + from dummy_thread import get_ident as _get_ident + +try: + from _abcoll import KeysView, ValuesView, ItemsView +except ImportError: + pass + + +class OrderedDict(dict): + 'Dictionary that remembers insertion order' + # An inherited dict maps keys to values. + # The inherited dict provides __getitem__, __len__, __contains__, and get. + # The remaining methods are order-aware. + # Big-O running times for all methods are the same as for regular dictionaries. + + # The internal self.__map dictionary maps keys to links in a doubly linked list. + # The circular doubly linked list starts and ends with a sentinel element. + # The sentinel element never gets deleted (this simplifies the algorithm). + # Each link is stored as a list of length three: [PREV, NEXT, KEY]. + + def __init__(self, *args, **kwds): + '''Initialize an ordered dictionary. Signature is the same as for + regular dictionaries, but keyword arguments are not recommended + because their insertion order is arbitrary. + + ''' + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + try: + self.__root + except AttributeError: + self.__root = root = [] # sentinel node + root[:] = [root, root, None] + self.__map = {} + self.__update(*args, **kwds) + + def __setitem__(self, key, value, dict_setitem=dict.__setitem__): + 'od.__setitem__(i, y) <==> od[i]=y' + # Setting a new item creates a new link which goes at the end of the linked + # list, and the inherited dictionary is updated with the new key/value pair. + if key not in self: + root = self.__root + last = root[0] + last[1] = root[0] = self.__map[key] = [last, root, key] + dict_setitem(self, key, value) + + def __delitem__(self, key, dict_delitem=dict.__delitem__): + 'od.__delitem__(y) <==> del od[y]' + # Deleting an existing item uses self.__map to find the link which is + # then removed by updating the links in the predecessor and successor nodes. + dict_delitem(self, key) + link_prev, link_next, key = self.__map.pop(key) + link_prev[1] = link_next + link_next[0] = link_prev + + def __iter__(self): + 'od.__iter__() <==> iter(od)' + root = self.__root + curr = root[1] + while curr is not root: + yield curr[2] + curr = curr[1] + + def __reversed__(self): + 'od.__reversed__() <==> reversed(od)' + root = self.__root + curr = root[0] + while curr is not root: + yield curr[2] + curr = curr[0] + + def clear(self): + 'od.clear() -> None. Remove all items from od.' + try: + for node in self.__map.itervalues(): + del node[:] + root = self.__root + root[:] = [root, root, None] + self.__map.clear() + except AttributeError: + pass + dict.clear(self) + + def popitem(self, last=True): + '''od.popitem() -> (k, v), return and remove a (key, value) pair. + Pairs are returned in LIFO order if last is true or FIFO order if false. + + ''' + if not self: + raise KeyError('dictionary is empty') + root = self.__root + if last: + link = root[0] + link_prev = link[0] + link_prev[1] = root + root[0] = link_prev + else: + link = root[1] + link_next = link[1] + root[1] = link_next + link_next[0] = root + key = link[2] + del self.__map[key] + value = dict.pop(self, key) + return key, value + + # -- the following methods do not depend on the internal structure -- + + def keys(self): + 'od.keys() -> list of keys in od' + return list(self) + + def values(self): + 'od.values() -> list of values in od' + return [self[key] for key in self] + + def items(self): + 'od.items() -> list of (key, value) pairs in od' + return [(key, self[key]) for key in self] + + def iterkeys(self): + 'od.iterkeys() -> an iterator over the keys in od' + return iter(self) + + def itervalues(self): + 'od.itervalues -> an iterator over the values in od' + for k in self: + yield self[k] + + def iteritems(self): + 'od.iteritems -> an iterator over the (key, value) items in od' + for k in self: + yield (k, self[k]) + + def update(*args, **kwds): + '''od.update(E, **F) -> None. Update od from dict/iterable E and F. + + If E is a dict instance, does: for k in E: od[k] = E[k] + If E has a .keys() method, does: for k in E.keys(): od[k] = E[k] + Or if E is an iterable of items, does: for k, v in E: od[k] = v + In either case, this is followed by: for k, v in F.items(): od[k] = v + + ''' + if len(args) > 2: + raise TypeError('update() takes at most 2 positional ' + 'arguments (%d given)' % (len(args),)) + elif not args: + raise TypeError('update() takes at least 1 argument (0 given)') + self = args[0] + # Make progressively weaker assumptions about "other" + other = () + if len(args) == 2: + other = args[1] + if isinstance(other, dict): + for key in other: + self[key] = other[key] + elif hasattr(other, 'keys'): + for key in other.keys(): + self[key] = other[key] + else: + for key, value in other: + self[key] = value + for key, value in kwds.items(): + self[key] = value + + __update = update # let subclasses override update without breaking __init__ + + __marker = object() + + def pop(self, key, default=__marker): + '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value. + If key is not found, d is returned if given, otherwise KeyError is raised. + + ''' + if key in self: + result = self[key] + del self[key] + return result + if default is self.__marker: + raise KeyError(key) + return default + + def setdefault(self, key, default=None): + 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' + if key in self: + return self[key] + self[key] = default + return default + + def __repr__(self, _repr_running={}): + 'od.__repr__() <==> repr(od)' + call_key = id(self), _get_ident() + if call_key in _repr_running: + return '...' + _repr_running[call_key] = 1 + try: + if not self: + return '%s()' % (self.__class__.__name__,) + return '%s(%r)' % (self.__class__.__name__, self.items()) + finally: + del _repr_running[call_key] + + def __reduce__(self): + 'Return state information for pickling' + items = [[k, self[k]] for k in self] + inst_dict = vars(self).copy() + for k in vars(OrderedDict()): + inst_dict.pop(k, None) + if inst_dict: + return (self.__class__, (items,), inst_dict) + return self.__class__, (items,) + + def copy(self): + 'od.copy() -> a shallow copy of od' + return self.__class__(self) + + @classmethod + def fromkeys(cls, iterable, value=None): + '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S + and values equal to v (which defaults to None). + + ''' + d = cls() + for key in iterable: + d[key] = value + return d + + def __eq__(self, other): + '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive + while comparison to a regular mapping is order-insensitive. + + ''' + if isinstance(other, OrderedDict): + return len(self)==len(other) and self.items() == other.items() + return dict.__eq__(self, other) + + def __ne__(self, other): + return not self == other + + # -- the following methods are only used in Python 2.7 -- + + def viewkeys(self): + "od.viewkeys() -> a set-like object providing a view on od's keys" + return KeysView(self) + + def viewvalues(self): + "od.viewvalues() -> an object providing a view on od's values" + return ValuesView(self) + + def viewitems(self): + "od.viewitems() -> a set-like object providing a view on od's items" + return ItemsView(self) diff --git a/tests/wpt/web-platform-tests/tools/third_party/funcsigs/funcsigs/version.py b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/funcsigs/version.py new file mode 100644 index 00000000000..896a370cad1 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/funcsigs/version.py @@ -0,0 +1 @@ +__version__ = "0.4" diff --git a/tests/wpt/web-platform-tests/tools/third_party/funcsigs/requirements/development.txt b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/requirements/development.txt new file mode 100644 index 00000000000..ecafb0a527d --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/requirements/development.txt @@ -0,0 +1,6 @@ +coverage +coveralls +pip +flake8 +sphinx +wheel diff --git a/tests/wpt/web-platform-tests/tools/third_party/funcsigs/requirements/production.txt b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/requirements/production.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/wpt/web-platform-tests/tools/third_party/funcsigs/setup.cfg b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/setup.cfg new file mode 100644 index 00000000000..5e4090017a9 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/setup.cfg @@ -0,0 +1,2 @@ +[wheel] +universal = 1 diff --git a/tests/wpt/web-platform-tests/tools/third_party/funcsigs/setup.py b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/setup.py new file mode 100644 index 00000000000..98b09126045 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/setup.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +from setuptools import setup +import re +import sys + +def load_version(filename='funcsigs/version.py'): + "Parse a __version__ number from a source file" + with open(filename) as source: + text = source.read() + match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", text) + if not match: + msg = "Unable to find version number in {}".format(filename) + raise RuntimeError(msg) + version = match.group(1) + return version + +def load_rst(filename='docs/source/guide_content.rst'): + "Purge refs directives from restructured text" + with open(filename) as source: + text = source.read() + doc = re.sub(r':\w+:`~?([a-zA-Z._()]+)`', r'*\1*', text) + return doc + +setup( + name="funcsigs", + version=load_version(), + packages=['funcsigs'], + zip_safe=False, + author="Aaron Iles", + author_email="aaron.iles@gmail.com", + url="http://funcsigs.readthedocs.org", + description="Python function signatures from PEP362 for Python 2.6, 2.7 and 3.2+", + long_description=open('README.rst').read(), + # long_description=load_rst(), + license="ASL", + install_requires = [], + classifiers = [ + 'Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: Apache Software License', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.2', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: Implementation :: CPython', + 'Programming Language :: Python :: Implementation :: PyPy', + 'Topic :: Software Development :: Libraries :: Python Modules' + ], + tests_require = [] if sys.version_info[0] > 2 else ['unittest2'], + test_suite = "tests" if sys.version_info[0] > 2 else 'unittest2.collector' +) diff --git a/tests/wpt/web-platform-tests/tools/third_party/funcsigs/tests/__init__.py b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/tests/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/wpt/web-platform-tests/tools/third_party/funcsigs/tests/test_formatannotation.py b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/tests/test_formatannotation.py new file mode 100644 index 00000000000..fd7a8873f85 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/tests/test_formatannotation.py @@ -0,0 +1,27 @@ +try: + # python 2.x + import unittest2 as unittest +except ImportError: + # python 3.x + import unittest + +import funcsigs + + +class TestFormatAnnotation(unittest.TestCase): + def test_string (self): + self.assertEqual(funcsigs.formatannotation("annotation"), + "'annotation'") + + def test_builtin_type (self): + self.assertEqual(funcsigs.formatannotation(int), + "int") + + def test_user_type (self): + class dummy (object): pass + self.assertEqual(funcsigs.formatannotation(dummy), + "tests.test_formatannotation.dummy") + + +if __name__ == "__main__": + unittest.begin() diff --git a/tests/wpt/web-platform-tests/tools/third_party/funcsigs/tests/test_funcsigs.py b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/tests/test_funcsigs.py new file mode 100644 index 00000000000..eecc0a8a709 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/tests/test_funcsigs.py @@ -0,0 +1,93 @@ +try: + # python 2.x + import unittest2 as unittest +except ImportError: + # python 3.x + import unittest + +import doctest +import sys + +import funcsigs as inspect + + +class TestFunctionSignatures(unittest.TestCase): + + @staticmethod + def signature(func): + sig = inspect.signature(func) + return (tuple((param.name, + (Ellipsis if param.default is param.empty else param.default), + (Ellipsis if param.annotation is param.empty + else param.annotation), + str(param.kind).lower()) + for param in sig.parameters.values()), + (Ellipsis if sig.return_annotation is sig.empty + else sig.return_annotation)) + + def test_zero_arguments(self): + def test(): + pass + self.assertEqual(self.signature(test), + ((), Ellipsis)) + + def test_single_positional_argument(self): + def test(a): + pass + self.assertEqual(self.signature(test), + (((('a', Ellipsis, Ellipsis, "positional_or_keyword")),), Ellipsis)) + + def test_single_keyword_argument(self): + def test(a=None): + pass + self.assertEqual(self.signature(test), + (((('a', None, Ellipsis, "positional_or_keyword")),), Ellipsis)) + + def test_var_args(self): + def test(*args): + pass + self.assertEqual(self.signature(test), + (((('args', Ellipsis, Ellipsis, "var_positional")),), Ellipsis)) + + def test_keywords_args(self): + def test(**kwargs): + pass + self.assertEqual(self.signature(test), + (((('kwargs', Ellipsis, Ellipsis, "var_keyword")),), Ellipsis)) + + def test_multiple_arguments(self): + def test(a, b=None, *args, **kwargs): + pass + self.assertEqual(self.signature(test), (( + ('a', Ellipsis, Ellipsis, "positional_or_keyword"), + ('b', None, Ellipsis, "positional_or_keyword"), + ('args', Ellipsis, Ellipsis, "var_positional"), + ('kwargs', Ellipsis, Ellipsis, "var_keyword"), + ), Ellipsis)) + + def test_has_version(self): + self.assertTrue(inspect.__version__) + + def test_readme(self): + doctest.testfile('../README.rst') + + def test_unbound_method(self): + if sys.version_info < (3,): + self_kind = "positional_only" + else: + self_kind = "positional_or_keyword" + class Test(object): + def method(self): + pass + def method_with_args(self, a): + pass + self.assertEqual(self.signature(Test.method), + (((('self', Ellipsis, Ellipsis, self_kind)),), Ellipsis)) + self.assertEqual(self.signature(Test.method_with_args), (( + ('self', Ellipsis, Ellipsis, self_kind), + ('a', Ellipsis, Ellipsis, "positional_or_keyword"), + ), Ellipsis)) + + +if __name__ == "__main__": + unittest.begin() diff --git a/tests/wpt/web-platform-tests/tools/third_party/funcsigs/tests/test_inspect.py b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/tests/test_inspect.py new file mode 100644 index 00000000000..323c323eafd --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/funcsigs/tests/test_inspect.py @@ -0,0 +1,1019 @@ +# Copyright 2001-2013 Python Software Foundation; All Rights Reserved +from __future__ import absolute_import, division, print_function +import collections +import sys + +try: + import unittest2 as unittest +except ImportError: + import unittest + +import funcsigs as inspect + + +class TestSignatureObject(unittest.TestCase): + @staticmethod + def signature(func): + sig = inspect.signature(func) + return (tuple((param.name, + (Ellipsis if param.default is param.empty else param.default), + (Ellipsis if param.annotation is param.empty + else param.annotation), + str(param.kind).lower()) + for param in sig.parameters.values()), + (Ellipsis if sig.return_annotation is sig.empty + else sig.return_annotation)) + + def __init__(self, *args, **kwargs): + unittest.TestCase.__init__(self, *args, **kwargs) + if not hasattr(self, 'assertRaisesRegex'): + self.assertRaisesRegex = self.assertRaisesRegexp + + if sys.version_info[0] > 2: + exec(""" +def test_signature_object(self): + S = inspect.Signature + P = inspect.Parameter + + self.assertEqual(str(S()), '()') + + def test(po, pk, *args, ko, **kwargs): + pass + sig = inspect.signature(test) + po = sig.parameters['po'].replace(kind=P.POSITIONAL_ONLY) + pk = sig.parameters['pk'] + args = sig.parameters['args'] + ko = sig.parameters['ko'] + kwargs = sig.parameters['kwargs'] + + S((po, pk, args, ko, kwargs)) + + with self.assertRaisesRegex(ValueError, 'wrong parameter order'): + S((pk, po, args, ko, kwargs)) + + with self.assertRaisesRegex(ValueError, 'wrong parameter order'): + S((po, args, pk, ko, kwargs)) + + with self.assertRaisesRegex(ValueError, 'wrong parameter order'): + S((args, po, pk, ko, kwargs)) + + with self.assertRaisesRegex(ValueError, 'wrong parameter order'): + S((po, pk, args, kwargs, ko)) + + kwargs2 = kwargs.replace(name='args') + with self.assertRaisesRegex(ValueError, 'duplicate parameter name'): + S((po, pk, args, kwargs2, ko)) +""") + + def test_signature_immutability(self): + def test(a): + pass + sig = inspect.signature(test) + + with self.assertRaises(AttributeError): + sig.foo = 'bar' + + # Python2 does not have MappingProxyType class + if sys.version_info[:2] < (3, 3): + return + + with self.assertRaises(TypeError): + sig.parameters['a'] = None + + def test_signature_on_noarg(self): + def test(): + pass + self.assertEqual(self.signature(test), ((), Ellipsis)) + + if sys.version_info[0] > 2: + exec(""" +def test_signature_on_wargs(self): + def test(a, b:'foo') -> 123: + pass + self.assertEqual(self.signature(test), + ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), + ('b', Ellipsis, 'foo', "positional_or_keyword")), + 123)) +""") + + if sys.version_info[0] > 2: + exec(""" +def test_signature_on_wkwonly(self): + def test(*, a:float, b:str) -> int: + pass + self.assertEqual(self.signature(test), + ((('a', Ellipsis, float, "keyword_only"), + ('b', Ellipsis, str, "keyword_only")), + int)) +""") + + if sys.version_info[0] > 2: + exec(""" +def test_signature_on_complex_args(self): + def test(a, b:'foo'=10, *args:'bar', spam:'baz', ham=123, **kwargs:int): + pass + self.assertEqual(self.signature(test), + ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), + ('b', 10, 'foo', "positional_or_keyword"), + ('args', Ellipsis, 'bar', "var_positional"), + ('spam', Ellipsis, 'baz', "keyword_only"), + ('ham', 123, Ellipsis, "keyword_only"), + ('kwargs', Ellipsis, int, "var_keyword")), + Ellipsis)) +""") + + def test_signature_on_builtin_function(self): + with self.assertRaisesRegex(ValueError, 'not supported by signature'): + inspect.signature(type) + with self.assertRaisesRegex(ValueError, 'not supported by signature'): + # support for 'wrapper_descriptor' + inspect.signature(type.__call__) + if hasattr(sys, 'pypy_version_info'): + raise ValueError('not supported by signature') + with self.assertRaisesRegex(ValueError, 'not supported by signature'): + # support for 'method-wrapper' + inspect.signature(min.__call__) + if hasattr(sys, 'pypy_version_info'): + raise ValueError('not supported by signature') + with self.assertRaisesRegex(ValueError, + 'no signature found for builtin function'): + # support for 'method-wrapper' + inspect.signature(min) + + def test_signature_on_non_function(self): + with self.assertRaisesRegex(TypeError, 'is not a callable object'): + inspect.signature(42) + + with self.assertRaisesRegex(TypeError, 'is not a Python function'): + inspect.Signature.from_function(42) + + if sys.version_info[0] > 2: + exec(""" +def test_signature_on_method(self): + class Test: + def foo(self, arg1, arg2=1) -> int: + pass + + meth = Test().foo + + self.assertEqual(self.signature(meth), + ((('arg1', Ellipsis, Ellipsis, "positional_or_keyword"), + ('arg2', 1, Ellipsis, "positional_or_keyword")), + int)) +""") + + if sys.version_info[0] > 2: + exec(""" +def test_signature_on_classmethod(self): + class Test: + @classmethod + def foo(cls, arg1, *, arg2=1): + pass + + meth = Test().foo + self.assertEqual(self.signature(meth), + ((('arg1', Ellipsis, Ellipsis, "positional_or_keyword"), + ('arg2', 1, Ellipsis, "keyword_only")), + Ellipsis)) + + meth = Test.foo + self.assertEqual(self.signature(meth), + ((('arg1', Ellipsis, Ellipsis, "positional_or_keyword"), + ('arg2', 1, Ellipsis, "keyword_only")), + Ellipsis)) +""") + + if sys.version_info[0] > 2: + exec(""" +def test_signature_on_staticmethod(self): + class Test: + @staticmethod + def foo(cls, *, arg): + pass + + meth = Test().foo + self.assertEqual(self.signature(meth), + ((('cls', Ellipsis, Ellipsis, "positional_or_keyword"), + ('arg', Ellipsis, Ellipsis, "keyword_only")), + Ellipsis)) + + meth = Test.foo + self.assertEqual(self.signature(meth), + ((('cls', Ellipsis, Ellipsis, "positional_or_keyword"), + ('arg', Ellipsis, Ellipsis, "keyword_only")), + Ellipsis)) +""") + + if sys.version_info[0] > 2: + exec(""" +def test_signature_on_partial(self): + from functools import partial + + def test(): + pass + + self.assertEqual(self.signature(partial(test)), ((), Ellipsis)) + + with self.assertRaisesRegex(ValueError, "has incorrect arguments"): + inspect.signature(partial(test, 1)) + + with self.assertRaisesRegex(ValueError, "has incorrect arguments"): + inspect.signature(partial(test, a=1)) + + def test(a, b, *, c, d): + pass + + self.assertEqual(self.signature(partial(test)), + ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), + ('b', Ellipsis, Ellipsis, "positional_or_keyword"), + ('c', Ellipsis, Ellipsis, "keyword_only"), + ('d', Ellipsis, Ellipsis, "keyword_only")), + Ellipsis)) + + self.assertEqual(self.signature(partial(test, 1)), + ((('b', Ellipsis, Ellipsis, "positional_or_keyword"), + ('c', Ellipsis, Ellipsis, "keyword_only"), + ('d', Ellipsis, Ellipsis, "keyword_only")), + Ellipsis)) + + self.assertEqual(self.signature(partial(test, 1, c=2)), + ((('b', Ellipsis, Ellipsis, "positional_or_keyword"), + ('c', 2, Ellipsis, "keyword_only"), + ('d', Ellipsis, Ellipsis, "keyword_only")), + Ellipsis)) + + self.assertEqual(self.signature(partial(test, b=1, c=2)), + ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), + ('b', 1, Ellipsis, "positional_or_keyword"), + ('c', 2, Ellipsis, "keyword_only"), + ('d', Ellipsis, Ellipsis, "keyword_only")), + Ellipsis)) + + self.assertEqual(self.signature(partial(test, 0, b=1, c=2)), + ((('b', 1, Ellipsis, "positional_or_keyword"), + ('c', 2, Ellipsis, "keyword_only"), + ('d', Ellipsis, Ellipsis, "keyword_only"),), + Ellipsis)) + + def test(a, *args, b, **kwargs): + pass + + self.assertEqual(self.signature(partial(test, 1)), + ((('args', Ellipsis, Ellipsis, "var_positional"), + ('b', Ellipsis, Ellipsis, "keyword_only"), + ('kwargs', Ellipsis, Ellipsis, "var_keyword")), + Ellipsis)) + + self.assertEqual(self.signature(partial(test, 1, 2, 3)), + ((('args', Ellipsis, Ellipsis, "var_positional"), + ('b', Ellipsis, Ellipsis, "keyword_only"), + ('kwargs', Ellipsis, Ellipsis, "var_keyword")), + Ellipsis)) + + + self.assertEqual(self.signature(partial(test, 1, 2, 3, test=True)), + ((('args', Ellipsis, Ellipsis, "var_positional"), + ('b', Ellipsis, Ellipsis, "keyword_only"), + ('kwargs', Ellipsis, Ellipsis, "var_keyword")), + Ellipsis)) + + self.assertEqual(self.signature(partial(test, 1, 2, 3, test=1, b=0)), + ((('args', Ellipsis, Ellipsis, "var_positional"), + ('b', 0, Ellipsis, "keyword_only"), + ('kwargs', Ellipsis, Ellipsis, "var_keyword")), + Ellipsis)) + + self.assertEqual(self.signature(partial(test, b=0)), + ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), + ('args', Ellipsis, Ellipsis, "var_positional"), + ('b', 0, Ellipsis, "keyword_only"), + ('kwargs', Ellipsis, Ellipsis, "var_keyword")), + Ellipsis)) + + self.assertEqual(self.signature(partial(test, b=0, test=1)), + ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), + ('args', Ellipsis, Ellipsis, "var_positional"), + ('b', 0, Ellipsis, "keyword_only"), + ('kwargs', Ellipsis, Ellipsis, "var_keyword")), + Ellipsis)) + + def test(a, b, c:int) -> 42: + pass + + sig = test.__signature__ = inspect.signature(test) + + self.assertEqual(self.signature(partial(partial(test, 1))), + ((('b', Ellipsis, Ellipsis, "positional_or_keyword"), + ('c', Ellipsis, int, "positional_or_keyword")), + 42)) + + self.assertEqual(self.signature(partial(partial(test, 1), 2)), + ((('c', Ellipsis, int, "positional_or_keyword"),), + 42)) + + psig = inspect.signature(partial(partial(test, 1), 2)) + + def foo(a): + return a + _foo = partial(partial(foo, a=10), a=20) + self.assertEqual(self.signature(_foo), + ((('a', 20, Ellipsis, "positional_or_keyword"),), + Ellipsis)) + # check that we don't have any side-effects in signature(), + # and the partial object is still functioning + self.assertEqual(_foo(), 20) + + def foo(a, b, c): + return a, b, c + _foo = partial(partial(foo, 1, b=20), b=30) + self.assertEqual(self.signature(_foo), + ((('b', 30, Ellipsis, "positional_or_keyword"), + ('c', Ellipsis, Ellipsis, "positional_or_keyword")), + Ellipsis)) + self.assertEqual(_foo(c=10), (1, 30, 10)) + _foo = partial(_foo, 2) # now 'b' has two values - + # positional and keyword + with self.assertRaisesRegex(ValueError, "has incorrect arguments"): + inspect.signature(_foo) + + def foo(a, b, c, *, d): + return a, b, c, d + _foo = partial(partial(foo, d=20, c=20), b=10, d=30) + self.assertEqual(self.signature(_foo), + ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), + ('b', 10, Ellipsis, "positional_or_keyword"), + ('c', 20, Ellipsis, "positional_or_keyword"), + ('d', 30, Ellipsis, "keyword_only")), + Ellipsis)) + ba = inspect.signature(_foo).bind(a=200, b=11) + self.assertEqual(_foo(*ba.args, **ba.kwargs), (200, 11, 20, 30)) + + def foo(a=1, b=2, c=3): + return a, b, c + _foo = partial(foo, a=10, c=13) + ba = inspect.signature(_foo).bind(11) + self.assertEqual(_foo(*ba.args, **ba.kwargs), (11, 2, 13)) + ba = inspect.signature(_foo).bind(11, 12) + self.assertEqual(_foo(*ba.args, **ba.kwargs), (11, 12, 13)) + ba = inspect.signature(_foo).bind(11, b=12) + self.assertEqual(_foo(*ba.args, **ba.kwargs), (11, 12, 13)) + ba = inspect.signature(_foo).bind(b=12) + self.assertEqual(_foo(*ba.args, **ba.kwargs), (10, 12, 13)) + _foo = partial(_foo, b=10) + ba = inspect.signature(_foo).bind(12, 14) + self.assertEqual(_foo(*ba.args, **ba.kwargs), (12, 14, 13)) +""") + + if sys.version_info[0] > 2: + exec(""" +def test_signature_on_decorated(self): + import functools + + def decorator(func): + @functools.wraps(func) + def wrapper(*args, **kwargs) -> int: + return func(*args, **kwargs) + return wrapper + + class Foo: + @decorator + def bar(self, a, b): + pass + + self.assertEqual(self.signature(Foo.bar), + ((('self', Ellipsis, Ellipsis, "positional_or_keyword"), + ('a', Ellipsis, Ellipsis, "positional_or_keyword"), + ('b', Ellipsis, Ellipsis, "positional_or_keyword")), + Ellipsis)) + + self.assertEqual(self.signature(Foo().bar), + ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), + ('b', Ellipsis, Ellipsis, "positional_or_keyword")), + Ellipsis)) + + # Test that we handle method wrappers correctly + def decorator(func): + @functools.wraps(func) + def wrapper(*args, **kwargs) -> int: + return func(42, *args, **kwargs) + sig = inspect.signature(func) + new_params = tuple(sig.parameters.values())[1:] + wrapper.__signature__ = sig.replace(parameters=new_params) + return wrapper + + class Foo: + @decorator + def __call__(self, a, b): + pass + + self.assertEqual(self.signature(Foo.__call__), + ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), + ('b', Ellipsis, Ellipsis, "positional_or_keyword")), + Ellipsis)) + + self.assertEqual(self.signature(Foo().__call__), + ((('b', Ellipsis, Ellipsis, "positional_or_keyword"),), + Ellipsis)) +""") + + if sys.version_info[0] > 2: + exec(""" +def test_signature_on_class(self): + class C: + def __init__(self, a): + pass + + self.assertEqual(self.signature(C), + ((('a', Ellipsis, Ellipsis, "positional_or_keyword"),), + Ellipsis)) + + class CM(type): + def __call__(cls, a): + pass + class C(metaclass=CM): + def __init__(self, b): + pass + + self.assertEqual(self.signature(C), + ((('a', Ellipsis, Ellipsis, "positional_or_keyword"),), + Ellipsis)) + + class CM(type): + def __new__(mcls, name, bases, dct, *, foo=1): + return super().__new__(mcls, name, bases, dct) + class C(metaclass=CM): + def __init__(self, b): + pass + + self.assertEqual(self.signature(C), + ((('b', Ellipsis, Ellipsis, "positional_or_keyword"),), + Ellipsis)) + + self.assertEqual(self.signature(CM), + ((('name', Ellipsis, Ellipsis, "positional_or_keyword"), + ('bases', Ellipsis, Ellipsis, "positional_or_keyword"), + ('dct', Ellipsis, Ellipsis, "positional_or_keyword"), + ('foo', 1, Ellipsis, "keyword_only")), + Ellipsis)) + + class CMM(type): + def __new__(mcls, name, bases, dct, *, foo=1): + return super().__new__(mcls, name, bases, dct) + def __call__(cls, nm, bs, dt): + return type(nm, bs, dt) + class CM(type, metaclass=CMM): + def __new__(mcls, name, bases, dct, *, bar=2): + return super().__new__(mcls, name, bases, dct) + class C(metaclass=CM): + def __init__(self, b): + pass + + self.assertEqual(self.signature(CMM), + ((('name', Ellipsis, Ellipsis, "positional_or_keyword"), + ('bases', Ellipsis, Ellipsis, "positional_or_keyword"), + ('dct', Ellipsis, Ellipsis, "positional_or_keyword"), + ('foo', 1, Ellipsis, "keyword_only")), + Ellipsis)) + + self.assertEqual(self.signature(CM), + ((('nm', Ellipsis, Ellipsis, "positional_or_keyword"), + ('bs', Ellipsis, Ellipsis, "positional_or_keyword"), + ('dt', Ellipsis, Ellipsis, "positional_or_keyword")), + Ellipsis)) + + self.assertEqual(self.signature(C), + ((('b', Ellipsis, Ellipsis, "positional_or_keyword"),), + Ellipsis)) + + class CM(type): + def __init__(cls, name, bases, dct, *, bar=2): + return super().__init__(name, bases, dct) + class C(metaclass=CM): + def __init__(self, b): + pass + + self.assertEqual(self.signature(CM), + ((('name', Ellipsis, Ellipsis, "positional_or_keyword"), + ('bases', Ellipsis, Ellipsis, "positional_or_keyword"), + ('dct', Ellipsis, Ellipsis, "positional_or_keyword"), + ('bar', 2, Ellipsis, "keyword_only")), + Ellipsis)) +""") + + def test_signature_on_callable_objects(self): + class Foo(object): + def __call__(self, a): + pass + + self.assertEqual(self.signature(Foo()), + ((('a', Ellipsis, Ellipsis, "positional_or_keyword"),), + Ellipsis)) + + class Spam(object): + pass + with self.assertRaisesRegex(TypeError, "is not a callable object"): + inspect.signature(Spam()) + + class Bar(Spam, Foo): + pass + + self.assertEqual(self.signature(Bar()), + ((('a', Ellipsis, Ellipsis, "positional_or_keyword"),), + Ellipsis)) + + class ToFail(object): + __call__ = type + with self.assertRaisesRegex(ValueError, "not supported by signature"): + inspect.signature(ToFail()) + + if sys.version_info[0] < 3: + return + + class Wrapped(object): + pass + Wrapped.__wrapped__ = lambda a: None + self.assertEqual(self.signature(Wrapped), + ((('a', Ellipsis, Ellipsis, "positional_or_keyword"),), + Ellipsis)) + + def test_signature_on_lambdas(self): + self.assertEqual(self.signature((lambda a=10: a)), + ((('a', 10, Ellipsis, "positional_or_keyword"),), + Ellipsis)) + + if sys.version_info[0] > 2: + exec(""" +def test_signature_equality(self): + def foo(a, *, b:int) -> float: pass + self.assertNotEqual(inspect.signature(foo), 42) + + def bar(a, *, b:int) -> float: pass + self.assertEqual(inspect.signature(foo), inspect.signature(bar)) + + def bar(a, *, b:int) -> int: pass + self.assertNotEqual(inspect.signature(foo), inspect.signature(bar)) + + def bar(a, *, b:int): pass + self.assertNotEqual(inspect.signature(foo), inspect.signature(bar)) + + def bar(a, *, b:int=42) -> float: pass + self.assertNotEqual(inspect.signature(foo), inspect.signature(bar)) + + def bar(a, *, c) -> float: pass + self.assertNotEqual(inspect.signature(foo), inspect.signature(bar)) + + def bar(a, b:int) -> float: pass + self.assertNotEqual(inspect.signature(foo), inspect.signature(bar)) + def spam(b:int, a) -> float: pass + self.assertNotEqual(inspect.signature(spam), inspect.signature(bar)) + + def foo(*, a, b, c): pass + def bar(*, c, b, a): pass + self.assertEqual(inspect.signature(foo), inspect.signature(bar)) + + def foo(*, a=1, b, c): pass + def bar(*, c, b, a=1): pass + self.assertEqual(inspect.signature(foo), inspect.signature(bar)) + + def foo(pos, *, a=1, b, c): pass + def bar(pos, *, c, b, a=1): pass + self.assertEqual(inspect.signature(foo), inspect.signature(bar)) + + def foo(pos, *, a, b, c): pass + def bar(pos, *, c, b, a=1): pass + self.assertNotEqual(inspect.signature(foo), inspect.signature(bar)) + + def foo(pos, *args, a=42, b, c, **kwargs:int): pass + def bar(pos, *args, c, b, a=42, **kwargs:int): pass + self.assertEqual(inspect.signature(foo), inspect.signature(bar)) +""") + + def test_signature_unhashable(self): + def foo(a): pass + sig = inspect.signature(foo) + with self.assertRaisesRegex(TypeError, 'unhashable type'): + hash(sig) + + + if sys.version_info[0] > 2: + exec(""" +def test_signature_str(self): + def foo(a:int=1, *, b, c=None, **kwargs) -> 42: + pass + self.assertEqual(str(inspect.signature(foo)), + '(a:int=1, *, b, c=None, **kwargs) -> 42') + + def foo(a:int=1, *args, b, c=None, **kwargs) -> 42: + pass + self.assertEqual(str(inspect.signature(foo)), + '(a:int=1, *args, b, c=None, **kwargs) -> 42') + + def foo(): + pass + self.assertEqual(str(inspect.signature(foo)), '()') +""") + + if sys.version_info[0] > 2: + exec(""" +def test_signature_str_positional_only(self): + P = inspect.Parameter + + def test(a_po, *, b, **kwargs): + return a_po, kwargs + + sig = inspect.signature(test) + new_params = list(sig.parameters.values()) + new_params[0] = new_params[0].replace(kind=P.POSITIONAL_ONLY) + test.__signature__ = sig.replace(parameters=new_params) + + self.assertEqual(str(inspect.signature(test)), + '(, *, b, **kwargs)') + + sig = inspect.signature(test) + new_params = list(sig.parameters.values()) + new_params[0] = new_params[0].replace(name=None) + test.__signature__ = sig.replace(parameters=new_params) + self.assertEqual(str(inspect.signature(test)), + '(<0>, *, b, **kwargs)') +""") + + if sys.version_info[0] > 2: + exec(""" +def test_signature_replace_anno(self): + def test() -> 42: + pass + + sig = inspect.signature(test) + sig = sig.replace(return_annotation=None) + self.assertIs(sig.return_annotation, None) + sig = sig.replace(return_annotation=sig.empty) + self.assertIs(sig.return_annotation, sig.empty) + sig = sig.replace(return_annotation=42) + self.assertEqual(sig.return_annotation, 42) + self.assertEqual(sig, inspect.signature(test)) +""") + + +class TestParameterObject(unittest.TestCase): + + def __init__(self, *args, **kwargs): + unittest.TestCase.__init__(self, *args, **kwargs) + if not hasattr(self, 'assertRaisesRegex'): + self.assertRaisesRegex = self.assertRaisesRegexp + + def test_signature_parameter_kinds(self): + P = inspect.Parameter + self.assertTrue(P.POSITIONAL_ONLY < P.POSITIONAL_OR_KEYWORD < \ + P.VAR_POSITIONAL < P.KEYWORD_ONLY < P.VAR_KEYWORD) + + self.assertEqual(str(P.POSITIONAL_ONLY), 'POSITIONAL_ONLY') + self.assertTrue('POSITIONAL_ONLY' in repr(P.POSITIONAL_ONLY)) + + def test_signature_parameter_object(self): + p = inspect.Parameter('foo', default=10, + kind=inspect.Parameter.POSITIONAL_ONLY) + self.assertEqual(p.name, 'foo') + self.assertEqual(p.default, 10) + self.assertIs(p.annotation, p.empty) + self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY) + + with self.assertRaisesRegex(ValueError, 'invalid value'): + inspect.Parameter('foo', default=10, kind='123') + + with self.assertRaisesRegex(ValueError, 'not a valid parameter name'): + inspect.Parameter('1', kind=inspect.Parameter.VAR_KEYWORD) + + with self.assertRaisesRegex(ValueError, + 'non-positional-only parameter'): + inspect.Parameter(None, kind=inspect.Parameter.VAR_KEYWORD) + + with self.assertRaisesRegex(ValueError, 'cannot have default values'): + inspect.Parameter('a', default=42, + kind=inspect.Parameter.VAR_KEYWORD) + + with self.assertRaisesRegex(ValueError, 'cannot have default values'): + inspect.Parameter('a', default=42, + kind=inspect.Parameter.VAR_POSITIONAL) + + p = inspect.Parameter('a', default=42, + kind=inspect.Parameter.POSITIONAL_OR_KEYWORD) + with self.assertRaisesRegex(ValueError, 'cannot have default values'): + p.replace(kind=inspect.Parameter.VAR_POSITIONAL) + + self.assertTrue(repr(p).startswith('') + + p = p.replace(name='1') + self.assertEqual(str(p), '<1>') + + def test_signature_parameter_immutability(self): + p = inspect.Parameter(None, kind=inspect.Parameter.POSITIONAL_ONLY) + + with self.assertRaises(AttributeError): + p.foo = 'bar' + + with self.assertRaises(AttributeError): + p.kind = 123 + + +class TestSignatureBind(unittest.TestCase): + @staticmethod + def call(func, *args, **kwargs): + sig = inspect.signature(func) + ba = sig.bind(*args, **kwargs) + return func(*ba.args, **ba.kwargs) + + def __init__(self, *args, **kwargs): + unittest.TestCase.__init__(self, *args, **kwargs) + if not hasattr(self, 'assertRaisesRegex'): + self.assertRaisesRegex = self.assertRaisesRegexp + + def test_signature_bind_empty(self): + def test(): + return 42 + + self.assertEqual(self.call(test), 42) + with self.assertRaisesRegex(TypeError, 'too many positional arguments'): + self.call(test, 1) + with self.assertRaisesRegex(TypeError, 'too many positional arguments'): + self.call(test, 1, spam=10) + with self.assertRaisesRegex(TypeError, 'too many keyword arguments'): + self.call(test, spam=1) + + def test_signature_bind_var(self): + def test(*args, **kwargs): + return args, kwargs + + self.assertEqual(self.call(test), ((), {})) + self.assertEqual(self.call(test, 1), ((1,), {})) + self.assertEqual(self.call(test, 1, 2), ((1, 2), {})) + self.assertEqual(self.call(test, foo='bar'), ((), {'foo': 'bar'})) + self.assertEqual(self.call(test, 1, foo='bar'), ((1,), {'foo': 'bar'})) + self.assertEqual(self.call(test, args=10), ((), {'args': 10})) + self.assertEqual(self.call(test, 1, 2, foo='bar'), + ((1, 2), {'foo': 'bar'})) + + def test_signature_bind_just_args(self): + def test(a, b, c): + return a, b, c + + self.assertEqual(self.call(test, 1, 2, 3), (1, 2, 3)) + + with self.assertRaisesRegex(TypeError, 'too many positional arguments'): + self.call(test, 1, 2, 3, 4) + + with self.assertRaisesRegex(TypeError, "'b' parameter lacking default"): + self.call(test, 1) + + with self.assertRaisesRegex(TypeError, "'a' parameter lacking default"): + self.call(test) + + def test(a, b, c=10): + return a, b, c + self.assertEqual(self.call(test, 1, 2, 3), (1, 2, 3)) + self.assertEqual(self.call(test, 1, 2), (1, 2, 10)) + + def test(a=1, b=2, c=3): + return a, b, c + self.assertEqual(self.call(test, a=10, c=13), (10, 2, 13)) + self.assertEqual(self.call(test, a=10), (10, 2, 3)) + self.assertEqual(self.call(test, b=10), (1, 10, 3)) + + def test_signature_bind_varargs_order(self): + def test(*args): + return args + + self.assertEqual(self.call(test), ()) + self.assertEqual(self.call(test, 1, 2, 3), (1, 2, 3)) + + def test_signature_bind_args_and_varargs(self): + def test(a, b, c=3, *args): + return a, b, c, args + + self.assertEqual(self.call(test, 1, 2, 3, 4, 5), (1, 2, 3, (4, 5))) + self.assertEqual(self.call(test, 1, 2), (1, 2, 3, ())) + self.assertEqual(self.call(test, b=1, a=2), (2, 1, 3, ())) + self.assertEqual(self.call(test, 1, b=2), (1, 2, 3, ())) + + with self.assertRaisesRegex(TypeError, + "multiple values for argument 'c'"): + self.call(test, 1, 2, 3, c=4) + + def test_signature_bind_just_kwargs(self): + def test(**kwargs): + return kwargs + + self.assertEqual(self.call(test), {}) + self.assertEqual(self.call(test, foo='bar', spam='ham'), + {'foo': 'bar', 'spam': 'ham'}) + + def test_signature_bind_args_and_kwargs(self): + def test(a, b, c=3, **kwargs): + return a, b, c, kwargs + + self.assertEqual(self.call(test, 1, 2), (1, 2, 3, {})) + self.assertEqual(self.call(test, 1, 2, foo='bar', spam='ham'), + (1, 2, 3, {'foo': 'bar', 'spam': 'ham'})) + self.assertEqual(self.call(test, b=2, a=1, foo='bar', spam='ham'), + (1, 2, 3, {'foo': 'bar', 'spam': 'ham'})) + self.assertEqual(self.call(test, a=1, b=2, foo='bar', spam='ham'), + (1, 2, 3, {'foo': 'bar', 'spam': 'ham'})) + self.assertEqual(self.call(test, 1, b=2, foo='bar', spam='ham'), + (1, 2, 3, {'foo': 'bar', 'spam': 'ham'})) + self.assertEqual(self.call(test, 1, b=2, c=4, foo='bar', spam='ham'), + (1, 2, 4, {'foo': 'bar', 'spam': 'ham'})) + self.assertEqual(self.call(test, 1, 2, 4, foo='bar'), + (1, 2, 4, {'foo': 'bar'})) + self.assertEqual(self.call(test, c=5, a=4, b=3), + (4, 3, 5, {})) + + if sys.version_info[0] > 2: + exec(""" +def test_signature_bind_kwonly(self): + def test(*, foo): + return foo + with self.assertRaisesRegex(TypeError, + 'too many positional arguments'): + self.call(test, 1) + self.assertEqual(self.call(test, foo=1), 1) + + def test(a, *, foo=1, bar): + return foo + with self.assertRaisesRegex(TypeError, + "'bar' parameter lacking default value"): + self.call(test, 1) + + def test(foo, *, bar): + return foo, bar + self.assertEqual(self.call(test, 1, bar=2), (1, 2)) + self.assertEqual(self.call(test, bar=2, foo=1), (1, 2)) + + with self.assertRaisesRegex(TypeError, + 'too many keyword arguments'): + self.call(test, bar=2, foo=1, spam=10) + + with self.assertRaisesRegex(TypeError, + 'too many positional arguments'): + self.call(test, 1, 2) + + with self.assertRaisesRegex(TypeError, + 'too many positional arguments'): + self.call(test, 1, 2, bar=2) + + with self.assertRaisesRegex(TypeError, + 'too many keyword arguments'): + self.call(test, 1, bar=2, spam='ham') + + with self.assertRaisesRegex(TypeError, + "'bar' parameter lacking default value"): + self.call(test, 1) + + def test(foo, *, bar, **bin): + return foo, bar, bin + self.assertEqual(self.call(test, 1, bar=2), (1, 2, {})) + self.assertEqual(self.call(test, foo=1, bar=2), (1, 2, {})) + self.assertEqual(self.call(test, 1, bar=2, spam='ham'), + (1, 2, {'spam': 'ham'})) + self.assertEqual(self.call(test, spam='ham', foo=1, bar=2), + (1, 2, {'spam': 'ham'})) + with self.assertRaisesRegex(TypeError, + "'foo' parameter lacking default value"): + self.call(test, spam='ham', bar=2) + self.assertEqual(self.call(test, 1, bar=2, bin=1, spam=10), + (1, 2, {'bin': 1, 'spam': 10})) +""") +# + if sys.version_info[0] > 2: + exec(""" +def test_signature_bind_arguments(self): + def test(a, *args, b, z=100, **kwargs): + pass + sig = inspect.signature(test) + ba = sig.bind(10, 20, b=30, c=40, args=50, kwargs=60) + # we won't have 'z' argument in the bound arguments object, as we didn't + # pass it to the 'bind' + self.assertEqual(tuple(ba.arguments.items()), + (('a', 10), ('args', (20,)), ('b', 30), + ('kwargs', {'c': 40, 'args': 50, 'kwargs': 60}))) + self.assertEqual(ba.kwargs, + {'b': 30, 'c': 40, 'args': 50, 'kwargs': 60}) + self.assertEqual(ba.args, (10, 20)) +""") +# + if sys.version_info[0] > 2: + exec(""" +def test_signature_bind_positional_only(self): + P = inspect.Parameter + + def test(a_po, b_po, c_po=3, foo=42, *, bar=50, **kwargs): + return a_po, b_po, c_po, foo, bar, kwargs + + sig = inspect.signature(test) + new_params = collections.OrderedDict(tuple(sig.parameters.items())) + for name in ('a_po', 'b_po', 'c_po'): + new_params[name] = new_params[name].replace(kind=P.POSITIONAL_ONLY) + new_sig = sig.replace(parameters=new_params.values()) + test.__signature__ = new_sig + + self.assertEqual(self.call(test, 1, 2, 4, 5, bar=6), + (1, 2, 4, 5, 6, {})) + + with self.assertRaisesRegex(TypeError, "parameter is positional only"): + self.call(test, 1, 2, c_po=4) + + with self.assertRaisesRegex(TypeError, "parameter is positional only"): + self.call(test, a_po=1, b_po=2) +""") + + +class TestBoundArguments(unittest.TestCase): + + def __init__(self, *args, **kwargs): + unittest.TestCase.__init__(self, *args, **kwargs) + if not hasattr(self, 'assertRaisesRegex'): + self.assertRaisesRegex = self.assertRaisesRegexp + + def test_signature_bound_arguments_unhashable(self): + def foo(a): pass + ba = inspect.signature(foo).bind(1) + + with self.assertRaisesRegex(TypeError, 'unhashable type'): + hash(ba) + + def test_signature_bound_arguments_equality(self): + def foo(a): pass + ba = inspect.signature(foo).bind(1) + self.assertEqual(ba, ba) + + ba2 = inspect.signature(foo).bind(1) + self.assertEqual(ba, ba2) + + ba3 = inspect.signature(foo).bind(2) + self.assertNotEqual(ba, ba3) + ba3.arguments['a'] = 1 + self.assertEqual(ba, ba3) + + def bar(b): pass + ba4 = inspect.signature(bar).bind(1) + self.assertNotEqual(ba, ba4) + + +if __name__ == "__main__": + unittest.begin() diff --git a/tests/wpt/web-platform-tests/tools/third_party/pluggy/.gitignore b/tests/wpt/web-platform-tests/tools/third_party/pluggy/.gitignore new file mode 100644 index 00000000000..e5c7e98041c --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/.gitignore @@ -0,0 +1,58 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ +*.swp diff --git a/tests/wpt/web-platform-tests/tools/third_party/pluggy/.travis.yml b/tests/wpt/web-platform-tests/tools/third_party/pluggy/.travis.yml new file mode 100644 index 00000000000..6fd136baf37 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/.travis.yml @@ -0,0 +1,48 @@ +sudo: false +language: python + +matrix: + include: + - python: '3.6' + env: TOXENV=check + - python: '3.6' + env: TOXENV=docs + - python: '2.7' + env: TOXENV=py27-pytestrelease + - python: '3.4' + env: TOXENV=py34-pytestrelease + - python: '3.5' + env: TOXENV=py35-pytestrelease + - python: '3.6' + env: TOXENV=py36-pytestrelease + - python: 'pypy' + env: TOXENV=pypy-pytestrelease + - python: 'nightly' + env: TOXENV=py37-pytestrelease + - python: '2.7' + env: TOXENV=py27-pytestmaster + - python: '2.7' + env: TOXENV=py27-pytestfeatures + - python: '3.6' + env: TOXENV=py36-pytestmaster + - python: '3.6' + env: TOXENV=py36-pytestfeatures + - python: '3.6' + env: TOXENV=benchmark + +install: + - pip install -U setuptools pip + - pip install -U tox + +script: + - tox + +notifications: + irc: + channels: + - "chat.freenode.net#pytest" + on_success: change + on_failure: change + skip_join: true +# email: +# - pytest-commit@python.org diff --git a/tests/wpt/web-platform-tests/tools/third_party/pluggy/CHANGELOG.rst b/tests/wpt/web-platform-tests/tools/third_party/pluggy/CHANGELOG.rst new file mode 100644 index 00000000000..91bf53fdccb --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/CHANGELOG.rst @@ -0,0 +1,152 @@ +0.6.0 +----- +- Add CI testing for the features, release, and master + branches of ``pytest`` (PR `#79`_). +- Document public API for ``_Result`` objects passed to wrappers + (PR `#85`_). +- Document and test hook LIFO ordering (PR `#85`_). +- Turn warnings into errors in test suite (PR `#89`_). +- Deprecate ``_Result.result`` (PR `#88`_). +- Convert ``_Multicall`` to a simple function distinguishing it from + the legacy version (PR `#90`_). +- Resolve E741 errors (PR `#96`_). +- Test and bug fix for unmarked hook collection (PRs `#97`_ and + `#102`_). +- Drop support for EOL Python 2.6 and 3.3 (PR `#103`_). +- Fix ``inspect`` based arg introspection on py3.6 (PR `#94`_). + +.. _#79: https://github.com/pytest-dev/pluggy/pull/79 +.. _#85: https://github.com/pytest-dev/pluggy/pull/85 +.. _#88: https://github.com/pytest-dev/pluggy/pull/88 +.. _#89: https://github.com/pytest-dev/pluggy/pull/89 +.. _#90: https://github.com/pytest-dev/pluggy/pull/90 +.. _#94: https://github.com/pytest-dev/pluggy/pull/94 +.. _#96: https://github.com/pytest-dev/pluggy/pull/96 +.. _#97: https://github.com/pytest-dev/pluggy/pull/97 +.. _#102: https://github.com/pytest-dev/pluggy/pull/102 +.. _#103: https://github.com/pytest-dev/pluggy/pull/103 + + +0.5.2 +----- +- fix bug where ``firstresult`` wrappers were being sent an incorrectly configured + ``_Result`` (a list was set instead of a single value). Add tests to check for + this as well as ``_Result.force_result()`` behaviour. Thanks to `@tgoodlet`_ + for the PR `#72`_. + +- fix incorrect ``getattr`` of ``DeprecationWarning`` from the ``warnings`` + module. Thanks to `@nicoddemus`_ for the PR `#77`_. + +- hide ``pytest`` tracebacks in certain core routines. Thanks to + `@nicoddemus`_ for the PR `#80`_. + +.. _#72: https://github.com/pytest-dev/pluggy/pull/72 +.. _#77: https://github.com/pytest-dev/pluggy/pull/77 +.. _#80: https://github.com/pytest-dev/pluggy/pull/80 + + +0.5.1 +----- +- fix a bug and add tests for case where ``firstresult`` hooks return + ``None`` results. Thanks to `@RonnyPfannschmidt`_ and `@tgoodlet`_ + for the issue (`#68`_) and PR (`#69`_) respectively. + +.. _#69: https://github.com/pytest-dev/pluggy/pull/69 +.. _#68: https://github.com/pytest-dev/pluggy/issuses/68 + + +0.5.0 +----- +- fix bug where callbacks for historic hooks would not be called for + already registered plugins. Thanks `@vodik`_ for the PR + and `@hpk42`_ for further fixes. + +- fix `#17`_ by considering only actual functions for hooks + this removes the ability to register arbitrary callable objects + which at first glance is a reasonable simplification, + thanks `@RonnyPfannschmidt`_ for report and pr. + +- fix `#19`_: allow registering hookspecs from instances. The PR from + `@tgoodlet`_ also modernized the varnames implementation. + +- resolve `#32`_: split up the test set into multiple modules. + Thanks to `@RonnyPfannschmidt`_ for the PR and `@tgoodlet`_ for + the initial request. + +- resolve `#14`_: add full sphinx docs. Thanks to `@tgoodlet`_ for + PR `#39`_. + +- add hook call mismatch warnings. Thanks to `@tgoodlet`_ for the + PR `#42`_. + +- resolve `#44`_: move to new-style classes. Thanks to `@MichalTHEDUDE`_ + for PR `#46`_. + +- add baseline benchmarking/speed tests using ``pytest-benchmark`` + in PR `#54`_. Thanks to `@tgoodlet`_. + +- update the README to showcase the API. Thanks to `@tgoodlet`_ for the + issue and PR `#55`_. + +- deprecate ``__multicall__`` and add a faster call loop implementation. + Thanks to `@tgoodlet`_ for PR `#58`_. + +- raise a comprehensible error when a ``hookimpl`` is called with positional + args. Thanks to `@RonnyPfannschmidt`_ for the issue and `@tgoodlet`_ for + PR `#60`_. + +- fix the ``firstresult`` test making it more complete + and remove a duplicate of that test. Thanks to `@tgoodlet`_ + for PR `#62`_. + +.. _#62: https://github.com/pytest-dev/pluggy/pull/62 +.. _#60: https://github.com/pytest-dev/pluggy/pull/60 +.. _#58: https://github.com/pytest-dev/pluggy/pull/58 +.. _#55: https://github.com/pytest-dev/pluggy/pull/55 +.. _#54: https://github.com/pytest-dev/pluggy/pull/54 +.. _#46: https://github.com/pytest-dev/pluggy/pull/46 +.. _#44: https://github.com/pytest-dev/pluggy/issues/44 +.. _#42: https://github.com/pytest-dev/pluggy/pull/42 +.. _#39: https://github.com/pytest-dev/pluggy/pull/39 +.. _#32: https://github.com/pytest-dev/pluggy/pull/32 +.. _#19: https://github.com/pytest-dev/pluggy/issues/19 +.. _#17: https://github.com/pytest-dev/pluggy/issues/17 +.. _#14: https://github.com/pytest-dev/pluggy/issues/14 + + +0.4.0 +----- +- add ``has_plugin(name)`` method to pluginmanager. thanks `@nicoddemus`_. + +- fix `#11`_: make plugin parsing more resilient against exceptions + from ``__getattr__`` functions. Thanks `@nicoddemus`_. + +- fix issue `#4`_: specific ``HookCallError`` exception for when a hook call + provides not enough arguments. + +- better error message when loading setuptools entrypoints fails + due to a ``VersionConflict``. Thanks `@blueyed`_. + +.. _#11: https://github.com/pytest-dev/pluggy/issues/11 +.. _#4: https://github.com/pytest-dev/pluggy/issues/4 + + +0.3.1 +----- +- avoid using deprecated-in-python3.5 getargspec method. Thanks + `@mdboom`_. + + +0.3.0 +----- +initial release + +.. contributors +.. _@hpk42: https://github.com/hpk42 +.. _@tgoodlet: https://github.com/tgoodlet +.. _@MichalTHEDUDE: https://github.com/MichalTHEDUDE +.. _@vodik: https://github.com/vodik +.. _@RonnyPfannschmidt: https://github.com/RonnyPfannschmidt +.. _@blueyed: https://github.com/blueyed +.. _@nicoddemus: https://github.com/nicoddemus +.. _@mdboom: https://github.com/mdboom diff --git a/tests/wpt/web-platform-tests/tools/third_party/pluggy/LICENSE b/tests/wpt/web-platform-tests/tools/third_party/pluggy/LICENSE new file mode 100644 index 00000000000..121017d0866 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 holger krekel (rather uses bitbucket/hpk42) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/tests/wpt/web-platform-tests/tools/third_party/pluggy/MANIFEST.in b/tests/wpt/web-platform-tests/tools/third_party/pluggy/MANIFEST.in new file mode 100644 index 00000000000..0cf8f3e0887 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/MANIFEST.in @@ -0,0 +1,7 @@ +include CHANGELOG +include README.rst +include setup.py +include tox.ini +include LICENSE +graft testing +recursive-exclude * *.pyc *.pyo diff --git a/tests/wpt/web-platform-tests/tools/third_party/pluggy/README.rst b/tests/wpt/web-platform-tests/tools/third_party/pluggy/README.rst new file mode 100644 index 00000000000..3636b6ec642 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/README.rst @@ -0,0 +1,80 @@ +pluggy - A minimalist production ready plugin system +==================================================== +|pypi| |anaconda| |versions| |travis| |appveyor| + + +This is the core framework used by the `pytest`_, `tox`_, and `devpi`_ projects. + +Please `read the docs`_ to learn more! + +A definitive example +******************** +.. code-block:: python + + import pluggy + + hookspec = pluggy.HookspecMarker("myproject") + hookimpl = pluggy.HookimplMarker("myproject") + + + class MySpec(object): + """A hook specification namespace. + """ + @hookspec + def myhook(self, arg1, arg2): + """My special little hook that you can customize. + """ + + + class Plugin_1(object): + """A hook implementation namespace. + """ + @hookimpl + def myhook(self, arg1, arg2): + print("inside Plugin_1.myhook()") + return arg1 + arg2 + + + class Plugin_2(object): + """A 2nd hook implementation namespace. + """ + @hookimpl + def myhook(self, arg1, arg2): + print("inside Plugin_2.myhook()") + return arg1 - arg2 + + + # create a manager and add the spec + pm = pluggy.PluginManager("myproject") + pm.add_hookspecs(MySpec) + + # register plugins + pm.register(Plugin_1()) + pm.register(Plugin_2()) + + # call our `myhook` hook + results = pm.hook.myhook(arg1=1, arg2=2) + print(results) + + +.. badges +.. |pypi| image:: https://img.shields.io/pypi/v/pluggy.svg + :target: https://pypi.python.org/pypi/pluggy +.. |versions| image:: https://img.shields.io/pypi/pyversions/pluggy.svg + :target: https://pypi.python.org/pypi/pluggy +.. |travis| image:: https://img.shields.io/travis/pytest-dev/pluggy/master.svg + :target: https://travis-ci.org/pytest-dev/pluggy +.. |appveyor| image:: https://img.shields.io/appveyor/ci/pytestbot/pluggy/master.svg + :target: https://ci.appveyor.com/project/pytestbot/pluggy +.. |anaconda| image:: https://anaconda.org/conda-forge/pluggy/badges/version.svg + :target: https://anaconda.org/conda-forge/pluggy + +.. links +.. _pytest: + http://pytest.org +.. _tox: + https://tox.readthedocs.org +.. _devpi: + http://doc.devpi.net +.. _read the docs: + https://pluggy.readthedocs.io/en/latest/ diff --git a/tests/wpt/web-platform-tests/tools/pytest/appveyor.yml b/tests/wpt/web-platform-tests/tools/third_party/pluggy/appveyor.yml similarity index 55% rename from tests/wpt/web-platform-tests/tools/pytest/appveyor.yml rename to tests/wpt/web-platform-tests/tools/third_party/pluggy/appveyor.yml index 4b73645f735..c3903f8bfcc 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/appveyor.yml +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/appveyor.yml @@ -1,9 +1,17 @@ environment: - COVERALLS_REPO_TOKEN: - secure: 2NJ5Ct55cHJ9WEg3xbSqCuv0rdgzzb6pnzOIG5OkMbTndw3wOBrXntWFoQrXiMFi - # this is pytest's token in coveralls.io, encrypted - # using pytestbot account as detailed here: - # https://www.appveyor.com/docs/build-configuration#secure-variables + matrix: + # note: please use "tox --listenvs" to populate the build matrix below + - TOXENV: "check" + - TOXENV: "docs" + - TOXENV: "py27-pytestrelease" + - TOXENV: "py34-pytestrelease" + - TOXENV: "py35-pytestrelease" + - TOXENV: "py36-pytestrelease" + - TOXENV: "pypy-pytestrelease" + - TOXENV: "py27-pytestmaster" + - TOXENV: "py27-pytestfeatures" + - TOXENV: "py36-pytestmaster" + - TOXENV: "py36-pytestfeatures" install: - echo Installed Pythons @@ -12,6 +20,7 @@ install: # install pypy using choco (redirect to a file and write to console in case # choco install returns non-zero, because choco install python.pypy is too # noisy) + # pypy is disabled until #1963 gets fixed - choco install python.pypy > pypy-inst.log 2>&1 || (type pypy-inst.log & exit /b 1) - set PATH=C:\tools\pypy\pypy;%PATH% # so tox can find pypy - echo PyPy installed @@ -23,6 +32,3 @@ build: false # Not a C# project, build stuff at the test step instead. test_script: - C:\Python35\python -m tox - # coveralls is not in tox's envlist, plus for PRs the secure variable - # is not defined so we have to check for it - - if defined COVERALLS_REPO_TOKEN C:\Python35\python -m tox -e coveralls diff --git a/tests/wpt/web-platform-tests/tools/third_party/pluggy/docs/_static/img/plug.png b/tests/wpt/web-platform-tests/tools/third_party/pluggy/docs/_static/img/plug.png new file mode 100644 index 00000000000..3339f8a608d Binary files /dev/null and b/tests/wpt/web-platform-tests/tools/third_party/pluggy/docs/_static/img/plug.png differ diff --git a/tests/wpt/web-platform-tests/tools/third_party/pluggy/docs/api_reference.rst b/tests/wpt/web-platform-tests/tools/third_party/pluggy/docs/api_reference.rst new file mode 100644 index 00000000000..aa15135ad3d --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/docs/api_reference.rst @@ -0,0 +1,14 @@ +Api Reference +============= + +.. automodule:: pluggy + :members: + :undoc-members: + :show-inheritance: + + +.. automethod:: pluggy._Result.get_result + +.. automethod:: pluggy._Result.force_result + +.. automethod:: pluggy._HookCaller.call_extra diff --git a/tests/wpt/web-platform-tests/tools/third_party/pluggy/docs/conf.py b/tests/wpt/web-platform-tests/tools/third_party/pluggy/docs/conf.py new file mode 100644 index 00000000000..04065218fda --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/docs/conf.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +import pkg_resources + + +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.doctest', + 'sphinx.ext.intersphinx', + 'sphinx.ext.coverage', + 'sphinx.ext.viewcode', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. + +dist = pkg_resources.get_distribution('pluggy') +project = dist.project_name +copyright = u'2016, Holger Krekel' +author = 'Holger Krekel' + +release = dist.version +# The short X.Y version. +version = u'.'.join(dist.version.split('.')[:2]) + + +language = None + +pygments_style = 'sphinx' +html_logo = '_static/img/plug.png' +html_theme = 'alabaster' +html_theme_options = { + # 'logo': 'img/plug.png', + # 'logo_name': 'true', + 'description': 'The `pytest` plugin system', + 'github_user': 'pytest-dev', + 'github_repo': 'pluggy', + 'github_button': 'true', + 'github_banner': 'true', + 'page_width': '1080px', + 'fixed_sidebar': 'false', +} +html_static_path = ['_static'] + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'pluggy', u'pluggy Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'pluggy', u'pluggy Documentation', + author, 'pluggy', 'One line description of project.', + 'Miscellaneous'), +] + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'https://docs.python.org/': None} diff --git a/tests/wpt/web-platform-tests/tools/third_party/pluggy/docs/examples/firstexample.py b/tests/wpt/web-platform-tests/tools/third_party/pluggy/docs/examples/firstexample.py new file mode 100644 index 00000000000..3cec7cd2144 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/docs/examples/firstexample.py @@ -0,0 +1,44 @@ +import pluggy + +hookspec = pluggy.HookspecMarker("myproject") +hookimpl = pluggy.HookimplMarker("myproject") + + +class MySpec(object): + """A hook specification namespace. + """ + @hookspec + def myhook(self, arg1, arg2): + """My special little hook that you can customize. + """ + + +class Plugin_1(object): + """A hook implementation namespace. + """ + @hookimpl + def myhook(self, arg1, arg2): + print("inside Plugin_1.myhook()") + return arg1 + arg2 + + +class Plugin_2(object): + """A 2nd hook implementation namespace. + """ + @hookimpl + def myhook(self, arg1, arg2): + print("inside Plugin_2.myhook()") + return arg1 - arg2 + + +# create a manager and add the spec +pm = pluggy.PluginManager("myproject") +pm.add_hookspecs(MySpec) + +# register plugins +pm.register(Plugin_1()) +pm.register(Plugin_2()) + +# call our `myhook` hook +results = pm.hook.myhook(arg1=1, arg2=2) +print(results) diff --git a/tests/wpt/web-platform-tests/tools/third_party/pluggy/docs/index.rst b/tests/wpt/web-platform-tests/tools/third_party/pluggy/docs/index.rst new file mode 100644 index 00000000000..db65a1023fd --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/docs/index.rst @@ -0,0 +1,705 @@ +``pluggy`` +========== + +The ``pytest`` plugin system +**************************** +``pluggy`` is the crystallized core of `plugin management and hook +calling`_ for `pytest`_. + +In fact, ``pytest`` is itself composed as a set of ``pluggy`` plugins +which are invoked in sequence according to a well defined set of protocols. +Some `200+ plugins`_ use ``pluggy`` to extend and customize ``pytest``'s default behaviour. + +In essence, ``pluggy`` enables function `hooking`_ so you can build "pluggable" systems. + +How's it work? +-------------- +A `plugin` is a `namespace`_ which defines hook functions. + +``pluggy`` manages *plugins* by relying on: + +- a hook *specification* - defines a call signature +- a set of hook *implementations* - aka `callbacks`_ +- the hook *caller* - a call loop which collects results + +where for each registered hook *specification*, a hook *call* will invoke up to ``N`` +registered hook *implementations*. + +``pluggy`` accomplishes all this by implementing a `request-response pattern`_ using *function* +subscriptions and can be thought of and used as a rudimentary busless `publish-subscribe`_ +event system. + +``pluggy``'s approach is meant to let a designer think carefuly about which objects are +explicitly needed by an extension writer. This is in contrast to subclass-based extension +systems which may expose unecessary state and behaviour or encourage `tight coupling`_ +in overlying frameworks. + + +A first example +--------------- + +.. literalinclude:: examples/firstexample.py + +Running this directly gets us:: + + $ python docs/examples/firstexample.py + + inside Plugin_2.myhook() + inside Plugin_1.myhook() + [-1, 3] + +For more details and advanced usage please read on. + +.. _define: + +Defining and Collecting Hooks +***************************** +A *plugin* is a namespace type (currently one of a ``class`` or module) +which defines a set of *hook* functions. + +As mentioned in :ref:`manage`, all *plugins* which define *hooks* +are managed by an instance of a :py:class:`pluggy.PluginManager` which +defines the primary ``pluggy`` API. + +In order for a ``PluginManager`` to detect functions in a namespace +intended to be *hooks*, they must be decorated using special ``pluggy`` *marks*. + +.. _marking_hooks: + +Marking hooks +------------- +The :py:class:`~pluggy.HookspecMarker` and :py:class:`~pluggy.HookimplMarker` +decorators are used to *mark* functions for detection by a ``PluginManager``: + +.. code-block:: python + + from pluggy import HookspecMarker, HookimplMarker + + hookspec = HookspecMarker('project_name') + hookimpl = HookimplMarker('project_name') + + +Each decorator type takes a single ``project_name`` string as its +lone argument the value of which is used to mark hooks for detection by +by a similarly configured ``PluginManager`` instance. + +That is, a *mark* type called with ``project_name`` returns an object which +can be used to decorate functions which will then be detected by a +``PluginManager`` which was instantiated with the the same ``project_name`` +value. + +Furthermore, each *hookimpl* or *hookspec* decorator can configure the +underlying call-time behavior of each *hook* object by providing special +*options* passed as keyword arguments. + + +.. note:: + The following sections correspond to similar documentation in + ``pytest`` for `Writing hook functions`_ and can be used + as a supplementary resource. + +.. _impls: + +Implementations +--------------- +A hook *implementation* (*hookimpl*) is just a (callback) function +which has been appropriately marked. + +*hookimpls* are loaded from a plugin using the +:py:meth:`~pluggy.PluginManager.register()` method: + +.. code-block:: python + + import sys + from pluggy import PluginManager, HookimplMarker + + hookimpl = HookimplMarker('myproject') + + @hookimpl + def setup_project(config, args): + """This hook is used to process the initial config + and possibly input arguments. + """ + if args: + config.process_args(args) + + return config + + pm = PluginManager('myproject') + + # load all hookimpls from the local module's namespace + plugin_name = pm.register(sys.modules[__name__]) + +.. _optionalhook: + +Optional validation +^^^^^^^^^^^^^^^^^^^ +Normally each *hookimpl* should be validated a against a corresponding +hook :ref:`specification `. If you want to make an exception +then the *hookimpl* should be marked with the ``"optionalhook"`` option: + +.. code-block:: python + + @hookimpl(optionalhook=True) + def setup_project(config, args): + """This hook is used to process the initial config + and possibly input arguments. + """ + if args: + config.process_args(args) + + return config + +Call time order +^^^^^^^^^^^^^^^ +By default hooks are :ref:`called ` in LIFO registered order, however, +a *hookimpl* can influence its call-time invocation position using special +attributes. If marked with a ``"tryfirst"`` or ``"trylast"`` option it +will be executed *first* or *last* respectively in the hook call loop: + +.. code-block:: python + + import sys + from pluggy import PluginManager, HookimplMarker + + hookimpl = HookimplMarker('myproject') + + @hookimpl(trylast=True) + def setup_project(config, args): + """Default implementation. + """ + if args: + config.process_args(args) + + return config + + + class SomeOtherPlugin(object): + """Some other plugin defining the same hook. + """ + @hookimpl(tryfirst=True) + def setup_project(config, args): + """Report what args were passed before calling + downstream hooks. + """ + if args: + print("Got args: {}".format(args)) + + return config + + pm = PluginManager('myproject') + + # load from the local module's namespace + pm.register(sys.modules[__name__]) + # load a plugin defined on a class + pm.register(SomePlugin()) + +For another example see the `hook function ordering`_ section of the +``pytest`` docs. + +.. note:: + ``tryfirst`` and ``trylast`` hooks are still invoked in LIFO order within + each category. + +Wrappers +^^^^^^^^ +A *hookimpl* can be marked with a ``"hookwrapper"`` option which indicates that +the function will be called to *wrap* (or surround) all other normal *hookimpl* +calls. A *hookwrapper* can thus execute some code ahead and after the execution +of all corresponding non-wrappper *hookimpls*. + +Much in the same way as a `@contextlib.contextmanager`_, *hookwrappers* must +be implemented as generator function with a single ``yield`` in its body: + + +.. code-block:: python + + @hookimpl(hookwrapper=True) + def setup_project(config, args): + """Wrap calls to ``setup_project()`` implementations which + should return json encoded config options. + """ + if config.debug: + print("Pre-hook config is {}".format( + config.tojson())) + + # get initial default config + defaults = config.tojson() + + # all corresponding hookimpls are invoked here + outcome = yield + + for item in outcome.get_result(): + print("JSON config override is {}".format(item)) + + if config.debug: + print("Post-hook config is {}".format( + config.tojson())) + + if config.use_defaults: + outcome.force_result(defaults) + +The generator is `sent`_ a :py:class:`pluggy._Result` object which can +be assigned in the ``yield`` expression and used to override or inspect +the final result(s) returned back to the caller using the +:py:meth:`~pluggy._Result.force_result` or +:py:meth:`~pluggy._Result.get_result` methods. + +.. note:: + Hook wrappers can **not** return results (as per generator function + semantics); they can only modify them using the ``_Result`` API. + +Also see the `hookwrapper`_ section in the ``pytest`` docs. + +.. _specs: + +Specifications +-------------- +A hook *specification* (*hookspec*) is a definition used to validate each +*hookimpl* ensuring that an extension writer has correctly defined their +callback function *implementation* . + +*hookspecs* are defined using similarly marked functions however only the +function *signature* (its name and names of all its arguments) is analyzed +and stored. As such, often you will see a *hookspec* defined with only +a docstring in its body. + +*hookspecs* are loaded using the +:py:meth:`~pluggy.PluginManager.add_hookspecs()` method and normally +should be added before registering corresponding *hookimpls*: + +.. code-block:: python + + import sys + from pluggy import PluginManager, HookspecMarker + + hookspec = HookspecMarker('myproject') + + @hookspec + def setup_project(config, args): + """This hook is used to process the inital config and input + arguments. + """ + + pm = PluginManager('myproject') + + # load from the local module's namespace + pm.add_hookspecs(sys.modules[__name__]) + + +Registering a *hookimpl* which does not meet the constraints of its +corresponding *hookspec* will result in an error. + +A *hookspec* can also be added **after** some *hookimpls* have been +registered however this is not normally recommended as it results in +delayed hook validation. + +.. note:: + The term *hookspec* can sometimes refer to the plugin-namespace + which defines ``hookspec`` decorated functions as in the case of + ``pytest``'s `hookspec module`_ + +Enforcing spec validation +^^^^^^^^^^^^^^^^^^^^^^^^^ +By default there is no strict requirement that each *hookimpl* has +a corresponding *hookspec*. However, if you'd like you enforce this +behavior you can run a check with the +:py:meth:`~pluggy.PluginManager.check_pending()` method. If you'd like +to enforce requisite *hookspecs* but with certain exceptions for some hooks +then make sure to mark those hooks as :ref:`optional `. + +Opt-in arguments +^^^^^^^^^^^^^^^^ +To allow for *hookspecs* to evolve over the lifetime of a project, +*hookimpls* can accept **less** arguments then defined in the spec. +This allows for extending hook arguments (and thus semantics) without +breaking existing *hookimpls*. + +In other words this is ok: + +.. code-block:: python + + @hookspec + def myhook(config, args): + pass + + @hookimpl + def myhook(args): + print(args) + + +whereas this is not: + +.. code-block:: python + + @hookspec + def myhook(config, args): + pass + + @hookimpl + def myhook(config, args, extra_arg): + print(args) + +.. _firstresult: + +First result only +^^^^^^^^^^^^^^^^^ +A *hookspec* can be marked such that when the *hook* is called the call loop +will only invoke up to the first *hookimpl* which returns a result other +then ``None``. + +.. code-block:: python + + @hookspec(firstresult=True) + def myhook(config, args): + pass + +This can be useful for optimizing a call loop for which you are only +interested in a single core *hookimpl*. An example is the +`pytest_cmdline_main`_ central routine of ``pytest``. + +Also see the `first result`_ section in the ``pytest`` docs. + +.. _historic: + +Historic hooks +^^^^^^^^^^^^^^ +You can mark a *hookspec* as being *historic* meaning that the hook +can be called with :py:meth:`~pluggy.PluginManager.call_historic()` **before** +having been registered: + +.. code-block:: python + + @hookspec(historic=True) + def myhook(config, args): + pass + +The implication is that late registered *hookimpls* will be called back +immediately at register time and **can not** return a result to the caller.** + +This turns out to be particularly useful when dealing with lazy or +dynamically loaded plugins. + +For more info see :ref:`call_historic`. + + +.. links +.. _@contextlib.contextmanager: + https://docs.python.org/3.6/library/contextlib.html#contextlib.contextmanager +.. _pytest_cmdline_main: + https://github.com/pytest-dev/pytest/blob/master/_pytest/hookspec.py#L80 +.. _hookspec module: + https://github.com/pytest-dev/pytest/blob/master/_pytest/hookspec.py +.. _Writing hook functions: + http://doc.pytest.org/en/latest/writing_plugins.html#writing-hook-functions +.. _hookwrapper: + http://doc.pytest.org/en/latest/writing_plugins.html#hookwrapper-executing-around-other-hooks +.. _hook function ordering: + http://doc.pytest.org/en/latest/writing_plugins.html#hook-function-ordering-call-example +.. _first result: + http://doc.pytest.org/en/latest/writing_plugins.html#firstresult-stop-at-first-non-none-result +.. _sent: + https://docs.python.org/3/reference/expressions.html#generator.send + +.. _manage: + +The Plugin Registry +******************* +``pluggy`` manages plugins using instances of the +:py:class:`pluggy.PluginManager`. + +A ``PluginManager`` is instantiated with a single +``str`` argument, the ``project_name``: + +.. code-block:: python + + import pluggy + pm = pluggy.PluginManager('my_project_name') + + +The ``project_name`` value is used when a ``PluginManager`` scans for *hook* +functions :ref:`defined on a plugin `. +This allows for multiple +plugin managers from multiple projects to define hooks alongside each other. + + +Registration +------------ +Each ``PluginManager`` maintains a *plugin* registry where each *plugin* +contains a set of *hookimpl* definitions. Loading *hookimpl* and *hookspec* +definitions to populate the registry is described in detail in the section on +:ref:`define`. + +In summary, you pass a plugin namespace object to the +:py:meth:`~pluggy.PluginManager.register()` and +:py:meth:`~pluggy.PluginManager.add_hookspec()` methods to collect +hook *implementations* and *specfications* from *plugin* namespaces respectively. + +You can unregister any *plugin*'s hooks using +:py:meth:`~pluggy.PluginManager.unregister()` and check if a plugin is +registered by passing its name to the +:py:meth:`~pluggy.PluginManager.is_registered()` method. + +Loading ``setuptools`` entry points +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +You can automatically load plugins registered through `setuptools entry points`_ +with the :py:meth:`~pluggy.PluginManager.load_setuptools_entrypoints()` +method. + +An example use of this is the `pytest entry point`_. + + +Blocking +-------- +You can block any plugin from being registered using +:py:meth:`~pluggy.PluginManager.set_blocked()` and check if a given +*plugin* is blocked by name using :py:meth:`~pluggy.PluginManager.is_blocked()`. + + +Inspection +---------- +You can use a variety of methods to inspect the both the registry +and particular plugins in it: + +- :py:meth:`~pluggy.PluginManager.list_name_plugin()` - + return a list of name-plugin pairs +- :py:meth:`~pluggy.PluginManager.get_plugins()` - retrieve all plugins +- :py:meth:`~pluggy.PluginManager.get_canonical_name()`- get a *plugin*'s + canonical name (the name it was registered with) +- :py:meth:`~pluggy.PluginManager.get_plugin()` - retrieve a plugin by its + canonical name + + +Parsing mark options +^^^^^^^^^^^^^^^^^^^^ +You can retrieve the *options* applied to a particular +*hookspec* or *hookimpl* as per :ref:`marking_hooks` using the +:py:meth:`~pluggy.PluginManager.parse_hookspec_opts()` and +:py:meth:`~pluggy.PluginManager.parse_hookimpl_opts()` respectively. + +.. links +.. _setuptools entry points: + http://setuptools.readthedocs.io/en/latest/setuptools.html#dynamic-discovery-of-services-and-plugins +.. _pytest entry point: + http://doc.pytest.org/en/latest/writing_plugins.html#setuptools-entry-points + + +.. _calling: + +Calling Hooks +************* +The core functionality of ``pluggy`` enables an extension provider +to override function calls made at certain points throughout a program. + +A particular *hook* is invoked by calling an instance of +a :py:class:`pluggy._HookCaller` which in turn *loops* through the +``1:N`` registered *hookimpls* and calls them in sequence. + +Every :py:class:`pluggy.PluginManager` has a ``hook`` attribute +which is an instance of this :py:class:`pluggy._HookRelay`. +The ``_HookRelay`` itself contains references (by hook name) to each +registered *hookimpl*'s ``_HookCaller`` instance. + +More practically you call a *hook* like so: + +.. code-block:: python + + import sys + import pluggy + import mypluginspec + import myplugin + from configuration import config + + pm = pluggy.PluginManager("myproject") + pm.add_hookspecs(mypluginspec) + pm.register(myplugin) + + # we invoke the _HookCaller and thus all underlying hookimpls + result_list = pm.hook.myhook(config=config, args=sys.argv) + +Note that you **must** call hooks using keyword `arguments`_ syntax! + +Hook implementations are called in LIFO registered order: *the last +registered plugin's hooks are called first*. As an example, the below +assertion should not error: + +.. code-block:: python + + from pluggy import PluginManager, HookimplMarker + + hookimpl = HookimplMarker('myproject') + + class Plugin1(object): + def myhook(self, args): + """Default implementation. + """ + return 1 + + class Plugin2(object): + def myhook(self, args): + """Default implementation. + """ + return 2 + + class Plugin3(object): + def myhook(self, args): + """Default implementation. + """ + return 3 + + pm = PluginManager('myproject') + pm.register(Plugin1()) + pm.register(Plugin2()) + pm.register(Plugin3()) + + assert pm.hook.myhook(args=()) == [3, 2, 1] + +Collecting results +------------------ +By default calling a hook results in all underlying :ref:`hookimpls +` functions to be invoked in sequence via a loop. Any function +which returns a value other then a ``None`` result will have that result +appended to a :py:class:`list` which is returned by the call. + +The only exception to this behaviour is if the hook has been marked to return +its :ref:`firstresult` in which case only the first single value (which is not +``None``) will be returned. + +.. _call_historic: + +Historic calls +-------------- +A *historic call* allows for all newly registered functions to receive all hook +calls that happened before their registration. The implication is that this is +only useful if you expect that some *hookimpls* may be registered **after** the +hook is initially invoked. + +Historic hooks must be :ref:`specially marked ` and called +using the :py:meth:`pluggy._HookCaller.call_historic()` method: + +.. code-block:: python + + # call with history; no results returned + pm.hook.myhook.call_historic(config=config, args=sys.argv) + + # ... more of our program ... + + # late loading of some plugin + import mylateplugin + + # historic call back is done here + pm.register(mylateplugin) + +Note that if you ``call_historic()`` the ``_HookCaller`` (and thus your +calling code) can not receive results back from the underlying *hookimpl* +functions. + +Calling with extras +------------------- +You can call a hook with temporarily participating *implementation* functions +(that aren't in the registry) using the +:py:meth:`pluggy._HookCaller.call_extra()` method. + + +Calling with a subset of registered plugins +------------------------------------------- +You can make a call using a subset of plugins by asking the +``PluginManager`` first for a ``_HookCaller`` with those plugins removed +using the :py:meth:`pluggy.PluginManager.subset_hook_caller()` method. + +You then can use that ``_HookCaller`` to make normal, ``call_historic()``, +or ``call_extra()`` calls as necessary. + + +.. links +.. _arguments: + https://docs.python.org/3/glossary.html#term-argument + + +Built-in tracing +**************** +``pluggy`` comes with some batteries included hook tracing for your +debugging needs. + + +Call tracing +------------ +To enable tracing use the +:py:meth:`pluggy.PluginManager.enable_tracing()` method which returns an +undo function to disable the behaviour. + +.. code-block:: python + + pm = PluginManager('myproject') + # magic line to set a writer function + pm.trace.root.setwriter(print) + undo = pm.enable_tracing() + + +Call monitoring +--------------- +Instead of using the built-in tracing mechanism you can also add your +own ``before`` and ``after`` monitoring functions using +:py:class:`pluggy.PluginManager.add_hookcall_monitoring()`. + +The expected signature and default implementations for these functions is: + +.. code-block:: python + + def before(hook_name, methods, kwargs): + pass + + def after(outcome, hook_name, methods, kwargs): + pass + +Public API +********** +Please see the :doc:`api_reference`. + +Development +*********** +Great care must taken when hacking on ``pluggy`` since multiple mature +projects rely on it. Our Github integrated CI process runs the full +`tox test suite`_ on each commit so be sure your changes can run on +all required `Python interpreters`_ and ``pytest`` versions. + +Release Policy +************** +Pluggy uses `Semantic Versioning`_. Breaking changes are only foreseen for +Major releases (incremented X in "X.Y.Z"). If you want to use ``pluggy`` +in your project you should thus use a dependency restriction like +``"pluggy>=0.1.0,<1.0"`` to avoid surprises. + + +.. hyperlinks +.. _pytest: + http://pytest.org +.. _request-response pattern: + https://en.wikipedia.org/wiki/Request%E2%80%93response +.. _publish-subscribe: + https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern +.. _hooking: + https://en.wikipedia.org/wiki/Hooking +.. _plugin management and hook calling: + http://doc.pytest.org/en/latest/writing_plugins.html +.. _namespace: + https://docs.python.org/3.6/tutorial/classes.html#python-scopes-and-namespaces +.. _callbacks: + https://en.wikipedia.org/wiki/Callback_(computer_programming) +.. _tox test suite: + https://github.com/pytest-dev/pluggy/blob/master/tox.ini +.. _Semantic Versioning: + http://semver.org/ +.. _tight coupling: + https://en.wikipedia.org/wiki/Coupling_%28computer_programming%29#Types_of_coupling +.. _Python interpreters: + https://github.com/pytest-dev/pluggy/blob/master/tox.ini#L2 +.. _200+ plugins: + http://plugincompat.herokuapp.com/ + + +.. Indices and tables +.. ================== +.. * :ref:`genindex` +.. * :ref:`modindex` +.. * :ref:`search` diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/pluggy.py b/tests/wpt/web-platform-tests/tools/third_party/pluggy/pluggy/__init__.py similarity index 69% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/pluggy.py rename to tests/wpt/web-platform-tests/tools/third_party/pluggy/pluggy/__init__.py index 2f848b23d35..ab5175d9566 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/pluggy.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/pluggy/__init__.py @@ -1,80 +1,18 @@ -""" -PluginManager, basic initialization and tracing. - -pluggy is the cristallized core of plugin management as used -by some 150 plugins for pytest. - -Pluggy uses semantic versioning. Breaking changes are only foreseen for -Major releases (incremented X in "X.Y.Z"). If you want to use pluggy in -your project you should thus use a dependency restriction like -"pluggy>=0.1.0,<1.0" to avoid surprises. - -pluggy is concerned with hook specification, hook implementations and hook -calling. For any given hook specification a hook call invokes up to N implementations. -A hook implementation can influence its position and type of execution: -if attributed "tryfirst" or "trylast" it will be tried to execute -first or last. However, if attributed "hookwrapper" an implementation -can wrap all calls to non-hookwrapper implementations. A hookwrapper -can thus execute some code ahead and after the execution of other hooks. - -Hook specification is done by way of a regular python function where -both the function name and the names of all its arguments are significant. -Each hook implementation function is verified against the original specification -function, including the names of all its arguments. To allow for hook specifications -to evolve over the livetime of a project, hook implementations can -accept less arguments. One can thus add new arguments and semantics to -a hook specification by adding another argument typically without breaking -existing hook implementations. - -The chosen approach is meant to let a hook designer think carefuly about -which objects are needed by an extension writer. By contrast, subclass-based -extension mechanisms often expose a lot more state and behaviour than needed, -thus restricting future developments. - -Pluggy currently consists of functionality for: - -- a way to register new hook specifications. Without a hook - specification no hook calling can be performed. - -- a registry of plugins which contain hook implementation functions. It - is possible to register plugins for which a hook specification is not yet - known and validate all hooks when the system is in a more referentially - consistent state. Setting an "optionalhook" attribution to a hook - implementation will avoid PluginValidationError's if a specification - is missing. This allows to have optional integration between plugins. - -- a "hook" relay object from which you can launch 1:N calls to - registered hook implementation functions - -- a mechanism for ordering hook implementation functions - -- mechanisms for two different type of 1:N calls: "firstresult" for when - the call should stop when the first implementation returns a non-None result. - And the other (default) way of guaranteeing that all hook implementations - will be called and their non-None result collected. - -- mechanisms for "historic" extension points such that all newly - registered functions will receive all hook calls that happened - before their registration. - -- a mechanism for discovering plugin objects which are based on - setuptools based entry points. - -- a simple tracing mechanism, including tracing of plugin calls and - their arguments. - -""" -import sys import inspect +import warnings +from .callers import _multicall, HookCallError, _Result, _legacymulticall -__version__ = '0.3.1' -__all__ = ["PluginManager", "PluginValidationError", +__version__ = '0.5.3.dev' + +__all__ = ["PluginManager", "PluginValidationError", "HookCallError", "HookspecMarker", "HookimplMarker"] -_py3 = sys.version_info > (3, 0) + +class PluginValidationError(Exception): + """ plugin failed validation. """ -class HookspecMarker: +class HookspecMarker(object): """ Decorator helper class for marking functions as hook specifications. You can instantiate it with a project_name to get a decorator. @@ -103,7 +41,7 @@ class HookspecMarker: if historic and firstresult: raise ValueError("cannot have a historic firstresult hook") setattr(func, self.project_name + "_spec", - dict(firstresult=firstresult, historic=historic)) + dict(firstresult=firstresult, historic=historic)) return func if function is not None: @@ -112,7 +50,7 @@ class HookspecMarker: return setattr_hookspec_opts -class HookimplMarker: +class HookimplMarker(object): """ Decorator helper class for marking functions as hook implementations. You can instantiate with a project_name to get a decorator. @@ -142,15 +80,15 @@ class HookimplMarker: If hookwrapper is True the hook implementations needs to execute exactly one "yield". The code before the yield is run early before any non-hookwrapper function is run. The code after the yield is run after all non-hookwrapper - function have run. The yield receives an ``_CallOutcome`` object representing + function have run. The yield receives a ``_Result`` object representing the exception or result outcome of the inner calls (including other hookwrapper calls). """ def setattr_hookimpl_opts(func): setattr(func, self.project_name + "_impl", - dict(hookwrapper=hookwrapper, optionalhook=optionalhook, - tryfirst=tryfirst, trylast=trylast)) + dict(hookwrapper=hookwrapper, optionalhook=optionalhook, + tryfirst=tryfirst, trylast=trylast)) return func if function is None: @@ -166,7 +104,7 @@ def normalize_hookimpl_opts(opts): opts.setdefault("optionalhook", False) -class _TagTracer: +class _TagTracer(object): def __init__(self): self._tag2proc = {} self.writer = None @@ -213,7 +151,7 @@ class _TagTracer: self._tag2proc[tags] = processor -class _TagTracerSub: +class _TagTracerSub(object): def __init__(self, root, tags): self.root = root self.tags = tags @@ -228,64 +166,7 @@ class _TagTracerSub: return self.__class__(self.root, self.tags + (name,)) -def _raise_wrapfail(wrap_controller, msg): - co = wrap_controller.gi_code - raise RuntimeError("wrap_controller at %r %s:%d %s" % - (co.co_name, co.co_filename, co.co_firstlineno, msg)) - - -def _wrapped_call(wrap_controller, func): - """ Wrap calling to a function with a generator which needs to yield - exactly once. The yield point will trigger calling the wrapped function - and return its _CallOutcome to the yield point. The generator then needs - to finish (raise StopIteration) in order for the wrapped call to complete. - """ - try: - next(wrap_controller) # first yield - except StopIteration: - _raise_wrapfail(wrap_controller, "did not yield") - call_outcome = _CallOutcome(func) - try: - wrap_controller.send(call_outcome) - _raise_wrapfail(wrap_controller, "has second yield") - except StopIteration: - pass - return call_outcome.get_result() - - -class _CallOutcome: - """ Outcome of a function call, either an exception or a proper result. - Calling the ``get_result`` method will return the result or reraise - the exception raised when the function was called. """ - excinfo = None - - def __init__(self, func): - try: - self.result = func() - except BaseException: - self.excinfo = sys.exc_info() - - def force_result(self, result): - self.result = result - self.excinfo = None - - def get_result(self): - if self.excinfo is None: - return self.result - else: - ex = self.excinfo - if _py3: - raise ex[1].with_traceback(ex[2]) - _reraise(*ex) # noqa - -if not _py3: - exec(""" -def _reraise(cls, val, tb): - raise cls, val, tb -""") - - -class _TracedHookExecution: +class _TracedHookExecution(object): def __init__(self, pluginmanager, before, after): self.pluginmanager = pluginmanager self.before = before @@ -296,7 +177,7 @@ class _TracedHookExecution: def __call__(self, hook, hook_impls, kwargs): self.before(hook.name, hook_impls, kwargs) - outcome = _CallOutcome(lambda: self.oldcall(hook, hook_impls, kwargs)) + outcome = _Result.from_call(lambda: self.oldcall(hook, hook_impls, kwargs)) self.after(outcome, hook.name, hook_impls, kwargs) return outcome.get_result() @@ -308,7 +189,7 @@ class PluginManager(object): """ Core Pluginmanager class which manages registration of plugin objects and 1:N hook calling. - You can register new hooks by calling ``addhooks(module_or_class)``. + You can register new hooks by calling ``add_hookspec(module_or_class)``. You can register plugin objects (which contain hooks) by calling ``register(plugin)``. The Pluginmanager is initialized with a prefix that is searched for in the names of the dict of registered @@ -330,7 +211,10 @@ class PluginManager(object): self.hook = _HookRelay(self.trace.root.get("hook")) self._implprefix = implprefix self._inner_hookexec = lambda hook, methods, kwargs: \ - _MultiCall(methods, kwargs, hook.spec_opts).execute() + hook.multicall( + methods, kwargs, + firstresult=hook.spec_opts.get('firstresult'), + ) def _hookexec(self, hook, methods, kwargs): # called from all hookcaller instances. @@ -347,7 +231,7 @@ class PluginManager(object): if self._name2plugin.get(plugin_name, -1) is None: return # blocked plugin, return None to indicate no registration raise ValueError("Plugin already registered: %s=%s\n%s" % - (plugin_name, plugin, self._name2plugin)) + (plugin_name, plugin, self._name2plugin)) # XXX if an error happens we should make sure no state has been # changed at point of return @@ -374,7 +258,12 @@ class PluginManager(object): def parse_hookimpl_opts(self, plugin, name): method = getattr(plugin, name) - res = getattr(method, self.project_name + "_impl", None) + if not inspect.isroutine(method): + return + try: + res = getattr(method, self.project_name + "_impl", None) + except Exception: + res = {} if res is not None and not isinstance(res, dict): # false positive res = None @@ -455,6 +344,10 @@ class PluginManager(object): """ Return a plugin or None for the given name. """ return self._name2plugin.get(name) + def has_plugin(self, name): + """ Return True if a plugin with the given name is registered. """ + return self.get_plugin(name) is not None + def get_name(self, plugin): """ Return name for registered plugin or None if not registered. """ for name, val in self._name2plugin.items(): @@ -467,14 +360,16 @@ class PluginManager(object): "Plugin %r\nhook %r\nhistoric incompatible to hookwrapper" % (hookimpl.plugin_name, hook.name)) - for arg in hookimpl.argnames: - if arg not in hook.argnames: - raise PluginValidationError( - "Plugin %r\nhook %r\nargument %r not available\n" - "plugin definition: %s\n" - "available hookargs: %s" % - (hookimpl.plugin_name, hook.name, arg, - _formatdef(hookimpl.function), ", ".join(hook.argnames))) + # positional arg checking + notinspec = set(hookimpl.argnames) - set(hook.argnames) + if notinspec: + raise PluginValidationError( + "Plugin %r for hook %r\nhookimpl definition: %s\n" + "Argument(s) %s are declared in the hookimpl but " + "can not be found in the hookspec" % + (hookimpl.plugin_name, hook.name, + _formatdef(hookimpl.function), notinspec) + ) def check_pending(self): """ Verify that all hooks which have not been verified against @@ -492,7 +387,8 @@ class PluginManager(object): def load_setuptools_entrypoints(self, entrypoint_name): """ Load modules from querying the specified setuptools entrypoint name. Return the number of loaded plugins. """ - from pkg_resources import iter_entry_points, DistributionNotFound + from pkg_resources import (iter_entry_points, DistributionNotFound, + VersionConflict) for ep in iter_entry_points(entrypoint_name): # is the plugin registered or blocked? if self.get_plugin(ep.name) or self.is_blocked(ep.name): @@ -501,6 +397,9 @@ class PluginManager(object): plugin = ep.load() except DistributionNotFound: continue + except VersionConflict as e: + raise PluginValidationError( + "Plugin %r could not be loaded: %s!" % (ep.name, e)) self.register(plugin, name=ep.name) self._plugin_distinfo.append((plugin, ep.dist)) return len(self._plugin_distinfo) @@ -528,7 +427,7 @@ class PluginManager(object): of HookImpl instances and the keyword arguments for the hook call. ``after(outcome, hook_name, hook_impls, kwargs)`` receives the - same arguments as ``before`` but also a :py:class:`_CallOutcome`` object + same arguments as ``before`` but also a :py:class:`_Result`` object which represents the result of the overall hook call. """ return _TracedHookExecution(self, before, after).undo @@ -543,7 +442,7 @@ class PluginManager(object): def after(outcome, hook_name, methods, kwargs): if outcome.excinfo is None: - hooktrace("finish", hook_name, "-->", outcome.result) + hooktrace("finish", hook_name, "-->", outcome.get_result()) hooktrace.root.indent -= 1 return self.add_hookcall_monitoring(before, after) @@ -568,91 +467,58 @@ class PluginManager(object): return orig -class _MultiCall: - """ execute a call into multiple python functions/methods. """ +def varnames(func): + """Return tuple of positional and keywrord argument names for a function, + method, class or callable. - # XXX note that the __multicall__ argument is supported only - # for pytest compatibility reasons. It was never officially - # supported there and is explicitly deprecated since 2.8 - # so we can remove it soon, allowing to avoid the below recursion - # in execute() and simplify/speed up the execute loop. - - def __init__(self, hook_impls, kwargs, specopts={}): - self.hook_impls = hook_impls - self.kwargs = kwargs - self.kwargs["__multicall__"] = self - self.specopts = specopts - - def execute(self): - all_kwargs = self.kwargs - self.results = results = [] - firstresult = self.specopts.get("firstresult") - - while self.hook_impls: - hook_impl = self.hook_impls.pop() - args = [all_kwargs[argname] for argname in hook_impl.argnames] - if hook_impl.hookwrapper: - return _wrapped_call(hook_impl.function(*args), self.execute) - res = hook_impl.function(*args) - if res is not None: - if firstresult: - return res - results.append(res) - - if not firstresult: - return results - - def __repr__(self): - status = "%d meths" % (len(self.hook_impls),) - if hasattr(self, "results"): - status = ("%d results, " % len(self.results)) + status - return "<_MultiCall %s, kwargs=%r>" % (status, self.kwargs) - - -def varnames(func, startindex=None): - """ return argument name tuple for a function, method, class or callable. - - In case of a class, its "__init__" method is considered. - For methods the "self" parameter is not included unless you are passing - an unbound method with Python3 (which has no supports for unbound methods) + In case of a class, its ``__init__`` method is considered. + For methods the ``self`` parameter is not included. """ cache = getattr(func, "__dict__", {}) try: return cache["_varnames"] except KeyError: pass + if inspect.isclass(func): try: func = func.__init__ except AttributeError: - return () - startindex = 1 - else: - if not inspect.isfunction(func) and not inspect.ismethod(func): + return (), () + elif not inspect.isroutine(func): # callable object? + try: func = getattr(func, '__call__', func) - if startindex is None: - startindex = int(inspect.ismethod(func)) + except Exception: + return () - try: - rawcode = func.__code__ - except AttributeError: - return () - try: - x = rawcode.co_varnames[startindex:rawcode.co_argcount] - except AttributeError: - x = () + try: # func MUST be a function or method here or we won't parse any args + spec = _getargspec(func) + except TypeError: + return (), () + + args, defaults = tuple(spec.args), spec.defaults + if defaults: + index = -len(defaults) + args, defaults = args[:index], tuple(args[index:]) else: - defaults = func.__defaults__ - if defaults: - x = x[:-len(defaults)] + defaults = () + + # strip any implicit instance arg + if args: + if inspect.ismethod(func) or ( + '.' in getattr(func, '__qualname__', ()) and args[0] == 'self' + ): + args = args[1:] + + assert "self" not in args # best naming practises check? try: - cache["_varnames"] = x + cache["_varnames"] = args, defaults except TypeError: pass - return x + return args, defaults -class _HookRelay: +class _HookRelay(object): """ hook holder object for performing 1:N hook calls where N is the number of registered plugins. @@ -663,26 +529,31 @@ class _HookRelay: class _HookCaller(object): - def __init__(self, name, hook_execute, specmodule_or_class=None, spec_opts=None): + def __init__(self, name, hook_execute, specmodule_or_class=None, + spec_opts=None): self.name = name self._wrappers = [] self._nonwrappers = [] self._hookexec = hook_execute + self._specmodule_or_class = None + self.argnames = None + self.kwargnames = None + self.multicall = _multicall + self.spec_opts = spec_opts or {} if specmodule_or_class is not None: - assert spec_opts is not None self.set_specification(specmodule_or_class, spec_opts) def has_spec(self): - return hasattr(self, "_specmodule_or_class") + return self._specmodule_or_class is not None def set_specification(self, specmodule_or_class, spec_opts): assert not self.has_spec() self._specmodule_or_class = specmodule_or_class specfunc = getattr(specmodule_or_class, self.name) - argnames = varnames(specfunc, startindex=inspect.isclass(specmodule_or_class)) - assert "self" not in argnames # sanity check + # get spec arg signature + argnames, self.kwargnames = varnames(specfunc) self.argnames = ["__multicall__"] + list(argnames) - self.spec_opts = spec_opts + self.spec_opts.update(spec_opts) if spec_opts.get("historic"): self._call_history = [] @@ -700,6 +571,8 @@ class _HookCaller(object): raise ValueError("plugin %r not found" % (plugin,)) def _add_hookimpl(self, hookimpl): + """A an implementation to the callback chain. + """ if hookimpl.hookwrapper: methods = self._wrappers else: @@ -716,17 +589,45 @@ class _HookCaller(object): i -= 1 methods.insert(i + 1, hookimpl) + if '__multicall__' in hookimpl.argnames: + warnings.warn( + "Support for __multicall__ is now deprecated and will be" + "removed in an upcoming release.", + DeprecationWarning + ) + self.multicall = _legacymulticall + def __repr__(self): return "<_HookCaller %r>" % (self.name,) - def __call__(self, **kwargs): + def __call__(self, *args, **kwargs): + if args: + raise TypeError("hook calling supports only keyword arguments") assert not self.is_historic() + if self.argnames: + notincall = set(self.argnames) - set(['__multicall__']) - set( + kwargs.keys()) + if notincall: + warnings.warn( + "Argument(s) {} which are declared in the hookspec " + "can not be found in this hook call" + .format(tuple(notincall)), + stacklevel=2, + ) return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs) def call_historic(self, proc=None, kwargs=None): + """ call the hook with given ``kwargs`` for all registered plugins and + for all plugins which will be registered afterwards. + + If ``proc`` is not None it will be called for for each non-None result + obtained from a hook implementation. + """ self._call_history.append((kwargs or {}, proc)) # historizing hooks don't return results - self._hookexec(self, self._nonwrappers + self._wrappers, kwargs) + res = self._hookexec(self, self._nonwrappers + self._wrappers, kwargs) + for x in res or []: + proc(x) def call_extra(self, methods, kwargs): """ Call the hook with some additional temporarily participating @@ -742,6 +643,8 @@ class _HookCaller(object): self._nonwrappers, self._wrappers = old def _maybe_apply_history(self, method): + """Apply call history to a new hookimpl if it is marked as historic. + """ if self.is_historic(): for kwargs, proc in self._call_history: res = self._hookexec(self, [method], kwargs) @@ -749,18 +652,22 @@ class _HookCaller(object): proc(res[0]) -class HookImpl: +class HookImpl(object): def __init__(self, plugin, plugin_name, function, hook_impl_opts): self.function = function - self.argnames = varnames(self.function) + self.argnames, self.kwargnames = varnames(self.function) self.plugin = plugin self.opts = hook_impl_opts self.plugin_name = plugin_name self.__dict__.update(hook_impl_opts) -class PluginValidationError(Exception): - """ plugin failed validation. """ +if hasattr(inspect, 'getfullargspec'): + def _getargspec(func): + return inspect.getfullargspec(func) +else: + def _getargspec(func): + return inspect.getargspec(func) if hasattr(inspect, 'signature'): diff --git a/tests/wpt/web-platform-tests/tools/third_party/pluggy/pluggy/callers.py b/tests/wpt/web-platform-tests/tools/third_party/pluggy/pluggy/callers.py new file mode 100644 index 00000000000..3ff67becffb --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/pluggy/callers.py @@ -0,0 +1,201 @@ +''' +Call loop machinery +''' +import sys +import warnings + +_py3 = sys.version_info > (3, 0) + + +if not _py3: + exec(""" +def _reraise(cls, val, tb): + raise cls, val, tb +""") + + +def _raise_wrapfail(wrap_controller, msg): + co = wrap_controller.gi_code + raise RuntimeError("wrap_controller at %r %s:%d %s" % + (co.co_name, co.co_filename, co.co_firstlineno, msg)) + + +class HookCallError(Exception): + """ Hook was called wrongly. """ + + +class _Result(object): + def __init__(self, result, excinfo): + self._result = result + self._excinfo = excinfo + + @property + def excinfo(self): + return self._excinfo + + @property + def result(self): + """Get the result(s) for this hook call (DEPRECATED in favor of ``get_result()``).""" + msg = 'Use get_result() which forces correct exception handling' + warnings.warn(DeprecationWarning(msg), stacklevel=2) + return self._result + + @classmethod + def from_call(cls, func): + __tracebackhide__ = True + result = excinfo = None + try: + result = func() + except BaseException: + excinfo = sys.exc_info() + + return cls(result, excinfo) + + def force_result(self, result): + """Force the result(s) to ``result``. + + If the hook was marked as a ``firstresult`` a single value should + be set otherwise set a (modified) list of results. Any exceptions + found during invocation will be deleted. + """ + self._result = result + self._excinfo = None + + def get_result(self): + """Get the result(s) for this hook call. + + If the hook was marked as a ``firstresult`` only a single value + will be returned otherwise a list of results. + """ + __tracebackhide__ = True + if self._excinfo is None: + return self._result + else: + ex = self._excinfo + if _py3: + raise ex[1].with_traceback(ex[2]) + _reraise(*ex) # noqa + + +def _wrapped_call(wrap_controller, func): + """ Wrap calling to a function with a generator which needs to yield + exactly once. The yield point will trigger calling the wrapped function + and return its ``_Result`` to the yield point. The generator then needs + to finish (raise StopIteration) in order for the wrapped call to complete. + """ + try: + next(wrap_controller) # first yield + except StopIteration: + _raise_wrapfail(wrap_controller, "did not yield") + call_outcome = _Result.from_call(func) + try: + wrap_controller.send(call_outcome) + _raise_wrapfail(wrap_controller, "has second yield") + except StopIteration: + pass + return call_outcome.get_result() + + +class _LegacyMultiCall(object): + """ execute a call into multiple python functions/methods. """ + + # XXX note that the __multicall__ argument is supported only + # for pytest compatibility reasons. It was never officially + # supported there and is explicitely deprecated since 2.8 + # so we can remove it soon, allowing to avoid the below recursion + # in execute() and simplify/speed up the execute loop. + + def __init__(self, hook_impls, kwargs, firstresult=False): + self.hook_impls = hook_impls + self.caller_kwargs = kwargs # come from _HookCaller.__call__() + self.caller_kwargs["__multicall__"] = self + self.firstresult = firstresult + + def execute(self): + caller_kwargs = self.caller_kwargs + self.results = results = [] + firstresult = self.firstresult + + while self.hook_impls: + hook_impl = self.hook_impls.pop() + try: + args = [caller_kwargs[argname] for argname in hook_impl.argnames] + except KeyError: + for argname in hook_impl.argnames: + if argname not in caller_kwargs: + raise HookCallError( + "hook call must provide argument %r" % (argname,)) + if hook_impl.hookwrapper: + return _wrapped_call(hook_impl.function(*args), self.execute) + res = hook_impl.function(*args) + if res is not None: + if firstresult: + return res + results.append(res) + + if not firstresult: + return results + + def __repr__(self): + status = "%d meths" % (len(self.hook_impls),) + if hasattr(self, "results"): + status = ("%d results, " % len(self.results)) + status + return "<_MultiCall %s, kwargs=%r>" % (status, self.caller_kwargs) + + +def _legacymulticall(hook_impls, caller_kwargs, firstresult=False): + return _LegacyMultiCall( + hook_impls, caller_kwargs, firstresult=firstresult).execute() + + +def _multicall(hook_impls, caller_kwargs, firstresult=False): + """Execute a call into multiple python functions/methods and return the + result(s). + + ``caller_kwargs`` comes from _HookCaller.__call__(). + """ + __tracebackhide__ = True + results = [] + excinfo = None + try: # run impl and wrapper setup functions in a loop + teardowns = [] + try: + for hook_impl in reversed(hook_impls): + try: + args = [caller_kwargs[argname] for argname in hook_impl.argnames] + except KeyError: + for argname in hook_impl.argnames: + if argname not in caller_kwargs: + raise HookCallError( + "hook call must provide argument %r" % (argname,)) + + if hook_impl.hookwrapper: + try: + gen = hook_impl.function(*args) + next(gen) # first yield + teardowns.append(gen) + except StopIteration: + _raise_wrapfail(gen, "did not yield") + else: + res = hook_impl.function(*args) + if res is not None: + results.append(res) + if firstresult: # halt further impl calls + break + except BaseException: + excinfo = sys.exc_info() + finally: + if firstresult: # first result hooks return a single value + outcome = _Result(results[0] if results else None, excinfo) + else: + outcome = _Result(results, excinfo) + + # run all wrapper post-yield blocks + for gen in reversed(teardowns): + try: + gen.send(outcome) + _raise_wrapfail(gen, "has second yield") + except StopIteration: + pass + + return outcome.get_result() diff --git a/tests/wpt/web-platform-tests/tools/third_party/pluggy/setup.cfg b/tests/wpt/web-platform-tests/tools/third_party/pluggy/setup.cfg new file mode 100644 index 00000000000..7e729cb4f24 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/setup.cfg @@ -0,0 +1,8 @@ +[bdist_wheel] +universal=1 + +[metadata] +license_file=LICENSE + +[devpi:upload] +formats=sdist.tgz,bdist_wheel diff --git a/tests/wpt/web-platform-tests/tools/third_party/pluggy/setup.py b/tests/wpt/web-platform-tests/tools/third_party/pluggy/setup.py new file mode 100644 index 00000000000..b7c0f697120 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/setup.py @@ -0,0 +1,51 @@ +import os +from setuptools import setup + +classifiers = [ + 'Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Operating System :: POSIX', + 'Operating System :: Microsoft :: Windows', + 'Operating System :: MacOS :: MacOS X', + 'Topic :: Software Development :: Testing', + 'Topic :: Software Development :: Libraries', + 'Topic :: Utilities', + 'Programming Language :: Python :: Implementation :: CPython', + 'Programming Language :: Python :: Implementation :: PyPy'] + [ + ('Programming Language :: Python :: %s' % x) for x in + '2 2.7 3 3.4 3.5 3.6'.split()] + +with open('README.rst') as fd: + long_description = fd.read() + + +def get_version(): + p = os.path.join(os.path.dirname( + os.path.abspath(__file__)), "pluggy/__init__.py") + with open(p) as f: + for line in f.readlines(): + if "__version__" in line: + return line.strip().split("=")[-1].strip(" '") + raise ValueError("could not read version") + + +def main(): + setup( + name='pluggy', + description='plugin and hook calling mechanisms for python', + long_description=long_description, + version=get_version(), + license='MIT license', + platforms=['unix', 'linux', 'osx', 'win32'], + author='Holger Krekel', + author_email='holger@merlinux.eu', + url='https://github.com/pytest-dev/pluggy', + python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', + classifiers=classifiers, + packages=['pluggy'], + ) + + +if __name__ == '__main__': + main() diff --git a/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/benchmark.py b/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/benchmark.py new file mode 100644 index 00000000000..5a913e9d418 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/benchmark.py @@ -0,0 +1,59 @@ +""" +Benchmarking and performance tests. +""" +import pytest +from pluggy import (_multicall, _legacymulticall, HookImpl, HookspecMarker, + HookimplMarker) + +hookspec = HookspecMarker("example") +hookimpl = HookimplMarker("example") + + +def MC(methods, kwargs, callertype, firstresult=False): + hookfuncs = [] + for method in methods: + f = HookImpl(None, "", method, method.example_impl) + hookfuncs.append(f) + return callertype(hookfuncs, kwargs, {"firstresult": firstresult}) + + +@hookimpl +def hook(arg1, arg2, arg3): + return arg1, arg2, arg3 + + +@hookimpl(hookwrapper=True) +def wrapper(arg1, arg2, arg3): + yield + + +@pytest.fixture( + params=[10, 100], + ids="hooks={}".format, +) +def hooks(request): + return [hook for i in range(request.param)] + + +@pytest.fixture( + params=[10, 100], + ids="wrappers={}".format, +) +def wrappers(request): + return [wrapper for i in range(request.param)] + + +@pytest.fixture( + params=[_multicall, _legacymulticall], + ids=lambda item: item.__name__ +) +def callertype(request): + return request.param + + +def inner_exec(methods, callertype): + return MC(methods, {'arg1': 1, 'arg2': 2, 'arg3': 3}, callertype) + + +def test_hook_and_wrappers_speed(benchmark, hooks, wrappers, callertype): + benchmark(inner_exec, hooks + wrappers, callertype) diff --git a/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/conftest.py b/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/conftest.py new file mode 100644 index 00000000000..3d61a349c88 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/conftest.py @@ -0,0 +1,30 @@ +import pytest + + +@pytest.fixture( + params=[ + lambda spec: spec, + lambda spec: spec() + ], + ids=[ + "spec-is-class", + "spec-is-instance" + ], +) +def he_pm(request, pm): + from pluggy import HookspecMarker + hookspec = HookspecMarker("example") + + class Hooks(object): + @hookspec + def he_method1(self, arg): + return arg + 1 + + pm.add_hookspecs(request.param(Hooks)) + return pm + + +@pytest.fixture +def pm(): + from pluggy import PluginManager + return PluginManager("example") diff --git a/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/test_details.py b/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/test_details.py new file mode 100644 index 00000000000..2fad198d958 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/test_details.py @@ -0,0 +1,103 @@ +import warnings + +import pytest + +from pluggy import PluginManager, HookimplMarker, HookspecMarker, _Result + +hookspec = HookspecMarker("example") +hookimpl = HookimplMarker("example") + + +def test_parse_hookimpl_override(): + class MyPluginManager(PluginManager): + def parse_hookimpl_opts(self, module_or_class, name): + opts = PluginManager.parse_hookimpl_opts( + self, module_or_class, name) + if opts is None: + if name.startswith("x1"): + opts = {} + return opts + + class Plugin(object): + def x1meth(self): + pass + + @hookimpl(hookwrapper=True, tryfirst=True) + def x1meth2(self): + pass + + class Spec(object): + @hookspec + def x1meth(self): + pass + + @hookspec + def x1meth2(self): + pass + + pm = MyPluginManager(hookspec.project_name) + pm.register(Plugin()) + pm.add_hookspecs(Spec) + assert not pm.hook.x1meth._nonwrappers[0].hookwrapper + assert not pm.hook.x1meth._nonwrappers[0].tryfirst + assert not pm.hook.x1meth._nonwrappers[0].trylast + assert not pm.hook.x1meth._nonwrappers[0].optionalhook + + assert pm.hook.x1meth2._wrappers[0].tryfirst + assert pm.hook.x1meth2._wrappers[0].hookwrapper + + +def test_plugin_getattr_raises_errors(): + """Pluggy must be able to handle plugins which raise weird exceptions + when getattr() gets called (#11). + """ + class DontTouchMe(object): + def __getattr__(self, x): + raise Exception('cant touch me') + + class Module(object): + pass + + module = Module() + module.x = DontTouchMe() + + pm = PluginManager(hookspec.project_name) + # register() would raise an error + pm.register(module, 'donttouch') + assert pm.get_plugin('donttouch') is module + + +def test_warning_on_call_vs_hookspec_arg_mismatch(): + """Verify that is a hook is called with less arguments then defined in the + spec that a warning is emitted. + """ + class Spec: + @hookspec + def myhook(self, arg1, arg2): + pass + + class Plugin: + @hookimpl + def myhook(self, arg1): + pass + + pm = PluginManager(hookspec.project_name) + pm.register(Plugin()) + pm.add_hookspecs(Spec()) + + with warnings.catch_warnings(record=True) as warns: + warnings.simplefilter('always') + + # calling should trigger a warning + pm.hook.myhook(arg1=1) + + assert len(warns) == 1 + warning = warns[-1] + assert issubclass(warning.category, Warning) + assert "Argument(s) ('arg2',)" in str(warning.message) + + +def test_result_deprecated(): + r = _Result(10, None) + with pytest.deprecated_call(): + assert r.result == 10 diff --git a/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/test_helpers.py b/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/test_helpers.py new file mode 100644 index 00000000000..b1780968446 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/test_helpers.py @@ -0,0 +1,68 @@ +from pluggy import _formatdef, varnames + + +def test_varnames(): + def f(x): + i = 3 # noqa + + class A(object): + def f(self, y): + pass + + class B(object): + def __call__(self, z): + pass + + assert varnames(f) == (("x",), ()) + assert varnames(A().f) == (('y',), ()) + assert varnames(B()) == (('z',), ()) + + +def test_varnames_default(): + def f(x, y=3): + pass + + assert varnames(f) == (("x",), ("y",)) + + +def test_varnames_class(): + class C(object): + def __init__(self, x): + pass + + class D(object): + pass + + class E(object): + def __init__(self, x): + pass + + class F(object): + pass + + assert varnames(C) == (("x",), ()) + assert varnames(D) == ((), ()) + assert varnames(E) == (("x",), ()) + assert varnames(F) == ((), ()) + + +def test_formatdef(): + def function1(): + pass + + assert _formatdef(function1) == 'function1()' + + def function2(arg1): + pass + + assert _formatdef(function2) == "function2(arg1)" + + def function3(arg1, arg2="qwe"): + pass + + assert _formatdef(function3) == "function3(arg1, arg2='qwe')" + + def function4(arg1, *args, **kwargs): + pass + + assert _formatdef(function4) == "function4(arg1, *args, **kwargs)" diff --git a/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/test_hookrelay.py b/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/test_hookrelay.py new file mode 100644 index 00000000000..5e7821bed8f --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/test_hookrelay.py @@ -0,0 +1,210 @@ +import pytest +from pluggy import PluginValidationError, HookimplMarker, HookspecMarker + + +hookspec = HookspecMarker("example") +hookimpl = HookimplMarker("example") + + +def test_happypath(pm): + class Api(object): + @hookspec + def hello(self, arg): + "api hook 1" + + pm.add_hookspecs(Api) + hook = pm.hook + assert hasattr(hook, 'hello') + assert repr(hook.hello).find("hello") != -1 + + class Plugin(object): + @hookimpl + def hello(self, arg): + return arg + 1 + + plugin = Plugin() + pm.register(plugin) + out = hook.hello(arg=3) + assert out == [4] + assert not hasattr(hook, 'world') + pm.unregister(plugin) + assert hook.hello(arg=3) == [] + + +def test_argmismatch(pm): + class Api(object): + @hookspec + def hello(self, arg): + "api hook 1" + + pm.add_hookspecs(Api) + + class Plugin(object): + @hookimpl + def hello(self, argwrong): + pass + + with pytest.raises(PluginValidationError) as exc: + pm.register(Plugin()) + + assert "argwrong" in str(exc.value) + + +def test_only_kwargs(pm): + class Api(object): + @hookspec + def hello(self, arg): + "api hook 1" + + pm.add_hookspecs(Api) + with pytest.raises(TypeError) as exc: + pm.hook.hello(3) + + comprehensible = "hook calling supports only keyword arguments" + assert comprehensible in str(exc.value) + + +def test_call_order(pm): + class Api(object): + @hookspec + def hello(self, arg): + "api hook 1" + + pm.add_hookspecs(Api) + + class Plugin1(object): + @hookimpl + def hello(self, arg): + return 1 + + class Plugin2(object): + @hookimpl + def hello(self, arg): + return 2 + + class Plugin3(object): + @hookimpl + def hello(self, arg): + return 3 + + class Plugin4(object): + @hookimpl(hookwrapper=True) + def hello(self, arg): + assert arg == 0 + outcome = yield + assert outcome.get_result() == [3, 2, 1] + + pm.register(Plugin1()) + pm.register(Plugin2()) + pm.register(Plugin3()) + pm.register(Plugin4()) # hookwrapper should get same list result + res = pm.hook.hello(arg=0) + assert res == [3, 2, 1] + + +def test_firstresult_definition(pm): + class Api(object): + @hookspec(firstresult=True) + def hello(self, arg): + "api hook 1" + + pm.add_hookspecs(Api) + + class Plugin1(object): + @hookimpl + def hello(self, arg): + return arg + 1 + + class Plugin2(object): + @hookimpl + def hello(self, arg): + return arg - 1 + + class Plugin3(object): + @hookimpl + def hello(self, arg): + return None + + class Plugin4(object): + @hookimpl(hookwrapper=True) + def hello(self, arg): + assert arg == 3 + outcome = yield + assert outcome.get_result() == 2 + + pm.register(Plugin1()) # discarded - not the last registered plugin + pm.register(Plugin2()) # used as result + pm.register(Plugin3()) # None result is ignored + pm.register(Plugin4()) # hookwrapper should get same non-list result + res = pm.hook.hello(arg=3) + assert res == 2 + + +def test_firstresult_force_result(pm): + """Verify forcing a result in a wrapper. + """ + class Api(object): + @hookspec(firstresult=True) + def hello(self, arg): + "api hook 1" + + pm.add_hookspecs(Api) + + class Plugin1(object): + @hookimpl + def hello(self, arg): + return arg + 1 + + class Plugin2(object): + @hookimpl(hookwrapper=True) + def hello(self, arg): + assert arg == 3 + outcome = yield + assert outcome.get_result() == 4 + outcome.force_result(0) + + class Plugin3(object): + @hookimpl + def hello(self, arg): + return None + + pm.register(Plugin1()) + pm.register(Plugin2()) # wrapper + pm.register(Plugin3()) # ignored since returns None + res = pm.hook.hello(arg=3) + assert res == 0 # this result is forced and not a list + + +def test_firstresult_returns_none(pm): + """If None results are returned by underlying implementations ensure + the multi-call loop returns a None value. + """ + class Api(object): + @hookspec(firstresult=True) + def hello(self, arg): + "api hook 1" + + pm.add_hookspecs(Api) + + class Plugin1(object): + @hookimpl + def hello(self, arg): + return None + + pm.register(Plugin1()) + res = pm.hook.hello(arg=3) + assert res is None + + +def test_firstresult_no_plugin(pm): + """If no implementations/plugins have been registered for a firstresult + hook the multi-call loop should return a None value. + """ + class Api(object): + @hookspec(firstresult=True) + def hello(self, arg): + "api hook 1" + + pm.add_hookspecs(Api) + res = pm.hook.hello(arg=3) + assert res is None diff --git a/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/test_method_ordering.py b/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/test_method_ordering.py new file mode 100644 index 00000000000..9584a0ae5a8 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/test_method_ordering.py @@ -0,0 +1,322 @@ +import pytest + + +import sys +import types + +from pluggy import PluginManager, HookImpl, HookimplMarker, HookspecMarker + +hookspec = HookspecMarker("example") +hookimpl = HookimplMarker("example") + + +@pytest.fixture +def hc(pm): + class Hooks(object): + @hookspec + def he_method1(self, arg): + pass + pm.add_hookspecs(Hooks) + return pm.hook.he_method1 + + +@pytest.fixture +def addmeth(hc): + def addmeth(tryfirst=False, trylast=False, hookwrapper=False): + def wrap(func): + hookimpl(tryfirst=tryfirst, trylast=trylast, + hookwrapper=hookwrapper)(func) + hc._add_hookimpl(HookImpl(None, "", func, func.example_impl)) + return func + return wrap + return addmeth + + +def funcs(hookmethods): + return [hookmethod.function for hookmethod in hookmethods] + + +def test_adding_nonwrappers(hc, addmeth): + @addmeth() + def he_method1(): + pass + + @addmeth() + def he_method2(): + pass + + @addmeth() + def he_method3(): + pass + assert funcs(hc._nonwrappers) == [he_method1, he_method2, he_method3] + + +def test_adding_nonwrappers_trylast(hc, addmeth): + @addmeth() + def he_method1_middle(): + pass + + @addmeth(trylast=True) + def he_method1(): + pass + + @addmeth() + def he_method1_b(): + pass + assert funcs(hc._nonwrappers) == [he_method1, he_method1_middle, he_method1_b] + + +def test_adding_nonwrappers_trylast3(hc, addmeth): + @addmeth() + def he_method1_a(): + pass + + @addmeth(trylast=True) + def he_method1_b(): + pass + + @addmeth() + def he_method1_c(): + pass + + @addmeth(trylast=True) + def he_method1_d(): + pass + assert funcs(hc._nonwrappers) == \ + [he_method1_d, he_method1_b, he_method1_a, he_method1_c] + + +def test_adding_nonwrappers_trylast2(hc, addmeth): + @addmeth() + def he_method1_middle(): + pass + + @addmeth() + def he_method1_b(): + pass + + @addmeth(trylast=True) + def he_method1(): + pass + assert funcs(hc._nonwrappers) == \ + [he_method1, he_method1_middle, he_method1_b] + + +def test_adding_nonwrappers_tryfirst(hc, addmeth): + @addmeth(tryfirst=True) + def he_method1(): + pass + + @addmeth() + def he_method1_middle(): + pass + + @addmeth() + def he_method1_b(): + pass + assert funcs(hc._nonwrappers) == [ + he_method1_middle, he_method1_b, he_method1] + + +def test_adding_wrappers_ordering(hc, addmeth): + @addmeth(hookwrapper=True) + def he_method1(): + pass + + @addmeth() + def he_method1_middle(): + pass + + @addmeth(hookwrapper=True) + def he_method3(): + pass + + assert funcs(hc._nonwrappers) == [he_method1_middle] + assert funcs(hc._wrappers) == [he_method1, he_method3] + + +def test_adding_wrappers_ordering_tryfirst(hc, addmeth): + @addmeth(hookwrapper=True, tryfirst=True) + def he_method1(): + pass + + @addmeth(hookwrapper=True) + def he_method2(): + pass + + assert hc._nonwrappers == [] + assert funcs(hc._wrappers) == [he_method2, he_method1] + + +def test_hookspec(pm): + class HookSpec(object): + @hookspec() + def he_myhook1(arg1): + pass + + @hookspec(firstresult=True) + def he_myhook2(arg1): + pass + + @hookspec(firstresult=False) + def he_myhook3(arg1): + pass + + pm.add_hookspecs(HookSpec) + assert not pm.hook.he_myhook1.spec_opts["firstresult"] + assert pm.hook.he_myhook2.spec_opts["firstresult"] + assert not pm.hook.he_myhook3.spec_opts["firstresult"] + + +@pytest.mark.parametrize('name', ["hookwrapper", "optionalhook", "tryfirst", "trylast"]) +@pytest.mark.parametrize('val', [True, False]) +def test_hookimpl(name, val): + @hookimpl(**{name: val}) + def he_myhook1(arg1): + pass + if val: + assert he_myhook1.example_impl.get(name) + else: + assert not hasattr(he_myhook1, name) + + +def test_load_setuptools_instantiation(monkeypatch, pm): + pkg_resources = pytest.importorskip("pkg_resources") + + def my_iter(name): + assert name == "hello" + + class EntryPoint(object): + name = "myname" + dist = None + + def load(self): + class PseudoPlugin(object): + x = 42 + return PseudoPlugin() + + return iter([EntryPoint()]) + + monkeypatch.setattr(pkg_resources, 'iter_entry_points', my_iter) + num = pm.load_setuptools_entrypoints("hello") + assert num == 1 + plugin = pm.get_plugin("myname") + assert plugin.x == 42 + assert pm.list_plugin_distinfo() == [(plugin, None)] + + +def test_load_setuptools_not_installed(monkeypatch, pm): + monkeypatch.setitem( + sys.modules, 'pkg_resources', + types.ModuleType("pkg_resources")) + + with pytest.raises(ImportError): + pm.load_setuptools_entrypoints("qwe") + + +def test_add_tracefuncs(he_pm): + out = [] + + class api1(object): + @hookimpl + def he_method1(self): + out.append("he_method1-api1") + + class api2(object): + @hookimpl + def he_method1(self): + out.append("he_method1-api2") + + he_pm.register(api1()) + he_pm.register(api2()) + + def before(hook_name, hook_impls, kwargs): + out.append((hook_name, list(hook_impls), kwargs)) + + def after(outcome, hook_name, hook_impls, kwargs): + out.append((outcome, hook_name, list(hook_impls), kwargs)) + + undo = he_pm.add_hookcall_monitoring(before, after) + + he_pm.hook.he_method1(arg=1) + assert len(out) == 4 + assert out[0][0] == "he_method1" + assert len(out[0][1]) == 2 + assert isinstance(out[0][2], dict) + assert out[1] == "he_method1-api2" + assert out[2] == "he_method1-api1" + assert len(out[3]) == 4 + assert out[3][1] == out[0][0] + + undo() + he_pm.hook.he_method1(arg=1) + assert len(out) == 4 + 2 + + +def test_hook_tracing(he_pm): + saveindent = [] + + class api1(object): + @hookimpl + def he_method1(self): + saveindent.append(he_pm.trace.root.indent) + + class api2(object): + @hookimpl + def he_method1(self): + saveindent.append(he_pm.trace.root.indent) + raise ValueError() + + he_pm.register(api1()) + out = [] + he_pm.trace.root.setwriter(out.append) + undo = he_pm.enable_tracing() + try: + indent = he_pm.trace.root.indent + he_pm.hook.he_method1(arg=1) + assert indent == he_pm.trace.root.indent + assert len(out) == 2 + assert 'he_method1' in out[0] + assert 'finish' in out[1] + + out[:] = [] + he_pm.register(api2()) + + with pytest.raises(ValueError): + he_pm.hook.he_method1(arg=1) + assert he_pm.trace.root.indent == indent + assert saveindent[0] > indent + finally: + undo() + + +@pytest.mark.parametrize('include_hookspec', [True, False]) +def test_prefix_hookimpl(include_hookspec): + pm = PluginManager(hookspec.project_name, "hello_") + + if include_hookspec: + class HookSpec(object): + @hookspec + def hello_myhook(self, arg1): + """ add to arg1 """ + + pm.add_hookspecs(HookSpec) + + class Plugin(object): + def hello_myhook(self, arg1): + return arg1 + 1 + + pm.register(Plugin()) + pm.register(Plugin()) + results = pm.hook.hello_myhook(arg1=17) + assert results == [18, 18] + + +def test_prefix_hookimpl_dontmatch_module(): + pm = PluginManager(hookspec.project_name, "hello_") + + class BadPlugin(object): + hello_module = __import__('email') + + pm.register(BadPlugin()) + pm.check_pending() diff --git a/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/test_multicall.py b/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/test_multicall.py new file mode 100644 index 00000000000..860a209b669 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/test_multicall.py @@ -0,0 +1,194 @@ +import pytest + +from pluggy import _multicall, _legacymulticall, HookImpl, HookCallError +from pluggy.callers import _LegacyMultiCall +from pluggy import HookspecMarker, HookimplMarker + + +hookspec = HookspecMarker("example") +hookimpl = HookimplMarker("example") + + +def test_uses_copy_of_methods(): + out = [lambda: 42] + mc = _LegacyMultiCall(out, {}) + repr(mc) + out[:] = [] + res = mc.execute() + return res == 42 + + +def MC(methods, kwargs, firstresult=False): + caller = _multicall + hookfuncs = [] + for method in methods: + f = HookImpl(None, "", method, method.example_impl) + hookfuncs.append(f) + if '__multicall__' in f.argnames: + caller = _legacymulticall + return caller(hookfuncs, kwargs, firstresult=firstresult) + + +def test_call_passing(): + class P1(object): + @hookimpl + def m(self, __multicall__, x): + assert len(__multicall__.results) == 1 + assert not __multicall__.hook_impls + return 17 + + class P2(object): + @hookimpl + def m(self, __multicall__, x): + assert __multicall__.results == [] + assert __multicall__.hook_impls + return 23 + + p1 = P1() + p2 = P2() + reslist = MC([p1.m, p2.m], {"x": 23}) + assert len(reslist) == 2 + # ensure reversed order + assert reslist == [23, 17] + + +def test_keyword_args(): + @hookimpl + def f(x): + return x + 1 + + class A(object): + @hookimpl + def f(self, x, y): + return x + y + + reslist = MC([f, A().f], dict(x=23, y=24)) + assert reslist == [24 + 23, 24] + + +def test_keyword_args_with_defaultargs(): + @hookimpl + def f(x, z=1): + return x + z + reslist = MC([f], dict(x=23, y=24)) + assert reslist == [24] + + +def test_tags_call_error(): + @hookimpl + def f(x): + return x + with pytest.raises(HookCallError): + MC([f], {}) + + +def test_call_subexecute(): + @hookimpl + def m(__multicall__): + subresult = __multicall__.execute() + return subresult + 1 + + @hookimpl + def n(): + return 1 + + res = MC([n, m], {}, firstresult=True) + assert res == 2 + + +def test_call_none_is_no_result(): + @hookimpl + def m1(): + return 1 + + @hookimpl + def m2(): + return None + + res = MC([m1, m2], {}, firstresult=True) + assert res == 1 + res = MC([m1, m2], {}, {}) + assert res == [1] + + +def test_hookwrapper(): + out = [] + + @hookimpl(hookwrapper=True) + def m1(): + out.append("m1 init") + yield None + out.append("m1 finish") + + @hookimpl + def m2(): + out.append("m2") + return 2 + + res = MC([m2, m1], {}) + assert res == [2] + assert out == ["m1 init", "m2", "m1 finish"] + out[:] = [] + res = MC([m2, m1], {}, firstresult=True) + assert res == 2 + assert out == ["m1 init", "m2", "m1 finish"] + + +def test_hookwrapper_order(): + out = [] + + @hookimpl(hookwrapper=True) + def m1(): + out.append("m1 init") + yield 1 + out.append("m1 finish") + + @hookimpl(hookwrapper=True) + def m2(): + out.append("m2 init") + yield 2 + out.append("m2 finish") + + res = MC([m2, m1], {}) + assert res == [] + assert out == ["m1 init", "m2 init", "m2 finish", "m1 finish"] + + +def test_hookwrapper_not_yield(): + @hookimpl(hookwrapper=True) + def m1(): + pass + + with pytest.raises(TypeError): + MC([m1], {}) + + +def test_hookwrapper_too_many_yield(): + @hookimpl(hookwrapper=True) + def m1(): + yield 1 + yield 2 + + with pytest.raises(RuntimeError) as ex: + MC([m1], {}) + assert "m1" in str(ex.value) + assert (__file__ + ':') in str(ex.value) + + +@pytest.mark.parametrize("exc", [ValueError, SystemExit]) +def test_hookwrapper_exception(exc): + out = [] + + @hookimpl(hookwrapper=True) + def m1(): + out.append("m1 init") + yield None + out.append("m1 finish") + + @hookimpl + def m2(): + raise exc + + with pytest.raises(exc): + MC([m2, m1], {}) + assert out == ["m1 init", "m1 finish"] diff --git a/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/test_pluginmanager.py b/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/test_pluginmanager.py new file mode 100644 index 00000000000..e2c86cc6442 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/test_pluginmanager.py @@ -0,0 +1,374 @@ +import pytest +import types + +from pluggy import (PluginValidationError, + HookCallError, HookimplMarker, HookspecMarker) + + +hookspec = HookspecMarker("example") +hookimpl = HookimplMarker("example") + + +def test_plugin_double_register(pm): + pm.register(42, name="abc") + with pytest.raises(ValueError): + pm.register(42, name="abc") + with pytest.raises(ValueError): + pm.register(42, name="def") + + +def test_pm(pm): + class A(object): + pass + + a1, a2 = A(), A() + pm.register(a1) + assert pm.is_registered(a1) + pm.register(a2, "hello") + assert pm.is_registered(a2) + out = pm.get_plugins() + assert a1 in out + assert a2 in out + assert pm.get_plugin('hello') == a2 + assert pm.unregister(a1) == a1 + assert not pm.is_registered(a1) + + out = pm.list_name_plugin() + assert len(out) == 1 + assert out == [("hello", a2)] + + +def test_has_plugin(pm): + class A(object): + pass + + a1 = A() + pm.register(a1, 'hello') + assert pm.is_registered(a1) + assert pm.has_plugin('hello') + + +def test_register_dynamic_attr(he_pm): + class A(object): + def __getattr__(self, name): + if name[0] != "_": + return 42 + raise AttributeError() + + a = A() + he_pm.register(a) + assert not he_pm.get_hookcallers(a) + + +def test_pm_name(pm): + class A(object): + pass + + a1 = A() + name = pm.register(a1, name="hello") + assert name == "hello" + pm.unregister(a1) + assert pm.get_plugin(a1) is None + assert not pm.is_registered(a1) + assert not pm.get_plugins() + name2 = pm.register(a1, name="hello") + assert name2 == name + pm.unregister(name="hello") + assert pm.get_plugin(a1) is None + assert not pm.is_registered(a1) + assert not pm.get_plugins() + + +def test_set_blocked(pm): + class A(object): + pass + + a1 = A() + name = pm.register(a1) + assert pm.is_registered(a1) + assert not pm.is_blocked(name) + pm.set_blocked(name) + assert pm.is_blocked(name) + assert not pm.is_registered(a1) + + pm.set_blocked("somename") + assert pm.is_blocked("somename") + assert not pm.register(A(), "somename") + pm.unregister(name="somename") + assert pm.is_blocked("somename") + + +def test_register_mismatch_method(he_pm): + class hello(object): + @hookimpl + def he_method_notexists(self): + pass + + he_pm.register(hello()) + with pytest.raises(PluginValidationError): + he_pm.check_pending() + + +def test_register_mismatch_arg(he_pm): + class hello(object): + @hookimpl + def he_method1(self, qlwkje): + pass + + with pytest.raises(PluginValidationError): + he_pm.register(hello()) + + +def test_register(pm): + class MyPlugin(object): + pass + my = MyPlugin() + pm.register(my) + assert my in pm.get_plugins() + my2 = MyPlugin() + pm.register(my2) + assert set([my, my2]).issubset(pm.get_plugins()) + + assert pm.is_registered(my) + assert pm.is_registered(my2) + pm.unregister(my) + assert not pm.is_registered(my) + assert my not in pm.get_plugins() + + +def test_register_unknown_hooks(pm): + class Plugin1(object): + @hookimpl + def he_method1(self, arg): + return arg + 1 + + pname = pm.register(Plugin1()) + + class Hooks(object): + @hookspec + def he_method1(self, arg): + pass + + pm.add_hookspecs(Hooks) + # assert not pm._unverified_hooks + assert pm.hook.he_method1(arg=1) == [2] + assert len(pm.get_hookcallers(pm.get_plugin(pname))) == 1 + + +def test_register_historic(pm): + class Hooks(object): + @hookspec(historic=True) + def he_method1(self, arg): + pass + pm.add_hookspecs(Hooks) + + pm.hook.he_method1.call_historic(kwargs=dict(arg=1)) + out = [] + + class Plugin(object): + @hookimpl + def he_method1(self, arg): + out.append(arg) + + pm.register(Plugin()) + assert out == [1] + + class Plugin2(object): + @hookimpl + def he_method1(self, arg): + out.append(arg * 10) + + pm.register(Plugin2()) + assert out == [1, 10] + pm.hook.he_method1.call_historic(kwargs=dict(arg=12)) + assert out == [1, 10, 120, 12] + + +def test_with_result_memorized(pm): + class Hooks(object): + @hookspec(historic=True) + def he_method1(self, arg): + pass + pm.add_hookspecs(Hooks) + + he_method1 = pm.hook.he_method1 + he_method1.call_historic(lambda res: out.append(res), dict(arg=1)) + out = [] + + class Plugin(object): + @hookimpl + def he_method1(self, arg): + return arg * 10 + + pm.register(Plugin()) + assert out == [10] + + +def test_with_callbacks_immediately_executed(pm): + class Hooks(object): + @hookspec(historic=True) + def he_method1(self, arg): + pass + pm.add_hookspecs(Hooks) + + class Plugin1(object): + @hookimpl + def he_method1(self, arg): + return arg * 10 + + class Plugin2(object): + @hookimpl + def he_method1(self, arg): + return arg * 20 + + class Plugin3(object): + @hookimpl + def he_method1(self, arg): + return arg * 30 + + out = [] + pm.register(Plugin1()) + pm.register(Plugin2()) + + he_method1 = pm.hook.he_method1 + he_method1.call_historic(lambda res: out.append(res), dict(arg=1)) + assert out == [20, 10] + pm.register(Plugin3()) + assert out == [20, 10, 30] + + +def test_register_historic_incompat_hookwrapper(pm): + class Hooks(object): + @hookspec(historic=True) + def he_method1(self, arg): + pass + + pm.add_hookspecs(Hooks) + + out = [] + + class Plugin(object): + @hookimpl(hookwrapper=True) + def he_method1(self, arg): + out.append(arg) + + with pytest.raises(PluginValidationError): + pm.register(Plugin()) + + +def test_call_extra(pm): + class Hooks(object): + @hookspec + def he_method1(self, arg): + pass + + pm.add_hookspecs(Hooks) + + def he_method1(arg): + return arg * 10 + + out = pm.hook.he_method1.call_extra([he_method1], dict(arg=1)) + assert out == [10] + + +def test_call_with_too_few_args(pm): + class Hooks(object): + @hookspec + def he_method1(self, arg): + pass + + pm.add_hookspecs(Hooks) + + class Plugin1(object): + @hookimpl + def he_method1(self, arg): + 0 / 0 + pm.register(Plugin1()) + with pytest.raises(HookCallError): + with pytest.warns(UserWarning): + pm.hook.he_method1() + + +def test_subset_hook_caller(pm): + class Hooks(object): + @hookspec + def he_method1(self, arg): + pass + + pm.add_hookspecs(Hooks) + + out = [] + + class Plugin1(object): + @hookimpl + def he_method1(self, arg): + out.append(arg) + + class Plugin2(object): + @hookimpl + def he_method1(self, arg): + out.append(arg * 10) + + class PluginNo(object): + pass + + plugin1, plugin2, plugin3 = Plugin1(), Plugin2(), PluginNo() + pm.register(plugin1) + pm.register(plugin2) + pm.register(plugin3) + pm.hook.he_method1(arg=1) + assert out == [10, 1] + out[:] = [] + + hc = pm.subset_hook_caller("he_method1", [plugin1]) + hc(arg=2) + assert out == [20] + out[:] = [] + + hc = pm.subset_hook_caller("he_method1", [plugin2]) + hc(arg=2) + assert out == [2] + out[:] = [] + + pm.unregister(plugin1) + hc(arg=2) + assert out == [] + out[:] = [] + + pm.hook.he_method1(arg=1) + assert out == [10] + + +def test_multicall_deprecated(pm): + class P1(object): + @hookimpl + def m(self, __multicall__, x): + pass + + pytest.deprecated_call(pm.register, P1()) + + +def test_add_hookspecs_nohooks(pm): + with pytest.raises(ValueError): + pm.add_hookspecs(10) + + +def test_reject_prefixed_module(pm): + """Verify that a module type attribute that contains the project + prefix in its name (in this case `'example_*'` isn't collected + when registering a module which imports it. + """ + pm._implprefix = 'example' + conftest = types.ModuleType("conftest") + src = (""" +def example_hook(): + pass +""") + exec(src, conftest.__dict__) + conftest.example_blah = types.ModuleType("example_blah") + name = pm.register(conftest) + assert name == 'conftest' + assert getattr(pm.hook, 'example_blah', None) is None + assert getattr(pm.hook, 'example_hook', None) # conftest.example_hook should be collected + assert pm.parse_hookimpl_opts(conftest, 'example_blah') is None + assert pm.parse_hookimpl_opts(conftest, 'example_hook') == {} diff --git a/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/test_tracer.py b/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/test_tracer.py new file mode 100644 index 00000000000..4a3e16cec43 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/testing/test_tracer.py @@ -0,0 +1,89 @@ + +from pluggy import _TagTracer + + +def test_simple(): + rootlogger = _TagTracer() + log = rootlogger.get("pytest") + log("hello") + out = [] + rootlogger.setwriter(out.append) + log("world") + assert len(out) == 1 + assert out[0] == "world [pytest]\n" + sublog = log.get("collection") + sublog("hello") + assert out[1] == "hello [pytest:collection]\n" + + +def test_indent(): + rootlogger = _TagTracer() + log = rootlogger.get("1") + out = [] + log.root.setwriter(lambda arg: out.append(arg)) + log("hello") + log.root.indent += 1 + log("line1") + log("line2") + log.root.indent += 1 + log("line3") + log("line4") + log.root.indent -= 1 + log("line5") + log.root.indent -= 1 + log("last") + assert len(out) == 7 + names = [x[:x.rfind(' [')] for x in out] + assert names == [ + 'hello', ' line1', ' line2', + ' line3', ' line4', ' line5', 'last'] + + +def test_readable_output_dictargs(): + rootlogger = _TagTracer() + + out = rootlogger.format_message(['test'], [1]) + assert out == ['1 [test]\n'] + + out2 = rootlogger.format_message(['test'], ['test', {'a': 1}]) + assert out2 == [ + 'test [test]\n', + ' a: 1\n' + ] + + +def test_setprocessor(): + rootlogger = _TagTracer() + log = rootlogger.get("1") + log2 = log.get("2") + assert log2.tags == tuple("12") + out = [] + rootlogger.setprocessor(tuple("12"), lambda *args: out.append(args)) + log("not seen") + log2("seen") + assert len(out) == 1 + tags, args = out[0] + assert "1" in tags + assert "2" in tags + assert args == ("seen",) + l2 = [] + rootlogger.setprocessor("1:2", lambda *args: l2.append(args)) + log2("seen") + tags, args = l2[0] + assert args == ("seen",) + + +def test_setmyprocessor(): + rootlogger = _TagTracer() + log = rootlogger.get("1") + log2 = log.get("2") + out = [] + log2.setmyprocessor(lambda *args: out.append(args)) + log("not seen") + assert not out + log2(42) + assert len(out) == 1 + tags, args = out[0] + assert "1" in tags + assert "2" in tags + assert args == (42,) diff --git a/tests/wpt/web-platform-tests/tools/third_party/pluggy/tox.ini b/tests/wpt/web-platform-tests/tools/third_party/pluggy/tox.ini new file mode 100644 index 00000000000..89d44e352db --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pluggy/tox.ini @@ -0,0 +1,44 @@ +[tox] +envlist=check,docs,py{27,34,35,36,py}-pytestrelease,py{27,36}-pytest{master,features} + +[testenv] +commands=py.test {posargs:testing/} +setenv= + _PYTEST_SETUP_SKIP_PLUGGY_DEP=1 +deps= + pytestrelease: pytest + pytestmaster: git+https://github.com/pytest-dev/pytest.git@master + pytestfeatures: git+https://github.com/pytest-dev/pytest.git@features + +[testenv:benchmark] +commands=py.test {posargs:testing/benchmark.py} +deps= + pytest + pytest-benchmark + +[testenv:check] +deps = + flake8 + restructuredtext_lint + pygments +commands = + flake8 pluggy.py setup.py testing + rst-lint CHANGELOG.rst README.rst + +[testenv:docs] +deps = + sphinx + pygments +commands = + sphinx-build -b html {toxinidir}/docs {toxinidir}/build/html-docs + +[pytest] +minversion=2.0 +#--pyargs --doctest-modules --ignore=.tox +addopts=-rxsX +norecursedirs=.tox ja .hg .env* +filterwarnings = + error + +[flake8] +max-line-length=99 diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/.gitattributes b/tests/wpt/web-platform-tests/tools/third_party/py/.gitattributes new file mode 100644 index 00000000000..1246879c4da --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/py/.gitattributes @@ -0,0 +1 @@ +*.dump eol=lf diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/.gitignore b/tests/wpt/web-platform-tests/tools/third_party/py/.gitignore new file mode 100644 index 00000000000..5bb0d457d49 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/py/.gitignore @@ -0,0 +1,12 @@ + +.cache/ +.tox/ +__pycache__/ + +*.pyc +*.pyo + +*.egg-info +.eggs/ + +dist/* diff --git a/tests/wpt/web-platform-tests/tools/py/.hgignore b/tests/wpt/web-platform-tests/tools/third_party/py/.hgignore similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/.hgignore rename to tests/wpt/web-platform-tests/tools/third_party/py/.hgignore diff --git a/tests/wpt/web-platform-tests/tools/py/.hgtags b/tests/wpt/web-platform-tests/tools/third_party/py/.hgtags similarity index 98% rename from tests/wpt/web-platform-tests/tools/py/.hgtags rename to tests/wpt/web-platform-tests/tools/third_party/py/.hgtags index d45ebb5a237..9d48095bf64 100644 --- a/tests/wpt/web-platform-tests/tools/py/.hgtags +++ b/tests/wpt/web-platform-tests/tools/third_party/py/.hgtags @@ -65,3 +65,4 @@ dc9ffbcaf1f7d72e96be3f68c11deebb7e7193c5 1.4.25 ba08706f08ddea1b77a426f00dfe2bdc244345e8 1.4.28 4e8054ada63f3327bcf759ae7cd36c7c8652bc9b 1.4.29 366ab346610c6de8aaa7617e24011794b40236c6 1.4.30 +657380e439f9b7e04918cb162cb2e46388244b42 1.4.31 diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/.travis.yml b/tests/wpt/web-platform-tests/tools/third_party/py/.travis.yml new file mode 100644 index 00000000000..917c59d14b7 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/py/.travis.yml @@ -0,0 +1,27 @@ +sudo: false +language: python +python: +- '2.7' +- '3.4' +- '3.5' +- '3.6' +- 'pypy-5.4' +env: +- DEPS="pytest~=2.9.0" +- DEPS="pytest~=3.0.0" +#- DEPS="pytest~=3.1.0" + +matrix: + + include: + - python: '2.7' + # using a different option due to pytest-addopts pytester issues + env: PYTEST_XADDOPTS="-n 3 --runslowtests" DEPS="pytest~=3.0.0 pytest-xdist" + allow_failures: + - python: 'pypy-5.4' +install: +- pip install -U setuptools setuptools_scm +- pip install $DEPS +- pip install -U . --force-reinstall +script: +- py.test --lsof $PYTEST_XADDOPTS diff --git a/tests/wpt/web-platform-tests/tools/py/AUTHORS b/tests/wpt/web-platform-tests/tools/third_party/py/AUTHORS similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/AUTHORS rename to tests/wpt/web-platform-tests/tools/third_party/py/AUTHORS diff --git a/tests/wpt/web-platform-tests/tools/py/CHANGELOG b/tests/wpt/web-platform-tests/tools/third_party/py/CHANGELOG similarity index 94% rename from tests/wpt/web-platform-tests/tools/py/CHANGELOG rename to tests/wpt/web-platform-tests/tools/third_party/py/CHANGELOG index 712fc4c5389..7e7b01b0b9e 100644 --- a/tests/wpt/web-platform-tests/tools/py/CHANGELOG +++ b/tests/wpt/web-platform-tests/tools/third_party/py/CHANGELOG @@ -1,3 +1,63 @@ +1.5.2 +===== + +- fix #169, #170: error importing py.log on Windows: no module named ``syslog``. + +1.5.1 +===== + +- fix #167 - prevent pip from installing py in unsupported Python versions. + +1.5.0 +===== + +NOTE: **this release has been removed from PyPI** due to missing package +metadata which caused a number of problems to py26 and py33 users. +This issue was fixed in the 1.5.1 release. + +- python 2.6 and 3.3 are no longer supported +- deprecate py.std and remove all internal uses +- fix #73 turn py.error into an actual module +- path join to / no longer produces leading double slashes +- fix #82 - remove unsupportable aliases +- fix python37 compatibility of path.sysfind on windows by correctly replacing vars +- turn iniconfig and apipkg into vendored packages and ease de-vendoring for distributions +- fix #68 remove invalid py.test.ensuretemp references +- fix #25 - deprecate path.listdir(sort=callable) +- add ``TerminalWriter.chars_on_current_line`` read-only property that tracks how many characters + have been written to the current line. + +1.4.34 +==================================================================== + +- fix issue119 / pytest issue708 where tmpdir may fail to make numbered directories + when the filesystem is case-insensitive. + +1.4.33 +==================================================================== + +- avoid imports in calls to py.path.local().fnmatch(). Thanks Andreas Pelme for + the PR. + +- fix issue106: Naive unicode encoding when calling fspath() in python2. Thanks Tiago Nobrega for the PR. + +- fix issue110: unittest.TestCase.assertWarns fails with py imported. + +1.4.32 +==================================================================== + +- fix issue70: added ability to copy all stat info in py.path.local.copy. + +- make TerminalWriter.fullwidth a property. This results in the correct + value when the terminal gets resized. + +- update supported html tags to include recent additions. + Thanks Denis Afonso for the PR. + +- Remove internal code in ``Source.compile`` meant to support earlier Python 3 versions that produced the side effect + of leaving ``None`` in ``sys.modules`` when called (see pytest-dev/pytest#2103). + Thanks Bruno Oliveira for the PR. + 1.4.31 ================================================== @@ -343,7 +403,7 @@ Changes between 1.4.0 and 1.4.1 - fix (pytest-) issue20 path.samefile(relpath) works as expected now -- fix (pytest-) issue8 len(long_list) now shows the lenght of the list +- fix (pytest-) issue8 len(long_list) now shows the length of the list Changes between 1.3.4 and 1.4.0 ================================================== diff --git a/tests/wpt/web-platform-tests/tools/py/LICENSE b/tests/wpt/web-platform-tests/tools/third_party/py/LICENSE similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/LICENSE rename to tests/wpt/web-platform-tests/tools/third_party/py/LICENSE diff --git a/tests/wpt/web-platform-tests/tools/py/MANIFEST.in b/tests/wpt/web-platform-tests/tools/third_party/py/MANIFEST.in similarity index 76% rename from tests/wpt/web-platform-tests/tools/py/MANIFEST.in rename to tests/wpt/web-platform-tests/tools/third_party/py/MANIFEST.in index 31fb010b487..239ad2283e1 100644 --- a/tests/wpt/web-platform-tests/tools/py/MANIFEST.in +++ b/tests/wpt/web-platform-tests/tools/third_party/py/MANIFEST.in @@ -1,9 +1,10 @@ include CHANGELOG include AUTHORS -include README.txt +include README.rst include setup.py include LICENSE include conftest.py include tox.ini graft doc graft testing +global-exclude *.pyc diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/README.rst b/tests/wpt/web-platform-tests/tools/third_party/py/README.rst new file mode 100644 index 00000000000..7092ae4c460 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/py/README.rst @@ -0,0 +1,34 @@ +.. image:: https://img.shields.io/pypi/v/py.svg + :target: https://pypi.org/project/py + +.. image:: https://anaconda.org/conda-forge/py/badges/version.svg + :target: https://anaconda.org/conda-forge/py + +.. image:: https://img.shields.io/pypi/pyversions/pytest.svg + :target: https://pypi.org/project/py + +.. image:: https://img.shields.io/travis/pytest-dev/py.svg + :target: https://travis-ci.org/pytest-dev/py + +.. image:: https://ci.appveyor.com/api/projects/status/10keglan6uqwj5al/branch/master?svg=true + :target: https://ci.appveyor.com/project/pytestbot/py + + +**NOTE**: this library is in **maintenance mode** and should not be used in new code. + +The py lib is a Python development support library featuring +the following tools and modules: + +* ``py.path``: uniform local and svn path objects +* ``py.apipkg``: explicit API control and lazy-importing +* ``py.iniconfig``: easy parsing of .ini files +* ``py.code``: dynamic code generation and introspection (deprecated, moved to ``pytest``). + +**NOTE**: prior to the 1.4 release this distribution used to +contain py.test which is now its own package, see http://pytest.org + +For questions and more information please visit http://py.readthedocs.org + +Bugs and issues: https://github.com/pytest-dev/py + +Authors: Holger Krekel and others, 2004-2017 diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/appveyor.yml b/tests/wpt/web-platform-tests/tools/third_party/py/appveyor.yml new file mode 100644 index 00000000000..5fbeca9ab65 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/py/appveyor.yml @@ -0,0 +1,26 @@ +environment: + matrix: + # note: please use "tox --listenvs" to populate the build matrix below + - TOXENV: "py27-pytest29" + - TOXENV: "py27-pytest30" + - TOXENV: "py27-pytest31" + - TOXENV: "py34-pytest29" + - TOXENV: "py34-pytest30" + - TOXENV: "py34-pytest31" + - TOXENV: "py35-pytest29" + - TOXENV: "py35-pytest30" + - TOXENV: "py35-pytest31" + - TOXENV: "py36-pytest29" + - TOXENV: "py36-pytest30" + - TOXENV: "py36-pytest31" + +install: + - echo Installed Pythons + - dir c:\Python* + + - C:\Python36\python -m pip install --upgrade --pre tox + +build: false # Not a C# project, build stuff at the test step instead. + +test_script: + - C:\Python36\python -m tox diff --git a/tests/wpt/web-platform-tests/tools/py/bench/localpath.py b/tests/wpt/web-platform-tests/tools/third_party/py/bench/localpath.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/bench/localpath.py rename to tests/wpt/web-platform-tests/tools/third_party/py/bench/localpath.py diff --git a/tests/wpt/web-platform-tests/tools/py/conftest.py b/tests/wpt/web-platform-tests/tools/third_party/py/conftest.py similarity index 61% rename from tests/wpt/web-platform-tests/tools/py/conftest.py rename to tests/wpt/web-platform-tests/tools/third_party/py/conftest.py index 11c2d442504..5bff3fe0224 100644 --- a/tests/wpt/web-platform-tests/tools/py/conftest.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/conftest.py @@ -1,46 +1,32 @@ import py +import pytest import sys -pytest_plugins = 'doctest pytester'.split() +pytest_plugins = 'doctest', 'pytester' collect_ignore = ['build', 'doc/_build'] -import os, py -pid = os.getpid() - def pytest_addoption(parser): group = parser.getgroup("pylib", "py lib testing options") group.addoption('--runslowtests', action="store_true", dest="runslowtests", default=False, help=("run slow tests")) -def pytest_funcarg__sshhost(request): +@pytest.fixture +def sshhost(request): val = request.config.getvalue("sshhost") if val: return val py.test.skip("need --sshhost option") -def pytest_generate_tests(metafunc): - multi = getattr(metafunc.function, 'multi', None) - if multi is not None: - assert len(multi.kwargs) == 1 - for name, l in multi.kwargs.items(): - for val in l: - metafunc.addcall(funcargs={name: val}) - elif 'anypython' in metafunc.funcargnames: - for name in ('python2.4', 'python2.5', 'python2.6', - 'python2.7', 'python3.1', 'pypy-c', 'jython'): - metafunc.addcall(id=name, param=name) + # XXX copied from execnet's conftest.py - needs to be merged winpymap = { 'python2.7': r'C:\Python27\python.exe', - 'python2.6': r'C:\Python26\python.exe', - 'python2.5': r'C:\Python25\python.exe', - 'python2.4': r'C:\Python24\python.exe', - 'python3.1': r'C:\Python31\python.exe', } + def getexecutable(name, cache={}): try: return cache[name] @@ -49,7 +35,8 @@ def getexecutable(name, cache={}): if executable: if name == "jython": import subprocess - popen = subprocess.Popen([str(executable), "--version"], + popen = subprocess.Popen( + [str(executable), "--version"], universal_newlines=True, stderr=subprocess.PIPE) out, err = popen.communicate() if not err or "2.5" not in err: @@ -57,7 +44,9 @@ def getexecutable(name, cache={}): cache[name] = executable return executable -def pytest_funcarg__anypython(request): + +@pytest.fixture(params=('python2.7', 'pypy-c', 'jython')) +def anypython(request): name = request.param executable = getexecutable(name) if executable is None: diff --git a/tests/wpt/web-platform-tests/tools/py/doc/Makefile b/tests/wpt/web-platform-tests/tools/third_party/py/doc/Makefile similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/Makefile rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/Makefile diff --git a/tests/wpt/web-platform-tests/tools/py/doc/_templates/layout.html b/tests/wpt/web-platform-tests/tools/third_party/py/doc/_templates/layout.html similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/_templates/layout.html rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/_templates/layout.html diff --git a/tests/wpt/web-platform-tests/tools/py/doc/announce/release-0.9.0.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-0.9.0.txt similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/announce/release-0.9.0.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-0.9.0.txt diff --git a/tests/wpt/web-platform-tests/tools/py/doc/announce/release-0.9.2.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-0.9.2.txt similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/announce/release-0.9.2.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-0.9.2.txt diff --git a/tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.0.0.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.0.0.txt similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.0.0.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.0.0.txt diff --git a/tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.0.1.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.0.1.txt similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.0.1.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.0.1.txt diff --git a/tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.0.2.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.0.2.txt similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.0.2.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.0.2.txt diff --git a/tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.1.0.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.1.0.txt similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.1.0.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.1.0.txt diff --git a/tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.1.1.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.1.1.txt similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.1.1.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.1.1.txt diff --git a/tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.2.0.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.2.0.txt similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.2.0.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.2.0.txt diff --git a/tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.2.1.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.2.1.txt similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.2.1.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.2.1.txt diff --git a/tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.3.0.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.3.0.txt similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.3.0.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.3.0.txt diff --git a/tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.3.1.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.3.1.txt similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.3.1.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.3.1.txt diff --git a/tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.3.2.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.3.2.txt similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.3.2.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.3.2.txt diff --git a/tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.3.3.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.3.3.txt similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.3.3.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.3.3.txt diff --git a/tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.3.4.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.3.4.txt similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.3.4.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.3.4.txt diff --git a/tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.4.0.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.4.0.txt similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.4.0.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.4.0.txt diff --git a/tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.4.1.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.4.1.txt similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/announce/release-1.4.1.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/release-1.4.1.txt diff --git a/tests/wpt/web-platform-tests/tools/py/doc/announce/releases.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/releases.txt similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/announce/releases.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/announce/releases.txt diff --git a/tests/wpt/web-platform-tests/tools/py/doc/changelog.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/changelog.txt similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/changelog.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/changelog.txt diff --git a/tests/wpt/web-platform-tests/tools/py/doc/code.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/code.txt similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/code.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/code.txt diff --git a/tests/wpt/web-platform-tests/tools/py/doc/conf.py b/tests/wpt/web-platform-tests/tools/third_party/py/doc/conf.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/conf.py rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/conf.py diff --git a/tests/wpt/web-platform-tests/tools/py/doc/download.html b/tests/wpt/web-platform-tests/tools/third_party/py/doc/download.html similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/download.html rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/download.html diff --git a/tests/wpt/web-platform-tests/tools/py/doc/example/genhtml.py b/tests/wpt/web-platform-tests/tools/third_party/py/doc/example/genhtml.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/example/genhtml.py rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/example/genhtml.py diff --git a/tests/wpt/web-platform-tests/tools/py/doc/example/genhtmlcss.py b/tests/wpt/web-platform-tests/tools/third_party/py/doc/example/genhtmlcss.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/example/genhtmlcss.py rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/example/genhtmlcss.py diff --git a/tests/wpt/web-platform-tests/tools/py/doc/example/genxml.py b/tests/wpt/web-platform-tests/tools/third_party/py/doc/example/genxml.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/example/genxml.py rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/example/genxml.py diff --git a/tests/wpt/web-platform-tests/tools/py/doc/faq.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/faq.txt similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/faq.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/faq.txt diff --git a/tests/wpt/web-platform-tests/tools/py/doc/img/pylib.png b/tests/wpt/web-platform-tests/tools/third_party/py/doc/img/pylib.png similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/img/pylib.png rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/img/pylib.png diff --git a/tests/wpt/web-platform-tests/tools/py/doc/index.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/index.txt similarity index 85% rename from tests/wpt/web-platform-tests/tools/py/doc/index.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/index.txt index 7eb5c63905e..c700b17e987 100644 --- a/tests/wpt/web-platform-tests/tools/py/doc/index.txt +++ b/tests/wpt/web-platform-tests/tools/third_party/py/doc/index.txt @@ -8,10 +8,6 @@ Welcome to py's documentation! see :ref:`CHANGELOG ` for latest changes. -.. note:: - - Since version 1.4, the testing tool "py.test" is part of its own `pytest distribution`_. - .. _`pytest distribution`: http://pytest.org Contents: diff --git a/tests/wpt/web-platform-tests/tools/py/doc/install.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/install.txt similarity index 97% rename from tests/wpt/web-platform-tests/tools/py/doc/install.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/install.txt index d0e981def45..fb4056d1fba 100644 --- a/tests/wpt/web-platform-tests/tools/py/doc/install.txt +++ b/tests/wpt/web-platform-tests/tools/third_party/py/doc/install.txt @@ -7,7 +7,7 @@ installation info in a nutshell **PyPI name**: py_ -**Pythons**: CPython 2.6, 2.7, 3.3, 3.4, PyPy-2.3 +**Pythons**: CPython 2.7, 3.4, 3.5, 3.6, PyPy-5.4 **Operating systems**: Linux, Windows, OSX, Unix diff --git a/tests/wpt/web-platform-tests/tools/py/doc/io.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/io.txt similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/io.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/io.txt diff --git a/tests/wpt/web-platform-tests/tools/py/doc/links.inc b/tests/wpt/web-platform-tests/tools/third_party/py/doc/links.inc similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/links.inc rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/links.inc diff --git a/tests/wpt/web-platform-tests/tools/py/doc/log.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/log.txt similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/log.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/log.txt diff --git a/tests/wpt/web-platform-tests/tools/py/doc/misc.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/misc.txt similarity index 98% rename from tests/wpt/web-platform-tests/tools/py/doc/misc.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/misc.txt index 8c3c0b3f7a3..4b453482757 100644 --- a/tests/wpt/web-platform-tests/tools/py/doc/misc.txt +++ b/tests/wpt/web-platform-tests/tools/third_party/py/doc/misc.txt @@ -90,4 +90,4 @@ right version:: Cross-Python Version compatibility helpers ============================================= -The ``py.builtin`` namespace provides a number of helpers that help to write python code compatible across Python interpreters, mainly Python2 and Python3. Type ``help(py.builtin)`` on a Python prompt for a the selection of builtins. +The ``py.builtin`` namespace provides a number of helpers that help to write python code compatible across Python interpreters, mainly Python2 and Python3. Type ``help(py.builtin)`` on a Python prompt for the selection of builtins. diff --git a/tests/wpt/web-platform-tests/tools/py/doc/path.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/path.txt similarity index 96% rename from tests/wpt/web-platform-tests/tools/py/doc/path.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/path.txt index 837c1d19272..c906179099a 100644 --- a/tests/wpt/web-platform-tests/tools/py/doc/path.txt +++ b/tests/wpt/web-platform-tests/tools/third_party/py/doc/path.txt @@ -21,13 +21,11 @@ filesystem. It's just a bit nicer in usage than the regular Python APIs, and of course all the functionality is bundled together rather than spread over a number of modules. -Example usage, here we use the ``py.test.ensuretemp()`` function to create -a ``py.path.local`` object for us (which wraps a directory): .. sourcecode:: pycon >>> import py - >>> temppath = py.test.ensuretemp('py.path_documentation') + >>> temppath = py.path.local('py.path_documentation') >>> foopath = temppath.join('foo') # get child 'foo' (lazily) >>> foopath.check() # check if child 'foo' exists False @@ -77,7 +75,7 @@ Example usage of ``py.path.svnwc``: .. sourcecode:: pycon .. >>> if not py.test.config.option.urlcheck: raise ValueError('skipchunk') - >>> temp = py.test.ensuretemp('py.path_documentation') + >>> temp = py.path.local('py.path_documentation') >>> wc = py.path.svnwc(temp.join('svnwc')) >>> wc.checkout('http://codespeak.net/svn/py/dist/py/path/local') >>> wc.join('local.py').check() diff --git a/tests/wpt/web-platform-tests/tools/py/doc/style.css b/tests/wpt/web-platform-tests/tools/third_party/py/doc/style.css similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/style.css rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/style.css diff --git a/tests/wpt/web-platform-tests/tools/py/doc/xml.txt b/tests/wpt/web-platform-tests/tools/third_party/py/doc/xml.txt similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/doc/xml.txt rename to tests/wpt/web-platform-tests/tools/third_party/py/doc/xml.txt diff --git a/tests/wpt/web-platform-tests/tools/py/py/__init__.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/__init__.py similarity index 89% rename from tests/wpt/web-platform-tests/tools/py/py/__init__.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/__init__.py index bdb9aa2181f..b5e0c1630c7 100644 --- a/tests/wpt/web-platform-tests/tools/py/py/__init__.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/__init__.py @@ -1,5 +1,5 @@ """ -py.test and pylib: rapid testing and development utils +pylib: rapid testing and development utils this module uses apipkg.py for lazy-loading sub modules and classes. The initpkg-dictionary below specifies @@ -8,15 +8,21 @@ dictionary or an import path. (c) Holger Krekel and others, 2004-2014 """ -__version__ = '1.4.31' +__version__ = '1.5.2' -from py import _apipkg +try: + from py._vendored_packages import apipkg + lib_not_mangled_by_packagers = True + vendor_prefix = '._vendored_packages.' +except ImportError: + import apipkg + lib_not_mangled_by_packagers = False + vendor_prefix = '' # so that py.error.* instances are picklable import sys -sys.modules['py.error'] = _apipkg.AliasModule("py.error", "py._error", 'error') -_apipkg.initpkg(__name__, attr={'_apipkg': _apipkg}, exportdefs={ +apipkg.initpkg(__name__, attr={'_apipkg': apipkg}, exportdefs={ # access to all standard lib modules 'std': '._std:std', # access to all posix errno's as classes @@ -28,8 +34,6 @@ _apipkg.initpkg(__name__, attr={'_apipkg': _apipkg}, exportdefs={ # pytest-2.0 has a flat namespace, we use alias modules # to keep old references compatible 'test' : 'pytest', - 'test.collect' : 'pytest', - 'test.cmdline' : 'pytest', # hook into the top-level standard library 'process' : { @@ -40,13 +44,13 @@ _apipkg.initpkg(__name__, attr={'_apipkg': _apipkg}, exportdefs={ }, 'apipkg' : { - 'initpkg' : '._apipkg:initpkg', - 'ApiModule' : '._apipkg:ApiModule', + 'initpkg' : vendor_prefix + 'apipkg:initpkg', + 'ApiModule' : vendor_prefix + 'apipkg:ApiModule', }, 'iniconfig' : { - 'IniConfig' : '._iniconfig:IniConfig', - 'ParseError' : '._iniconfig:ParseError', + 'IniConfig' : vendor_prefix + 'iniconfig:IniConfig', + 'ParseError' : vendor_prefix + 'iniconfig:ParseError', }, 'path' : { diff --git a/tests/wpt/web-platform-tests/tools/py/py/__metainfo.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/__metainfo.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/py/__metainfo.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/__metainfo.py diff --git a/tests/wpt/web-platform-tests/tools/py/py/_builtin.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_builtin.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/py/_builtin.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_builtin.py diff --git a/tests/wpt/web-platform-tests/tools/py/py/_code/__init__.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_code/__init__.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/py/_code/__init__.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_code/__init__.py diff --git a/tests/wpt/web-platform-tests/tools/py/py/_code/_assertionnew.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_code/_assertionnew.py similarity index 91% rename from tests/wpt/web-platform-tests/tools/py/py/_code/_assertionnew.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_code/_assertionnew.py index afb1b31ff05..d03f29d8708 100644 --- a/tests/wpt/web-platform-tests/tools/py/py/_code/_assertionnew.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_code/_assertionnew.py @@ -10,27 +10,10 @@ import py from py._code.assertion import _format_explanation, BuiltinAssertionError -if sys.platform.startswith("java") and sys.version_info < (2, 5, 2): - # See http://bugs.jython.org/issue1497 - _exprs = ("BoolOp", "BinOp", "UnaryOp", "Lambda", "IfExp", "Dict", - "ListComp", "GeneratorExp", "Yield", "Compare", "Call", - "Repr", "Num", "Str", "Attribute", "Subscript", "Name", - "List", "Tuple") - _stmts = ("FunctionDef", "ClassDef", "Return", "Delete", "Assign", - "AugAssign", "Print", "For", "While", "If", "With", "Raise", - "TryExcept", "TryFinally", "Assert", "Import", "ImportFrom", - "Exec", "Global", "Expr", "Pass", "Break", "Continue") - _expr_nodes = set(getattr(ast, name) for name in _exprs) - _stmt_nodes = set(getattr(ast, name) for name in _stmts) - def _is_ast_expr(node): - return node.__class__ in _expr_nodes - def _is_ast_stmt(node): - return node.__class__ in _stmt_nodes -else: - def _is_ast_expr(node): - return isinstance(node, ast.expr) - def _is_ast_stmt(node): - return isinstance(node, ast.stmt) +def _is_ast_expr(node): + return isinstance(node, ast.expr) +def _is_ast_stmt(node): + return isinstance(node, ast.stmt) class Failure(Exception): diff --git a/tests/wpt/web-platform-tests/tools/py/py/_code/_assertionold.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_code/_assertionold.py similarity index 99% rename from tests/wpt/web-platform-tests/tools/py/py/_code/_assertionold.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_code/_assertionold.py index 4e81fb3ef6e..1bb70a875d0 100644 --- a/tests/wpt/web-platform-tests/tools/py/py/_code/_assertionold.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_code/_assertionold.py @@ -2,6 +2,7 @@ import py import sys, inspect from compiler import parse, ast, pycodegen from py._code.assertion import BuiltinAssertionError, _format_explanation +import types passthroughex = py.builtin._sysex @@ -470,7 +471,7 @@ def check(s, frame=None): def interpret(source, frame, should_fail=False): module = Interpretable(parse(source, 'exec').node) #print "got module", module - if isinstance(frame, py.std.types.FrameType): + if isinstance(frame, types.FrameType): frame = py.code.Frame(frame) try: module.run(frame) diff --git a/tests/wpt/web-platform-tests/tools/py/py/_code/_py2traceback.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_code/_py2traceback.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/py/_code/_py2traceback.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_code/_py2traceback.py diff --git a/tests/wpt/web-platform-tests/tools/py/py/_code/assertion.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_code/assertion.py similarity index 94% rename from tests/wpt/web-platform-tests/tools/py/py/_code/assertion.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_code/assertion.py index 4ce80c75b1c..ff1643799c9 100644 --- a/tests/wpt/web-platform-tests/tools/py/py/_code/assertion.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_code/assertion.py @@ -87,8 +87,4 @@ if sys.version_info > (3, 0): reinterpret_old = "old reinterpretation not available for py3" else: from py._code._assertionold import interpret as reinterpret_old -if sys.version_info >= (2, 6) or (sys.platform.startswith("java")): - from py._code._assertionnew import interpret as reinterpret -else: - reinterpret = reinterpret_old - +from py._code._assertionnew import interpret as reinterpret diff --git a/tests/wpt/web-platform-tests/tools/py/py/_code/code.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_code/code.py similarity index 96% rename from tests/wpt/web-platform-tests/tools/py/py/_code/code.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_code/code.py index f14c562a296..dad796283fe 100644 --- a/tests/wpt/web-platform-tests/tools/py/py/_code/code.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_code/code.py @@ -1,6 +1,6 @@ import py import sys -from inspect import CO_VARARGS, CO_VARKEYWORDS +from inspect import CO_VARARGS, CO_VARKEYWORDS, isclass builtin_repr = repr @@ -11,6 +11,9 @@ if sys.version_info[0] >= 3: else: from py._code._py2traceback import format_exception_only +import traceback + + class Code(object): """ wrapper around Python code objects """ def __init__(self, rawcode): @@ -21,7 +24,7 @@ class Code(object): self.firstlineno = rawcode.co_firstlineno - 1 self.name = rawcode.co_name except AttributeError: - raise TypeError("not a code object: %r" %(rawcode,)) + raise TypeError("not a code object: %r" % (rawcode,)) self.raw = rawcode def __eq__(self, other): @@ -106,7 +109,7 @@ class Frame(object): """ f_locals = self.f_locals.copy() f_locals.update(vars) - py.builtin.exec_(code, self.f_globals, f_locals ) + py.builtin.exec_(code, self.f_globals, f_locals) def repr(self, object): """ return a 'safe' (non-recursive, one-line) string repr for 'object' @@ -130,6 +133,7 @@ class Frame(object): pass # this can occur when using Psyco return retval + class TracebackEntry(object): """ a single entry in a traceback """ @@ -153,7 +157,7 @@ class TracebackEntry(object): return self.lineno - self.frame.code.firstlineno def __repr__(self): - return "" %(self.frame.code.path, self.lineno+1) + return "" % (self.frame.code.path, self.lineno+1) @property def statement(self): @@ -237,17 +241,19 @@ class TracebackEntry(object): raise except: line = "???" - return " File %r:%d in %s\n %s\n" %(fn, self.lineno+1, name, line) + return " File %r:%d in %s\n %s\n" % (fn, self.lineno+1, name, line) def name(self): return self.frame.code.raw.co_name name = property(name, None, None, "co_name of underlaying code") + class Traceback(list): """ Traceback objects encapsulate and offer higher level access to Traceback entries. """ Entry = TracebackEntry + def __init__(self, tb): """ initialize from given python traceback object. """ if hasattr(tb, 'tb_next'): @@ -362,7 +368,8 @@ class ExceptionInfo(object): self.traceback = py.code.Traceback(self.tb) def __repr__(self): - return "" % (self.typename, len(self.traceback)) + return "" % ( + self.typename, len(self.traceback)) def exconly(self, tryshort=False): """ return the exception as a string @@ -391,7 +398,7 @@ class ExceptionInfo(object): return ReprFileLocation(path, lineno+1, exconly) def getrepr(self, showlocals=False, style="long", - abspath=False, tbfilter=True, funcargs=False): + abspath=False, tbfilter=True, funcargs=False): """ return str()able representation of this exception info. showlocals: show locals per traceback entry style: long|short|no|native traceback style @@ -401,13 +408,14 @@ class ExceptionInfo(object): """ if style == 'native': return ReprExceptionInfo(ReprTracebackNative( - py.std.traceback.format_exception( + traceback.format_exception( self.type, self.value, self.traceback[0]._rawentry, )), self._getreprcrash()) - fmt = FormattedExcinfo(showlocals=showlocals, style=style, + fmt = FormattedExcinfo( + showlocals=showlocals, style=style, abspath=abspath, tbfilter=tbfilter, funcargs=funcargs) return fmt.repr_excinfo(self) @@ -419,7 +427,7 @@ class ExceptionInfo(object): def __unicode__(self): entry = self.traceback[-1] loc = ReprFileLocation(entry.path, entry.lineno + 1, self.exconly()) - return unicode(loc) + return loc.__unicode__() class FormattedExcinfo(object): @@ -428,7 +436,8 @@ class FormattedExcinfo(object): flow_marker = ">" fail_marker = "E" - def __init__(self, showlocals=False, style="long", abspath=True, tbfilter=True, funcargs=False): + def __init__(self, showlocals=False, style="long", + abspath=True, tbfilter=True, funcargs=False): self.showlocals = showlocals self.style = style self.tbfilter = tbfilter @@ -521,7 +530,7 @@ class FormattedExcinfo(object): #else: # self._line("%-10s =\\" % (name,)) # # XXX - # py.std.pprint.pprint(value, stream=self.excinfowriter) + # pprint.pprint(value, stream=self.excinfowriter) return ReprLocals(lines) def repr_traceback_entry(self, entry, excinfo=None): @@ -779,7 +788,7 @@ def getrawcode(obj, trycall=True): obj = getattr(obj, 'f_code', obj) obj = getattr(obj, '__code__', obj) if trycall and not hasattr(obj, 'co_firstlineno'): - if hasattr(obj, '__call__') and not py.std.inspect.isclass(obj): + if hasattr(obj, '__call__') and not isclass(obj): x = getrawcode(obj.__call__, trycall=False) if hasattr(x, 'co_firstlineno'): return x diff --git a/tests/wpt/web-platform-tests/tools/py/py/_code/source.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_code/source.py similarity index 94% rename from tests/wpt/web-platform-tests/tools/py/py/_code/source.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_code/source.py index 3a648e63579..7fc7b23a96c 100644 --- a/tests/wpt/web-platform-tests/tools/py/py/_code/source.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_code/source.py @@ -193,15 +193,8 @@ class Source(object): if flag & _AST_FLAG: return co lines = [(x + "\n") for x in self.lines] - if sys.version_info[0] >= 3: - # XXX py3's inspect.getsourcefile() checks for a module - # and a pep302 __loader__ ... we don't have a module - # at code compile-time so we need to fake it here - m = ModuleType("_pycodecompile_pseudo_module") - py.std.inspect.modulesbyfile[filename] = None - py.std.sys.modules[None] = m - m.__loader__ = 1 - py.std.linecache.cache[filename] = (1, None, lines, filename) + import linecache + linecache.cache[filename] = (1, None, lines, filename) return co # @@ -232,8 +225,8 @@ def getfslineno(obj): code = py.code.Code(obj) except TypeError: try: - fn = (py.std.inspect.getsourcefile(obj) or - py.std.inspect.getfile(obj)) + fn = (inspect.getsourcefile(obj) or + inspect.getfile(obj)) except TypeError: return "", -1 @@ -256,7 +249,7 @@ def getfslineno(obj): def findsource(obj): try: - sourcelines, lineno = py.std.inspect.findsource(obj) + sourcelines, lineno = inspect.findsource(obj) except py.builtin._sysex: raise except: @@ -342,8 +335,6 @@ def get_statement_startend2(lineno, node): def getstatementrange_ast(lineno, source, assertion=False, astnode=None): if astnode is None: content = str(source) - if sys.version_info < (2,7): - content += "\n" try: astnode = compile(content, "source", "exec", 1024) # 1024 for AST except ValueError: diff --git a/tests/wpt/web-platform-tests/tools/py/py/_error.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_error.py similarity index 94% rename from tests/wpt/web-platform-tests/tools/py/py/_error.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_error.py index 550fb521a04..a6375de9fa2 100644 --- a/tests/wpt/web-platform-tests/tools/py/py/_error.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_error.py @@ -2,6 +2,7 @@ create errno-specific classes for IO or os calls. """ +from types import ModuleType import sys, os, errno class Error(EnvironmentError): @@ -23,6 +24,7 @@ _winerrnomap = { 2: errno.ENOENT, 3: errno.ENOENT, 17: errno.EEXIST, + 18: errno.EXDEV, 13: errno.EBUSY, # empty cd drive, but ENOMEDIUM seems unavailiable 22: errno.ENOTDIR, 20: errno.ENOTDIR, @@ -30,7 +32,7 @@ _winerrnomap = { 5: errno.EACCES, # anything better? } -class ErrorMaker(object): +class ErrorMaker(ModuleType): """ lazily provides Exception classes for each possible POSIX errno (as defined per the 'errno' module). All such instances subclass EnvironmentError. @@ -85,4 +87,5 @@ class ErrorMaker(object): __tracebackhide__ = True -error = ErrorMaker() +error = ErrorMaker('py.error') +sys.modules[error.__name__] = error \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/tools/py/py/_io/__init__.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_io/__init__.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/py/_io/__init__.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_io/__init__.py diff --git a/tests/wpt/web-platform-tests/tools/py/py/_io/capture.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_io/capture.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/py/_io/capture.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_io/capture.py diff --git a/tests/wpt/web-platform-tests/tools/py/py/_io/saferepr.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_io/saferepr.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/py/_io/saferepr.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_io/saferepr.py diff --git a/tests/wpt/web-platform-tests/tools/py/py/_io/terminalwriter.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_io/terminalwriter.py similarity index 91% rename from tests/wpt/web-platform-tests/tools/py/py/_io/terminalwriter.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_io/terminalwriter.py index cef1ff58097..74d31259dac 100644 --- a/tests/wpt/web-platform-tests/tools/py/py/_io/terminalwriter.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_io/terminalwriter.py @@ -31,9 +31,9 @@ def _getdimensions(): def get_terminal_width(): - height = width = 0 + width = 0 try: - height, width = _getdimensions() + _, width = _getdimensions() except py.builtin._sysex: raise except: @@ -129,7 +129,7 @@ class TerminalWriter(object): if stringio: self.stringio = file = py.io.TextIO() else: - file = py.std.sys.stdout + from sys import stdout as file elif py.builtin.callable(file) and not ( hasattr(file, "write") and hasattr(file, "flush")): file = WriteFile(file, encoding=encoding) @@ -137,9 +137,32 @@ class TerminalWriter(object): file = colorama.AnsiToWin32(file).stream self.encoding = encoding or getattr(file, 'encoding', "utf-8") self._file = file - self.fullwidth = get_terminal_width() self.hasmarkup = should_do_markup(file) self._lastlen = 0 + self._chars_on_current_line = 0 + + @property + def fullwidth(self): + if hasattr(self, '_terminal_width'): + return self._terminal_width + return get_terminal_width() + + @fullwidth.setter + def fullwidth(self, value): + self._terminal_width = value + + @property + def chars_on_current_line(self): + """Return the number of characters written so far in the current line. + + Please note that this count does not produce correct results after a reline() call, + see #164. + + .. versionadded:: 1.5.0 + + :rtype: int + """ + return self._chars_on_current_line def _escaped(self, text, esc): if esc and self.hasmarkup: @@ -191,12 +214,22 @@ class TerminalWriter(object): if msg: if not isinstance(msg, (bytes, text)): msg = text(msg) + + self._update_chars_on_current_line(msg) + if self.hasmarkup and kw: markupmsg = self.markup(msg, **kw) else: markupmsg = msg write_out(self._file, markupmsg) + def _update_chars_on_current_line(self, text): + fields = text.rsplit('\n', 1) + if '\n' in text: + self._chars_on_current_line = len(fields[-1]) + else: + self._chars_on_current_line += len(fields[-1]) + def line(self, s='', **kw): self.write(s, **kw) self._checkfill(s) @@ -220,6 +253,9 @@ class Win32ConsoleWriter(TerminalWriter): if msg: if not isinstance(msg, (bytes, text)): msg = text(msg) + + self._update_chars_on_current_line(msg) + oldcolors = None if self.hasmarkup and kw: handle = GetStdHandle(STD_OUTPUT_HANDLE) diff --git a/tests/wpt/web-platform-tests/tools/py/py/_log/__init__.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_log/__init__.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/py/_log/__init__.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_log/__init__.py diff --git a/tests/wpt/web-platform-tests/tools/py/py/_log/log.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_log/log.py similarity index 91% rename from tests/wpt/web-platform-tests/tools/py/py/_log/log.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_log/log.py index ce47e8c754a..56969bcb58c 100644 --- a/tests/wpt/web-platform-tests/tools/py/py/_log/log.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_log/log.py @@ -14,7 +14,9 @@ XXX implement this API: (maybe put it into slogger.py?) debug=py.log.STDOUT, command=None) """ -import py, sys +import py +import sys + class Message(object): def __init__(self, keywords, args): @@ -70,6 +72,7 @@ class KeywordMapper: def getstate(self): return self.keywords2consumer.copy() + def setstate(self, state): self.keywords2consumer.clear() self.keywords2consumer.update(state) @@ -104,17 +107,22 @@ class KeywordMapper: consumer = File(consumer) self.keywords2consumer[keywords] = consumer + def default_consumer(msg): """ the default consumer, prints the message to stdout (using 'print') """ sys.stderr.write(str(msg)+"\n") default_keywordmapper = KeywordMapper() + def setconsumer(keywords, consumer): default_keywordmapper.setconsumer(keywords, consumer) + def setstate(state): default_keywordmapper.setstate(state) + + def getstate(): return default_keywordmapper.getstate() @@ -122,11 +130,12 @@ def getstate(): # Consumers # + class File(object): """ log consumer wrapping a file(-like) object """ def __init__(self, f): assert hasattr(f, 'write') - #assert isinstance(f, file) or not hasattr(f, 'open') + # assert isinstance(f, file) or not hasattr(f, 'open') self._file = f def __call__(self, msg): @@ -135,6 +144,7 @@ class File(object): if hasattr(self._file, 'flush'): self._file.flush() + class Path(object): """ log consumer that opens and writes to a Path """ def __init__(self, filename, append=False, @@ -158,29 +168,39 @@ class Path(object): if not self._buffering: self._file.flush() + def STDOUT(msg): """ consumer that writes to sys.stdout """ sys.stdout.write(str(msg)+"\n") + def STDERR(msg): """ consumer that writes to sys.stderr """ sys.stderr.write(str(msg)+"\n") + class Syslog: """ consumer that writes to the syslog daemon """ - def __init__(self, priority = None): + def __init__(self, priority=None): if priority is None: priority = self.LOG_INFO self.priority = priority def __call__(self, msg): """ write a message to the log """ - py.std.syslog.syslog(self.priority, str(msg)) + import syslog + syslog.syslog(self.priority, str(msg)) -for _prio in "EMERG ALERT CRIT ERR WARNING NOTICE INFO DEBUG".split(): - _prio = "LOG_" + _prio - try: - setattr(Syslog, _prio, getattr(py.std.syslog, _prio)) - except AttributeError: - pass + +try: + import syslog +except ImportError: + pass +else: + for _prio in "EMERG ALERT CRIT ERR WARNING NOTICE INFO DEBUG".split(): + _prio = "LOG_" + _prio + try: + setattr(Syslog, _prio, getattr(syslog, _prio)) + except AttributeError: + pass diff --git a/tests/wpt/web-platform-tests/tools/py/py/_log/warning.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_log/warning.py similarity index 92% rename from tests/wpt/web-platform-tests/tools/py/py/_log/warning.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_log/warning.py index 722e31e910d..6ef20d98a2d 100644 --- a/tests/wpt/web-platform-tests/tools/py/py/_log/warning.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_log/warning.py @@ -32,9 +32,11 @@ def _apiwarn(startversion, msg, stacklevel=2, function=None): msg = "%s (since version %s)" %(msg, startversion) warn(msg, stacklevel=stacklevel+1, function=function) + def warn(msg, stacklevel=1, function=None): if function is not None: - filename = py.std.inspect.getfile(function) + import inspect + filename = inspect.getfile(function) lineno = py.code.getrawcode(function).co_firstlineno else: try: @@ -67,10 +69,11 @@ def warn(msg, stacklevel=1, function=None): filename = module path = py.path.local(filename) warning = DeprecationWarning(msg, path, lineno) - py.std.warnings.warn_explicit(warning, category=Warning, + import warnings + warnings.warn_explicit(warning, category=Warning, filename=str(warning.path), lineno=warning.lineno, - registry=py.std.warnings.__dict__.setdefault( + registry=warnings.__dict__.setdefault( "__warningsregistry__", {}) ) diff --git a/tests/wpt/web-platform-tests/tools/py/py/_path/__init__.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_path/__init__.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/py/_path/__init__.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_path/__init__.py diff --git a/tests/wpt/web-platform-tests/tools/py/py/_path/cacheutil.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_path/cacheutil.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/py/_path/cacheutil.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_path/cacheutil.py diff --git a/tests/wpt/web-platform-tests/tools/py/py/_path/common.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_path/common.py similarity index 86% rename from tests/wpt/web-platform-tests/tools/py/py/_path/common.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_path/common.py index d407434cb2a..2d490b56a86 100644 --- a/tests/wpt/web-platform-tests/tools/py/py/_path/common.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_path/common.py @@ -1,11 +1,49 @@ """ """ -import os, sys, posixpath +import warnings +import os +import sys +import posixpath +import fnmatch import py # Moved from local.py. iswin32 = sys.platform == "win32" or (getattr(os, '_name', False) == 'nt') +try: + from os import fspath +except ImportError: + def fspath(path): + """ + Return the string representation of the path. + If str or bytes is passed in, it is returned unchanged. + This code comes from PEP 519, modified to support earlier versions of + python. + + This is required for python < 3.6. + """ + if isinstance(path, (py.builtin.text, py.builtin.bytes)): + return path + + # Work from the object's type to match method resolution of other magic + # methods. + path_type = type(path) + try: + return path_type.__fspath__(path) + except AttributeError: + if hasattr(path_type, '__fspath__'): + raise + try: + import pathlib + except ImportError: + pass + else: + if isinstance(path, pathlib.PurePath): + return py.builtin.text(path) + + raise TypeError("expected str, bytes or os.PathLike object, not " + + path_type.__name__) + class Checkers: _depend_on_existence = 'exists', 'link', 'dir', 'file' @@ -89,7 +127,7 @@ class PathBase(object): Checkers = Checkers def __div__(self, other): - return self.join(str(other)) + return self.join(fspath(other)) __truediv__ = __div__ # py3k def basename(self): @@ -135,11 +173,16 @@ class PathBase(object): def readlines(self, cr=1): """ read and return a list of lines from the path. if cr is False, the newline will be removed from the end of each line. """ + if sys.version_info < (3, ): + mode = 'rU' + else: # python 3 deprecates mode "U" in favor of "newline" option + mode = 'r' + if not cr: - content = self.read('rU') + content = self.read(mode) return content.split('\n') else: - f = self.open('rU') + f = self.open(mode) try: return f.readlines() finally: @@ -149,14 +192,16 @@ newline will be removed from the end of each line. """ """ (deprecated) return object unpickled from self.read() """ f = self.open('rb') try: - return py.error.checked_call(py.std.pickle.load, f) + import pickle + return py.error.checked_call(pickle.load, f) finally: f.close() def move(self, target): """ move this path to target. """ if target.relto(self): - raise py.error.EINVAL(target, + raise py.error.EINVAL( + target, "cannot move path into a subdirectory of itself") try: self.rename(target) @@ -186,7 +231,7 @@ newline will be removed from the end of each line. """ path.check(file=1, link=1) # a link pointing to a file """ if not kw: - kw = {'exists' : 1} + kw = {'exists': 1} return self.Checkers(self)._evaluate(kw) def fnmatch(self, pattern): @@ -335,6 +380,9 @@ newline will be removed from the end of each line. """ def _sortlist(self, res, sort): if sort: if hasattr(sort, '__call__'): + warnings.warn(DeprecationWarning( + "listdir(sort=callable) is deprecated and breaks on python3" + ), stacklevel=3) res.sort(sort) else: res.sort() @@ -343,11 +391,14 @@ newline will be removed from the end of each line. """ """ return True if other refers to the same stat object as self. """ return self.strpath == str(other) + def __fspath__(self): + return self.strpath + class Visitor: def __init__(self, fil, rec, ignore, bf, sort): - if isinstance(fil, str): + if isinstance(fil, py.builtin._basestring): fil = FNMatcher(fil) - if isinstance(rec, str): + if isinstance(rec, py.builtin._basestring): self.rec = FNMatcher(rec) elif not hasattr(rec, '__call__') and rec: self.rec = lambda path: True @@ -399,5 +450,4 @@ class FNMatcher: name = str(path) # path.strpath # XXX svn? if not os.path.isabs(pattern): pattern = '*' + path.sep + pattern - return py.std.fnmatch.fnmatch(name, pattern) - + return fnmatch.fnmatch(name, pattern) diff --git a/tests/wpt/web-platform-tests/tools/py/py/_path/local.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_path/local.py similarity index 83% rename from tests/wpt/web-platform-tests/tools/py/py/_path/local.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_path/local.py index d569404ec21..c550fa2f1ab 100644 --- a/tests/wpt/web-platform-tests/tools/py/py/_path/local.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_path/local.py @@ -4,13 +4,13 @@ local path implementation. from __future__ import with_statement from contextlib import contextmanager -import sys, os, re, atexit, io +import sys, os, re, atexit, io, uuid import py from py._path import common -from py._path.common import iswin32 +from py._path.common import iswin32, fspath from stat import S_ISLNK, S_ISDIR, S_ISREG -from os.path import abspath, normpath, isabs, exists, isdir, isfile, islink, dirname +from os.path import abspath, normcase, normpath, isabs, exists, isdir, isfile, islink, dirname if sys.version_info > (3,0): def map_as_list(func, iter): @@ -147,22 +147,25 @@ class LocalPath(FSBase): """ if path is None: self.strpath = py.error.checked_call(os.getcwd) - elif isinstance(path, common.PathBase): - self.strpath = path.strpath - elif isinstance(path, py.builtin._basestring): + else: + try: + path = fspath(path) + except TypeError: + raise ValueError("can only pass None, Path instances " + "or non-empty strings to LocalPath") if expanduser: path = os.path.expanduser(path) self.strpath = abspath(path) - else: - raise ValueError("can only pass None, Path instances " - "or non-empty strings to LocalPath") def __hash__(self): return hash(self.strpath) def __eq__(self, other): - s1 = self.strpath - s2 = getattr(other, "strpath", other) + s1 = fspath(self) + try: + s2 = fspath(other) + except TypeError: + return False if iswin32: s1 = s1.lower() try: @@ -175,15 +178,15 @@ class LocalPath(FSBase): return not (self == other) def __lt__(self, other): - return self.strpath < getattr(other, "strpath", other) + return fspath(self) < fspath(other) def __gt__(self, other): - return self.strpath > getattr(other, "strpath", other) + return fspath(self) > fspath(other) def samefile(self, other): """ return True if 'other' references the same file as 'self'. """ - other = getattr(other, "strpath", other) + other = fspath(other) if not isabs(other): other = abspath(other) if self == other: @@ -202,14 +205,16 @@ class LocalPath(FSBase): if rec: # force remove of readonly files on windows if iswin32: - self.chmod(448, rec=1) # octcal 0700 - py.error.checked_call(py.std.shutil.rmtree, self.strpath, + self.chmod(0o700, rec=1) + import shutil + py.error.checked_call( + shutil.rmtree, self.strpath, ignore_errors=ignore_errors) else: py.error.checked_call(os.rmdir, self.strpath) else: if iswin32: - self.chmod(448) # octcal 0700 + self.chmod(0o700) py.error.checked_call(os.remove, self.strpath) def computehash(self, hashtype="md5", chunksize=524288): @@ -320,7 +325,7 @@ class LocalPath(FSBase): of the args is an absolute path. """ sep = self.sep - strargs = [getattr(arg, "strpath", arg) for arg in args] + strargs = [fspath(arg) for arg in args] strpath = self.strpath if kwargs.get('abs'): newargs = [] @@ -330,13 +335,16 @@ class LocalPath(FSBase): strargs = newargs break newargs.insert(0, arg) + # special case for when we have e.g. strpath == "/" + actual_sep = "" if strpath.endswith(sep) else sep for arg in strargs: arg = arg.strip(sep) if iswin32: # allow unix style paths even on windows. arg = arg.strip('/') arg = arg.replace('/', sep) - strpath = strpath + sep + arg + strpath = strpath + actual_sep + arg + actual_sep = sep obj = object.__new__(self.__class__) obj.strpath = normpath(strpath) return obj @@ -402,8 +410,13 @@ class LocalPath(FSBase): """ return last modification time of the path. """ return self.stat().mtime - def copy(self, target, mode=False): - """ copy path to target.""" + def copy(self, target, mode=False, stat=False): + """ copy path to target. + + If mode is True, will copy copy permission from path to target. + If stat is True, copy permission, last modification + time, last access time, and flags from path to target. + """ if self.check(file=1): if target.check(dir=1): target = target.join(self.basename) @@ -411,6 +424,8 @@ class LocalPath(FSBase): copychunked(self, target) if mode: copymode(self.strpath, target.strpath) + if stat: + copystat(self, target) else: def rec(p): return p.check(link=0) @@ -427,24 +442,27 @@ class LocalPath(FSBase): newx.ensure(dir=1) if mode: copymode(x.strpath, newx.strpath) + if stat: + copystat(x, newx) def rename(self, target): """ rename this path to target. """ - target = getattr(target, "strpath", target) + target = fspath(target) return py.error.checked_call(os.rename, self.strpath, target) def dump(self, obj, bin=1): """ pickle object into path location""" f = self.open('wb') + import pickle try: - py.error.checked_call(py.std.pickle.dump, obj, f, bin) + py.error.checked_call(pickle.dump, obj, f, bin) finally: f.close() def mkdir(self, *args): """ create & return the directory joined with args. """ p = self.join(*args) - py.error.checked_call(os.mkdir, getattr(p, "strpath", p)) + py.error.checked_call(os.mkdir, fspath(p)) return p def write_binary(self, data, ensure=False): @@ -672,7 +690,8 @@ class LocalPath(FSBase): return sys.modules[modname] except KeyError: # we have a custom modname, do a pseudo-import - mod = py.std.types.ModuleType(modname) + import types + mod = types.ModuleType(modname) mod.__file__ = str(self) sys.modules[modname] = mod try: @@ -717,7 +736,7 @@ class LocalPath(FSBase): else: if paths is None: if iswin32: - paths = py.std.os.environ['Path'].split(';') + paths = os.environ['Path'].split(';') if '' not in paths and '.' not in paths: paths.append('.') try: @@ -725,10 +744,10 @@ class LocalPath(FSBase): except KeyError: pass else: - paths = [re.sub('%SystemRoot%', systemroot, path) + paths = [path.replace('%SystemRoot%', systemroot) for path in paths] else: - paths = py.std.os.environ['PATH'].split(':') + paths = os.environ['PATH'].split(':') tryadd = [] if iswin32: tryadd += os.environ['PATHEXT'].split(os.pathsep) @@ -759,16 +778,18 @@ class LocalPath(FSBase): return cls(x) _gethomedir = classmethod(_gethomedir) - #""" - #special class constructors for local filesystem paths - #""" + # """ + # special class constructors for local filesystem paths + # """ + @classmethod def get_temproot(cls): """ return the system's temporary directory (where tempfiles are usually created in) """ - return py.path.local(py.std.tempfile.gettempdir()) - get_temproot = classmethod(get_temproot) + import tempfile + return py.path.local(tempfile.gettempdir()) + @classmethod def mkdtemp(cls, rootdir=None): """ return a Path object pointing to a fresh new temporary directory (which we created ourself). @@ -777,58 +798,43 @@ class LocalPath(FSBase): if rootdir is None: rootdir = cls.get_temproot() return cls(py.error.checked_call(tempfile.mkdtemp, dir=str(rootdir))) - mkdtemp = classmethod(mkdtemp) def make_numbered_dir(cls, prefix='session-', rootdir=None, keep=3, lock_timeout = 172800): # two days """ return unique directory with a number greater than the current maximum one. The number is assumed to start directly after prefix. if keep is true directories with a number less than (maxnum-keep) - will be removed. + will be removed. If .lock files are used (lock_timeout non-zero), + algorithm is multi-process safe. """ if rootdir is None: rootdir = cls.get_temproot() + nprefix = normcase(prefix) def parse_num(path): """ parse the number out of a path (if it matches the prefix) """ - bn = path.basename - if bn.startswith(prefix): + nbasename = normcase(path.basename) + if nbasename.startswith(nprefix): try: - return int(bn[len(prefix):]) + return int(nbasename[len(nprefix):]) except ValueError: pass - # compute the maximum number currently in use with the - # prefix - lastmax = None - while True: - maxnum = -1 - for path in rootdir.listdir(): - num = parse_num(path) - if num is not None: - maxnum = max(maxnum, num) - - # make the new directory - try: - udir = rootdir.mkdir(prefix + str(maxnum+1)) - except py.error.EEXIST: - # race condition: another thread/process created the dir - # in the meantime. Try counting again - if lastmax == maxnum: - raise - lastmax = maxnum - continue - break - - # put a .lock file in the new directory that will be removed at - # process exit - if lock_timeout: - lockfile = udir.join('.lock') + def create_lockfile(path): + """ exclusively create lockfile. Throws when failed """ mypid = os.getpid() + lockfile = path.join('.lock') if hasattr(lockfile, 'mksymlinkto'): lockfile.mksymlinkto(str(mypid)) else: - lockfile.write(str(mypid)) + fd = py.error.checked_call(os.open, str(lockfile), os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644) + with os.fdopen(fd, 'w') as f: + f.write(str(mypid)) + return lockfile + + def atexit_remove_lockfile(lockfile): + """ ensure lockfile is removed at process exit """ + mypid = os.getpid() def try_remove_lockfile(): # in a fork() situation, only the last process should # remove the .lock, otherwise the other processes run the @@ -843,19 +849,82 @@ class LocalPath(FSBase): pass atexit.register(try_remove_lockfile) + # compute the maximum number currently in use with the prefix + lastmax = None + while True: + maxnum = -1 + for path in rootdir.listdir(): + num = parse_num(path) + if num is not None: + maxnum = max(maxnum, num) + + # make the new directory + try: + udir = rootdir.mkdir(prefix + str(maxnum+1)) + if lock_timeout: + lockfile = create_lockfile(udir) + atexit_remove_lockfile(lockfile) + except (py.error.EEXIST, py.error.ENOENT, py.error.EBUSY): + # race condition (1): another thread/process created the dir + # in the meantime - try again + # race condition (2): another thread/process spuriously acquired + # lock treating empty directory as candidate + # for removal - try again + # race condition (3): another thread/process tried to create the lock at + # the same time (happened in Python 3.3 on Windows) + # https://ci.appveyor.com/project/pytestbot/py/build/1.0.21/job/ffi85j4c0lqwsfwa + if lastmax == maxnum: + raise + lastmax = maxnum + continue + break + + def get_mtime(path): + """ read file modification time """ + try: + return path.lstat().mtime + except py.error.Error: + pass + + garbage_prefix = prefix + 'garbage-' + + def is_garbage(path): + """ check if path denotes directory scheduled for removal """ + bn = path.basename + return bn.startswith(garbage_prefix) + # prune old directories - if keep: + udir_time = get_mtime(udir) + if keep and udir_time: for path in rootdir.listdir(): num = parse_num(path) if num is not None and num <= (maxnum - keep): - lf = path.join('.lock') try: - t1 = lf.lstat().mtime - t2 = lockfile.lstat().mtime - if not lock_timeout or abs(t2-t1) < lock_timeout: - continue # skip directories still locked - except py.error.Error: - pass # assume that it means that there is no 'lf' + # try acquiring lock to remove directory as exclusive user + if lock_timeout: + create_lockfile(path) + except (py.error.EEXIST, py.error.ENOENT, py.error.EBUSY): + path_time = get_mtime(path) + if not path_time: + # assume directory doesn't exist now + continue + if abs(udir_time - path_time) < lock_timeout: + # assume directory with lockfile exists + # and lock timeout hasn't expired yet + continue + + # path dir locked for exclusive use + # and scheduled for removal to avoid another thread/process + # treating it as a new directory or removal candidate + garbage_path = rootdir.join(garbage_prefix + str(uuid.uuid4())) + try: + path.rename(garbage_path) + garbage_path.remove(rec=1) + except KeyboardInterrupt: + raise + except: # this might be py.error.Error, WindowsError ... + pass + if is_garbage(path): try: path.remove(rec=1) except KeyboardInterrupt: @@ -886,11 +955,22 @@ class LocalPath(FSBase): return udir make_numbered_dir = classmethod(make_numbered_dir) + def copymode(src, dest): - py.std.shutil.copymode(src, dest) + """ copy permission from src to dst. """ + import shutil + shutil.copymode(src, dest) + + +def copystat(src, dest): + """ copy permission, last modification time, + last access time, and flags from src to dst.""" + import shutil + shutil.copystat(str(src), str(dest)) + def copychunked(src, dest): - chunksize = 524288 # half a meg of bytes + chunksize = 524288 # half a meg of bytes fsrc = src.open('rb') try: fdest = dest.open('wb') @@ -905,6 +985,7 @@ def copychunked(src, dest): finally: fsrc.close() + def isimportable(name): if name and (name[0].isalpha() or name[0] == '_'): name = name.replace("_", '') diff --git a/tests/wpt/web-platform-tests/tools/py/py/_path/svnurl.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_path/svnurl.py similarity index 99% rename from tests/wpt/web-platform-tests/tools/py/py/_path/svnurl.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_path/svnurl.py index 78d71317ac0..6589a71d09e 100644 --- a/tests/wpt/web-platform-tests/tools/py/py/_path/svnurl.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_path/svnurl.py @@ -315,7 +315,7 @@ class InfoSvnCommand: # locked, see 'svn help ls' lspattern = re.compile( r'^ *(?P\d+) +(?P.+?) +(0? *(?P\d+))? ' - '*(?P\w+ +\d{2} +[\d:]+) +(?P.*)$') + r'*(?P\w+ +\d{2} +[\d:]+) +(?P.*)$') def __init__(self, line): # this is a typical line from 'svn ls http://...' #_ 1127 jum 0 Jul 13 15:28 branch/ diff --git a/tests/wpt/web-platform-tests/tools/py/py/_path/svnwc.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_path/svnwc.py similarity index 99% rename from tests/wpt/web-platform-tests/tools/py/py/_path/svnwc.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_path/svnwc.py index 00d3b4bbaf3..3138dd85da3 100644 --- a/tests/wpt/web-platform-tests/tools/py/py/_path/svnwc.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_path/svnwc.py @@ -94,7 +94,7 @@ def _getsvnversion(ver=[]): def _escape_helper(text): text = str(text) - if py.std.sys.platform != 'win32': + if sys.platform != 'win32': text = str(text).replace('$', '\\$') return text @@ -327,7 +327,7 @@ def fixlocale(): return '' # some nasty chunk of code to solve path and url conversion and quoting issues -ILLEGAL_CHARS = '* | \ / : < > ? \t \n \x0b \x0c \r'.split(' ') +ILLEGAL_CHARS = '* | \\ / : < > ? \t \n \x0b \x0c \r'.split(' ') if os.sep in ILLEGAL_CHARS: ILLEGAL_CHARS.remove(os.sep) ISWINDOWS = sys.platform == 'win32' @@ -354,7 +354,7 @@ def path_to_fspath(path, addat=True): def url_from_path(path): fspath = path_to_fspath(path, False) - quote = py.std.urllib.quote + from urllib import quote if ISWINDOWS: match = _reg_allow_disk.match(fspath) fspath = fspath.replace('\\', '/') @@ -504,7 +504,7 @@ class SvnWCCommandPath(common.PathBase): if url is None: url = self.url if rev is None or rev == -1: - if (py.std.sys.platform != 'win32' and + if (sys.platform != 'win32' and _getsvnversion() == '1.3'): url += "@HEAD" else: @@ -785,7 +785,7 @@ recursively. """ info = InfoSvnWCCommand(output) # Can't reliably compare on Windows without access to win32api - if py.std.sys.platform != 'win32': + if sys.platform != 'win32': if info.path != self.localpath: raise py.error.ENOENT(self, "not a versioned resource:" + " %s != %s" % (info.path, self.localpath)) diff --git a/tests/wpt/web-platform-tests/tools/py/py/_process/__init__.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_process/__init__.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/py/_process/__init__.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_process/__init__.py diff --git a/tests/wpt/web-platform-tests/tools/py/py/_process/cmdexec.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_process/cmdexec.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/py/_process/cmdexec.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_process/cmdexec.py diff --git a/tests/wpt/web-platform-tests/tools/py/py/_process/forkedfunc.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_process/forkedfunc.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/py/_process/forkedfunc.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_process/forkedfunc.py diff --git a/tests/wpt/web-platform-tests/tools/py/py/_process/killproc.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_process/killproc.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/py/_process/killproc.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_process/killproc.py diff --git a/tests/wpt/web-platform-tests/tools/py/py/_std.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_std.py similarity index 65% rename from tests/wpt/web-platform-tests/tools/py/py/_std.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_std.py index 97a9853323b..74d43672654 100644 --- a/tests/wpt/web-platform-tests/tools/py/py/_std.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_std.py @@ -1,4 +1,10 @@ import sys +import warnings + + +class PyStdIsDeprecatedWarning(DeprecationWarning): + pass + class Std(object): """ makes top-level python modules available as an attribute, @@ -9,6 +15,8 @@ class Std(object): self.__dict__ = sys.modules def __getattr__(self, name): + warnings.warn("py.std is deprecated, plase import %s directly" % name, + category=PyStdIsDeprecatedWarning) try: m = __import__(name) except ImportError: diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/__init__.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/apipkg-1.4.dist-info/DESCRIPTION.rst b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/apipkg-1.4.dist-info/DESCRIPTION.rst new file mode 100644 index 00000000000..548222007fd --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/apipkg-1.4.dist-info/DESCRIPTION.rst @@ -0,0 +1,87 @@ +Welcome to apipkg! +------------------------ + +With apipkg you can control the exported namespace of a +python package and greatly reduce the number of imports for your users. +It is a `small pure python module`_ that works on virtually all Python +versions, including CPython2.3 to Python3.1, Jython and PyPy. It co-operates +well with Python's ``help()`` system, custom importers (PEP302) and common +command line completion tools. + +Usage is very simple: you can require 'apipkg' as a dependency or you +can copy paste the <200 Lines of code into your project. + + +Tutorial example +------------------- + +Here is a simple ``mypkg`` package that specifies one namespace +and exports two objects imported from different modules:: + + # mypkg/__init__.py + import apipkg + apipkg.initpkg(__name__, { + 'path': { + 'Class1': "_mypkg.somemodule:Class1", + 'clsattr': "_mypkg.othermodule:Class2.attr", + } + } + +The package is initialized with a dictionary as namespace. + +You need to create a ``_mypkg`` package with a ``somemodule.py`` +and ``othermodule.py`` containing the respective classes. +The ``_mypkg`` is not special - it's a completely +regular python package. + +Namespace dictionaries contain ``name: value`` mappings +where the value may be another namespace dictionary or +a string specifying an import location. On accessing +an namespace attribute an import will be performed:: + + >>> import mypkg + >>> mypkg.path + + >>> mypkg.path.Class1 # '_mypkg.somemodule' gets imported now + + >>> mypkg.path.clsattr # '_mypkg.othermodule' gets imported now + 4 # the value of _mypkg.othermodule.Class2.attr + +The ``mypkg.path`` namespace and its two entries are +loaded when they are accessed. This means: + +* lazy loading - only what is actually needed is ever loaded + +* only the root "mypkg" ever needs to be imported to get + access to the complete functionality. + +* the underlying modules are also accessible, for example:: + + from mypkg.sub import Class1 + + +Including apipkg in your package +-------------------------------------- + +If you don't want to add an ``apipkg`` dependency to your package you +can copy the `apipkg.py`_ file somewhere to your own package, +for example ``_mypkg/apipkg.py`` in the above example. You +then import the ``initpkg`` function from that new place and +are good to go. + +.. _`small pure python module`: +.. _`apipkg.py`: http://bitbucket.org/hpk42/apipkg/src/tip/apipkg.py + +Feedback? +----------------------- + +If you have questions you are welcome to + +* join the #pylib channel on irc.freenode.net +* subscribe to the http://codespeak.net/mailman/listinfo/py-dev list. +* create an issue on http://bitbucket.org/hpk42/apipkg/issues + +have fun, +holger krekel + + diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/apipkg-1.4.dist-info/INSTALLER b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/apipkg-1.4.dist-info/INSTALLER new file mode 100644 index 00000000000..a1b589e38a3 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/apipkg-1.4.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/apipkg-1.4.dist-info/METADATA b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/apipkg-1.4.dist-info/METADATA new file mode 100644 index 00000000000..eb7e60acffa --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/apipkg-1.4.dist-info/METADATA @@ -0,0 +1,109 @@ +Metadata-Version: 2.0 +Name: apipkg +Version: 1.4 +Summary: apipkg: namespace control and lazy-import mechanism +Home-page: http://bitbucket.org/hpk42/apipkg +Author: holger krekel +Author-email: holger at merlinux.eu +License: MIT License +Platform: unix +Platform: linux +Platform: osx +Platform: cygwin +Platform: win32 +Classifier: Development Status :: 4 - Beta +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: POSIX +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Topic :: Software Development :: Libraries +Classifier: Programming Language :: Python + +Welcome to apipkg! +------------------------ + +With apipkg you can control the exported namespace of a +python package and greatly reduce the number of imports for your users. +It is a `small pure python module`_ that works on virtually all Python +versions, including CPython2.3 to Python3.1, Jython and PyPy. It co-operates +well with Python's ``help()`` system, custom importers (PEP302) and common +command line completion tools. + +Usage is very simple: you can require 'apipkg' as a dependency or you +can copy paste the <200 Lines of code into your project. + + +Tutorial example +------------------- + +Here is a simple ``mypkg`` package that specifies one namespace +and exports two objects imported from different modules:: + + # mypkg/__init__.py + import apipkg + apipkg.initpkg(__name__, { + 'path': { + 'Class1': "_mypkg.somemodule:Class1", + 'clsattr': "_mypkg.othermodule:Class2.attr", + } + } + +The package is initialized with a dictionary as namespace. + +You need to create a ``_mypkg`` package with a ``somemodule.py`` +and ``othermodule.py`` containing the respective classes. +The ``_mypkg`` is not special - it's a completely +regular python package. + +Namespace dictionaries contain ``name: value`` mappings +where the value may be another namespace dictionary or +a string specifying an import location. On accessing +an namespace attribute an import will be performed:: + + >>> import mypkg + >>> mypkg.path + + >>> mypkg.path.Class1 # '_mypkg.somemodule' gets imported now + + >>> mypkg.path.clsattr # '_mypkg.othermodule' gets imported now + 4 # the value of _mypkg.othermodule.Class2.attr + +The ``mypkg.path`` namespace and its two entries are +loaded when they are accessed. This means: + +* lazy loading - only what is actually needed is ever loaded + +* only the root "mypkg" ever needs to be imported to get + access to the complete functionality. + +* the underlying modules are also accessible, for example:: + + from mypkg.sub import Class1 + + +Including apipkg in your package +-------------------------------------- + +If you don't want to add an ``apipkg`` dependency to your package you +can copy the `apipkg.py`_ file somewhere to your own package, +for example ``_mypkg/apipkg.py`` in the above example. You +then import the ``initpkg`` function from that new place and +are good to go. + +.. _`small pure python module`: +.. _`apipkg.py`: http://bitbucket.org/hpk42/apipkg/src/tip/apipkg.py + +Feedback? +----------------------- + +If you have questions you are welcome to + +* join the #pylib channel on irc.freenode.net +* subscribe to the http://codespeak.net/mailman/listinfo/py-dev list. +* create an issue on http://bitbucket.org/hpk42/apipkg/issues + +have fun, +holger krekel + + diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/apipkg-1.4.dist-info/RECORD b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/apipkg-1.4.dist-info/RECORD new file mode 100644 index 00000000000..dc72959dfe0 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/apipkg-1.4.dist-info/RECORD @@ -0,0 +1,9 @@ +apipkg.py,sha256=BNnv_qvq8zZvku-uudoqgp3XTNFbwsNUmtzOKrVI7X0,6420 +apipkg-1.4.dist-info/top_level.txt,sha256=3TGS6nmN7kjxhUK4LpPCB3QkQI34QYGrT0ZQGWajoZ8,7 +apipkg-1.4.dist-info/METADATA,sha256=Fk_8BrHyXE--kvB3_ZBKgwvPaKusAZUjchH-kpB63Hs,3491 +apipkg-1.4.dist-info/DESCRIPTION.rst,sha256=RkMQqk5ljhGy0DiZkR_nbpjqvwCIhuIEHsyvkn3O96k,2803 +apipkg-1.4.dist-info/metadata.json,sha256=GdshYrA_7gAII3E3EQMH-31BHzU-klTZ6bPQzlDmuy4,779 +apipkg-1.4.dist-info/WHEEL,sha256=AvR0WeTpDaxT645bl5FQxUK6NPsTls2ttpcGJg3j1Xg,110 +apipkg-1.4.dist-info/RECORD,, +apipkg-1.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +__pycache__/apipkg.cpython-35.pyc,, diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/pluggy-0.3.1.dist-info/WHEEL b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/apipkg-1.4.dist-info/WHEEL similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/vendored_packages/pluggy-0.3.1.dist-info/WHEEL rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/apipkg-1.4.dist-info/WHEEL diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/apipkg-1.4.dist-info/metadata.json b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/apipkg-1.4.dist-info/metadata.json new file mode 100644 index 00000000000..05609b99373 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/apipkg-1.4.dist-info/metadata.json @@ -0,0 +1 @@ +{"license": "MIT License", "name": "apipkg", "metadata_version": "2.0", "generator": "bdist_wheel (0.24.0)", "summary": "apipkg: namespace control and lazy-import mechanism", "platform": "unix", "version": "1.4", "extensions": {"python.details": {"project_urls": {"Home": "http://bitbucket.org/hpk42/apipkg"}, "document_names": {"description": "DESCRIPTION.rst"}, "contacts": [{"role": "author", "email": "holger at merlinux.eu", "name": "holger krekel"}]}}, "classifiers": ["Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: POSIX", "Operating System :: Microsoft :: Windows", "Operating System :: MacOS :: MacOS X", "Topic :: Software Development :: Libraries", "Programming Language :: Python"]} \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/apipkg-1.4.dist-info/top_level.txt b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/apipkg-1.4.dist-info/top_level.txt new file mode 100644 index 00000000000..e2221c8f9e9 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/apipkg-1.4.dist-info/top_level.txt @@ -0,0 +1 @@ +apipkg diff --git a/tests/wpt/web-platform-tests/tools/py/py/_apipkg.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/apipkg.py similarity index 88% rename from tests/wpt/web-platform-tests/tools/py/py/_apipkg.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/apipkg.py index a73b8f6d0bc..9d56e0bcbae 100644 --- a/tests/wpt/web-platform-tests/tools/py/py/_apipkg.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/apipkg.py @@ -9,7 +9,9 @@ import os import sys from types import ModuleType -__version__ = '1.3.dev' + +__version__ = '1.4' + def _py_abspath(path): """ @@ -22,7 +24,20 @@ def _py_abspath(path): else: return os.path.abspath(path) -def initpkg(pkgname, exportdefs, attr=dict()): + +def distribution_version(name): + """try to get the version of the named distribution, + returs None on failure""" + from pkg_resources import get_distribution, DistributionNotFound + try: + dist = get_distribution(name) + except DistributionNotFound: + pass + else: + return dist.version + + +def initpkg(pkgname, exportdefs, attr=dict(), eager=False): """ initialize given package from the export definitions. """ oldmod = sys.modules.get(pkgname) d = {} @@ -43,6 +58,12 @@ def initpkg(pkgname, exportdefs, attr=dict()): oldmod.__dict__.update(d) mod = ApiModule(pkgname, exportdefs, implprefix=pkgname, attr=d) sys.modules[pkgname] = mod + # eagerload in bypthon to avoid their monkeypatching breaking packages + if 'bpython' in sys.modules or eager: + for module in sys.modules.values(): + if isinstance(module, ApiModule): + module.__dict__ + def importobj(modpath, attrname): module = __import__(modpath, None, None, ['__doc__']) @@ -55,6 +76,7 @@ def importobj(modpath, attrname): retval = getattr(retval, x) return retval + class ApiModule(ModuleType): def __docget(self): try: @@ -62,6 +84,7 @@ class ApiModule(ModuleType): except AttributeError: if '__doc__' in self.__map__: return self.__makeattr('__doc__') + def __docset(self, value): self.__doc = value __doc__ = property(__docget, __docset) @@ -132,8 +155,10 @@ class ApiModule(ModuleType): __getattr__ = __makeattr + @property def __dict__(self): - # force all the content of the module to be loaded when __dict__ is read + # force all the content of the module + # to be loaded when __dict__ is read dictdescr = ModuleType.__dict__['__dict__'] dict = dictdescr.__get__(self) if dict is not None: @@ -144,7 +169,6 @@ class ApiModule(ModuleType): except AttributeError: pass return dict - __dict__ = property(__dict__) def AliasModule(modname, modpath, attrname=None): diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/iniconfig-1.0.0.dist-info/DESCRIPTION.rst b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/iniconfig-1.0.0.dist-info/DESCRIPTION.rst new file mode 100644 index 00000000000..6d59bc222cc --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/iniconfig-1.0.0.dist-info/DESCRIPTION.rst @@ -0,0 +1,53 @@ +iniconfig: brain-dead simple parsing of ini files +======================================================= + +iniconfig is a small and simple INI-file parser module +having a unique set of features: + +* tested against Python2.4 across to Python3.2, Jython, PyPy +* maintains order of sections and entries +* supports multi-line values with or without line-continuations +* supports "#" comments everywhere +* raises errors with proper line-numbers +* no bells and whistles like automatic substitutions +* iniconfig raises an Error if two sections have the same name. + +If you encounter issues or have feature wishes please report them to: + + http://github.org/RonnyPfannschmidt/iniconfig/issues + +Basic Example +=================================== + +If you have an ini file like this:: + + # content of example.ini + [section1] # comment + name1=value1 # comment + name1b=value1,value2 # comment + + [section2] + name2= + line1 + line2 + +then you can do:: + + >>> import iniconfig + >>> ini = iniconfig.IniConfig("example.ini") + >>> ini['section1']['name1'] # raises KeyError if not exists + 'value1' + >>> ini.get('section1', 'name1b', [], lambda x: x.split(",")) + ['value1', 'value2'] + >>> ini.get('section1', 'notexist', [], lambda x: x.split(",")) + [] + >>> [x.name for x in list(ini)] + ['section1', 'section2'] + >>> list(list(ini)[0].items()) + [('name1', 'value1'), ('name1b', 'value1,value2')] + >>> 'section1' in ini + True + >>> 'inexistendsection' in ini + False + + diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/iniconfig-1.0.0.dist-info/INSTALLER b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/iniconfig-1.0.0.dist-info/INSTALLER new file mode 100644 index 00000000000..a1b589e38a3 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/iniconfig-1.0.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/iniconfig-1.0.0.dist-info/METADATA b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/iniconfig-1.0.0.dist-info/METADATA new file mode 100644 index 00000000000..79ea62dc34c --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/iniconfig-1.0.0.dist-info/METADATA @@ -0,0 +1,78 @@ +Metadata-Version: 2.0 +Name: iniconfig +Version: 1.0.0 +Summary: iniconfig: brain-dead simple config-ini parsing +Home-page: http://github.com/RonnyPfannschmidt/iniconfig +Author: Ronny Pfannschmidt, Holger Krekel +Author-email: opensource@ronnypfannschmidt.de, holger.krekel@gmail.com +License: MIT License +Platform: unix +Platform: linux +Platform: osx +Platform: cygwin +Platform: win32 +Classifier: Development Status :: 4 - Beta +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: POSIX +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Topic :: Software Development :: Libraries +Classifier: Topic :: Utilities +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 3 + +iniconfig: brain-dead simple parsing of ini files +======================================================= + +iniconfig is a small and simple INI-file parser module +having a unique set of features: + +* tested against Python2.4 across to Python3.2, Jython, PyPy +* maintains order of sections and entries +* supports multi-line values with or without line-continuations +* supports "#" comments everywhere +* raises errors with proper line-numbers +* no bells and whistles like automatic substitutions +* iniconfig raises an Error if two sections have the same name. + +If you encounter issues or have feature wishes please report them to: + + http://github.org/RonnyPfannschmidt/iniconfig/issues + +Basic Example +=================================== + +If you have an ini file like this:: + + # content of example.ini + [section1] # comment + name1=value1 # comment + name1b=value1,value2 # comment + + [section2] + name2= + line1 + line2 + +then you can do:: + + >>> import iniconfig + >>> ini = iniconfig.IniConfig("example.ini") + >>> ini['section1']['name1'] # raises KeyError if not exists + 'value1' + >>> ini.get('section1', 'name1b', [], lambda x: x.split(",")) + ['value1', 'value2'] + >>> ini.get('section1', 'notexist', [], lambda x: x.split(",")) + [] + >>> [x.name for x in list(ini)] + ['section1', 'section2'] + >>> list(list(ini)[0].items()) + [('name1', 'value1'), ('name1b', 'value1,value2')] + >>> 'section1' in ini + True + >>> 'inexistendsection' in ini + False + + diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/iniconfig-1.0.0.dist-info/RECORD b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/iniconfig-1.0.0.dist-info/RECORD new file mode 100644 index 00000000000..ec2f5e17487 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/iniconfig-1.0.0.dist-info/RECORD @@ -0,0 +1,9 @@ +iniconfig.py,sha256=-pBe5AF_6aAwo1CxJQ8i_zJq6ejc6IxHta7qk2tNJhY,5208 +iniconfig-1.0.0.dist-info/DESCRIPTION.rst,sha256=BDLMwWqfjpwZ5yqXRvz1x6bf8Dnt_pZhElekAwtL19o,1522 +iniconfig-1.0.0.dist-info/METADATA,sha256=bb2T8WUSDXXiUVxZ4WXhbffq6stikMTlB1jyrPbLfyU,2405 +iniconfig-1.0.0.dist-info/RECORD,, +iniconfig-1.0.0.dist-info/WHEEL,sha256=3XK1Z4AI42GuJXciCpiHMOkbehxRV8QDBW8IU41k3ZU,96 +iniconfig-1.0.0.dist-info/metadata.json,sha256=UYYwW0p815nU4qz8Iq1gGqIYaAcsCyGju3jXvTOyXSI,950 +iniconfig-1.0.0.dist-info/top_level.txt,sha256=7KfM0fugdlToj9UW7enKXk2HYALQD8qHiyKtjhSzgN8,10 +iniconfig-1.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +__pycache__/iniconfig.cpython-35.pyc,, diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/iniconfig-1.0.0.dist-info/WHEEL b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/iniconfig-1.0.0.dist-info/WHEEL new file mode 100644 index 00000000000..15b96c99cac --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/iniconfig-1.0.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.30.0.a0) +Root-Is-Purelib: true +Tag: cp35-none-any + diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/iniconfig-1.0.0.dist-info/metadata.json b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/iniconfig-1.0.0.dist-info/metadata.json new file mode 100644 index 00000000000..084daa6c06b --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/iniconfig-1.0.0.dist-info/metadata.json @@ -0,0 +1 @@ +{"classifiers": ["Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: POSIX", "Operating System :: Microsoft :: Windows", "Operating System :: MacOS :: MacOS X", "Topic :: Software Development :: Libraries", "Topic :: Utilities", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 3"], "extensions": {"python.details": {"contacts": [{"email": "opensource@ronnypfannschmidt.de, holger.krekel@gmail.com", "name": "Ronny Pfannschmidt, Holger Krekel", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "http://github.com/RonnyPfannschmidt/iniconfig"}}}, "generator": "bdist_wheel (0.30.0.a0)", "license": "MIT License", "metadata_version": "2.0", "name": "iniconfig", "platform": "unix", "summary": "iniconfig: brain-dead simple config-ini parsing", "version": "1.0.0"} \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/iniconfig-1.0.0.dist-info/top_level.txt b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/iniconfig-1.0.0.dist-info/top_level.txt new file mode 100644 index 00000000000..9dda53692d2 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/iniconfig-1.0.0.dist-info/top_level.txt @@ -0,0 +1 @@ +iniconfig diff --git a/tests/wpt/web-platform-tests/tools/py/py/_iniconfig.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/iniconfig.py similarity index 92% rename from tests/wpt/web-platform-tests/tools/py/py/_iniconfig.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/iniconfig.py index 92b50bd853a..6ad9eaf868b 100644 --- a/tests/wpt/web-platform-tests/tools/py/py/_iniconfig.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_vendored_packages/iniconfig.py @@ -1,12 +1,11 @@ """ brain-dead simple parser for ini-style files. (C) Ronny Pfannschmidt, Holger Krekel -- MIT licensed """ -__version__ = "0.2.dev2" - __all__ = ['IniConfig', 'ParseError'] COMMENTCHARS = "#;" + class ParseError(Exception): def __init__(self, path, lineno, msg): Exception.__init__(self, path, lineno, msg) @@ -15,7 +14,8 @@ class ParseError(Exception): self.msg = msg def __str__(self): - return "%s:%s: %s" %(self.path, self.lineno+1, self.msg) + return "%s:%s: %s" % (self.path, self.lineno+1, self.msg) + class SectionWrapper(object): def __init__(self, config, name): @@ -26,13 +26,15 @@ class SectionWrapper(object): return self.config.lineof(self.name, name) def get(self, key, default=None, convert=str): - return self.config.get(self.name, key, convert=convert, default=default) + return self.config.get(self.name, key, + convert=convert, default=default) def __getitem__(self, key): return self.config.sections[self.name][key] def __iter__(self): section = self.config.sections.get(self.name, []) + def lineof(key): return self.config.lineof(self.name, key) for name in sorted(section, key=lineof): @@ -45,7 +47,7 @@ class SectionWrapper(object): class IniConfig(object): def __init__(self, path, data=None): - self.path = str(path) # convenience + self.path = str(path) # convenience if data is None: f = open(self.path) try: @@ -64,11 +66,11 @@ class IniConfig(object): self._sources[section, name] = lineno if name is None: if section in self.sections: - self._raise(lineno, 'duplicate section %r'%(section, )) + self._raise(lineno, 'duplicate section %r' % (section, )) self.sections[section] = {} else: if name in self.sections[section]: - self._raise(lineno, 'duplicate name %r'%(name, )) + self._raise(lineno, 'duplicate name %r' % (name, )) self.sections[section][name] = value def _raise(self, lineno, msg): @@ -157,6 +159,7 @@ class IniConfig(object): def __contains__(self, arg): return arg in self.sections + def iscommentline(line): c = line.lstrip()[:1] return c in COMMENTCHARS diff --git a/tests/wpt/web-platform-tests/tools/py/py/_xmlgen.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/_xmlgen.py similarity index 89% rename from tests/wpt/web-platform-tests/tools/py/py/_xmlgen.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/_xmlgen.py index 2ffcaa14b8e..1c835458843 100644 --- a/tests/wpt/web-platform-tests/tools/py/py/_xmlgen.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/py/_xmlgen.py @@ -74,16 +74,18 @@ class html(Namespace): __tagclass__ = HtmlTag __stickyname__ = True __tagspec__ = dict([(x,1) for x in ( - 'a,abbr,acronym,address,applet,area,b,bdo,big,blink,' - 'blockquote,body,br,button,caption,center,cite,code,col,' - 'colgroup,comment,dd,del,dfn,dir,div,dl,dt,em,embed,' - 'fieldset,font,form,frameset,h1,h2,h3,h4,h5,h6,head,html,' - 'i,iframe,img,input,ins,kbd,label,legend,li,link,listing,' - 'map,marquee,menu,meta,multicol,nobr,noembed,noframes,' - 'noscript,object,ol,optgroup,option,p,pre,q,s,script,' - 'select,small,span,strike,strong,style,sub,sup,table,' - 'tbody,td,textarea,tfoot,th,thead,title,tr,tt,u,ul,xmp,' - 'base,basefont,frame,hr,isindex,param,samp,var' + 'a,abbr,acronym,address,applet,area,article,aside,audio,b,' + 'base,basefont,bdi,bdo,big,blink,blockquote,body,br,button,' + 'canvas,caption,center,cite,code,col,colgroup,command,comment,' + 'datalist,dd,del,details,dfn,dir,div,dl,dt,em,embed,' + 'fieldset,figcaption,figure,footer,font,form,frame,frameset,h1,' + 'h2,h3,h4,h5,h6,head,header,hgroup,hr,html,i,iframe,img,input,' + 'ins,isindex,kbd,keygen,label,legend,li,link,listing,map,mark,' + 'marquee,menu,meta,meter,multicol,nav,nobr,noembed,noframes,' + 'noscript,object,ol,optgroup,option,output,p,param,pre,progress,' + 'q,rp,rt,ruby,s,samp,script,section,select,small,source,span,' + 'strike,strong,style,sub,summary,sup,table,tbody,td,textarea,' + 'tfoot,th,thead,time,title,tr,track,tt,u,ul,xmp,var,video,wbr' ).split(',') if x]) class Style(object): diff --git a/tests/wpt/web-platform-tests/tools/py/py/test.py b/tests/wpt/web-platform-tests/tools/third_party/py/py/test.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/py/test.py rename to tests/wpt/web-platform-tests/tools/third_party/py/py/test.py diff --git a/tests/wpt/web-platform-tests/tools/py/setup.cfg b/tests/wpt/web-platform-tests/tools/third_party/py/setup.cfg similarity index 66% rename from tests/wpt/web-platform-tests/tools/py/setup.cfg rename to tests/wpt/web-platform-tests/tools/third_party/py/setup.cfg index 272e488f363..5f25c2febfd 100644 --- a/tests/wpt/web-platform-tests/tools/py/setup.cfg +++ b/tests/wpt/web-platform-tests/tools/third_party/py/setup.cfg @@ -1,5 +1,8 @@ [wheel] universal = 1 +[metadata] +license_file = LICENSE + [devpi:upload] formats=sdist.tgz,bdist_wheel diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/setup.py b/tests/wpt/web-platform-tests/tools/third_party/py/setup.py new file mode 100644 index 00000000000..959323b0c75 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/py/setup.py @@ -0,0 +1,53 @@ +import os +import sys + +from setuptools import setup, find_packages + + +def get_version(): + p = os.path.join(os.path.dirname( + os.path.abspath(__file__)), "py", "__init__.py") + with open(p) as f: + for line in f.readlines(): + if "__version__" in line: + return line.strip().split("=")[-1].strip(" '") + raise ValueError("could not read version") + + +def main(): + setup( + name='py', + description='library with cross-python path, ini-parsing, io, code, log facilities', + long_description=open('README.rst').read(), + version=get_version(), + url='http://py.readthedocs.io/', + license='MIT license', + platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], + python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', + author='holger krekel, Ronny Pfannschmidt, Benjamin Peterson and others', + author_email='pytest-dev@python.org', + classifiers=['Development Status :: 6 - Mature', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Operating System :: POSIX', + 'Operating System :: Microsoft :: Windows', + 'Operating System :: MacOS :: MacOS X', + 'Topic :: Software Development :: Testing', + 'Topic :: Software Development :: Libraries', + 'Topic :: Utilities', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: Implementation :: CPython', + 'Programming Language :: Python :: Implementation :: PyPy', + ], + packages=find_packages(exclude=['tasks', 'testing']), + zip_safe=False, + ) + +if __name__ == '__main__': + main() diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/tasks/__init__.py b/tests/wpt/web-platform-tests/tools/third_party/py/tasks/__init__.py new file mode 100644 index 00000000000..5d74b649e11 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/py/tasks/__init__.py @@ -0,0 +1,12 @@ +""" +Invoke tasks to help with pytest development and release process. +""" + +import invoke + +from . import vendoring + + +ns = invoke.Collection( + vendoring +) diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/tasks/vendoring.py b/tests/wpt/web-platform-tests/tools/third_party/py/tasks/vendoring.py new file mode 100644 index 00000000000..fbc171bc3e0 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/py/tasks/vendoring.py @@ -0,0 +1,23 @@ +from __future__ import absolute_import, print_function +import py +import invoke + +VENDOR_TARGET = py.path.local("py/_vendored_packages") +GOOD_FILES = 'README.md', '__init__.py' + +@invoke.task() +def remove_libs(ctx): + print("removing vendored libs") + for path in VENDOR_TARGET.listdir(): + if path.basename not in GOOD_FILES: + print(" ", path) + path.remove() + +@invoke.task(pre=[remove_libs]) +def update_libs(ctx): + print("installing libs") + ctx.run("pip install -t {target} apipkg iniconfig".format(target=VENDOR_TARGET)) + ctx.run("git add {target}".format(target=VENDOR_TARGET)) + print("Please commit to finish the update after running the tests:") + print() + print(' git commit -am "Updated vendored libs"') diff --git a/tests/wpt/web-platform-tests/tools/py/testing/code/test_assertion.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/code/test_assertion.py similarity index 89% rename from tests/wpt/web-platform-tests/tools/py/testing/code/test_assertion.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/code/test_assertion.py index e2154d0fc7a..e2a7f903998 100644 --- a/tests/wpt/web-platform-tests/tools/py/testing/code/test_assertion.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/testing/code/test_assertion.py @@ -1,7 +1,9 @@ import pytest, py +import re def exvalue(): - return py.std.sys.exc_info()[1] + import sys + return sys.exc_info()[1] def f(): return 2 @@ -23,13 +25,7 @@ def test_assert_within_finally(): i = 42 """) s = excinfo.exconly() - assert py.std.re.search("division.+by zero", s) is not None - - #def g(): - # A.f() - #excinfo = getexcinfo(TypeError, g) - #msg = getmsg(excinfo) - #assert msg.find("must be called with A") != -1 + assert re.search("ZeroDivisionError:.*division", s) is not None def test_assert_multiline_1(): @@ -67,7 +63,6 @@ def test_is(): assert s.startswith("assert 1 is 2") -@py.test.mark.skipif("sys.version_info < (2,6)") def test_attrib(): class Foo(object): b = 1 @@ -79,7 +74,6 @@ def test_attrib(): s = str(e) assert s.startswith("assert 1 == 2") -@py.test.mark.skipif("sys.version_info < (2,6)") def test_attrib_inst(): class Foo(object): b = 1 @@ -108,7 +102,7 @@ def test_assert_keyword_arg(): assert f(x=5) except AssertionError: e = exvalue() - assert "x=5" in e.msg + assert "x=5" in str(e) # These tests should both fail, but should fail nicely... class WeirdRepr: @@ -121,8 +115,8 @@ def bug_test_assert_repr(): assert v == 1 except AssertionError: e = exvalue() - assert e.msg.find('WeirdRepr') != -1 - assert e.msg.find('second line') != -1 + assert str(e).find('WeirdRepr') != -1 + assert str(e).find('second line') != -1 assert 0 def test_assert_non_string(): @@ -130,7 +124,7 @@ def test_assert_non_string(): assert 0, ['list'] except AssertionError: e = exvalue() - assert e.msg.find("list") != -1 + assert str(e).find("list") != -1 def test_assert_implicit_multiline(): try: @@ -139,9 +133,12 @@ def test_assert_implicit_multiline(): 2, 3] except AssertionError: e = exvalue() - assert e.msg.find('assert [1, 2, 3] !=') != -1 - + assert str(e).find('assert [1, 2, 3] !=') != -1 +@py.test.mark.xfail(py.test.__version__[0] != "2", + reason="broken on modern pytest", + run=False +) def test_assert_with_brokenrepr_arg(): class BrokenRepr: def __repr__(self): 0 / 0 @@ -154,14 +151,14 @@ def test_multiple_statements_per_line(): a = 1; assert a == 2 except AssertionError: e = exvalue() - assert "assert 1 == 2" in e.msg + assert "assert 1 == 2" in str(e) def test_power(): try: assert 2**3 == 7 except AssertionError: e = exvalue() - assert "assert (2 ** 3) == 7" in e.msg + assert "assert (2 ** 3) == 7" in str(e) class TestView: @@ -228,7 +225,6 @@ def test_underscore_api(): py.code._reinterpret_old # used by pypy py.code._reinterpret -@py.test.mark.skipif("sys.version_info < (2,6)") def test_assert_customizable_reprcompare(monkeypatch): util = pytest.importorskip("_pytest.assertion.util") monkeypatch.setattr(util, '_reprcompare', lambda *args: 'hello') @@ -277,16 +273,17 @@ def test_assert_raise_alias(testdir): "*1 failed*", ]) - -@pytest.mark.skipif("sys.version_info < (2,5)") +@py.test.mark.xfail(py.test.__version__[0] != "2", + reason="broken on modern pytest", + run=False) def test_assert_raise_subclass(): class SomeEx(AssertionError): def __init__(self, *args): super(SomeEx, self).__init__() try: raise SomeEx("hello") - except AssertionError: - s = str(exvalue()) + except AssertionError as e: + s = str(e) assert 're-run' not in s assert 'could not determine' in s diff --git a/tests/wpt/web-platform-tests/tools/py/testing/code/test_code.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/code/test_code.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/testing/code/test_code.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/code/test_code.py diff --git a/tests/wpt/web-platform-tests/tools/py/testing/code/test_excinfo.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/code/test_excinfo.py similarity index 93% rename from tests/wpt/web-platform-tests/tools/py/testing/code/test_excinfo.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/code/test_excinfo.py index 65742c6f62e..c148ab8cfbd 100644 --- a/tests/wpt/web-platform-tests/tools/py/testing/code/test_excinfo.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/testing/code/test_excinfo.py @@ -1,11 +1,14 @@ # -*- coding: utf-8 -*- import py +import pytest +import sys +from test_source import astonly + from py._code.code import FormattedExcinfo, ReprExceptionInfo queue = py.builtin._tryimport('queue', 'Queue') failsonjython = py.test.mark.xfail("sys.platform.startswith('java')") -from test_source import astonly try: import importlib @@ -14,21 +17,32 @@ except ImportError: else: invalidate_import_caches = getattr(importlib, "invalidate_caches", None) -import pytest + pytest_version_info = tuple(map(int, pytest.__version__.split(".")[:3])) +broken_on_modern_pytest = pytest.mark.xfail( + pytest_version_info[0] != 2, + reason="this test hasn't been fixed after moving py.code into pytest", + run=False + ) + + class TWMock: def __init__(self): self.lines = [] + def sep(self, sep, line=None): self.lines.append((sep, line)) + def line(self, line, **kw): self.lines.append(line) + def markup(self, text, **kw): return text fullwidth = 80 + def test_excinfo_simple(): try: raise ValueError @@ -36,18 +50,22 @@ def test_excinfo_simple(): info = py.code.ExceptionInfo() assert info.type == ValueError + def test_excinfo_getstatement(): def g(): raise ValueError + def f(): g() try: f() except ValueError: excinfo = py.code.ExceptionInfo() - linenumbers = [py.code.getrawcode(f).co_firstlineno-1+3, - py.code.getrawcode(f).co_firstlineno-1+1, - py.code.getrawcode(g).co_firstlineno-1+1,] + linenumbers = [ + py.code.getrawcode(f).co_firstlineno-1+3, + py.code.getrawcode(f).co_firstlineno-1+1, + py.code.getrawcode(g).co_firstlineno-1+1, + ] l = list(excinfo.traceback) foundlinenumbers = [x.lineno for x in l] assert foundlinenumbers == linenumbers @@ -92,7 +110,7 @@ class TestTraceback_f_g_h: def test_traceback_entry_getsource(self): tb = self.excinfo.traceback - s = str(tb[-1].getsource() ) + s = str(tb[-1].getsource()) assert s.startswith("def f():") assert s.endswith("raise ValueError") @@ -164,10 +182,12 @@ class TestTraceback_f_g_h: def test_traceback_no_recursion_index(self): def do_stuff(): raise RuntimeError + def reraise_me(): import sys exc, val, tb = sys.exc_info() py.builtin._reraise(exc, val, tb) + def f(n): try: do_stuff() @@ -179,7 +199,7 @@ class TestTraceback_f_g_h: assert recindex is None def test_traceback_messy_recursion(self): - #XXX: simplified locally testable version + # XXX: simplified locally testable version decorator = py.test.importorskip('decorator').decorator def log(f, *k, **kw): @@ -195,17 +215,18 @@ class TestTraceback_f_g_h: excinfo = py.test.raises(ValueError, fail) assert excinfo.traceback.recursionindex() is None - - def test_traceback_getcrashentry(self): def i(): __tracebackhide__ = True raise ValueError + def h(): i() + def g(): __tracebackhide__ = True h() + def f(): g() @@ -221,6 +242,7 @@ class TestTraceback_f_g_h: def g(): __tracebackhide__ = True raise ValueError + def f(): __tracebackhide__ = True g() @@ -233,9 +255,11 @@ class TestTraceback_f_g_h: assert entry.lineno == co.firstlineno + 2 assert entry.frame.code.name == 'g' + def hello(x): x + 5 + def test_tbentry_reinterpret(): try: hello("hello") @@ -245,6 +269,7 @@ def test_tbentry_reinterpret(): msg = tbentry.reinterpret() assert msg.startswith("TypeError: ('hello' + 5)") + def test_excinfo_exconly(): excinfo = py.test.raises(ValueError, h) assert excinfo.exconly().startswith('ValueError') @@ -254,11 +279,13 @@ def test_excinfo_exconly(): assert msg.startswith('ValueError') assert msg.endswith("world") + def test_excinfo_repr(): excinfo = py.test.raises(ValueError, h) s = repr(excinfo) assert s == "" + def test_excinfo_str(): excinfo = py.test.raises(ValueError, h) s = str(excinfo) @@ -266,20 +293,20 @@ def test_excinfo_str(): assert s.endswith("ValueError") assert len(s.split(":")) >= 3 # on windows it's 4 + def test_excinfo_errisinstance(): excinfo = py.test.raises(ValueError, h) assert excinfo.errisinstance(ValueError) + def test_excinfo_no_sourcecode(): try: exec ("raise ValueError()") except ValueError: excinfo = py.code.ExceptionInfo() s = str(excinfo.traceback[-1]) - if py.std.sys.version_info < (2,5): - assert s == " File '':1 in ?\n ???\n" - else: - assert s == " File '':1 in \n ???\n" + assert s == " File '':1 in \n ???\n" + def test_excinfo_no_python_sourcecode(tmpdir): #XXX: simplified locally testable version @@ -292,7 +319,7 @@ def test_excinfo_no_python_sourcecode(tmpdir): excinfo = py.test.raises(ValueError, template.render, h=h) for item in excinfo.traceback: - print(item) #XXX: for some reason jinja.Template.render is printed in full + print(item) # XXX: for some reason jinja.Template.render is printed in full item.source # shouldnt fail if item.path.basename == 'test.txt': assert str(item.source) == '{{ h()}}:' @@ -309,6 +336,7 @@ def test_entrysource_Queue_example(): s = str(source).strip() assert s.startswith("def get") + def test_codepath_Queue_example(): try: queue.Queue().get(timeout=0.001) @@ -320,6 +348,7 @@ def test_codepath_Queue_example(): assert path.basename.lower() == "queue.py" assert path.check() + class TestFormattedExcinfo: def pytest_funcarg__importasmod(self, request): def importasmod(source): @@ -355,6 +384,7 @@ class TestFormattedExcinfo: assert lines[0] == "| def f(x):" assert lines[1] == " pass" + @broken_on_modern_pytest def test_repr_source_excinfo(self): """ check if indentation is right """ pr = FormattedExcinfo() @@ -372,7 +402,6 @@ class TestFormattedExcinfo: 'E assert 0' ] - def test_repr_source_not_existing(self): pr = FormattedExcinfo() co = compile("raise ValueError()", "", "exec") @@ -600,7 +629,10 @@ raise ValueError() def entry(): func1() """) - excinfo = py.test.raises(ValueError, mod.entry) + try: + mod.entry() + except ValueError: + excinfo = py.code.ExceptionInfo() from py._code.code import Code monkeypatch.setattr(Code, 'path', 'bogus') excinfo.traceback[0].frame.code.path = "bogus" @@ -650,10 +682,11 @@ raise ValueError() p = FormattedExcinfo() def raiseos(): raise OSError(2) - monkeypatch.setattr(py.std.os, 'getcwd', raiseos) + monkeypatch.setattr('os.getcwd', raiseos) assert p._makepath(__file__) == __file__ reprtb = p.repr_traceback(excinfo) + @broken_on_modern_pytest def test_repr_excinfo_addouterr(self, importasmod): mod = importasmod(""" def entry(): @@ -696,6 +729,7 @@ raise ValueError() assert reprtb.extraline == "!!! Recursion detected (same locals & position)" assert str(reprtb) + @broken_on_modern_pytest def test_tb_entry_AssertionError(self, importasmod): # probably this test is a bit redundant # as py/magic/testing/test_assertion.py @@ -720,7 +754,10 @@ raise ValueError() def entry(): f(0) """) - excinfo = py.test.raises(ValueError, mod.entry) + try: + mod.entry() + except ValueError: + excinfo = py.code.ExceptionInfo() for style in ("short", "long", "no"): for showlocals in (True, False): @@ -736,6 +773,7 @@ raise ValueError() x = py.builtin._totext(MyRepr()) assert x == py.builtin._totext("я", "utf-8") + @broken_on_modern_pytest def test_toterminal_long(self, importasmod): mod = importasmod(""" def g(x): @@ -762,6 +800,7 @@ raise ValueError() assert tw.lines[9] == "" assert tw.lines[10].endswith("mod.py:3: ValueError") + @broken_on_modern_pytest def test_toterminal_long_missing_source(self, importasmod, tmpdir): mod = importasmod(""" def g(x): @@ -787,6 +826,7 @@ raise ValueError() assert tw.lines[7] == "" assert tw.lines[8].endswith("mod.py:3: ValueError") + @broken_on_modern_pytest def test_toterminal_long_incomplete_source(self, importasmod, tmpdir): mod = importasmod(""" def g(x): @@ -812,6 +852,7 @@ raise ValueError() assert tw.lines[7] == "" assert tw.lines[8].endswith("mod.py:3: ValueError") + @broken_on_modern_pytest def test_toterminal_long_filenames(self, importasmod): mod = importasmod(""" def f(): @@ -836,14 +877,16 @@ raise ValueError() finally: old.chdir() - @py.test.mark.multi(reproptions=[ - {'style': style, 'showlocals': showlocals, - 'funcargs': funcargs, 'tbfilter': tbfilter - } for style in ("long", "short", "no") - for showlocals in (True, False) - for tbfilter in (True, False) - for funcargs in (True, False)]) - def test_format_excinfo(self, importasmod, reproptions): + @pytest.mark.parametrize('style', ("long", "short", "no")) + @pytest.mark.parametrize('showlocals', (True, False), + ids=['locals', 'nolocals']) + @pytest.mark.parametrize('tbfilter', (True, False), + ids=['tbfilter', 'nofilter']) + @pytest.mark.parametrize('funcargs', (True, False), + ids=['funcargs', 'nofuncargs']) + def test_format_excinfo(self, importasmod, + style, showlocals, tbfilter, funcargs): + mod = importasmod(""" def g(x): raise ValueError(x) @@ -852,11 +895,16 @@ raise ValueError() """) excinfo = py.test.raises(ValueError, mod.f) tw = py.io.TerminalWriter(stringio=True) - repr = excinfo.getrepr(**reproptions) + repr = excinfo.getrepr( + style=style, + showlocals=showlocals, + funcargs=funcargs, + tbfilter=tbfilter + ) repr.toterminal(tw) assert tw.stringio.getvalue() - + @broken_on_modern_pytest def test_native_style(self): excinfo = self.excinfo_from_exec(""" assert 0 @@ -867,10 +915,9 @@ raise ValueError() assert s.startswith('Traceback (most recent call last):\n File') assert s.endswith('\nAssertionError: assert 0') assert 'exec (source.compile())' in s - # python 2.4 fails to get the source line for the assert - if py.std.sys.version_info >= (2, 5): - assert s.count('assert 0') == 2 + assert s.count('assert 0') == 2 + @broken_on_modern_pytest def test_traceback_repr_style(self, importasmod): mod = importasmod(""" def f(): diff --git a/tests/wpt/web-platform-tests/tools/py/testing/code/test_source.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/code/test_source.py similarity index 97% rename from tests/wpt/web-platform-tests/tools/py/testing/code/test_source.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/code/test_source.py index 830de2c95de..3492761a4e9 100644 --- a/tests/wpt/web-platform-tests/tools/py/testing/code/test_source.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/testing/code/test_source.py @@ -1,6 +1,7 @@ from py.code import Source import py import sys +import inspect from py._code.source import _ast if _ast is not None: @@ -168,9 +169,9 @@ class TestSourceParsingAndCompiling: def f(): raise ValueError() """) - source1 = py.std.inspect.getsource(co1) + source1 = inspect.getsource(co1) assert 'KeyError' in source1 - source2 = py.std.inspect.getsource(co2) + source2 = inspect.getsource(co2) assert 'ValueError' in source2 def test_getstatement(self): @@ -251,7 +252,6 @@ class TestSourceParsingAndCompiling: assert getstatement(2, source).lines == source.lines[2:3] assert getstatement(3, source).lines == source.lines[3:4] - @py.test.mark.skipif("sys.version_info < (2,6)") def test_getstatementrange_out_of_bounds_py3(self): source = Source("if xxx:\n from .collections import something") r = source.getstatementrange(1) @@ -261,7 +261,6 @@ class TestSourceParsingAndCompiling: source = Source(":") py.test.raises(SyntaxError, lambda: source.getstatementrange(0)) - @py.test.mark.skipif("sys.version_info < (2,6)") def test_compile_to_ast(self): import ast source = Source("x = 4") @@ -379,8 +378,6 @@ def test_deindent(): lines = deindent(source.splitlines()) assert lines == ['', 'def f():', ' def g():', ' pass', ' '] -@py.test.mark.xfail("sys.version_info[:3] < (2,7,0) or " - "((3,0) <= sys.version_info[:2] < (3,2))") def test_source_of_class_at_eof_without_newline(tmpdir): # this test fails because the implicit inspect.getsource(A) below # does not return the "x = 1" last line. @@ -451,7 +448,7 @@ def test_getfslineno(): fspath, lineno = getfslineno(A) - _, A_lineno = py.std.inspect.findsource(A) + _, A_lineno = inspect.findsource(A) assert fspath.basename == "test_source.py" assert lineno == A_lineno diff --git a/tests/wpt/web-platform-tests/tools/py/testing/conftest.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/conftest.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/testing/conftest.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/conftest.py diff --git a/tests/wpt/web-platform-tests/tools/py/testing/io_/__init__.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/io_/__init__.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/testing/io_/__init__.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/io_/__init__.py diff --git a/tests/wpt/web-platform-tests/tools/py/testing/io_/test_capture.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/io_/test_capture.py similarity index 98% rename from tests/wpt/web-platform-tests/tools/py/testing/io_/test_capture.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/io_/test_capture.py index 5745e12a1a1..b5fedd0abc6 100644 --- a/tests/wpt/web-platform-tests/tools/py/testing/io_/test_capture.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/testing/io_/test_capture.py @@ -366,7 +366,7 @@ class TestStdCaptureFD(TestStdCapture): def test_callcapture(self): def func(x, y): print (x) - py.std.sys.stderr.write(str(y)) + sys.stderr.write(str(y)) return 42 res, out, err = py.io.StdCaptureFD.call(func, 3, y=4) @@ -460,7 +460,7 @@ def test_callcapture_nofd(): assert err.startswith("4") @needsdup -@py.test.mark.multi(use=[True, False]) +@py.test.mark.parametrize('use', [True, False]) def test_fdcapture_tmpfile_remains_the_same(tmpfile, use): if not use: tmpfile = True @@ -472,7 +472,7 @@ def test_fdcapture_tmpfile_remains_the_same(tmpfile, use): capfile2 = cap.err.tmpfile assert capfile2 == capfile -@py.test.mark.multi(method=['StdCapture', 'StdCaptureFD']) +@py.test.mark.parametrize('method', ['StdCapture', 'StdCaptureFD']) def test_capturing_and_logging_fundamentals(testdir, method): if method == "StdCaptureFD" and not hasattr(os, 'dup'): py.test.skip("need os.dup") diff --git a/tests/wpt/web-platform-tests/tools/py/testing/io_/test_saferepr.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/io_/test_saferepr.py similarity index 92% rename from tests/wpt/web-platform-tests/tools/py/testing/io_/test_saferepr.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/io_/test_saferepr.py index 1ed9c4faf62..97be1416fec 100644 --- a/tests/wpt/web-platform-tests/tools/py/testing/io_/test_saferepr.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/testing/io_/test_saferepr.py @@ -39,10 +39,7 @@ class TestSafeRepr: assert 'Exception' in saferepr(BrokenRepr(Exception("broken"))) s = saferepr(BrokenReprException("really broken")) assert 'TypeError' in s - if py.std.sys.version_info < (2,6): - assert 'unknown' in saferepr(BrokenRepr("string")) - else: - assert 'TypeError' in saferepr(BrokenRepr("string")) + assert 'TypeError' in saferepr(BrokenRepr("string")) s2 = saferepr(BrokenRepr(BrokenReprException('omg even worse'))) assert 'NameError' not in s2 diff --git a/tests/wpt/web-platform-tests/tools/py/testing/io_/test_terminalwriter.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/io_/test_terminalwriter.py similarity index 92% rename from tests/wpt/web-platform-tests/tools/py/testing/io_/test_terminalwriter.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/io_/test_terminalwriter.py index 0a15541bd23..7e9ebf409ec 100644 --- a/tests/wpt/web-platform-tests/tools/py/testing/io_/test_terminalwriter.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/testing/io_/test_terminalwriter.py @@ -73,7 +73,7 @@ def test_terminalwriter_dumb_term_no_markup(monkeypatch): monkeypatch.undo() def test_terminalwriter_file_unicode(tmpdir): - f = py.std.codecs.open(str(tmpdir.join("xyz")), "wb", "utf8") + f = codecs.open(str(tmpdir.join("xyz")), "wb", "utf8") tw = py.io.TerminalWriter(file=f) assert tw.encoding == "utf8" @@ -89,7 +89,7 @@ def test_unicode_encoding(): def test_unicode_on_file_with_ascii_encoding(tmpdir, monkeypatch, encoding): msg = py.builtin._totext('hell\xf6', "latin1") #pytest.raises(UnicodeEncodeError, lambda: bytes(msg)) - f = py.std.codecs.open(str(tmpdir.join("x")), "w", encoding) + f = codecs.open(str(tmpdir.join("x")), "w", encoding) tw = py.io.TerminalWriter(f) tw.line(msg) f.close() @@ -226,6 +226,27 @@ def test_terminal_with_callable_write_and_flush(): assert l == set(["2"]) +def test_chars_on_current_line(): + tw = py.io.TerminalWriter(stringio=True) + + written = [] + + def write_and_check(s, expected): + tw.write(s, bold=True) + written.append(s) + assert tw.chars_on_current_line == expected + assert tw.stringio.getvalue() == ''.join(written) + + write_and_check('foo', 3) + write_and_check('bar', 6) + write_and_check('\n', 0) + write_and_check('\n', 0) + write_and_check('\n\n\n', 0) + write_and_check('\nfoo', 3) + write_and_check('\nfbar\nhello', 5) + write_and_check('10', 7) + + @pytest.mark.skipif(sys.platform == "win32", reason="win32 has no native ansi") def test_attr_hasmarkup(): tw = py.io.TerminalWriter(stringio=True) diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/testing/log/__init__.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/log/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/wpt/web-platform-tests/tools/py/testing/log/test_log.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/log/test_log.py similarity index 99% rename from tests/wpt/web-platform-tests/tools/py/testing/log/test_log.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/log/test_log.py index b41bc3a5821..5c706d9b6ad 100644 --- a/tests/wpt/web-platform-tests/tools/py/testing/log/test_log.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/testing/log/test_log.py @@ -1,10 +1,10 @@ import py -import sys from py._log.log import default_keywordmapper callcapture = py.io.StdCapture.call + def setup_module(mod): mod._oldstate = default_keywordmapper.getstate() @@ -13,6 +13,7 @@ def teardown_module(mod): class TestLogProducer: def setup_method(self, meth): + from py._log.log import default_keywordmapper default_keywordmapper.setstate(_oldstate) def test_getstate_setstate(self): diff --git a/tests/wpt/web-platform-tests/tools/py/testing/log/test_warning.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/log/test_warning.py similarity index 88% rename from tests/wpt/web-platform-tests/tools/py/testing/log/test_warning.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/log/test_warning.py index 8c89cf8adbb..a460c319e87 100644 --- a/tests/wpt/web-platform-tests/tools/py/testing/log/test_warning.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/testing/log/test_warning.py @@ -1,8 +1,18 @@ +import sys +from distutils.version import LooseVersion + import pytest + import py mypath = py.path.local(__file__).new(ext=".py") + +win = sys.platform.startswith('win') +pytestmark = pytest.mark.skipif(win and LooseVersion(pytest.__version__) >= LooseVersion('3.1'), + reason='apiwarn is not compatible with pytest >= 3.1 (#162)') + + @pytest.mark.xfail def test_forwarding_to_warnings_module(): pytest.deprecated_call(py.log._apiwarn, "1.3", "..") diff --git a/tests/wpt/web-platform-tests/tools/py/testing/path/common.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/path/common.py similarity index 93% rename from tests/wpt/web-platform-tests/tools/py/testing/path/common.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/path/common.py index 4834fba12d0..d69a1c39d09 100644 --- a/tests/wpt/web-platform-tests/tools/py/testing/path/common.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/testing/path/common.py @@ -1,6 +1,8 @@ import py import sys +import pytest + class CommonFSTests(object): def test_constructor_equality(self, path1): p = path1.__class__(path1) @@ -186,9 +188,12 @@ class CommonFSTests(object): assert "sampledir" in l assert not path1.sep.join(["sampledir", "otherfile"]) in l - def test_visit_filterfunc_is_string(self, path1): + @pytest.mark.parametrize('fil', ['*dir', u'*dir', + pytest.mark.skip("sys.version_info <" + " (3,6)")(b'*dir')]) + def test_visit_filterfunc_is_string(self, path1, fil): l = [] - for i in path1.visit('*dir'): + for i in path1.visit(fil): l.append(i.relto(path1)) assert len(l), 2 assert "sampledir" in l @@ -429,6 +434,26 @@ class CommonFSTests(object): assert dest.join('otherfile').check(file=1) assert not source.join('sampledir').check() + def test_fspath_protocol_match_strpath(self, path1): + assert path1.__fspath__() == path1.strpath + + def test_fspath_func_match_strpath(self, path1): + try: + from os import fspath + except ImportError: + from py._path.common import fspath + assert fspath(path1) == path1.strpath + + @py.test.mark.skip("sys.version_info < (3,6)") + def test_fspath_open(self, path1): + f = path1.join('opentestfile') + open(f) + + @py.test.mark.skip("sys.version_info < (3,6)") + def test_fspath_fsencode(self, path1): + from os import fsencode + assert fsencode(path1) == fsencode(path1.strpath) + def setuptestfs(path): if path.join('samplefile').check(): return @@ -452,10 +477,7 @@ def setuptestfs(path): otherdir.ensure('__init__.py') module_a = otherdir.ensure('a.py') - if sys.version_info >= (2,6): - module_a.write('from .b import stuff as result\n') - else: - module_a.write('from b import stuff as result\n') + module_a.write('from .b import stuff as result\n') module_b = otherdir.ensure('b.py') module_b.write('stuff="got it"\n') module_c = otherdir.ensure('c.py') diff --git a/tests/wpt/web-platform-tests/tools/py/testing/path/conftest.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/path/conftest.py similarity index 98% rename from tests/wpt/web-platform-tests/tools/py/testing/path/conftest.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/path/conftest.py index a9711b2ce30..84fb5c82694 100644 --- a/tests/wpt/web-platform-tests/tools/py/testing/path/conftest.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/testing/path/conftest.py @@ -47,7 +47,7 @@ def getrepowc(tmpdir, reponame='basetestrepo', wcname='wc'): print_("created svn repository", repo) wcdir.ensure(dir=1) wc = py.path.svnwc(wcdir) - if py.std.sys.platform == 'win32': + if sys.platform == 'win32': repourl = "file://" + '/' + str(repo).replace('\\', '/') else: repourl = "file://%s" % repo diff --git a/tests/wpt/web-platform-tests/tools/py/testing/path/repotest.dump b/tests/wpt/web-platform-tests/tools/third_party/py/testing/path/repotest.dump similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/testing/path/repotest.dump rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/path/repotest.dump diff --git a/tests/wpt/web-platform-tests/tools/py/testing/path/svntestbase.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/path/svntestbase.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/testing/path/svntestbase.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/path/svntestbase.py diff --git a/tests/wpt/web-platform-tests/tools/py/testing/path/test_cacheutil.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/path/test_cacheutil.py similarity index 80% rename from tests/wpt/web-platform-tests/tools/py/testing/path/test_cacheutil.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/path/test_cacheutil.py index 0b5cd31332f..c9fc07463a7 100644 --- a/tests/wpt/web-platform-tests/tools/py/testing/path/test_cacheutil.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/testing/path/test_cacheutil.py @@ -1,6 +1,8 @@ -import py +import pytest from py._path import cacheutil +import time + class BasicCacheAPITest: cache = None def test_getorbuild(self): @@ -10,21 +12,22 @@ class BasicCacheAPITest: assert val == 42 def test_cache_get_key_error(self): - py.test.raises(KeyError, "self.cache._getentry(-23)") + pytest.raises(KeyError, "self.cache._getentry(-23)") def test_delentry_non_raising(self): - val = self.cache.getorbuild(100, lambda: 100) + self.cache.getorbuild(100, lambda: 100) self.cache.delentry(100) - py.test.raises(KeyError, "self.cache._getentry(100)") + pytest.raises(KeyError, "self.cache._getentry(100)") def test_delentry_raising(self): - val = self.cache.getorbuild(100, lambda: 100) + self.cache.getorbuild(100, lambda: 100) self.cache.delentry(100) - py.test.raises(KeyError, "self.cache.delentry(100, raising=True)") + pytest.raises(KeyError, self.cache.delentry, 100, raising=True) def test_clear(self): self.cache.clear() + class TestBuildcostAccess(BasicCacheAPITest): cache = cacheutil.BuildcostAccessCache(maxentries=128) @@ -36,6 +39,7 @@ class TestBuildcostAccess(BasicCacheAPITest): # test fail randomly. Let's rather use incrementing # numbers instead. l = [0] + def counter(): l[0] = l[0] + 1 return l[0] @@ -65,20 +69,21 @@ class TestAging(BasicCacheAPITest): def test_cache_eviction(self): self.cache.getorbuild(17, lambda: 17) - endtime = py.std.time.time() + self.maxsecs * 10 - while py.std.time.time() < endtime: + endtime = time.time() + self.maxsecs * 10 + while time.time() < endtime: try: self.cache._getentry(17) except KeyError: break - py.std.time.sleep(self.maxsecs*0.3) + time.sleep(self.maxsecs*0.3) else: - py.test.fail("waiting for cache eviction failed") + pytest.fail("waiting for cache eviction failed") + def test_prune_lowestweight(): maxsecs = 0.05 cache = cacheutil.AgingCache(maxentries=10, maxseconds=maxsecs) for x in range(cache.maxentries): cache.getorbuild(x, lambda: x) - py.std.time.sleep(maxsecs*1.1) + time.sleep(maxsecs*1.1) cache.getorbuild(cache.maxentries+1, lambda: 42) diff --git a/tests/wpt/web-platform-tests/tools/py/testing/path/test_local.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/path/test_local.py similarity index 79% rename from tests/wpt/web-platform-tests/tools/py/testing/path/test_local.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/path/test_local.py index bcf131fd2b7..c9075d6fbb4 100644 --- a/tests/wpt/web-platform-tests/tools/py/testing/path/test_local.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/testing/path/test_local.py @@ -1,30 +1,61 @@ # -*- coding: utf-8 -*- from __future__ import with_statement +import time import py import pytest -import os, sys +import os +import sys +import multiprocessing from py.path import local import common failsonjython = py.test.mark.xfail("sys.platform.startswith('java')") -failsonjywin32 = py.test.mark.xfail("sys.platform.startswith('java') " - "and getattr(os, '_name', None) == 'nt'") +failsonjywin32 = py.test.mark.xfail( + "sys.platform.startswith('java') " + "and getattr(os, '_name', None) == 'nt'") win32only = py.test.mark.skipif( "not (sys.platform == 'win32' or getattr(os, '_name', None) == 'nt')") skiponwin32 = py.test.mark.skipif( "sys.platform == 'win32' or getattr(os, '_name', None) == 'nt'") +ATIME_RESOLUTION = 0.01 + + +@pytest.yield_fixture(scope="session") +def path1(tmpdir_factory): + path = tmpdir_factory.mktemp('path') + common.setuptestfs(path) + yield path + assert path.join("samplefile").check() + + +@pytest.fixture +def fake_fspath_obj(request): + class FakeFSPathClass(object): + def __init__(self, path): + self._path = path + + def __fspath__(self): + return self._path + + return FakeFSPathClass(os.path.join("this", "is", "a", "fake", "path")) + + +def batch_make_numbered_dirs(rootdir, repeats): + try: + for i in range(repeats): + dir_ = py.path.local.make_numbered_dir(prefix='repro-', rootdir=rootdir) + file_ = dir_.join('foo') + file_.write('%s' % i) + actual = int(file_.read()) + assert actual == i, 'int(file_.read()) is %s instead of %s' % (actual, i) + dir_.join('.lock').remove(ignore_errors=True) + return True + except KeyboardInterrupt: + # makes sure that interrupting test session won't hang it + os.exit(2) -def pytest_funcarg__path1(request): - def setup(): - path1 = request.getfuncargvalue("tmpdir") - common.setuptestfs(path1) - return path1 - def teardown(path1): - # post check - assert path1.join("samplefile").check() - return request.cached_setup(setup, teardown, scope="session") class TestLocalPath(common.CommonFSTests): def test_join_normpath(self, tmpdir): @@ -38,7 +69,7 @@ class TestLocalPath(common.CommonFSTests): def test_dirpath_abs_no_abs(self, tmpdir): p = tmpdir.join('foo') assert p.dirpath('/bar') == tmpdir.join('bar') - assert tmpdir.dirpath('/bar', abs=True) == py.path.local('/bar') + assert tmpdir.dirpath('/bar', abs=True) == local('/bar') def test_gethash(self, tmpdir): md5 = py.builtin._tryimport('md5', 'hashlib').md5 @@ -72,7 +103,8 @@ class TestLocalPath(common.CommonFSTests): def test_remove_routes_ignore_errors(self, tmpdir, monkeypatch): l = [] - monkeypatch.setattr(py.std.shutil, 'rmtree', + monkeypatch.setattr( + 'shutil.rmtree', lambda *args, **kwargs: l.append(kwargs)) tmpdir.remove() assert not l[0]['ignore_errors'] @@ -82,7 +114,7 @@ class TestLocalPath(common.CommonFSTests): assert l[0]['ignore_errors'] == val def test_initialize_curdir(self): - assert str(local()) == py.std.os.getcwd() + assert str(local()) == os.getcwd() @skiponwin32 def test_chdir_gone(self, path1): @@ -114,7 +146,6 @@ class TestLocalPath(common.CommonFSTests): p = local('samplefile') assert p.check() - @pytest.mark.xfail("sys.version_info < (2,6) and sys.platform == 'win32'") def test_tilde_expansion(self, monkeypatch, tmpdir): monkeypatch.setenv("HOME", str(tmpdir)) p = py.path.local("~", expanduser=True) @@ -130,7 +161,16 @@ class TestLocalPath(common.CommonFSTests): assert path2 != path3 def test_eq_with_none(self, path1): - assert path1 != None + assert path1 != None # noqa + + def test_eq_non_ascii_unicode(self, path1): + path2 = path1.join(u'temp') + path3 = path1.join(u'ação') + path4 = path1.join(u'ディレクトリ') + + assert path2 != path3 + assert path2 != path4 + assert path4 != path3 def test_gt_with_strings(self, path1): path2 = path1.join('sampledir') @@ -140,7 +180,7 @@ class TestLocalPath(common.CommonFSTests): assert path2 < "ttt" assert "ttt" > path2 path4 = path1.join("aaa") - l = [path2, path4,path3] + l = [path2, path4, path3] assert sorted(l) == [path4, path2, path3] def test_open_and_ensure(self, path1): @@ -154,14 +194,15 @@ class TestLocalPath(common.CommonFSTests): p.write("hello", ensure=1) assert p.read() == "hello" - @py.test.mark.multi(bin=(False, True)) + @py.test.mark.parametrize('bin', (False, True)) def test_dump(self, tmpdir, bin): path = tmpdir.join("dumpfile%s" % int(bin)) try: - d = {'answer' : 42} + d = {'answer': 42} path.dump(d, bin=bin) f = path.open('rb+') - dnew = py.std.pickle.load(f) + import pickle + dnew = pickle.load(f) assert d == dnew finally: f.close() @@ -172,7 +213,7 @@ class TestLocalPath(common.CommonFSTests): import time try: fd, name = tempfile.mkstemp() - py.std.os.close(fd) + os.close(fd) except AttributeError: name = tempfile.mktemp() open(name, 'w').close() @@ -185,7 +226,7 @@ class TestLocalPath(common.CommonFSTests): path.setmtime() assert path.mtime() != mtime finally: - py.std.os.remove(name) + os.remove(name) def test_normpath(self, path1): new1 = path1.join("/otherdir") @@ -213,12 +254,12 @@ class TestLocalPath(common.CommonFSTests): try: res = tmpdir.chdir() assert str(res) == str(old) - assert py.std.os.getcwd() == str(tmpdir) + assert os.getcwd() == str(tmpdir) finally: old.chdir() def test_ensure_filepath_withdir(self, tmpdir): - newfile = tmpdir.join('test1','test') + newfile = tmpdir.join('test1', 'test') newfile.ensure() assert newfile.check(file=1) newfile.write("42") @@ -233,7 +274,13 @@ class TestLocalPath(common.CommonFSTests): assert newfile.check(file=1) def test_ensure_dirpath(self, tmpdir): - newfile = tmpdir.join('test1','testfile') + newfile = tmpdir.join('test1', 'testfile') + t = newfile.ensure(dir=1) + assert t == newfile + assert newfile.check(dir=1) + + def test_ensure_non_ascii_unicode(self, tmpdir): + newfile = tmpdir.join(u'ação',u'ディレクトリ') t = newfile.ensure(dir=1) assert t == newfile assert newfile.check(dir=1) @@ -267,8 +314,8 @@ class TestLocalPath(common.CommonFSTests): assert l2.read() == 'foo' def test_visit_depth_first(self, tmpdir): - p1 = tmpdir.ensure("a","1") - p2 = tmpdir.ensure("b","2") + tmpdir.ensure("a", "1") + tmpdir.ensure("b", "2") p3 = tmpdir.ensure("breadth") l = list(tmpdir.visit(lambda x: x.check(file=1))) assert len(l) == 3 @@ -276,8 +323,8 @@ class TestLocalPath(common.CommonFSTests): assert l[2] == p3 def test_visit_rec_fnmatch(self, tmpdir): - p1 = tmpdir.ensure("a","123") - p2 = tmpdir.ensure(".b","345") + p1 = tmpdir.ensure("a", "123") + tmpdir.ensure(".b", "345") l = list(tmpdir.visit("???", rec="[!.]*")) assert len(l) == 1 # check that breadth comes last @@ -298,6 +345,21 @@ class TestLocalPath(common.CommonFSTests): x2 = py.path.local.sysfind(name, paths=[x.dirpath()]) assert x2 == x + def test_fspath_protocol_other_class(self, fake_fspath_obj): + # py.path is always absolute + py_path = py.path.local(fake_fspath_obj) + str_path = fake_fspath_obj.__fspath__() + assert py_path.check(endswith=str_path) + assert py_path.join(fake_fspath_obj).strpath == os.path.join( + py_path.strpath, str_path) + + def test_make_numbered_dir_multiprocess_safe(self, tmpdir): + # https://github.com/pytest-dev/py/issues/30 + pool = multiprocessing.Pool() + results = [pool.apply_async(batch_make_numbered_dirs, [tmpdir, 100]) for _ in range(20)] + for r in results: + assert r.get() + class TestExecutionOnWindows: pytestmark = win32only @@ -327,17 +389,16 @@ class TestExecution: assert y == x def test_sysfind_multiple(self, tmpdir, monkeypatch): - monkeypatch.setenv('PATH', - "%s:%s" % (tmpdir.ensure('a'), - tmpdir.join('b')), - prepend=":") + monkeypatch.setenv('PATH', "%s:%s" % ( + tmpdir.ensure('a'), + tmpdir.join('b')), + prepend=":") tmpdir.ensure('b', 'a') - checker = lambda x: x.dirpath().basename == 'b' - x = py.path.local.sysfind('a', checker=checker) + x = py.path.local.sysfind( + 'a', checker=lambda x: x.dirpath().basename == 'b') assert x.basename == 'a' assert x.dirpath().basename == 'b' - checker = lambda x: None - assert py.path.local.sysfind('a', checker=checker) is None + assert py.path.local.sysfind('a', checker=lambda x: None) is None def test_sysexec(self): x = py.path.local.sysfind('ls') @@ -347,9 +408,8 @@ class TestExecution: def test_sysexec_failing(self): x = py.path.local.sysfind('false') - py.test.raises(py.process.cmdexec.Error, """ + with pytest.raises(py.process.cmdexec.Error): x.sysexec('aksjdkasjd') - """) def test_make_numbered_dir(self, tmpdir): tmpdir.ensure('base.not_an_int', dir=1) @@ -357,18 +417,37 @@ class TestExecution: numdir = local.make_numbered_dir(prefix='base.', rootdir=tmpdir, keep=2, lock_timeout=0) assert numdir.check() - assert numdir.basename == 'base.%d' %i - if i>=1: + assert numdir.basename == 'base.%d' % i + if i >= 1: assert numdir.new(ext=str(i-1)).check() - if i>=2: + if i >= 2: assert numdir.new(ext=str(i-2)).check() - if i>=3: + if i >= 3: assert not numdir.new(ext=str(i-3)).check() + def test_make_numbered_dir_case_insensitive(self, tmpdir, monkeypatch): + # https://github.com/pytest-dev/pytest/issues/708 + monkeypatch.setattr(py._path.local, 'normcase', + lambda path: path.lower()) + monkeypatch.setattr(tmpdir, 'listdir', + lambda: [tmpdir._fastjoin('case.0')]) + numdir = local.make_numbered_dir(prefix='CAse.', rootdir=tmpdir, + keep=2, lock_timeout=0) + assert numdir.basename.endswith('.1') + + def test_make_numbered_dir_case_sensitive(self, tmpdir, monkeypatch): + # https://github.com/pytest-dev/pytest/issues/708 + monkeypatch.setattr(py._path.local, 'normcase', lambda path: path) + monkeypatch.setattr(tmpdir, 'listdir', + lambda: [tmpdir._fastjoin('case.0')]) + numdir = local.make_numbered_dir(prefix='CAse.', rootdir=tmpdir, + keep=2, lock_timeout=0) + assert numdir.basename.endswith('.0') + def test_make_numbered_dir_NotImplemented_Error(self, tmpdir, monkeypatch): def notimpl(x, y): raise NotImplementedError(42) - monkeypatch.setattr(py.std.os, 'symlink', notimpl) + monkeypatch.setattr(os, 'symlink', notimpl) x = tmpdir.make_numbered_dir(rootdir=tmpdir, lock_timeout=0) assert x.relto(tmpdir) assert x.check() @@ -378,15 +457,15 @@ class TestExecution: numdir = local.make_numbered_dir(prefix='base2.', rootdir=tmpdir, keep=2) assert numdir.check() - assert numdir.basename == 'base2.%d' %i + assert numdir.basename == 'base2.%d' % i for j in range(i): assert numdir.new(ext=str(j)).check() def test_error_preservation(self, path1): - py.test.raises (EnvironmentError, path1.join('qwoeqiwe').mtime) - py.test.raises (EnvironmentError, path1.join('qwoeqiwe').read) + py.test.raises(EnvironmentError, path1.join('qwoeqiwe').mtime) + py.test.raises(EnvironmentError, path1.join('qwoeqiwe').read) - #def test_parentdirmatch(self): + # def test_parentdirmatch(self): # local.parentdirmatch('std', startmodule=__name__) # @@ -401,13 +480,13 @@ class TestImport: p = tmpdir.ensure("a", "test_x123.py") p.pyimport() tmpdir.join("a").move(tmpdir.join("b")) - pytest.raises(tmpdir.ImportMismatchError, - lambda: tmpdir.join("b", "test_x123.py").pyimport()) + with pytest.raises(tmpdir.ImportMismatchError): + tmpdir.join("b", "test_x123.py").pyimport() def test_pyimport_messy_name(self, tmpdir): # http://bitbucket.org/hpk42/py-trunk/issue/129 path = tmpdir.ensure('foo__init__.py') - obj = path.pyimport() + path.pyimport() def test_pyimport_dir(self, tmpdir): p = tmpdir.join("hello_123") @@ -454,7 +533,7 @@ class TestImport: def test_pyimport_check_filepath_consistency(self, monkeypatch, tmpdir): name = 'pointsback123' - ModuleType = type(py.std.os) + ModuleType = type(os) p = tmpdir.ensure(name + '.py') for ending in ('.pyc', '$py.class', '.pyo'): mod = ModuleType(name) @@ -468,8 +547,7 @@ class TestImport: pseudopath = tmpdir.ensure(name+"123.py") mod.__file__ = str(pseudopath) monkeypatch.setitem(sys.modules, name, mod) - excinfo = py.test.raises(pseudopath.ImportMismatchError, - "p.pyimport()") + excinfo = py.test.raises(pseudopath.ImportMismatchError, p.pyimport) modname, modfile, orig = excinfo.value.args assert modname == name assert modfile == pseudopath @@ -502,14 +580,16 @@ def test_pypkgdir(tmpdir): assert pkg.pypkgpath() == pkg assert pkg.join('subdir', '__init__.py').pypkgpath() == pkg + def test_pypkgdir_unimportable(tmpdir): - pkg = tmpdir.ensure('pkg1-1', dir=1) # unimportable + pkg = tmpdir.ensure('pkg1-1', dir=1) # unimportable pkg.ensure("__init__.py") subdir = pkg.ensure("subdir/__init__.py").dirpath() assert subdir.pypkgpath() == subdir assert subdir.ensure("xyz.py").pypkgpath() == subdir assert not pkg.pypkgpath() + def test_isimportable(): from py._path.local import isimportable assert not isimportable("") @@ -521,17 +601,20 @@ def test_isimportable(): assert not isimportable("x-1") assert not isimportable("x:1") + def test_homedir_from_HOME(monkeypatch): path = os.getcwd() monkeypatch.setenv("HOME", path) assert py.path.local._gethomedir() == py.path.local(path) + def test_homedir_not_exists(monkeypatch): monkeypatch.delenv("HOME", raising=False) monkeypatch.delenv("HOMEDRIVE", raising=False) homedir = py.path.local._gethomedir() assert homedir is None + def test_samefile(tmpdir): assert tmpdir.samefile(tmpdir) p = tmpdir.ensure("hello") @@ -543,14 +626,17 @@ def test_samefile(tmpdir): p2 = p.__class__(str(p).upper()) assert p1.samefile(p2) + def test_listdir_single_arg(tmpdir): tmpdir.ensure("hello") assert tmpdir.listdir("hello")[0].basename == "hello" + def test_mkdtemp_rootdir(tmpdir): dtmp = local.mkdtemp(rootdir=tmpdir) assert tmpdir.listdir() == [dtmp] + class TestWINLocalPath: pytestmark = win32only @@ -592,7 +678,7 @@ class TestWINLocalPath: def test_sysfind_in_currentdir(self, path1): cmd = py.path.local.sysfind('cmd') - root = cmd.new(dirname='', basename='') # c:\ in most installations + root = cmd.new(dirname='', basename='') # c:\ in most installations with root.as_cwd(): x = py.path.local.sysfind(cmd.relto(root)) assert x.check(file=1) @@ -606,6 +692,7 @@ class TestWINLocalPath: pattern = posixpath.sep.join([str(tmpdir), "*", "b"]) assert b.fnmatch(pattern) + class TestPOSIXLocalPath: pytestmark = skiponwin32 @@ -664,7 +751,7 @@ class TestPOSIXLocalPath: def test_symlink_remove(self, tmpdir): linkpath = tmpdir.join('test') - linkpath.mksymlinkto(linkpath) # point to itself + linkpath.mksymlinkto(linkpath) # point to itself assert linkpath.check(link=1) linkpath.remove() assert not linkpath.check() @@ -716,9 +803,9 @@ class TestPOSIXLocalPath: # we could wait here but timer resolution is very # system dependent path.read() - time.sleep(0.01) + time.sleep(ATIME_RESOLUTION) atime2 = path.atime() - time.sleep(0.01) + time.sleep(ATIME_RESOLUTION) duration = time.time() - now assert (atime2-atime1) <= duration @@ -740,7 +827,7 @@ class TestPOSIXLocalPath: def test_join_to_root(self, path1): root = path1.parts()[0] assert len(str(root)) == 1 - assert str(root.join('a')) == '//a' # posix allows two slashes + assert str(root.join('a')) == '/a' def test_join_root_to_root_with_no_abs(self, path1): nroot = path1.join('/') @@ -758,7 +845,7 @@ class TestPOSIXLocalPath: def test_chmod_rec_int(self, path1): # XXX fragile test - recfilter = lambda x: x.check(dotfile=0, link=0) + def recfilter(x): return x.check(dotfile=0, link=0) oldmodes = {} for x in path1.visit(rec=recfilter): oldmodes[x] = x.stat().mode @@ -767,7 +854,7 @@ class TestPOSIXLocalPath: for x in path1.visit(rec=recfilter): assert x.stat().mode & int("777", 8) == int("772", 8) finally: - for x,y in oldmodes.items(): + for x, y in oldmodes.items(): x.chmod(y) def test_copy_archiving(self, tmpdir): @@ -781,6 +868,34 @@ class TestPOSIXLocalPath: a.copy(b, mode=True) assert b.join(f.basename).stat().mode == newmode + def test_copy_stat_file(self, tmpdir): + src = tmpdir.ensure('src') + dst = tmpdir.join('dst') + # a small delay before the copy + time.sleep(ATIME_RESOLUTION) + src.copy(dst, stat=True) + oldstat = src.stat() + newstat = dst.stat() + assert oldstat.mode == newstat.mode + assert (dst.atime() - src.atime()) < ATIME_RESOLUTION + assert (dst.mtime() - src.mtime()) < ATIME_RESOLUTION + + def test_copy_stat_dir(self, tmpdir): + test_files = ['a', 'b', 'c'] + src = tmpdir.join('src') + for f in test_files: + src.join(f).write(f, ensure=True) + dst = tmpdir.join('dst') + # a small delay before the copy + time.sleep(ATIME_RESOLUTION) + src.copy(dst, stat=True) + for f in test_files: + oldstat = src.join(f).stat() + newstat = dst.join(f).stat() + assert (newstat.atime - oldstat.atime) < ATIME_RESOLUTION + assert (newstat.mtime - oldstat.mtime) < ATIME_RESOLUTION + assert oldstat.mode == newstat.mode + @failsonjython def test_chown_identity(self, path1): owner = path1.stat().owner @@ -807,7 +922,7 @@ class TestPOSIXLocalPath: class TestUnicodePy2Py3: def test_join_ensure(self, tmpdir, monkeypatch): - if sys.version_info >= (3,0) and "LANG" not in os.environ: + if sys.version_info >= (3, 0) and "LANG" not in os.environ: pytest.skip("cannot run test without locale") x = py.path.local(tmpdir.strpath) part = "hällo" @@ -815,14 +930,15 @@ class TestUnicodePy2Py3: assert x.join(part) == y def test_listdir(self, tmpdir): - if sys.version_info >= (3,0) and "LANG" not in os.environ: + if sys.version_info >= (3, 0) and "LANG" not in os.environ: pytest.skip("cannot run test without locale") x = py.path.local(tmpdir.strpath) part = "hällo" y = x.ensure(part) assert x.listdir(part)[0] == y - @pytest.mark.xfail(reason="changing read/write might break existing usages") + @pytest.mark.xfail( + reason="changing read/write might break existing usages") def test_read_write(self, tmpdir): x = tmpdir.join("hello") part = py.builtin._totext("hällo", "utf8") @@ -831,6 +947,7 @@ class TestUnicodePy2Py3: x.write(part.encode(sys.getdefaultencoding())) assert x.read() == part.encode(sys.getdefaultencoding()) + class TestBinaryAndTextMethods: def test_read_binwrite(self, tmpdir): x = tmpdir.join("hello") diff --git a/tests/wpt/web-platform-tests/tools/py/testing/path/test_svnauth.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/path/test_svnauth.py similarity index 98% rename from tests/wpt/web-platform-tests/tools/py/testing/path/test_svnauth.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/path/test_svnauth.py index b3f36656168..654f033224f 100644 --- a/tests/wpt/web-platform-tests/tools/py/testing/path/test_svnauth.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/testing/path/test_svnauth.py @@ -1,11 +1,11 @@ import py -import svntestbase from py.path import SvnAuth import time import sys svnbin = py.path.local.sysfind('svn') + def make_repo_auth(repo, userdata): """ write config to repo @@ -277,7 +277,7 @@ class Setup: if sys.platform == 'win32': repodir = '/' + str(repodir).replace('\\', '/') self.repo = py.path.svnurl("file://%s" % repodir) - if py.std.sys.platform == 'win32': + if sys.platform == 'win32': # remove trailing slash... repodir = repodir[1:] self.repopath = py.path.local(repodir) @@ -322,6 +322,12 @@ class TestSvnWCAuthFunctional: assert log[0].msg == 'added foo.txt' def test_switch(self, setup): + import pytest + try: + import xdist + pytest.skip('#160: fails under xdist') + except ImportError: + pass wc = py.path.svnwc(setup.temppath, auth=setup.auth) svnurl = 'svn://localhost:%s/%s' % (setup.port, setup.repopath.basename) wc.checkout(svnurl) diff --git a/tests/wpt/web-platform-tests/tools/py/testing/path/test_svnurl.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/path/test_svnurl.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/testing/path/test_svnurl.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/path/test_svnurl.py diff --git a/tests/wpt/web-platform-tests/tools/py/testing/path/test_svnwc.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/path/test_svnwc.py similarity index 97% rename from tests/wpt/web-platform-tests/tools/py/testing/path/test_svnwc.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/path/test_svnwc.py index 9e6b524acab..c643d9983fb 100644 --- a/tests/wpt/web-platform-tests/tools/py/testing/path/test_svnwc.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/testing/path/test_svnwc.py @@ -5,6 +5,12 @@ from py._path.svnwc import InfoSvnWCCommand, XMLWCStatus, parse_wcinfotime from py._path import svnwc as svncommon from svntestbase import CommonSvnTests + +pytestmark = pytest.mark.xfail(sys.platform.startswith('win'), + reason='#161 all tests in this file are failing on Windows', + run=False) + + def test_make_repo(path1, tmpdir): repo = tmpdir.join("repo") py.process.cmdexec('svnadmin create %s' % repo) @@ -106,15 +112,17 @@ class TestWCSvnCommandPath(CommonSvnTests): assert r.join('sampledir/otherfile').basename in [item.basename for item in s.unchanged] - @pytest.mark.xfail(reason="svn-1.7 has buggy 'status --xml' output") def test_status_update(self, path1): + # not a mark because the global "pytestmark" will end up overwriting a mark here + pytest.xfail("svn-1.7 has buggy 'status --xml' output") r = path1 try: r.update(rev=1) s = r.status(updates=1, rec=1) # Comparing just the file names, because paths are unpredictable # on Windows. (long vs. 8.3 paths) - py.std.pprint.pprint(s.allpath()) + import pprint + pprint.pprint(s.allpath()) assert r.join('anotherfile').basename in [item.basename for item in s.update_available] #assert len(s.update_available) == 1 diff --git a/tests/wpt/web-platform-tests/tools/py/testing/process/__init__.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/process/__init__.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/testing/process/__init__.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/process/__init__.py diff --git a/tests/wpt/web-platform-tests/tools/py/testing/process/test_cmdexec.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/process/test_cmdexec.py similarity index 91% rename from tests/wpt/web-platform-tests/tools/py/testing/process/test_cmdexec.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/process/test_cmdexec.py index b539e0af381..98463d906d1 100644 --- a/tests/wpt/web-platform-tests/tools/py/testing/process/test_cmdexec.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/testing/process/test_cmdexec.py @@ -2,7 +2,9 @@ import py from py.process import cmdexec def exvalue(): - return py.std.sys.exc_info()[1] + import sys + return sys.exc_info()[1] + class Test_exec_cmd: def test_simple(self): @@ -17,7 +19,7 @@ class Test_exec_cmd: assert py.builtin._istext(out) def test_simple_error(self): - py.test.raises (cmdexec.Error, cmdexec, 'exit 1') + py.test.raises(cmdexec.Error, cmdexec, 'exit 1') def test_simple_error_exact_status(self): try: diff --git a/tests/wpt/web-platform-tests/tools/py/testing/process/test_forkedfunc.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/process/test_forkedfunc.py similarity index 95% rename from tests/wpt/web-platform-tests/tools/py/testing/process/test_forkedfunc.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/process/test_forkedfunc.py index d4f9f985e0f..ae0d9ab7e6d 100644 --- a/tests/wpt/web-platform-tests/tools/py/testing/process/test_forkedfunc.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/testing/process/test_forkedfunc.py @@ -70,8 +70,6 @@ def test_forkedfunc_on_stdout(): def test_forkedfunc_signal(): result = py.process.ForkedFunc(boxseg).waitfinish() assert result.retval is None - if sys.version_info < (2,4): - py.test.skip("signal detection does not work with python prior 2.4") assert result.signal == 11 def test_forkedfunc_huge_data(): @@ -116,8 +114,6 @@ def test_kill_func_forked(): ff = py.process.ForkedFunc(box_fun) os.kill(ff.pid, 15) result = ff.waitfinish() - if py.std.sys.version_info < (2,4): - py.test.skip("signal detection does not work with python prior 2.4") assert result.signal == 15 diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/testing/process/test_killproc.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/process/test_killproc.py new file mode 100644 index 00000000000..b0d6e2f5153 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/py/testing/process/test_killproc.py @@ -0,0 +1,18 @@ +import pytest +import sys +import py + + +@pytest.mark.skipif("sys.platform.startswith('java')") +def test_kill(tmpdir): + subprocess = pytest.importorskip("subprocess") + t = tmpdir.join("t.py") + t.write("import time ; time.sleep(100)") + proc = subprocess.Popen([sys.executable, str(t)]) + assert proc.poll() is None # no return value yet + py.process.kill(proc.pid) + ret = proc.wait() + if sys.platform == "win32" and ret == 0: + pytest.skip("XXX on win32, subprocess.Popen().wait() on a killed " + "process does not yield return value != 0") + assert ret != 0 diff --git a/tests/wpt/web-platform-tests/tools/py/testing/root/__init__.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/root/__init__.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/testing/root/__init__.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/root/__init__.py diff --git a/tests/wpt/web-platform-tests/tools/py/testing/root/test_builtin.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/root/test_builtin.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/testing/root/test_builtin.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/root/test_builtin.py diff --git a/tests/wpt/web-platform-tests/tools/py/testing/root/test_error.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/root/test_error.py similarity index 57% rename from tests/wpt/web-platform-tests/tools/py/testing/root/test_error.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/root/test_error.py index a34e0068d92..a1185f33dc9 100644 --- a/tests/wpt/web-platform-tests/tools/py/testing/root/test_error.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/testing/root/test_error.py @@ -3,18 +3,26 @@ import py import errno + def test_error_classes(): for name in errno.errorcode.values(): x = getattr(py.error, name) assert issubclass(x, py.error.Error) assert issubclass(x, EnvironmentError) + +def test_has_name(): + assert py.error.__name__ == 'py.error' + + def test_picklability_issue1(): + import pickle e1 = py.error.ENOENT() - s = py.std.pickle.dumps(e1) - e2 = py.std.pickle.loads(s) + s = pickle.dumps(e1) + e2 = pickle.loads(s) assert isinstance(e2, py.error.ENOENT) + def test_unknown_error(): num = 3999 cls = py.error._geterrnoclass(num) @@ -24,6 +32,7 @@ def test_unknown_error(): cls2 = py.error._geterrnoclass(num) assert cls is cls2 + def test_error_conversion_ENOTDIR(testdir): p = testdir.makepyfile("") excinfo = py.test.raises(py.error.Error, py.error.checked_call, p.listdir) @@ -35,3 +44,25 @@ def test_error_conversion_ENOTDIR(testdir): def test_checked_call_supports_kwargs(tmpdir): import tempfile py.error.checked_call(tempfile.mkdtemp, dir=str(tmpdir)) + + +try: + import unittest + unittest.TestCase.assertWarns +except (ImportError, AttributeError): + pass # required interface not available +else: + import sys + import warnings + + class Case(unittest.TestCase): + def test_assertWarns(self): + # Clear everything "py.*" from sys.modules and re-import py + # as a fresh start + for mod in tuple(sys.modules.keys()): + if mod and (mod == 'py' or mod.startswith('py.')): + del sys.modules[mod] + import py + + with self.assertWarns(UserWarning): + warnings.warn('this should work') diff --git a/tests/wpt/web-platform-tests/tools/py/testing/root/test_py_imports.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/root/test_py_imports.py similarity index 84% rename from tests/wpt/web-platform-tests/tools/py/testing/root/test_py_imports.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/root/test_py_imports.py index 5f5954e9943..31fe6ead810 100644 --- a/tests/wpt/web-platform-tests/tools/py/testing/root/test_py_imports.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/testing/root/test_py_imports.py @@ -1,20 +1,17 @@ import py -import types import sys -def checksubpackage(name): + +@py.test.mark.parametrize('name', [x for x in dir(py) if x[0] != '_']) +def test_dir(name): obj = getattr(py, name) - if hasattr(obj, '__map__'): # isinstance(obj, Module): + if hasattr(obj, '__map__'): # isinstance(obj, Module): keys = dir(obj) assert len(keys) > 0 print (obj.__map__) for name in list(obj.__map__): assert hasattr(obj, name), (obj, name) -def test_dir(): - for name in dir(py): - if not name.startswith('_'): - yield checksubpackage, name def test_virtual_module_identity(): from py import path as path1 @@ -24,11 +21,12 @@ def test_virtual_module_identity(): from py.path import local as local2 assert local1 is local2 + def test_importall(): base = py._pydir nodirs = [ ] - if sys.version_info >= (3,0): + if sys.version_info >= (3, 0): nodirs.append(base.join('_code', '_assertionold.py')) else: nodirs.append(base.join('_code', '_assertionnew.py')) @@ -40,7 +38,7 @@ def test_importall(): if p.basename == '__init__.py': continue relpath = p.new(ext='').relto(base) - if base.sep in relpath: # not py/*.py itself + if base.sep in relpath: # not py/*.py itself for x in nodirs: if p == x or p.relto(x): break @@ -52,10 +50,16 @@ def test_importall(): except py.test.skip.Exception: pass + def check_import(modpath): py.builtin.print_("checking import", modpath) assert __import__(modpath) + +def test_star_import(): + exec("from py import *") + + def test_all_resolves(): seen = py.builtin.set([py]) lastlength = None @@ -65,4 +69,3 @@ def test_all_resolves(): for value in item.__dict__.values(): if isinstance(value, type(py.test)): seen.add(value) - diff --git a/tests/wpt/web-platform-tests/tools/py/testing/root/test_std.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/root/test_std.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/py/testing/root/test_std.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/root/test_std.py diff --git a/tests/wpt/web-platform-tests/tools/py/testing/root/test_xmlgen.py b/tests/wpt/web-platform-tests/tools/third_party/py/testing/root/test_xmlgen.py similarity index 97% rename from tests/wpt/web-platform-tests/tools/py/testing/root/test_xmlgen.py rename to tests/wpt/web-platform-tests/tools/third_party/py/testing/root/test_xmlgen.py index 704d1492cb3..fc0e82665f7 100644 --- a/tests/wpt/web-platform-tests/tools/py/testing/root/test_xmlgen.py +++ b/tests/wpt/web-platform-tests/tools/third_party/py/testing/root/test_xmlgen.py @@ -1,6 +1,7 @@ import py from py._xmlgen import unicode, html, raw +import sys class ns(py.xml.Namespace): pass @@ -12,14 +13,14 @@ def test_escape(): return uvalue def __str__(self): x = self.__unicode__() - if py.std.sys.version_info[0] < 3: + if sys.version_info[0] < 3: return x.encode('utf-8') return x y = py.xml.escape(uvalue) assert y == uvalue x = py.xml.escape(A()) assert x == uvalue - if py.std.sys.version_info[0] < 3: + if sys.version_info[0] < 3: assert isinstance(x, unicode) assert isinstance(y, unicode) y = py.xml.escape(uvalue.encode('utf-8')) diff --git a/tests/wpt/web-platform-tests/tools/third_party/py/tox.ini b/tests/wpt/web-platform-tests/tools/third_party/py/tox.ini new file mode 100644 index 00000000000..601661cf8e2 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/py/tox.ini @@ -0,0 +1,33 @@ +[tox] +envlist=py{27,34,35,36}-pytest{29,30,31} + +[testenv] +changedir=testing +commands= + pip install -U .. # hande the install order fallout since pytest depends on pip + + py.test --confcutdir=.. -rfsxX --junitxml={envlogdir}/junit-{envname}.xml [] +deps= + pytest29: pytest~=2.9.0 + pytest30: pytest~=3.0.0 + pytest31: pytest~=3.1.0 + +[testenv:py27-xdist] +basepython=python2.7 +deps= + pytest~=2.9.0 + pytest-xdist<=1.16.0 +commands= + pip install -U .. # hande the install order fallout since pytest depends on pip + py.test -n3 -rfsxX --confcutdir=.. --runslowtests \ + --junitxml={envlogdir}/junit-{envname}.xml [] + +[testenv:jython] +changedir=testing +commands= + {envpython} -m pip install -U .. # hande the install order fallout since pytest depends on pip + {envpython} -m pytest --confcutdir=.. -rfsxX --junitxml={envlogdir}/junit-{envname}0.xml {posargs:io_ code} + +[pytest] +rsyncdirs = conftest.py py doc testing +addopts = -ra diff --git a/tests/wpt/web-platform-tests/tools/pytest/.gitattributes b/tests/wpt/web-platform-tests/tools/third_party/pytest/.gitattributes similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/.gitattributes rename to tests/wpt/web-platform-tests/tools/third_party/pytest/.gitattributes diff --git a/tests/wpt/web-platform-tests/tools/pytest/.github/ISSUE_TEMPLATE.md b/tests/wpt/web-platform-tests/tools/third_party/pytest/.github/ISSUE_TEMPLATE.md similarity index 84% rename from tests/wpt/web-platform-tests/tools/pytest/.github/ISSUE_TEMPLATE.md rename to tests/wpt/web-platform-tests/tools/third_party/pytest/.github/ISSUE_TEMPLATE.md index bc62e8a3f7d..fbcbb16fc35 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/.github/ISSUE_TEMPLATE.md +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/.github/ISSUE_TEMPLATE.md @@ -4,5 +4,5 @@ Here's a quick checklist in what to include: - [ ] Include a detailed description of the bug or suggestion - [ ] `pip list` of the virtual environment you are using -- [ ] py.test and operating system versions +- [ ] pytest and operating system versions - [ ] Minimal example if possible diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/.github/PULL_REQUEST_TEMPLATE.md b/tests/wpt/web-platform-tests/tools/third_party/pytest/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000000..bf9fc199f59 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,15 @@ +Thanks for submitting a PR, your contribution is really appreciated! + +Here's a quick checklist that should be present in PRs: + +- [ ] Add a new news fragment into the changelog folder + * name it `$issue_id.$type` for example (588.bug) + * if you don't have an issue_id change it to the pr id after creating the pr + * ensure type is one of `removal`, `feature`, `bugfix`, `vendor`, `doc` or `trivial` + * Make sure to use full sentences with correct case and punctuation, for example: "Fix issue with non-ascii contents in doctest text files." +- [ ] Target: for `bugfix`, `vendor`, `doc` or `trivial` fixes, target `master`; for removals or features target `features`; +- [ ] Make sure to include reasonable tests for your change if necessary + +Unless your change is a trivial or a documentation fix (e.g., a typo or reword of a small section) please: + +- [ ] Add yourself to `AUTHORS`, in alphabetical order; diff --git a/tests/wpt/web-platform-tests/tools/pytest/.gitignore b/tests/wpt/web-platform-tests/tools/third_party/pytest/.gitignore similarity index 83% rename from tests/wpt/web-platform-tests/tools/pytest/.gitignore rename to tests/wpt/web-platform-tests/tools/third_party/pytest/.gitignore index e4355b859cc..3b7ec9facf2 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/.gitignore +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/.gitignore @@ -16,7 +16,11 @@ include/ *.class *.orig *~ +.hypothesis/ +# autogenerated +_pytest/_version.py +# setuptools .eggs/ doc/*/_build @@ -32,3 +36,4 @@ env/ .coverage .ropeproject .idea +.hypothesis diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/.travis.yml b/tests/wpt/web-platform-tests/tools/third_party/pytest/.travis.yml new file mode 100644 index 00000000000..938391cde09 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/.travis.yml @@ -0,0 +1,56 @@ +sudo: false +language: python +python: + - '3.6' +# command to install dependencies +install: + - pip install --upgrade --pre tox +# # command to run tests +env: + matrix: + # coveralls is not listed in tox's envlist, but should run in travis + - TOXENV=coveralls + # note: please use "tox --listenvs" to populate the build matrix below + - TOXENV=linting + - TOXENV=py27 + - TOXENV=py34 + - TOXENV=py36 + - TOXENV=py27-pexpect + - TOXENV=py27-xdist + - TOXENV=py27-trial + - TOXENV=py27-numpy + - TOXENV=py27-pluggymaster + - TOXENV=py36-pexpect + - TOXENV=py36-xdist + - TOXENV=py36-trial + - TOXENV=py36-numpy + - TOXENV=py36-pluggymaster + - TOXENV=py27-nobyte + - TOXENV=doctesting + - TOXENV=docs + +matrix: + include: + - env: TOXENV=pypy + python: 'pypy-5.4' + - env: TOXENV=py35 + python: '3.5' + - env: TOXENV=py35-freeze + python: '3.5' + - env: TOXENV=py37 + python: 'nightly' + allow_failures: + - env: TOXENV=py37 + python: 'nightly' + +script: tox --recreate + +notifications: + irc: + channels: + - "chat.freenode.net#pytest" + on_success: change + on_failure: change + skip_join: true + email: + - pytest-commit@python.org diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/AUTHORS b/tests/wpt/web-platform-tests/tools/third_party/pytest/AUTHORS new file mode 100644 index 00000000000..44ae6aa43ab --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/AUTHORS @@ -0,0 +1,189 @@ +Holger Krekel, holger at merlinux eu +merlinux GmbH, Germany, office at merlinux eu + +Contributors include:: + +Abdeali JK +Abhijeet Kasurde +Ahn Ki-Wook +Alexander Johnson +Alexei Kozlenok +Anatoly Bubenkoff +Andras Tim +Andreas Zeidler +Andrzej Ostrowski +Andy Freeland +Anthon van der Neut +Anthony Sottile +Antony Lee +Armin Rigo +Aron Curzon +Aviv Palivoda +Barney Gale +Ben Webb +Benjamin Peterson +Bernard Pratz +Bob Ippolito +Brian Dorsey +Brian Okken +Brianna Laugher +Bruno Oliveira +Cal Leeming +Carl Friedrich Bolz +Ceridwen +Charles Cloud +Charnjit SiNGH (CCSJ) +Chris Lamb +Christian Boelsen +Christian Theunert +Christian Tismer +Christopher Gilling +Daniel Grana +Daniel Hahler +Daniel Nuri +Daniel Wandschneider +Danielle Jenkins +Dave Hunt +David Díaz-Barquero +David Mohr +David Vierra +Daw-Ran Liou +Denis Kirisov +Diego Russo +Dmitry Dygalo +Dmitry Pribysh +Duncan Betts +Edison Gustavo Muenz +Edoardo Batini +Eduardo Schettino +Eli Boyarski +Elizaveta Shashkova +Endre Galaczi +Eric Hunsberger +Eric Siegerman +Erik M. Bray +Feng Ma +Florian Bruhin +Floris Bruynooghe +Gabriel Reis +George Kussumoto +Georgy Dyuldin +Graham Horler +Greg Price +Grig Gheorghiu +Grigorii Eremeev (budulianin) +Guido Wesdorp +Harald Armin Massa +Hugo van Kemenade +Hui Wang (coldnight) +Ian Bicking +Jaap Broekhuizen +Jan Balster +Janne Vanhala +Jason R. Coombs +Javier Domingo Cansino +Javier Romero +Jeff Widman +John Eddie Ayson +John Towler +Jon Sonesen +Jonas Obrist +Jordan Guymon +Jordan Moldow +Joshua Bronson +Jurko Gospodnetić +Justyna Janczyszyn +Kale Kundert +Katarzyna Jachim +Kevin Cox +Kodi B. Arfer +Lawrence Mitchell +Lee Kamentsky +Lev Maximov +Llandy Riveron Del Risco +Loic Esteve +Lukas Bednar +Luke Murphy +Maciek Fijalkowski +Maho +Maik Figura +Mandeep Bhutani +Manuel Krebber +Marc Schlaich +Marcin Bachry +Mark Abramowitz +Markus Unterwaditzer +Martijn Faassen +Martin Altmayer +Martin K. Scherer +Martin Prusse +Mathieu Clabaut +Matt Bachmann +Matt Duck +Matt Williams +Matthias Hafner +Maxim Filipenko +mbyt +Michael Aquilina +Michael Birtwell +Michael Droettboom +Michael Seifert +Michal Wajszczuk +Mihai Capotă +Mike Lundy +Nathaniel Waisbrot +Ned Batchelder +Neven Mundar +Nicolas Delaby +Oleg Pidsadnyi +Oliver Bestwalter +Omar Kohl +Omer Hadari +Patrick Hayes +Paweł Adamczak +Pieter Mulder +Piotr Banaszkiewicz +Punyashloka Biswal +Quentin Pradet +Ralf Schmitt +Ran Benita +Raphael Pierzina +Raquel Alegre +Ravi Chandra +Roberto Polli +Romain Dorgueil +Roman Bolshakov +Ronny Pfannschmidt +Ross Lawley +Russel Winder +Ryan Wooden +Samuel Dion-Girardeau +Samuele Pedroni +Segev Finer +Simon Gomizelj +Skylar Downes +Srinivas Reddy Thatiparthy +Stefan Farmbauer +Stefan Zimmermann +Stefano Taschini +Steffen Allner +Stephan Obermann +Tarcisio Fischer +Tareq Alayan +Ted Xiao +Thomas Grainger +Thomas Hisch +Tom Dalton +Tom Viner +Trevor Bekolay +Tyler Goodlet +Vasily Kuznetsov +Victor Uriarte +Vidar T. Fauske +Vitaly Lashmanov +Vlad Dragos +Wouter van Ackooy +Xuan Luong +Xuecong Liao +Zoltán Máté +Roland Puntaier diff --git a/tests/wpt/web-platform-tests/tools/pytest/CHANGELOG.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/CHANGELOG.rst similarity index 58% rename from tests/wpt/web-platform-tests/tools/pytest/CHANGELOG.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/CHANGELOG.rst index f18f646f008..7e7bfaf0441 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/CHANGELOG.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/CHANGELOG.rst @@ -1,5 +1,1608 @@ -2.9.1 -===== +.. + You should *NOT* be adding new change log entries to this file, this + file is managed by towncrier. You *may* edit previous change logs to + fix problems like typo corrections or such. + To add a new change log entry, please see + https://pip.pypa.io/en/latest/development/#adding-a-news-entry + we named the news folder changelog + +.. towncrier release notes start + +Pytest 3.3.0 (2017-11-23) +========================= + +Deprecations and Removals +------------------------- + +- Pytest no longer supports Python **2.6** and **3.3**. Those Python versions + are EOL for some time now and incur maintenance and compatibility costs on + the pytest core team, and following up with the rest of the community we + decided that they will no longer be supported starting on this version. Users + which still require those versions should pin pytest to ``<3.3``. (`#2812 + `_) + +- Remove internal ``_preloadplugins()`` function. This removal is part of the + ``pytest_namespace()`` hook deprecation. (`#2636 + `_) + +- Internally change ``CallSpec2`` to have a list of marks instead of a broken + mapping of keywords. This removes the keywords attribute of the internal + ``CallSpec2`` class. (`#2672 + `_) + +- Remove ParameterSet.deprecated_arg_dict - its not a public api and the lack + of the underscore was a naming error. (`#2675 + `_) + +- Remove the internal multi-typed attribute ``Node._evalskip`` and replace it + with the boolean ``Node._skipped_by_mark``. (`#2767 + `_) + +- The ``params`` list passed to ``pytest.fixture`` is now for + all effects considered immutable and frozen at the moment of the ``pytest.fixture`` + call. Previously the list could be changed before the first invocation of the fixture + allowing for a form of dynamic parametrization (for example, updated from command-line options), + but this was an unwanted implementation detail which complicated the internals and prevented + some internal cleanup. See issue `#2959 `_ + for details and a recommended workaround. + +Features +-------- + +- ``pytest_fixture_post_finalizer`` hook can now receive a ``request`` + argument. (`#2124 `_) + +- Replace the old introspection code in compat.py that determines the available + arguments of fixtures with inspect.signature on Python 3 and + funcsigs.signature on Python 2. This should respect ``__signature__`` + declarations on functions. (`#2267 + `_) + +- Report tests with global ``pytestmark`` variable only once. (`#2549 + `_) + +- Now pytest displays the total progress percentage while running tests. The + previous output style can be set by configuring the ``console_output_style`` + setting to ``classic``. (`#2657 `_) + +- Match ``warns`` signature to ``raises`` by adding ``match`` keyword. (`#2708 + `_) + +- Pytest now captures and displays output from the standard `logging` module. + The user can control the logging level to be captured by specifying options + in ``pytest.ini``, the command line and also during individual tests using + markers. Also, a ``caplog`` fixture is available that enables users to test + the captured log during specific tests (similar to ``capsys`` for example). + For more information, please see the `logging docs + `_. This feature was + introduced by merging the popular `pytest-catchlog + `_ plugin, thanks to `Thomas Hisch + `_. Be advised that during the merging the + backward compatibility interface with the defunct ``pytest-capturelog`` has + been dropped. (`#2794 `_) + +- Add ``allow_module_level`` kwarg to ``pytest.skip()``, enabling to skip the + whole module. (`#2808 `_) + +- Allow setting ``file_or_dir``, ``-c``, and ``-o`` in PYTEST_ADDOPTS. (`#2824 + `_) + +- Return stdout/stderr capture results as a ``namedtuple``, so ``out`` and + ``err`` can be accessed by attribute. (`#2879 + `_) + +- Add ``capfdbinary``, a version of ``capfd`` which returns bytes from + ``readouterr()``. (`#2923 + `_) + +- Add ``capsysbinary`` a version of ``capsys`` which returns bytes from + ``readouterr()``. (`#2934 + `_) + +- Implement feature to skip ``setup.py`` files when run with + ``--doctest-modules``. (`#502 + `_) + + +Bug Fixes +--------- + +- Resume output capturing after ``capsys/capfd.disabled()`` context manager. + (`#1993 `_) + +- ``pytest_fixture_setup`` and ``pytest_fixture_post_finalizer`` hooks are now + called for all ``conftest.py`` files. (`#2124 + `_) + +- If an exception happens while loading a plugin, pytest no longer hides the + original traceback. In python2 it will show the original traceback with a new + message that explains in which plugin. In python3 it will show 2 canonized + exceptions, the original exception while loading the plugin in addition to an + exception that PyTest throws about loading a plugin. (`#2491 + `_) + +- ``capsys`` and ``capfd`` can now be used by other fixtures. (`#2709 + `_) + +- Internal ``pytester`` plugin properly encodes ``bytes`` arguments to + ``utf-8``. (`#2738 `_) + +- ``testdir`` now uses use the same method used by ``tmpdir`` to create its + temporary directory. This changes the final structure of the ``testdir`` + directory slightly, but should not affect usage in normal scenarios and + avoids a number of potential problems. (`#2751 + `_) + +- Pytest no longer complains about warnings with unicode messages being + non-ascii compatible even for ascii-compatible messages. As a result of this, + warnings with unicode messages are converted first to an ascii representation + for safety. (`#2809 `_) + +- Change return value of pytest command when ``--maxfail`` is reached from + ``2`` (interrupted) to ``1`` (failed). (`#2845 + `_) + +- Fix issue in assertion rewriting which could lead it to rewrite modules which + should not be rewritten. (`#2939 + `_) + +- Handle marks without description in ``pytest.ini``. (`#2942 + `_) + + +Trivial/Internal Changes +------------------------ + +- pytest now depends on `attrs `_ for internal + structures to ease code maintainability. (`#2641 + `_) + +- Refactored internal Python 2/3 compatibility code to use ``six``. (`#2642 + `_) + +- Stop vendoring ``pluggy`` - we're missing out on its latest changes for not + much benefit (`#2719 `_) + +- Internal refactor: simplify ascii string escaping by using the + backslashreplace error handler in newer Python 3 versions. (`#2734 + `_) + +- Remove unnecessary mark evaluator in unittest plugin (`#2767 + `_) + +- Calls to ``Metafunc.addcall`` now emit a deprecation warning. This function + is scheduled to be removed in ``pytest-4.0``. (`#2876 + `_) + +- Internal move of the parameterset extraction to a more maintainable place. + (`#2877 `_) + +- Internal refactoring to simplify scope node lookup. (`#2910 + `_) + +- Configure ``pytest`` to prevent pip from installing pytest in unsupported + Python versions. (`#2922 + `_) + + +Pytest 3.2.5 (2017-11-15) +========================= + +Bug Fixes +--------- + +- Remove ``py<1.5`` restriction from ``pytest`` as this can cause version + conflicts in some installations. (`#2926 + `_) + + +Pytest 3.2.4 (2017-11-13) +========================= + +Bug Fixes +--------- + +- Fix the bug where running with ``--pyargs`` will result in items with + empty ``parent.nodeid`` if run from a different root directory. (`#2775 + `_) + +- Fix issue with ``@pytest.parametrize`` if argnames was specified as keyword arguments. + (`#2819 `_) + +- Strip whitespace from marker names when reading them from INI config. (`#2856 + `_) + +- Show full context of doctest source in the pytest output, if the line number of + failed example in the docstring is < 9. (`#2882 + `_) + +- Match fixture paths against actual path segments in order to avoid matching folders which share a prefix. + (`#2836 `_) + +Improved Documentation +---------------------- + +- Introduce a dedicated section about conftest.py. (`#1505 + `_) + +- Explicitly mention ``xpass`` in the documentation of ``xfail``. (`#1997 + `_) + +- Append example for pytest.param in the example/parametrize document. (`#2658 + `_) + +- Clarify language of proposal for fixtures parameters (`#2893 + `_) + +- List python 3.6 in the documented supported versions in the getting started + document. (`#2903 `_) + +- Clarify the documentation of available fixture scopes. (`#538 + `_) + +- Add documentation about the ``python -m pytest`` invocation adding the + current directory to sys.path. (`#911 + `_) + + +Pytest 3.2.3 (2017-10-03) +========================= + +Bug Fixes +--------- + +- Fix crash in tab completion when no prefix is given. (`#2748 + `_) + +- The equality checking function (``__eq__``) of ``MarkDecorator`` returns + ``False`` if one object is not an instance of ``MarkDecorator``. (`#2758 + `_) + +- When running ``pytest --fixtures-per-test``: don't crash if an item has no + _fixtureinfo attribute (e.g. doctests) (`#2788 + `_) + + +Improved Documentation +---------------------- + +- In help text of ``-k`` option, add example of using ``not`` to not select + certain tests whose names match the provided expression. (`#1442 + `_) + +- Add note in ``parametrize.rst`` about calling ``metafunc.parametrize`` + multiple times. (`#1548 `_) + + +Trivial/Internal Changes +------------------------ + +- Set ``xfail_strict=True`` in pytest's own test suite to catch expected + failures as soon as they start to pass. (`#2722 + `_) + +- Fix typo in example of passing a callable to markers (in example/markers.rst) + (`#2765 `_) + + +Pytest 3.2.2 (2017-09-06) +========================= + +Bug Fixes +--------- + +- Calling the deprecated `request.getfuncargvalue()` now shows the source of + the call. (`#2681 `_) + +- Allow tests declared as ``@staticmethod`` to use fixtures. (`#2699 + `_) + +- Fixed edge-case during collection: attributes which raised ``pytest.fail`` + when accessed would abort the entire collection. (`#2707 + `_) + +- Fix ``ReprFuncArgs`` with mixed unicode and UTF-8 args. (`#2731 + `_) + + +Improved Documentation +---------------------- + +- In examples on working with custom markers, add examples demonstrating the + usage of ``pytest.mark.MARKER_NAME.with_args`` in comparison with + ``pytest.mark.MARKER_NAME.__call__`` (`#2604 + `_) + +- In one of the simple examples, use `pytest_collection_modifyitems()` to skip + tests based on a command-line option, allowing its sharing while preventing a + user error when acessing `pytest.config` before the argument parsing. (`#2653 + `_) + + +Trivial/Internal Changes +------------------------ + +- Fixed minor error in 'Good Practices/Manual Integration' code snippet. + (`#2691 `_) + +- Fixed typo in goodpractices.rst. (`#2721 + `_) + +- Improve user guidance regarding ``--resultlog`` deprecation. (`#2739 + `_) + + +Pytest 3.2.1 (2017-08-08) +========================= + +Bug Fixes +--------- + +- Fixed small terminal glitch when collecting a single test item. (`#2579 + `_) + +- Correctly consider ``/`` as the file separator to automatically mark plugin + files for rewrite on Windows. (`#2591 `_) + +- Properly escape test names when setting ``PYTEST_CURRENT_TEST`` environment + variable. (`#2644 `_) + +- Fix error on Windows and Python 3.6+ when ``sys.stdout`` has been replaced + with a stream-like object which does not implement the full ``io`` module + buffer protocol. In particular this affects ``pytest-xdist`` users on the + aforementioned platform. (`#2666 `_) + + +Improved Documentation +---------------------- + +- Explicitly document which pytest features work with ``unittest``. (`#2626 + `_) + + +Pytest 3.2.0 (2017-07-30) +========================= + +Deprecations and Removals +------------------------- + +- ``pytest.approx`` no longer supports ``>``, ``>=``, ``<`` and ``<=`` + operators to avoid surprising/inconsistent behavior. See `the approx docs + `_ for more + information. (`#2003 `_) + +- All old-style specific behavior in current classes in the pytest's API is + considered deprecated at this point and will be removed in a future release. + This affects Python 2 users only and in rare situations. (`#2147 + `_) + +- A deprecation warning is now raised when using marks for parameters + in ``pytest.mark.parametrize``. Use ``pytest.param`` to apply marks to + parameters instead. (`#2427 `_) + + +Features +-------- + +- Add support for numpy arrays (and dicts) to approx. (`#1994 + `_) + +- Now test function objects have a ``pytestmark`` attribute containing a list + of marks applied directly to the test function, as opposed to marks inherited + from parent classes or modules. (`#2516 `_) + +- Collection ignores local virtualenvs by default; `--collect-in-virtualenv` + overrides this behavior. (`#2518 `_) + +- Allow class methods decorated as ``@staticmethod`` to be candidates for + collection as a test function. (Only for Python 2.7 and above. Python 2.6 + will still ignore static methods.) (`#2528 `_) + +- Introduce ``mark.with_args`` in order to allow passing functions/classes as + sole argument to marks. (`#2540 `_) + +- New ``cache_dir`` ini option: sets the directory where the contents of the + cache plugin are stored. Directory may be relative or absolute path: if relative path, then + directory is created relative to ``rootdir``, otherwise it is used as is. + Additionally path may contain environment variables which are expanded during + runtime. (`#2543 `_) + +- Introduce the ``PYTEST_CURRENT_TEST`` environment variable that is set with + the ``nodeid`` and stage (``setup``, ``call`` and ``teardown``) of the test + being currently executed. See the `documentation + `_ for more info. (`#2583 `_) + +- Introduced ``@pytest.mark.filterwarnings`` mark which allows overwriting the + warnings filter on a per test, class or module level. See the `docs + `_ for more information. (`#2598 `_) + +- ``--last-failed`` now remembers forever when a test has failed and only + forgets it if it passes again. This makes it easy to fix a test suite by + selectively running files and fixing tests incrementally. (`#2621 + `_) + +- New ``pytest_report_collectionfinish`` hook which allows plugins to add + messages to the terminal reporting after collection has been finished + successfully. (`#2622 `_) + +- Added support for `PEP-415's `_ + ``Exception.__suppress_context__``. Now if a ``raise exception from None`` is + caught by pytest, pytest will no longer chain the context in the test report. + The behavior now matches Python's traceback behavior. (`#2631 + `_) + +- Exceptions raised by ``pytest.fail``, ``pytest.skip`` and ``pytest.xfail`` + now subclass BaseException, making them harder to be caught unintentionally + by normal code. (`#580 `_) + + +Bug Fixes +--------- + +- Set ``stdin`` to a closed ``PIPE`` in ``pytester.py.Testdir.popen()`` for + avoid unwanted interactive ``pdb`` (`#2023 `_) + +- Add missing ``encoding`` attribute to ``sys.std*`` streams when using + ``capsys`` capture mode. (`#2375 `_) + +- Fix terminal color changing to black on Windows if ``colorama`` is imported + in a ``conftest.py`` file. (`#2510 `_) + +- Fix line number when reporting summary of skipped tests. (`#2548 + `_) + +- capture: ensure that EncodedFile.name is a string. (`#2555 + `_) + +- The options ``--fixtures`` and ``--fixtures-per-test`` will now keep + indentation within docstrings. (`#2574 `_) + +- doctests line numbers are now reported correctly, fixing `pytest-sugar#122 + `_. (`#2610 + `_) + +- Fix non-determinism in order of fixture collection. Adds new dependency + (ordereddict) for Python 2.6. (`#920 `_) + + +Improved Documentation +---------------------- + +- Clarify ``pytest_configure`` hook call order. (`#2539 + `_) + +- Extend documentation for testing plugin code with the ``pytester`` plugin. + (`#971 `_) + + +Trivial/Internal Changes +------------------------ + +- Update help message for ``--strict`` to make it clear it only deals with + unregistered markers, not warnings. (`#2444 `_) + +- Internal code move: move code for pytest.approx/pytest.raises to own files in + order to cut down the size of python.py (`#2489 `_) + +- Renamed the utility function ``_pytest.compat._escape_strings`` to + ``_ascii_escaped`` to better communicate the function's purpose. (`#2533 + `_) + +- Improve error message for CollectError with skip/skipif. (`#2546 + `_) + +- Emit warning about ``yield`` tests being deprecated only once per generator. + (`#2562 `_) + +- Ensure final collected line doesn't include artifacts of previous write. + (`#2571 `_) + +- Fixed all flake8 errors and warnings. (`#2581 `_) + +- Added ``fix-lint`` tox environment to run automatic pep8 fixes on the code. + (`#2582 `_) + +- Turn warnings into errors in pytest's own test suite in order to catch + regressions due to deprecations more promptly. (`#2588 + `_) + +- Show multiple issue links in CHANGELOG entries. (`#2620 + `_) + + +Pytest 3.1.3 (2017-07-03) +========================= + +Bug Fixes +--------- + +- Fix decode error in Python 2 for doctests in docstrings. (`#2434 + `_) + +- Exceptions raised during teardown by finalizers are now suppressed until all + finalizers are called, with the initial exception reraised. (`#2440 + `_) + +- Fix incorrect "collected items" report when specifying tests on the command- + line. (`#2464 `_) + +- ``deprecated_call`` in context-manager form now captures deprecation warnings + even if the same warning has already been raised. Also, ``deprecated_call`` + will always produce the same error message (previously it would produce + different messages in context-manager vs. function-call mode). (`#2469 + `_) + +- Fix issue where paths collected by pytest could have triple leading ``/`` + characters. (`#2475 `_) + +- Fix internal error when trying to detect the start of a recursive traceback. + (`#2486 `_) + + +Improved Documentation +---------------------- + +- Explicitly state for which hooks the calls stop after the first non-None + result. (`#2493 `_) + + +Trivial/Internal Changes +------------------------ + +- Create invoke tasks for updating the vendored packages. (`#2474 + `_) + +- Update copyright dates in LICENSE, README.rst and in the documentation. + (`#2499 `_) + + +Pytest 3.1.2 (2017-06-08) +========================= + +Bug Fixes +--------- + +- Required options added via ``pytest_addoption`` will no longer prevent using + --help without passing them. (#1999) + +- Respect ``python_files`` in assertion rewriting. (#2121) + +- Fix recursion error detection when frames in the traceback contain objects + that can't be compared (like ``numpy`` arrays). (#2459) + +- ``UnicodeWarning`` is issued from the internal pytest warnings plugin only + when the message contains non-ascii unicode (Python 2 only). (#2463) + +- Added a workaround for Python 3.6 ``WindowsConsoleIO`` breaking due to Pytests's + ``FDCapture``. Other code using console handles might still be affected by the + very same issue and might require further workarounds/fixes, i.e. ``colorama``. + (#2467) + + +Improved Documentation +---------------------- + +- Fix internal API links to ``pluggy`` objects. (#2331) + +- Make it clear that ``pytest.xfail`` stops test execution at the calling point + and improve overall flow of the ``skipping`` docs. (#810) + + +Pytest 3.1.1 (2017-05-30) +========================= + +Bug Fixes +--------- + +- pytest warning capture no longer overrides existing warning filters. The + previous behaviour would override all filters and caused regressions in test + suites which configure warning filters to match their needs. Note that as a + side-effect of this is that ``DeprecationWarning`` and + ``PendingDeprecationWarning`` are no longer shown by default. (#2430) + +- Fix issue with non-ascii contents in doctest text files. (#2434) + +- Fix encoding errors for unicode warnings in Python 2. (#2436) + +- ``pytest.deprecated_call`` now captures ``PendingDeprecationWarning`` in + context manager form. (#2441) + + +Improved Documentation +---------------------- + +- Addition of towncrier for changelog management. (#2390) + + +3.1.0 (2017-05-22) +================== + + +New Features +------------ + +* The ``pytest-warnings`` plugin has been integrated into the core and now ``pytest`` automatically + captures and displays warnings at the end of the test session. + + .. warning:: + + This feature may disrupt test suites which apply and treat warnings themselves, and can be + disabled in your ``pytest.ini``: + + .. code-block:: ini + + [pytest] + addopts = -p no:warnings + + See the `warnings documentation page `_ for more + information. + + Thanks `@nicoddemus`_ for the PR. + +* Added ``junit_suite_name`` ini option to specify root ```` name for JUnit XML reports (`#533`_). + +* Added an ini option ``doctest_encoding`` to specify which encoding to use for doctest files. + Thanks `@wheerd`_ for the PR (`#2101`_). + +* ``pytest.warns`` now checks for subclass relationship rather than + class equality. Thanks `@lesteve`_ for the PR (`#2166`_) + +* ``pytest.raises`` now asserts that the error message matches a text or regex + with the ``match`` keyword argument. Thanks `@Kriechi`_ for the PR. + +* ``pytest.param`` can be used to declare test parameter sets with marks and test ids. + Thanks `@RonnyPfannschmidt`_ for the PR. + + +Changes +------- + +* remove all internal uses of pytest_namespace hooks, + this is to prepare the removal of preloadconfig in pytest 4.0 + Thanks to `@RonnyPfannschmidt`_ for the PR. + +* pytest now warns when a callable ids raises in a parametrized test. Thanks `@fogo`_ for the PR. + +* It is now possible to skip test classes from being collected by setting a + ``__test__`` attribute to ``False`` in the class body (`#2007`_). Thanks + to `@syre`_ for the report and `@lwm`_ for the PR. + +* Change junitxml.py to produce reports that comply with Junitxml schema. + If the same test fails with failure in call and then errors in teardown + we split testcase element into two, one containing the error and the other + the failure. (`#2228`_) Thanks to `@kkoukiou`_ for the PR. + +* Testcase reports with a ``url`` attribute will now properly write this to junitxml. + Thanks `@fushi`_ for the PR (`#1874`_). + +* Remove common items from dict comparision output when verbosity=1. Also update + the truncation message to make it clearer that pytest truncates all + assertion messages if verbosity < 2 (`#1512`_). + Thanks `@mattduck`_ for the PR + +* ``--pdbcls`` no longer implies ``--pdb``. This makes it possible to use + ``addopts=--pdbcls=module.SomeClass`` on ``pytest.ini``. Thanks `@davidszotten`_ for + the PR (`#1952`_). + +* fix `#2013`_: turn RecordedWarning into ``namedtuple``, + to give it a comprehensible repr while preventing unwarranted modification. + +* fix `#2208`_: ensure a iteration limit for _pytest.compat.get_real_func. + Thanks `@RonnyPfannschmidt`_ for the report and PR. + +* Hooks are now verified after collection is complete, rather than right after loading installed plugins. This + makes it easy to write hooks for plugins which will be loaded during collection, for example using the + ``pytest_plugins`` special variable (`#1821`_). + Thanks `@nicoddemus`_ for the PR. + +* Modify ``pytest_make_parametrize_id()`` hook to accept ``argname`` as an + additional parameter. + Thanks `@unsignedint`_ for the PR. + +* Add ``venv`` to the default ``norecursedirs`` setting. + Thanks `@The-Compiler`_ for the PR. + +* ``PluginManager.import_plugin`` now accepts unicode plugin names in Python 2. + Thanks `@reutsharabani`_ for the PR. + +* fix `#2308`_: When using both ``--lf`` and ``--ff``, only the last failed tests are run. + Thanks `@ojii`_ for the PR. + +* Replace minor/patch level version numbers in the documentation with placeholders. + This significantly reduces change-noise as different contributors regnerate + the documentation on different platforms. + Thanks `@RonnyPfannschmidt`_ for the PR. + +* fix `#2391`_: consider pytest_plugins on all plugin modules + Thanks `@RonnyPfannschmidt`_ for the PR. + + +Bug Fixes +--------- + +* Fix ``AttributeError`` on ``sys.stdout.buffer`` / ``sys.stderr.buffer`` + while using ``capsys`` fixture in python 3. (`#1407`_). + Thanks to `@asottile`_. + +* Change capture.py's ``DontReadFromInput`` class to throw ``io.UnsupportedOperation`` errors rather + than ValueErrors in the ``fileno`` method (`#2276`_). + Thanks `@metasyn`_ and `@vlad-dragos`_ for the PR. + +* Fix exception formatting while importing modules when the exception message + contains non-ascii characters (`#2336`_). + Thanks `@fabioz`_ for the report and `@nicoddemus`_ for the PR. + +* Added documentation related to issue (`#1937`_) + Thanks `@skylarjhdownes`_ for the PR. + +* Allow collecting files with any file extension as Python modules (`#2369`_). + Thanks `@Kodiologist`_ for the PR. + +* Show the correct error message when collect "parametrize" func with wrong args (`#2383`_). + Thanks `@The-Compiler`_ for the report and `@robin0371`_ for the PR. + + +.. _@davidszotten: https://github.com/davidszotten +.. _@fabioz: https://github.com/fabioz +.. _@fogo: https://github.com/fogo +.. _@fushi: https://github.com/fushi +.. _@Kodiologist: https://github.com/Kodiologist +.. _@Kriechi: https://github.com/Kriechi +.. _@mandeep: https://github.com/mandeep +.. _@mattduck: https://github.com/mattduck +.. _@metasyn: https://github.com/metasyn +.. _@MichalTHEDUDE: https://github.com/MichalTHEDUDE +.. _@ojii: https://github.com/ojii +.. _@reutsharabani: https://github.com/reutsharabani +.. _@robin0371: https://github.com/robin0371 +.. _@skylarjhdownes: https://github.com/skylarjhdownes +.. _@unsignedint: https://github.com/unsignedint +.. _@wheerd: https://github.com/wheerd + + +.. _#1407: https://github.com/pytest-dev/pytest/issues/1407 +.. _#1512: https://github.com/pytest-dev/pytest/issues/1512 +.. _#1821: https://github.com/pytest-dev/pytest/issues/1821 +.. _#1874: https://github.com/pytest-dev/pytest/pull/1874 +.. _#1937: https://github.com/pytest-dev/pytest/issues/1937 +.. _#1952: https://github.com/pytest-dev/pytest/pull/1952 +.. _#2007: https://github.com/pytest-dev/pytest/issues/2007 +.. _#2013: https://github.com/pytest-dev/pytest/issues/2013 +.. _#2101: https://github.com/pytest-dev/pytest/pull/2101 +.. _#2166: https://github.com/pytest-dev/pytest/pull/2166 +.. _#2208: https://github.com/pytest-dev/pytest/issues/2208 +.. _#2228: https://github.com/pytest-dev/pytest/issues/2228 +.. _#2276: https://github.com/pytest-dev/pytest/issues/2276 +.. _#2308: https://github.com/pytest-dev/pytest/issues/2308 +.. _#2336: https://github.com/pytest-dev/pytest/issues/2336 +.. _#2369: https://github.com/pytest-dev/pytest/issues/2369 +.. _#2383: https://github.com/pytest-dev/pytest/issues/2383 +.. _#2391: https://github.com/pytest-dev/pytest/issues/2391 +.. _#533: https://github.com/pytest-dev/pytest/issues/533 + + + +3.0.7 (2017-03-14) +================== + + +* Fix issue in assertion rewriting breaking due to modules silently discarding + other modules when importing fails + Notably, importing the ``anydbm`` module is fixed. (`#2248`_). + Thanks `@pfhayes`_ for the PR. + +* junitxml: Fix problematic case where system-out tag occured twice per testcase + element in the XML report. Thanks `@kkoukiou`_ for the PR. + +* Fix regression, pytest now skips unittest correctly if run with ``--pdb`` + (`#2137`_). Thanks to `@gst`_ for the report and `@mbyt`_ for the PR. + +* Ignore exceptions raised from descriptors (e.g. properties) during Python test collection (`#2234`_). + Thanks to `@bluetech`_. + +* ``--override-ini`` now correctly overrides some fundamental options like ``python_files`` (`#2238`_). + Thanks `@sirex`_ for the report and `@nicoddemus`_ for the PR. + +* Replace ``raise StopIteration`` usages in the code by simple ``returns`` to finish generators, in accordance to `PEP-479`_ (`#2160`_). + Thanks `@tgoodlet`_ for the report and `@nicoddemus`_ for the PR. + +* Fix internal errors when an unprintable ``AssertionError`` is raised inside a test. + Thanks `@omerhadari`_ for the PR. + +* Skipping plugin now also works with test items generated by custom collectors (`#2231`_). + Thanks to `@vidartf`_. + +* Fix trailing whitespace in console output if no .ini file presented (`#2281`_). Thanks `@fbjorn`_ for the PR. + +* Conditionless ``xfail`` markers no longer rely on the underlying test item + being an instance of ``PyobjMixin``, and can therefore apply to tests not + collected by the built-in python test collector. Thanks `@barneygale`_ for the + PR. + + +.. _@pfhayes: https://github.com/pfhayes +.. _@bluetech: https://github.com/bluetech +.. _@gst: https://github.com/gst +.. _@sirex: https://github.com/sirex +.. _@vidartf: https://github.com/vidartf +.. _@kkoukiou: https://github.com/KKoukiou +.. _@omerhadari: https://github.com/omerhadari +.. _@fbjorn: https://github.com/fbjorn + +.. _#2248: https://github.com/pytest-dev/pytest/issues/2248 +.. _#2137: https://github.com/pytest-dev/pytest/issues/2137 +.. _#2160: https://github.com/pytest-dev/pytest/issues/2160 +.. _#2231: https://github.com/pytest-dev/pytest/issues/2231 +.. _#2234: https://github.com/pytest-dev/pytest/issues/2234 +.. _#2238: https://github.com/pytest-dev/pytest/issues/2238 +.. _#2281: https://github.com/pytest-dev/pytest/issues/2281 + +.. _PEP-479: https://www.python.org/dev/peps/pep-0479/ + + +3.0.6 (2017-01-22) +================== + +* pytest no longer generates ``PendingDeprecationWarning`` from its own operations, which was introduced by mistake in version ``3.0.5`` (`#2118`_). + Thanks to `@nicoddemus`_ for the report and `@RonnyPfannschmidt`_ for the PR. + + +* pytest no longer recognizes coroutine functions as yield tests (`#2129`_). + Thanks to `@malinoff`_ for the PR. + +* Plugins loaded by the ``PYTEST_PLUGINS`` environment variable are now automatically + considered for assertion rewriting (`#2185`_). + Thanks `@nicoddemus`_ for the PR. + +* Improve error message when pytest.warns fails (`#2150`_). The type(s) of the + expected warnings and the list of caught warnings is added to the + error message. Thanks `@lesteve`_ for the PR. + +* Fix ``pytester`` internal plugin to work correctly with latest versions of + ``zope.interface`` (`#1989`_). Thanks `@nicoddemus`_ for the PR. + +* Assert statements of the ``pytester`` plugin again benefit from assertion rewriting (`#1920`_). + Thanks `@RonnyPfannschmidt`_ for the report and `@nicoddemus`_ for the PR. + +* Specifying tests with colons like ``test_foo.py::test_bar`` for tests in + subdirectories with ini configuration files now uses the correct ini file + (`#2148`_). Thanks `@pelme`_. + +* Fail ``testdir.runpytest().assert_outcomes()`` explicitly if the pytest + terminal output it relies on is missing. Thanks to `@eli-b`_ for the PR. + + +.. _@barneygale: https://github.com/barneygale +.. _@lesteve: https://github.com/lesteve +.. _@malinoff: https://github.com/malinoff +.. _@pelme: https://github.com/pelme +.. _@eli-b: https://github.com/eli-b + +.. _#2118: https://github.com/pytest-dev/pytest/issues/2118 + +.. _#1989: https://github.com/pytest-dev/pytest/issues/1989 +.. _#1920: https://github.com/pytest-dev/pytest/issues/1920 +.. _#2129: https://github.com/pytest-dev/pytest/issues/2129 +.. _#2148: https://github.com/pytest-dev/pytest/issues/2148 +.. _#2150: https://github.com/pytest-dev/pytest/issues/2150 +.. _#2185: https://github.com/pytest-dev/pytest/issues/2185 + + +3.0.5 (2016-12-05) +================== + +* Add warning when not passing ``option=value`` correctly to ``-o/--override-ini`` (`#2105`_). + Also improved the help documentation. Thanks to `@mbukatov`_ for the report and + `@lwm`_ for the PR. + +* Now ``--confcutdir`` and ``--junit-xml`` are properly validated if they are directories + and filenames, respectively (`#2089`_ and `#2078`_). Thanks to `@lwm`_ for the PR. + +* Add hint to error message hinting possible missing ``__init__.py`` (`#478`_). Thanks `@DuncanBetts`_. + +* More accurately describe when fixture finalization occurs in documentation (`#687`_). Thanks `@DuncanBetts`_. + +* Provide ``:ref:`` targets for ``recwarn.rst`` so we can use intersphinx referencing. + Thanks to `@dupuy`_ for the report and `@lwm`_ for the PR. + +* In Python 2, use a simple ``+-`` ASCII string in the string representation of ``pytest.approx`` (for example ``"4 +- 4.0e-06"``) + because it is brittle to handle that in different contexts and representations internally in pytest + which can result in bugs such as `#2111`_. In Python 3, the representation still uses ``±`` (for example ``4 ± 4.0e-06``). + Thanks `@kerrick-lyft`_ for the report and `@nicoddemus`_ for the PR. + +* Using ``item.Function``, ``item.Module``, etc., is now issuing deprecation warnings, prefer + ``pytest.Function``, ``pytest.Module``, etc., instead (`#2034`_). + Thanks `@nmundar`_ for the PR. + +* Fix error message using ``approx`` with complex numbers (`#2082`_). + Thanks `@adler-j`_ for the report and `@nicoddemus`_ for the PR. + +* Fixed false-positives warnings from assertion rewrite hook for modules imported more than + once by the ``pytest_plugins`` mechanism. + Thanks `@nicoddemus`_ for the PR. + +* Remove an internal cache which could cause hooks from ``conftest.py`` files in + sub-directories to be called in other directories incorrectly (`#2016`_). + Thanks `@d-b-w`_ for the report and `@nicoddemus`_ for the PR. + +* Remove internal code meant to support earlier Python 3 versions that produced the side effect + of leaving ``None`` in ``sys.modules`` when expressions were evaluated by pytest (for example passing a condition + as a string to ``pytest.mark.skipif``)(`#2103`_). + Thanks `@jaraco`_ for the report and `@nicoddemus`_ for the PR. + +* Cope gracefully with a .pyc file with no matching .py file (`#2038`_). Thanks + `@nedbat`_. + +.. _@syre: https://github.com/syre +.. _@adler-j: https://github.com/adler-j +.. _@d-b-w: https://bitbucket.org/d-b-w/ +.. _@DuncanBetts: https://github.com/DuncanBetts +.. _@dupuy: https://bitbucket.org/dupuy/ +.. _@kerrick-lyft: https://github.com/kerrick-lyft +.. _@lwm: https://github.com/lwm +.. _@mbukatov: https://github.com/mbukatov +.. _@nedbat: https://github.com/nedbat +.. _@nmundar: https://github.com/nmundar + +.. _#2016: https://github.com/pytest-dev/pytest/issues/2016 +.. _#2034: https://github.com/pytest-dev/pytest/issues/2034 +.. _#2038: https://github.com/pytest-dev/pytest/issues/2038 +.. _#2078: https://github.com/pytest-dev/pytest/issues/2078 +.. _#2082: https://github.com/pytest-dev/pytest/issues/2082 +.. _#2089: https://github.com/pytest-dev/pytest/issues/2089 +.. _#2103: https://github.com/pytest-dev/pytest/issues/2103 +.. _#2105: https://github.com/pytest-dev/pytest/issues/2105 +.. _#2111: https://github.com/pytest-dev/pytest/issues/2111 +.. _#478: https://github.com/pytest-dev/pytest/issues/478 +.. _#687: https://github.com/pytest-dev/pytest/issues/687 + + +3.0.4 (2016-11-09) +================== + +* Import errors when collecting test modules now display the full traceback (`#1976`_). + Thanks `@cwitty`_ for the report and `@nicoddemus`_ for the PR. + +* Fix confusing command-line help message for custom options with two or more ``metavar`` properties (`#2004`_). + Thanks `@okulynyak`_ and `@davehunt`_ for the report and `@nicoddemus`_ for the PR. + +* When loading plugins, import errors which contain non-ascii messages are now properly handled in Python 2 (`#1998`_). + Thanks `@nicoddemus`_ for the PR. + +* Fixed cyclic reference when ``pytest.raises`` is used in context-manager form (`#1965`_). Also as a + result of this fix, ``sys.exc_info()`` is left empty in both context-manager and function call usages. + Previously, ``sys.exc_info`` would contain the exception caught by the context manager, + even when the expected exception occurred. + Thanks `@MSeifert04`_ for the report and the PR. + +* Fixed false-positives warnings from assertion rewrite hook for modules that were rewritten but + were later marked explicitly by ``pytest.register_assert_rewrite`` + or implicitly as a plugin (`#2005`_). + Thanks `@RonnyPfannschmidt`_ for the report and `@nicoddemus`_ for the PR. + +* Report teardown output on test failure (`#442`_). + Thanks `@matclab`_ for the PR. + +* Fix teardown error message in generated xUnit XML. + Thanks `@gdyuldin`_ for the PR. + +* Properly handle exceptions in ``multiprocessing`` tasks (`#1984`_). + Thanks `@adborden`_ for the report and `@nicoddemus`_ for the PR. + +* Clean up unittest TestCase objects after tests are complete (`#1649`_). + Thanks `@d_b_w`_ for the report and PR. + + +.. _@adborden: https://github.com/adborden +.. _@cwitty: https://github.com/cwitty +.. _@d_b_w: https://github.com/d_b_w +.. _@gdyuldin: https://github.com/gdyuldin +.. _@matclab: https://github.com/matclab +.. _@MSeifert04: https://github.com/MSeifert04 +.. _@okulynyak: https://github.com/okulynyak + +.. _#442: https://github.com/pytest-dev/pytest/issues/442 +.. _#1965: https://github.com/pytest-dev/pytest/issues/1965 +.. _#1976: https://github.com/pytest-dev/pytest/issues/1976 +.. _#1984: https://github.com/pytest-dev/pytest/issues/1984 +.. _#1998: https://github.com/pytest-dev/pytest/issues/1998 +.. _#2004: https://github.com/pytest-dev/pytest/issues/2004 +.. _#2005: https://github.com/pytest-dev/pytest/issues/2005 +.. _#1649: https://github.com/pytest-dev/pytest/issues/1649 + + +3.0.3 (2016-09-28) +================== + +* The ``ids`` argument to ``parametrize`` again accepts ``unicode`` strings + in Python 2 (`#1905`_). + Thanks `@philpep`_ for the report and `@nicoddemus`_ for the PR. + +* Assertions are now being rewritten for plugins in development mode + (``pip install -e``) (`#1934`_). + Thanks `@nicoddemus`_ for the PR. + +* Fix pkg_resources import error in Jython projects (`#1853`_). + Thanks `@raquel-ucl`_ for the PR. + +* Got rid of ``AttributeError: 'Module' object has no attribute '_obj'`` exception + in Python 3 (`#1944`_). + Thanks `@axil`_ for the PR. + +* Explain a bad scope value passed to ``@fixture`` declarations or + a ``MetaFunc.parametrize()`` call. Thanks `@tgoodlet`_ for the PR. + +* This version includes ``pluggy-0.4.0``, which correctly handles + ``VersionConflict`` errors in plugins (`#704`_). + Thanks `@nicoddemus`_ for the PR. + + +.. _@philpep: https://github.com/philpep +.. _@raquel-ucl: https://github.com/raquel-ucl +.. _@axil: https://github.com/axil +.. _@tgoodlet: https://github.com/tgoodlet +.. _@vlad-dragos: https://github.com/vlad-dragos + +.. _#1853: https://github.com/pytest-dev/pytest/issues/1853 +.. _#1905: https://github.com/pytest-dev/pytest/issues/1905 +.. _#1934: https://github.com/pytest-dev/pytest/issues/1934 +.. _#1944: https://github.com/pytest-dev/pytest/issues/1944 +.. _#704: https://github.com/pytest-dev/pytest/issues/704 + + + + +3.0.2 (2016-09-01) +================== + +* Improve error message when passing non-string ids to ``pytest.mark.parametrize`` (`#1857`_). + Thanks `@okken`_ for the report and `@nicoddemus`_ for the PR. + +* Add ``buffer`` attribute to stdin stub class ``pytest.capture.DontReadFromInput`` + Thanks `@joguSD`_ for the PR. + +* Fix ``UnicodeEncodeError`` when string comparison with unicode has failed. (`#1864`_) + Thanks `@AiOO`_ for the PR. + +* ``pytest_plugins`` is now handled correctly if defined as a string (as opposed as + a sequence of strings) when modules are considered for assertion rewriting. + Due to this bug, much more modules were being rewritten than necessary + if a test suite uses ``pytest_plugins`` to load internal plugins (`#1888`_). + Thanks `@jaraco`_ for the report and `@nicoddemus`_ for the PR (`#1891`_). + +* Do not call tearDown and cleanups when running tests from + ``unittest.TestCase`` subclasses with ``--pdb`` + enabled. This allows proper post mortem debugging for all applications + which have significant logic in their tearDown machinery (`#1890`_). Thanks + `@mbyt`_ for the PR. + +* Fix use of deprecated ``getfuncargvalue`` method in the internal doctest plugin. + Thanks `@ViviCoder`_ for the report (`#1898`_). + +.. _@joguSD: https://github.com/joguSD +.. _@AiOO: https://github.com/AiOO +.. _@mbyt: https://github.com/mbyt +.. _@ViviCoder: https://github.com/ViviCoder + +.. _#1857: https://github.com/pytest-dev/pytest/issues/1857 +.. _#1864: https://github.com/pytest-dev/pytest/issues/1864 +.. _#1888: https://github.com/pytest-dev/pytest/issues/1888 +.. _#1891: https://github.com/pytest-dev/pytest/pull/1891 +.. _#1890: https://github.com/pytest-dev/pytest/issues/1890 +.. _#1898: https://github.com/pytest-dev/pytest/issues/1898 + + +3.0.1 (2016-08-23) +================== + +* Fix regression when ``importorskip`` is used at module level (`#1822`_). + Thanks `@jaraco`_ and `@The-Compiler`_ for the report and `@nicoddemus`_ for the PR. + +* Fix parametrization scope when session fixtures are used in conjunction + with normal parameters in the same call (`#1832`_). + Thanks `@The-Compiler`_ for the report, `@Kingdread`_ and `@nicoddemus`_ for the PR. + +* Fix internal error when parametrizing tests or fixtures using an empty ``ids`` argument (`#1849`_). + Thanks `@OPpuolitaival`_ for the report and `@nicoddemus`_ for the PR. + +* Fix loader error when running ``pytest`` embedded in a zipfile. + Thanks `@mbachry`_ for the PR. + + +.. _@Kingdread: https://github.com/Kingdread +.. _@mbachry: https://github.com/mbachry +.. _@OPpuolitaival: https://github.com/OPpuolitaival + +.. _#1822: https://github.com/pytest-dev/pytest/issues/1822 +.. _#1832: https://github.com/pytest-dev/pytest/issues/1832 +.. _#1849: https://github.com/pytest-dev/pytest/issues/1849 + + +3.0.0 (2016-08-18) +================== + +**Incompatible changes** + + +A number of incompatible changes were made in this release, with the intent of removing features deprecated for a long +time or change existing behaviors in order to make them less surprising/more useful. + +* Reinterpretation mode has now been removed. Only plain and rewrite + mode are available, consequently the ``--assert=reinterp`` option is + no longer available. This also means files imported from plugins or + ``conftest.py`` will not benefit from improved assertions by + default, you should use ``pytest.register_assert_rewrite()`` to + explicitly turn on assertion rewriting for those files. Thanks + `@flub`_ for the PR. + +* The following deprecated commandline options were removed: + + * ``--genscript``: no longer supported; + * ``--no-assert``: use ``--assert=plain`` instead; + * ``--nomagic``: use ``--assert=plain`` instead; + * ``--report``: use ``-r`` instead; + + Thanks to `@RedBeardCode`_ for the PR (`#1664`_). + +* ImportErrors in plugins now are a fatal error instead of issuing a + pytest warning (`#1479`_). Thanks to `@The-Compiler`_ for the PR. + +* Removed support code for Python 3 versions < 3.3 (`#1627`_). + +* Removed all ``py.test-X*`` entry points. The versioned, suffixed entry points + were never documented and a leftover from a pre-virtualenv era. These entry + points also created broken entry points in wheels, so removing them also + removes a source of confusion for users (`#1632`_). + Thanks `@obestwalter`_ for the PR. + +* ``pytest.skip()`` now raises an error when used to decorate a test function, + as opposed to its original intent (to imperatively skip a test inside a test function). Previously + this usage would cause the entire module to be skipped (`#607`_). + Thanks `@omarkohl`_ for the complete PR (`#1519`_). + +* Exit tests if a collection error occurs. A poll indicated most users will hit CTRL-C + anyway as soon as they see collection errors, so pytest might as well make that the default behavior (`#1421`_). + A ``--continue-on-collection-errors`` option has been added to restore the previous behaviour. + Thanks `@olegpidsadnyi`_ and `@omarkohl`_ for the complete PR (`#1628`_). + +* Renamed the pytest ``pdb`` module (plugin) into ``debugging`` to avoid clashes with the builtin ``pdb`` module. + +* Raise a helpful failure message when requesting a parametrized fixture at runtime, + e.g. with ``request.getfixturevalue``. Previously these parameters were simply + never defined, so a fixture decorated like ``@pytest.fixture(params=[0, 1, 2])`` + only ran once (`#460`_). + Thanks to `@nikratio`_ for the bug report, `@RedBeardCode`_ and `@tomviner`_ for the PR. + +* ``_pytest.monkeypatch.monkeypatch`` class has been renamed to ``_pytest.monkeypatch.MonkeyPatch`` + so it doesn't conflict with the ``monkeypatch`` fixture. + +* ``--exitfirst / -x`` can now be overridden by a following ``--maxfail=N`` + and is just a synonym for ``--maxfail=1``. + + +**New Features** + +* Support nose-style ``__test__`` attribute on methods of classes, + including unittest-style Classes. If set to ``False``, the test will not be + collected. + +* New ``doctest_namespace`` fixture for injecting names into the + namespace in which doctests run. + Thanks `@milliams`_ for the complete PR (`#1428`_). + +* New ``--doctest-report`` option available to change the output format of diffs + when running (failing) doctests (implements `#1749`_). + Thanks `@hartym`_ for the PR. + +* New ``name`` argument to ``pytest.fixture`` decorator which allows a custom name + for a fixture (to solve the funcarg-shadowing-fixture problem). + Thanks `@novas0x2a`_ for the complete PR (`#1444`_). + +* New ``approx()`` function for easily comparing floating-point numbers in + tests. + Thanks `@kalekundert`_ for the complete PR (`#1441`_). + +* Ability to add global properties in the final xunit output file by accessing + the internal ``junitxml`` plugin (experimental). + Thanks `@tareqalayan`_ for the complete PR `#1454`_). + +* New ``ExceptionInfo.match()`` method to match a regular expression on the + string representation of an exception (`#372`_). + Thanks `@omarkohl`_ for the complete PR (`#1502`_). + +* ``__tracebackhide__`` can now also be set to a callable which then can decide + whether to filter the traceback based on the ``ExceptionInfo`` object passed + to it. Thanks `@The-Compiler`_ for the complete PR (`#1526`_). + +* New ``pytest_make_parametrize_id(config, val)`` hook which can be used by plugins to provide + friendly strings for custom types. + Thanks `@palaviv`_ for the PR. + +* ``capsys`` and ``capfd`` now have a ``disabled()`` context-manager method, which + can be used to temporarily disable capture within a test. + Thanks `@nicoddemus`_ for the PR. + +* New cli flag ``--fixtures-per-test``: shows which fixtures are being used + for each selected test item. Features doc strings of fixtures by default. + Can also show where fixtures are defined if combined with ``-v``. + Thanks `@hackebrot`_ for the PR. + +* Introduce ``pytest`` command as recommended entry point. Note that ``py.test`` + still works and is not scheduled for removal. Closes proposal + `#1629`_. Thanks `@obestwalter`_ and `@davehunt`_ for the complete PR + (`#1633`_). + +* New cli flags: + + + ``--setup-plan``: performs normal collection and reports + the potential setup and teardown and does not execute any fixtures and tests; + + ``--setup-only``: performs normal collection, executes setup and teardown of + fixtures and reports them; + + ``--setup-show``: performs normal test execution and additionally shows + setup and teardown of fixtures; + + ``--keep-duplicates``: py.test now ignores duplicated paths given in the command + line. To retain the previous behavior where the same test could be run multiple + times by specifying it in the command-line multiple times, pass the ``--keep-duplicates`` + argument (`#1609`_); + + Thanks `@d6e`_, `@kvas-it`_, `@sallner`_, `@ioggstream`_ and `@omarkohl`_ for the PRs. + +* New CLI flag ``--override-ini``/``-o``: overrides values from the ini file. + For example: ``"-o xfail_strict=True"``'. + Thanks `@blueyed`_ and `@fengxx`_ for the PR. + +* New hooks: + + + ``pytest_fixture_setup(fixturedef, request)``: executes fixture setup; + + ``pytest_fixture_post_finalizer(fixturedef)``: called after the fixture's + finalizer and has access to the fixture's result cache. + + Thanks `@d6e`_, `@sallner`_. + +* Issue warnings for asserts whose test is a tuple literal. Such asserts will + never fail because tuples are always truthy and are usually a mistake + (see `#1562`_). Thanks `@kvas-it`_, for the PR. + +* Allow passing a custom debugger class (e.g. ``--pdbcls=IPython.core.debugger:Pdb``). + Thanks to `@anntzer`_ for the PR. + + +**Changes** + +* Plugins now benefit from assertion rewriting. Thanks + `@sober7`_, `@nicoddemus`_ and `@flub`_ for the PR. + +* Change ``report.outcome`` for ``xpassed`` tests to ``"passed"`` in non-strict + mode and ``"failed"`` in strict mode. Thanks to `@hackebrot`_ for the PR + (`#1795`_) and `@gprasad84`_ for report (`#1546`_). + +* Tests marked with ``xfail(strict=False)`` (the default) now appear in + JUnitXML reports as passing tests instead of skipped. + Thanks to `@hackebrot`_ for the PR (`#1795`_). + +* Highlight path of the file location in the error report to make it easier to copy/paste. + Thanks `@suzaku`_ for the PR (`#1778`_). + +* Fixtures marked with ``@pytest.fixture`` can now use ``yield`` statements exactly like + those marked with the ``@pytest.yield_fixture`` decorator. This change renders + ``@pytest.yield_fixture`` deprecated and makes ``@pytest.fixture`` with ``yield`` statements + the preferred way to write teardown code (`#1461`_). + Thanks `@csaftoiu`_ for bringing this to attention and `@nicoddemus`_ for the PR. + +* Explicitly passed parametrize ids do not get escaped to ascii (`#1351`_). + Thanks `@ceridwen`_ for the PR. + +* Fixtures are now sorted in the error message displayed when an unknown + fixture is declared in a test function. + Thanks `@nicoddemus`_ for the PR. + +* ``pytest_terminal_summary`` hook now receives the ``exitstatus`` + of the test session as argument. Thanks `@blueyed`_ for the PR (`#1809`_). + +* Parametrize ids can accept ``None`` as specific test id, in which case the + automatically generated id for that argument will be used. + Thanks `@palaviv`_ for the complete PR (`#1468`_). + +* The parameter to xunit-style setup/teardown methods (``setup_method``, + ``setup_module``, etc.) is now optional and may be omitted. + Thanks `@okken`_ for bringing this to attention and `@nicoddemus`_ for the PR. + +* Improved automatic id generation selection in case of duplicate ids in + parametrize. + Thanks `@palaviv`_ for the complete PR (`#1474`_). + +* Now pytest warnings summary is shown up by default. Added a new flag + ``--disable-pytest-warnings`` to explicitly disable the warnings summary (`#1668`_). + +* Make ImportError during collection more explicit by reminding + the user to check the name of the test module/package(s) (`#1426`_). + Thanks `@omarkohl`_ for the complete PR (`#1520`_). + +* Add ``build/`` and ``dist/`` to the default ``--norecursedirs`` list. Thanks + `@mikofski`_ for the report and `@tomviner`_ for the PR (`#1544`_). + +* ``pytest.raises`` in the context manager form accepts a custom + ``message`` to raise when no exception occurred. + Thanks `@palaviv`_ for the complete PR (`#1616`_). + +* ``conftest.py`` files now benefit from assertion rewriting; previously it + was only available for test modules. Thanks `@flub`_, `@sober7`_ and + `@nicoddemus`_ for the PR (`#1619`_). + +* Text documents without any doctests no longer appear as "skipped". + Thanks `@graingert`_ for reporting and providing a full PR (`#1580`_). + +* Ensure that a module within a namespace package can be found when it + is specified on the command line together with the ``--pyargs`` + option. Thanks to `@taschini`_ for the PR (`#1597`_). + +* Always include full assertion explanation during assertion rewriting. The previous behaviour was hiding + sub-expressions that happened to be ``False``, assuming this was redundant information. + Thanks `@bagerard`_ for reporting (`#1503`_). Thanks to `@davehunt`_ and + `@tomviner`_ for the PR. + +* ``OptionGroup.addoption()`` now checks if option names were already + added before, to make it easier to track down issues like `#1618`_. + Before, you only got exceptions later from ``argparse`` library, + giving no clue about the actual reason for double-added options. + +* ``yield``-based tests are considered deprecated and will be removed in pytest-4.0. + Thanks `@nicoddemus`_ for the PR. + +* ``[pytest]`` sections in ``setup.cfg`` files should now be named ``[tool:pytest]`` + to avoid conflicts with other distutils commands (see `#567`_). ``[pytest]`` sections in + ``pytest.ini`` or ``tox.ini`` files are supported and unchanged. + Thanks `@nicoddemus`_ for the PR. + +* Using ``pytest_funcarg__`` prefix to declare fixtures is considered deprecated and will be + removed in pytest-4.0 (`#1684`_). + Thanks `@nicoddemus`_ for the PR. + +* Passing a command-line string to ``pytest.main()`` is considered deprecated and scheduled + for removal in pytest-4.0. It is recommended to pass a list of arguments instead (`#1723`_). + +* Rename ``getfuncargvalue`` to ``getfixturevalue``. ``getfuncargvalue`` is + still present but is now considered deprecated. Thanks to `@RedBeardCode`_ and `@tomviner`_ + for the PR (`#1626`_). + +* ``optparse`` type usage now triggers DeprecationWarnings (`#1740`_). + + +* ``optparse`` backward compatibility supports float/complex types (`#457`_). + +* Refined logic for determining the ``rootdir``, considering only valid + paths which fixes a number of issues: `#1594`_, `#1435`_ and `#1471`_. + Updated the documentation according to current behavior. Thanks to + `@blueyed`_, `@davehunt`_ and `@matthiasha`_ for the PR. + +* Always include full assertion explanation. The previous behaviour was hiding + sub-expressions that happened to be False, assuming this was redundant information. + Thanks `@bagerard`_ for reporting (`#1503`_). Thanks to `@davehunt`_ and + `@tomviner`_ for PR. + +* Better message in case of not using parametrized variable (see `#1539`_). + Thanks to `@tramwaj29`_ for the PR. + +* Updated docstrings with a more uniform style. + +* Add stderr write for ``pytest.exit(msg)`` during startup. Previously the message was never shown. + Thanks `@BeyondEvil`_ for reporting `#1210`_. Thanks to `@JonathonSonesen`_ and + `@tomviner`_ for the PR. + +* No longer display the incorrect test deselection reason (`#1372`_). + Thanks `@ronnypfannschmidt`_ for the PR. + +* The ``--resultlog`` command line option has been deprecated: it is little used + and there are more modern and better alternatives (see `#830`_). + Thanks `@nicoddemus`_ for the PR. + +* Improve error message with fixture lookup errors: add an 'E' to the first + line and '>' to the rest. Fixes `#717`_. Thanks `@blueyed`_ for reporting and + a PR, `@eolo999`_ for the initial PR and `@tomviner`_ for his guidance during + EuroPython2016 sprint. + + +**Bug Fixes** + +* Parametrize now correctly handles duplicated test ids. + +* Fix internal error issue when the ``method`` argument is missing for + ``teardown_method()`` (`#1605`_). + +* Fix exception visualization in case the current working directory (CWD) gets + deleted during testing (`#1235`_). Thanks `@bukzor`_ for reporting. PR by + `@marscher`_. + +* Improve test output for logical expression with brackets (`#925`_). + Thanks `@DRMacIver`_ for reporting and `@RedBeardCode`_ for the PR. + +* Create correct diff for strings ending with newlines (`#1553`_). + Thanks `@Vogtinator`_ for reporting and `@RedBeardCode`_ and + `@tomviner`_ for the PR. + +* ``ConftestImportFailure`` now shows the traceback making it easier to + identify bugs in ``conftest.py`` files (`#1516`_). Thanks `@txomon`_ for + the PR. + +* Text documents without any doctests no longer appear as "skipped". + Thanks `@graingert`_ for reporting and providing a full PR (`#1580`_). + +* Fixed collection of classes with custom ``__new__`` method. + Fixes `#1579`_. Thanks to `@Stranger6667`_ for the PR. + +* Fixed scope overriding inside metafunc.parametrize (`#634`_). + Thanks to `@Stranger6667`_ for the PR. + +* Fixed the total tests tally in junit xml output (`#1798`_). + Thanks to `@cryporchild`_ for the PR. + +* Fixed off-by-one error with lines from ``request.node.warn``. + Thanks to `@blueyed`_ for the PR. + + +.. _#1210: https://github.com/pytest-dev/pytest/issues/1210 +.. _#1235: https://github.com/pytest-dev/pytest/issues/1235 +.. _#1351: https://github.com/pytest-dev/pytest/issues/1351 +.. _#1372: https://github.com/pytest-dev/pytest/issues/1372 +.. _#1421: https://github.com/pytest-dev/pytest/issues/1421 +.. _#1426: https://github.com/pytest-dev/pytest/issues/1426 +.. _#1428: https://github.com/pytest-dev/pytest/pull/1428 +.. _#1435: https://github.com/pytest-dev/pytest/issues/1435 +.. _#1441: https://github.com/pytest-dev/pytest/pull/1441 +.. _#1444: https://github.com/pytest-dev/pytest/pull/1444 +.. _#1454: https://github.com/pytest-dev/pytest/pull/1454 +.. _#1461: https://github.com/pytest-dev/pytest/pull/1461 +.. _#1468: https://github.com/pytest-dev/pytest/pull/1468 +.. _#1471: https://github.com/pytest-dev/pytest/issues/1471 +.. _#1474: https://github.com/pytest-dev/pytest/pull/1474 +.. _#1479: https://github.com/pytest-dev/pytest/issues/1479 +.. _#1502: https://github.com/pytest-dev/pytest/pull/1502 +.. _#1503: https://github.com/pytest-dev/pytest/issues/1503 +.. _#1516: https://github.com/pytest-dev/pytest/pull/1516 +.. _#1519: https://github.com/pytest-dev/pytest/pull/1519 +.. _#1520: https://github.com/pytest-dev/pytest/pull/1520 +.. _#1526: https://github.com/pytest-dev/pytest/pull/1526 +.. _#1539: https://github.com/pytest-dev/pytest/issues/1539 +.. _#1544: https://github.com/pytest-dev/pytest/issues/1544 +.. _#1546: https://github.com/pytest-dev/pytest/issues/1546 +.. _#1553: https://github.com/pytest-dev/pytest/issues/1553 +.. _#1562: https://github.com/pytest-dev/pytest/issues/1562 +.. _#1579: https://github.com/pytest-dev/pytest/issues/1579 +.. _#1580: https://github.com/pytest-dev/pytest/pull/1580 +.. _#1594: https://github.com/pytest-dev/pytest/issues/1594 +.. _#1597: https://github.com/pytest-dev/pytest/pull/1597 +.. _#1605: https://github.com/pytest-dev/pytest/issues/1605 +.. _#1616: https://github.com/pytest-dev/pytest/pull/1616 +.. _#1618: https://github.com/pytest-dev/pytest/issues/1618 +.. _#1619: https://github.com/pytest-dev/pytest/issues/1619 +.. _#1626: https://github.com/pytest-dev/pytest/pull/1626 +.. _#1627: https://github.com/pytest-dev/pytest/pull/1627 +.. _#1628: https://github.com/pytest-dev/pytest/pull/1628 +.. _#1629: https://github.com/pytest-dev/pytest/issues/1629 +.. _#1632: https://github.com/pytest-dev/pytest/issues/1632 +.. _#1633: https://github.com/pytest-dev/pytest/pull/1633 +.. _#1664: https://github.com/pytest-dev/pytest/pull/1664 +.. _#1668: https://github.com/pytest-dev/pytest/issues/1668 +.. _#1684: https://github.com/pytest-dev/pytest/pull/1684 +.. _#1723: https://github.com/pytest-dev/pytest/pull/1723 +.. _#1740: https://github.com/pytest-dev/pytest/issues/1740 +.. _#1749: https://github.com/pytest-dev/pytest/issues/1749 +.. _#1778: https://github.com/pytest-dev/pytest/pull/1778 +.. _#1795: https://github.com/pytest-dev/pytest/pull/1795 +.. _#1798: https://github.com/pytest-dev/pytest/pull/1798 +.. _#1809: https://github.com/pytest-dev/pytest/pull/1809 +.. _#372: https://github.com/pytest-dev/pytest/issues/372 +.. _#457: https://github.com/pytest-dev/pytest/issues/457 +.. _#460: https://github.com/pytest-dev/pytest/pull/460 +.. _#567: https://github.com/pytest-dev/pytest/pull/567 +.. _#607: https://github.com/pytest-dev/pytest/issues/607 +.. _#634: https://github.com/pytest-dev/pytest/issues/634 +.. _#717: https://github.com/pytest-dev/pytest/issues/717 +.. _#830: https://github.com/pytest-dev/pytest/issues/830 +.. _#925: https://github.com/pytest-dev/pytest/issues/925 + + +.. _@anntzer: https://github.com/anntzer +.. _@bagerard: https://github.com/bagerard +.. _@BeyondEvil: https://github.com/BeyondEvil +.. _@blueyed: https://github.com/blueyed +.. _@ceridwen: https://github.com/ceridwen +.. _@cryporchild: https://github.com/cryporchild +.. _@csaftoiu: https://github.com/csaftoiu +.. _@d6e: https://github.com/d6e +.. _@davehunt: https://github.com/davehunt +.. _@DRMacIver: https://github.com/DRMacIver +.. _@eolo999: https://github.com/eolo999 +.. _@fengxx: https://github.com/fengxx +.. _@flub: https://github.com/flub +.. _@gprasad84: https://github.com/gprasad84 +.. _@graingert: https://github.com/graingert +.. _@hartym: https://github.com/hartym +.. _@JonathonSonesen: https://github.com/JonathonSonesen +.. _@kalekundert: https://github.com/kalekundert +.. _@kvas-it: https://github.com/kvas-it +.. _@marscher: https://github.com/marscher +.. _@mikofski: https://github.com/mikofski +.. _@milliams: https://github.com/milliams +.. _@nikratio: https://github.com/nikratio +.. _@novas0x2a: https://github.com/novas0x2a +.. _@obestwalter: https://github.com/obestwalter +.. _@okken: https://github.com/okken +.. _@olegpidsadnyi: https://github.com/olegpidsadnyi +.. _@omarkohl: https://github.com/omarkohl +.. _@palaviv: https://github.com/palaviv +.. _@RedBeardCode: https://github.com/RedBeardCode +.. _@sallner: https://github.com/sallner +.. _@sober7: https://github.com/sober7 +.. _@Stranger6667: https://github.com/Stranger6667 +.. _@suzaku: https://github.com/suzaku +.. _@tareqalayan: https://github.com/tareqalayan +.. _@taschini: https://github.com/taschini +.. _@tramwaj29: https://github.com/tramwaj29 +.. _@txomon: https://github.com/txomon +.. _@Vogtinator: https://github.com/Vogtinator +.. _@matthiasha: https://github.com/matthiasha + + +2.9.2 (2016-05-31) +================== + +**Bug Fixes** + +* fix `#510`_: skip tests where one parameterize dimension was empty + thanks Alex Stapleton for the Report and `@RonnyPfannschmidt`_ for the PR + +* Fix Xfail does not work with condition keyword argument. + Thanks `@astraw38`_ for reporting the issue (`#1496`_) and `@tomviner`_ + for PR the (`#1524`_). + +* Fix win32 path issue when putting custom config file with absolute path + in ``pytest.main("-c your_absolute_path")``. + +* Fix maximum recursion depth detection when raised error class is not aware + of unicode/encoded bytes. + Thanks `@prusse-martin`_ for the PR (`#1506`_). + +* Fix ``pytest.mark.skip`` mark when used in strict mode. + Thanks `@pquentin`_ for the PR and `@RonnyPfannschmidt`_ for + showing how to fix the bug. + +* Minor improvements and fixes to the documentation. + Thanks `@omarkohl`_ for the PR. + +* Fix ``--fixtures`` to show all fixture definitions as opposed to just + one per fixture name. + Thanks to `@hackebrot`_ for the PR. + +.. _#510: https://github.com/pytest-dev/pytest/issues/510 +.. _#1506: https://github.com/pytest-dev/pytest/pull/1506 +.. _#1496: https://github.com/pytest-dev/pytest/issues/1496 +.. _#1524: https://github.com/pytest-dev/pytest/pull/1524 + +.. _@prusse-martin: https://github.com/prusse-martin +.. _@astraw38: https://github.com/astraw38 + + +2.9.1 (2016-03-17) +================== **Bug Fixes** @@ -23,17 +1626,19 @@ * Fix (`#649`_): parametrized test nodes cannot be specified to run on the command line. +* Fix (`#138`_): better reporting for python 3.3+ chained exceptions .. _#1437: https://github.com/pytest-dev/pytest/issues/1437 .. _#469: https://github.com/pytest-dev/pytest/issues/469 .. _#1431: https://github.com/pytest-dev/pytest/pull/1431 .. _#649: https://github.com/pytest-dev/pytest/issues/649 +.. _#138: https://github.com/pytest-dev/pytest/issues/138 .. _@asottile: https://github.com/asottile -2.9.0 -===== +2.9.0 (2016-02-29) +================== **New Features** @@ -51,7 +1656,7 @@ ``xfail_strict`` ini option that can be used to configure it project-wise. Thanks `@rabbbit`_ for the request and `@nicoddemus`_ for the PR (`#1355`_). -* ``Parser.addini`` now supports options of type ``bool``. +* ``Parser.addini`` now supports options of type ``bool``. Thanks `@nicoddemus`_ for the PR. * New ``ALLOW_BYTES`` doctest option. This strips ``b`` prefixes from byte strings @@ -62,26 +1667,26 @@ Fixes `#1366`_. Thanks to `@hpk42`_ for the report and `@RonnyPfannschmidt`_ for the PR. -* Catch ``IndexError`` exceptions when getting exception source location. +* Catch ``IndexError`` exceptions when getting exception source location. Fixes a pytest internal error for dynamically generated code (fixtures and tests) where source lines are fake by intention. **Changes** -* **Important**: `py.code `_ has been - merged into the ``pytest`` repository as ``pytest._code``. This decision - was made because ``py.code`` had very few uses outside ``pytest`` and the - fact that it was in a different repository made it difficult to fix bugs on +* **Important**: `py.code `_ has been + merged into the ``pytest`` repository as ``pytest._code``. This decision + was made because ``py.code`` had very few uses outside ``pytest`` and the + fact that it was in a different repository made it difficult to fix bugs on its code in a timely manner. The team hopes with this to be able to better refactor out and improve that code. This change shouldn't affect users, but it is useful to let users aware if they encounter any strange behavior. - - Keep in mind that the code for ``pytest._code`` is **private** and + + Keep in mind that the code for ``pytest._code`` is **private** and **experimental**, so you definitely should not import it explicitly! - Please note that the original ``py.code`` is still available in - `pylib `_. + Please note that the original ``py.code`` is still available in + `pylib `_. * ``pytest_enter_pdb`` now optionally receives the pytest config object. Thanks `@nicoddemus`_ for the PR. @@ -117,7 +1722,7 @@ Thanks `@biern`_ for the PR. * Fix `traceback style docs`_ to describe all of the available options - (auto/long/short/line/native/no), with `auto` being the default since v2.6. + (auto/long/short/line/native/no), with ``auto`` being the default since v2.6. Thanks `@hackebrot`_ for the PR. * Fix (`#1422`_): junit record_xml_property doesn't allow multiple records @@ -125,6 +1730,7 @@ .. _`traceback style docs`: https://pytest.org/latest/usage.html#modifying-python-traceback-printing +.. _#1609: https://github.com/pytest-dev/pytest/issues/1609 .. _#1422: https://github.com/pytest-dev/pytest/issues/1422 .. _#1379: https://github.com/pytest-dev/pytest/issues/1379 .. _#1366: https://github.com/pytest-dev/pytest/issues/1366 @@ -149,14 +1755,16 @@ .. _@RonnyPfannschmidt: https://github.com/RonnyPfannschmidt .. _@rabbbit: https://github.com/rabbbit .. _@hackebrot: https://github.com/hackebrot +.. _@pquentin: https://github.com/pquentin +.. _@ioggstream: https://github.com/ioggstream -2.8.7 -===== +2.8.7 (2016-01-24) +================== - fix #1338: use predictable object resolution for monkeypatch -2.8.6 -===== +2.8.6 (2016-01-21) +================== - fix #1259: allow for double nodeids in junitxml, this was a regression failing plugins combinations @@ -172,7 +1780,7 @@ - fix #1292: monkeypatch calls (setattr, setenv, etc.) are now O(1). Thanks David R. MacIver for the report and Bruno Oliveira for the PR. -- fix #1223: captured stdout and stderr are now properly displayed before +- fix #1223: captured stdout and stderr are now properly displayed before entering pdb when ``--pdb`` is used instead of being thrown away. Thanks Cal Leeming for the PR. @@ -187,8 +1795,8 @@ Thanks Georgy Dyuldin for the PR. -2.8.5 -===== +2.8.5 (2015-12-11) +================== - fix #1243: fixed issue where class attributes injected during collection could break pytest. PR by Alexei Kozlenok, thanks Ronny Pfannschmidt and Bruno Oliveira for the review and help. @@ -201,8 +1809,8 @@ Bruno Oliveira for the PR. -2.8.4 -===== +2.8.4 (2015-12-06) +================== - fix #1190: ``deprecated_call()`` now works when the deprecated function has been already called by another test in the same @@ -225,8 +1833,8 @@ - a number of documentation modernizations wrt good practices. Thanks Bruno Oliveira for the PR. -2.8.3 -===== +2.8.3 (2015-11-18) +================== - fix #1169: add __name__ attribute to testcases in TestCaseFunction to support the @unittest.skip decorator on functions and methods. @@ -247,14 +1855,14 @@ Thanks Gabriel Reis for the PR. - add more talks to the documentation -- extend documentation on the --ignore cli option -- use pytest-runner for setuptools integration +- extend documentation on the --ignore cli option +- use pytest-runner for setuptools integration - minor fixes for interaction with OS X El Capitan system integrity protection (thanks Florian) -2.8.2 -===== +2.8.2 (2015-10-07) +================== - fix #1085: proper handling of encoding errors when passing encoded byte strings to pytest.parametrize in Python 2. @@ -273,8 +1881,8 @@ Thanks Sergey B Kirpichev and Vital Kudzelka for contributing and Bruno Oliveira for the PR. -2.8.1 -===== +2.8.1 (2015-09-29) +================== - fix #1034: Add missing nodeid on pytest_logwarning call in addhook. Thanks Simon Gomizelj for the PR. @@ -298,7 +1906,7 @@ - (experimental) adapt more SEMVER style versioning and change meaning of master branch in git repo: "master" branch now keeps the bugfixes, changes - aimed for micro releases. "features" branch will only be be released + aimed for micro releases. "features" branch will only be released with minor or major pytest releases. - Fix issue #766 by removing documentation references to distutils. @@ -320,8 +1928,8 @@ - fix issue 1029: transform errors when writing cache values into pytest-warnings -2.8.0 -===== +2.8.0 (2015-09-18) +================== - new ``--lf`` and ``-ff`` options to run only the last failing tests or "failing tests first" from the last run. This functionality is provided @@ -432,7 +2040,7 @@ - new option ``--import-mode`` to allow to change test module importing behaviour to append to sys.path instead of prepending. This better allows - to run test modules against installated versions of a package even if the + to run test modules against installed versions of a package even if the package under test has the same import root. In this example:: testing/__init__.py @@ -510,8 +2118,8 @@ properly used to discover ``rootdir`` and ``ini`` files. Thanks Peter Lauri for the report and Bruno Oliveira for the PR. -2.7.3 (compared to 2.7.2) -============================= +2.7.3 (2015-09-15) +================== - Allow 'dev', 'rc', or other non-integer version strings in ``importorskip``. Thanks to Eric Hunsberger for the PR. @@ -553,8 +2161,8 @@ directories created by this fixture (defaults to $TEMP/pytest-$USER). Thanks Bruno Oliveira for the PR. -2.7.2 (compared to 2.7.1) -============================= +2.7.2 (2015-06-23) +================== - fix issue767: pytest.raises value attribute does not contain the exception instance on Python 2.6. Thanks Eric Siegerman for providing the test @@ -582,15 +2190,15 @@ which has a refined algorithm for traceback generation. -2.7.1 (compared to 2.7.0) -============================= +2.7.1 (2015-05-19) +================== - fix issue731: do not get confused by the braces which may be present and unbalanced in an object's repr while collapsing False explanations. Thanks Carl Meyer for the report and test case. - fix issue553: properly handling inspect.getsourcelines failures in - FixtureLookupError which would lead to to an internal error, + FixtureLookupError which would lead to an internal error, obfuscating the original problem. Thanks talljosh for initial diagnose/patch and Bruno Oliveira for final patch. @@ -615,8 +2223,8 @@ - reintroduced _pytest fixture of the pytester plugin which is used at least by pytest-xdist. -2.7.0 (compared to 2.6.4) -============================= +2.7.0 (2015-03-26) +================== - fix issue435: make reload() work when assert rewriting is active. Thanks Daniel Hahler. @@ -648,7 +2256,7 @@ - fix issue655: work around different ways that cause python2/3 to leak sys.exc_info into fixtures/tests causing failures in 3rd party code -- fix issue615: assertion re-writing did not correctly escape % signs +- fix issue615: assertion rewriting did not correctly escape % signs when formatting boolean operations, which tripped over mixing booleans with modulo operators. Thanks to Tom Viner for the report, triaging and fix. @@ -685,8 +2293,8 @@ ``sys.last_traceback`` are set, so that a user can inspect the error via postmortem debugging (almarklein). -2.6.4 -===== +2.6.4 (2014-10-24) +================== - Improve assertion failure reporting on iterables, by using ndiff and pprint. @@ -714,8 +2322,8 @@ - fix issue614: fixed pastebin support. -2.6.3 -===== +2.6.3 (2014-09-24) +================== - fix issue575: xunit-xml was reporting collection errors as failures instead of errors, thanks Oleg Sinyavskiy. @@ -732,8 +2340,8 @@ dep). Thanks Charles Cloud for analysing the issue. - fix conftest related fixture visibility issue: when running with a - CWD outside a test package pytest would get fixture discovery wrong. - Thanks to Wolfgang Schnerring for figuring out a reproducable example. + CWD outside of a test package pytest would get fixture discovery wrong. + Thanks to Wolfgang Schnerring for figuring out a reproducible example. - Introduce pytest_enter_pdb hook (needed e.g. by pytest_timeout to cancel the timeout when interactively entering pdb). Thanks Wolfgang Schnerring. @@ -741,8 +2349,8 @@ - check xfail/skip also with non-python function test items. Thanks Floris Bruynooghe. -2.6.2 -===== +2.6.2 (2014-09-05) +================== - Added function pytest.freeze_includes(), which makes it easy to embed pytest into executables using tools like cx_freeze. @@ -770,8 +2378,8 @@ replace the py.test introspection message but are shown in addition to them. -2.6.1 -===== +2.6.1 (2014-08-07) +================== - No longer show line numbers in the --verbose output, the output is now purely the nodeid. The line number is still shown in failure reports. @@ -907,8 +2515,8 @@ in monkeypatch plugin. Improves output in documentation. -2.5.2 -===== +2.5.2 (2014-01-29) +================== - fix issue409 -- better interoperate with cx_freeze by not trying to import from collections.abc which causes problems @@ -932,11 +2540,11 @@ - fix issue429: comparing byte strings with non-ascii chars in assert expressions now work better. Thanks Floris Bruynooghe. -- make capfd/capsys.capture private, its unused and shouldnt be exposed +- make capfd/capsys.capture private, its unused and shouldn't be exposed -2.5.1 -===== +2.5.1 (2013-12-17) +================== - merge new documentation styling PR from Tobias Bieniek. @@ -956,8 +2564,8 @@ -2.5.0 -===== +2.5.0 (2013-12-12) +================== - dropped python2.5 from automated release testing of pytest itself which means it's probably going to break soon (but still works @@ -989,7 +2597,7 @@ to problems for more than >966 non-function scoped parameters). - fix issue290 - there is preliminary support now for parametrizing - with repeated same values (sometimes useful to to test if calling + with repeated same values (sometimes useful to test if calling a second time works as with the first time). - close issue240 - document precisely how pytest module importing @@ -1092,8 +2700,8 @@ - fix verbose reporting for @mock'd test functions -2.4.2 -===== +2.4.2 (2013-10-04) +================== - on Windows require colorama and a newer py lib so that py.io.TerminalWriter() now uses colorama instead of its own ctypes hacks. (fixes issue365) @@ -1123,8 +2731,8 @@ - add pluginmanager.do_configure(config) as a link to config.do_configure() for plugin-compatibility -2.4.1 -===== +2.4.1 (2013-10-02) +================== - When using parser.addoption() unicode arguments to the "type" keyword should also be converted to the respective types. @@ -1203,7 +2811,7 @@ new features: - fix issue322: tearDownClass is not run if setUpClass failed. Thanks Mathieu Agopian for the initial fix. Also make all of pytest/nose - finalizer mimick the same generic behaviour: if a setupX exists and + finalizer mimic the same generic behaviour: if a setupX exists and fails, don't run teardownX. This internally introduces a new method "node.addfinalizer()" helper which can only be called during the setup phase of a node. @@ -1308,8 +2916,8 @@ Bug fixes: ".section(title)" and ".line(msg)" methods to print extra information at the end of a test run. -2.3.5 -===== +2.3.5 (2013-04-30) +================== - fix issue169: respect --tb=style with setup/teardown errors as well. @@ -1322,11 +2930,11 @@ Bug fixes: (thanks Adam Goucher) - Issue 265 - integrate nose setup/teardown with setupstate - so it doesnt try to teardown if it did not setup + so it doesn't try to teardown if it did not setup -- issue 271 - dont write junitxml on slave nodes +- issue 271 - don't write junitxml on slave nodes -- Issue 274 - dont try to show full doctest example +- Issue 274 - don't try to show full doctest example when doctest does not know the example location - issue 280 - disable assertion rewriting on buggy CPython 2.6.0 @@ -1362,7 +2970,7 @@ Bug fixes: - allow to specify prefixes starting with "_" when customizing python_functions test discovery. (thanks Graham Horler) -- improve PYTEST_DEBUG tracing output by puting +- improve PYTEST_DEBUG tracing output by putting extra data on a new lines with additional indent - ensure OutcomeExceptions like skip/fail have initialized exception attributes @@ -1373,8 +2981,8 @@ Bug fixes: - fix issue266 - accept unicode in MarkEvaluator expressions -2.3.4 -===== +2.3.4 (2012-11-20) +================== - yielded test functions will now have autouse-fixtures active but cannot accept fixtures as funcargs - it's anyway recommended to @@ -1393,8 +3001,8 @@ Bug fixes: need to write as -k "TestClass and test_method" to match a certain method in a certain test class. -2.3.3 -===== +2.3.3 (2012-11-06) +================== - fix issue214 - parse modules that contain special objects like e. g. flask's request object which blows up on getattr access if no request @@ -1411,7 +3019,7 @@ Bug fixes: - fix issue209 - reintroduce python2.4 support by depending on newer pylib which re-introduced statement-finding for pre-AST interpreters -- nose support: only call setup if its a callable, thanks Andrew +- nose support: only call setup if it's a callable, thanks Andrew Taumoefolau - fix issue219 - add py2.4-3.3 classifiers to TROVE list @@ -1425,8 +3033,8 @@ Bug fixes: - fix issue127 - improve documentation for pytest_addoption() and add a ``config.getoption(name)`` helper function for consistency. -2.3.2 -===== +2.3.2 (2012-10-25) +================== - fix issue208 and fix issue29 use new py version to avoid long pauses when printing tracebacks in long modules @@ -1458,8 +3066,8 @@ Bug fixes: - add tox.ini to pytest distribution so that ignore-dirs and others config bits are properly distributed for maintainers who run pytest-own tests -2.3.1 -===== +2.3.1 (2012-10-20) +================== - fix issue202 - fix regression: using "self" from fixture functions now works as expected (it's the same "self" instance that a test method @@ -1471,8 +3079,8 @@ Bug fixes: - link to web pages from --markers output which provides help for pytest.mark.* usage. -2.3.0 -===== +2.3.0 (2012-10-19) +================== - fix issue202 - better automatic names for parametrized test functions - fix issue139 - introduce @pytest.fixture which allows direct scoping @@ -1507,7 +3115,7 @@ Bug fixes: - fix issue128: show captured output when capsys/capfd are used -- fix issue179: propperly show the dependency chain of factories +- fix issue179: properly show the dependency chain of factories - pluginmanager.register(...) now raises ValueError if the plugin has been already registered or the name is taken @@ -1548,10 +3156,10 @@ Bug fixes: - don't show deselected reason line if there is none - - py.test -vv will show all of assert comparisations instead of truncating + - py.test -vv will show all of assert comparisons instead of truncating -2.2.4 -===== +2.2.4 (2012-05-22) +================== - fix error message for rewritten assertions involving the % operator - fix issue 126: correctly match all invalid xml characters for junitxml @@ -1559,7 +3167,7 @@ Bug fixes: - fix issue with unittest: now @unittest.expectedFailure markers should be processed correctly (you can also use @pytest.mark markers) - document integration with the extended distribute/setuptools test commands -- fix issue 140: propperly get the real functions +- fix issue 140: properly get the real functions of bound classmethods for setup/teardown_class - fix issue #141: switch from the deceased paste.pocoo.org to bpaste.net - fix issue #143: call unconfigure/sessionfinish always when @@ -1567,13 +3175,13 @@ Bug fixes: - fix issue #144: better mangle test ids to junitxml classnames - upgrade distribute_setup.py to 0.6.27 -2.2.3 -===== +2.2.3 (2012-02-05) +================== -- fix uploaded package to only include neccesary files +- fix uploaded package to only include necessary files -2.2.2 -===== +2.2.2 (2012-02-05) +================== - fix issue101: wrong args to unittest.TestCase test function now produce better output @@ -1592,8 +3200,8 @@ Bug fixes: - allow adding of attributes to test reports such that it also works with distributed testing (no upgrade of pytest-xdist needed) -2.2.1 -===== +2.2.1 (2011-12-16) +================== - fix issue99 (in pytest and py) internallerrors with resultlog now produce better output - fixed by normalizing pytest_internalerror @@ -1609,14 +3217,14 @@ Bug fixes: - fix collection crash due to unknown-source collected items, thanks to Ralf Schmitt (fixed by depending on a more recent pylib) -2.2.0 -===== +2.2.0 (2011-11-18) +================== - fix issue90: introduce eager tearing down of test items so that teardown function are called earlier. - add an all-powerful metafunc.parametrize function which allows to parametrize test function arguments in multiple steps and therefore - from indepdenent plugins and palces. + from independent plugins and places. - add a @pytest.mark.parametrize helper which allows to easily call a test function with different argument values - Add examples to the "parametrize" example page, including a quick port @@ -1644,8 +3252,8 @@ Bug fixes: - simplify junitxml output code by relying on py.xml - add support for skip properties on unittest classes and functions -2.1.3 -===== +2.1.3 (2011-10-18) +================== - fix issue79: assertion rewriting failed on some comparisons in boolops - correctly handle zero length arguments (a la pytest '') @@ -1653,8 +3261,8 @@ Bug fixes: - fix issue75 / skipping test failure on jython - fix issue77 / Allow assertrepr_compare hook to apply to a subset of tests -2.1.2 -===== +2.1.2 (2011-09-24) +================== - fix assertion rewriting on files with windows newlines on some Python versions - refine test discovery by package/module name (--pyargs), thanks Florian Mayer @@ -1676,8 +3284,8 @@ Bug fixes: - fix issue61: assertion rewriting on boolean operations with 3 or more operands - you can now build a man page with "cd doc ; make man" -2.1.0 -===== +2.1.0 (2011-07-09) +================== - fix issue53 call nosestyle setup functions with correct ordering - fix issue58 and issue59: new assertion code fixes @@ -1696,8 +3304,8 @@ Bug fixes: - report KeyboardInterrupt even if interrupted during session startup - fix issue 35 - provide PDF doc version and download link from index page -2.0.3 -===== +2.0.3 (2011-05-11) +================== - fix issue38: nicer tracebacks on calls to hooks, particularly early configure/sessionstart ones @@ -1711,13 +3319,13 @@ Bug fixes: - don't require zlib (and other libs) for genscript plugin without --genscript actually being used. -- speed up skips (by not doing a full traceback represenation +- speed up skips (by not doing a full traceback representation internally) - fix issue37: avoid invalid characters in junitxml's output -2.0.2 -===== +2.0.2 (2011-03-09) +================== - tackle issue32 - speed up test runs of very quick test functions by reducing the relative overhead @@ -1759,17 +3367,17 @@ Bug fixes: this. - fixed typos in the docs (thanks Victor Garcia, Brianna Laugher) and particular - thanks to Laura Creighton who also revieved parts of the documentation. + thanks to Laura Creighton who also reviewed parts of the documentation. -- fix slighly wrong output of verbose progress reporting for classes +- fix slightly wrong output of verbose progress reporting for classes (thanks Amaury) - more precise (avoiding of) deprecation warnings for node.Class|Function accesses - avoid std unittest assertion helper code in tracebacks (thanks Ronny) -2.0.1 -===== +2.0.1 (2011-02-07) +================== - refine and unify initial capturing so that it works nicely even if the logging module is used on an early-loaded conftest.py @@ -1817,12 +3425,12 @@ Bug fixes: parametraization remains the "pytest_generate_tests" mechanism, see the docs. -2.0.0 -===== +2.0.0 (2010-11-25) +================== - pytest-2.0 is now its own package and depends on pylib-2.0 - new ability: python -m pytest / python -m pytest.main ability -- new python invcation: pytest.main(args, plugins) to load +- new python invocation: pytest.main(args, plugins) to load some custom plugins early. - try harder to run unittest test suites in a more compatible manner by deferring setup/teardown semantics to the unittest package. @@ -1862,8 +3470,8 @@ Bug fixes: - add ability to use "class" level for cached_setup helper - fix strangeness: mark.* objects are now immutable, create new instances -1.3.4 -===== +1.3.4 (2010-09-14) +================== - fix issue111: improve install documentation for windows - fix issue119: fix custom collectability of __init__.py as a module @@ -1871,8 +3479,8 @@ Bug fixes: - fix issue115: unify internal exception passthrough/catching/GeneratorExit - fix issue118: new --tb=native for presenting cpython-standard exceptions -1.3.3 -===== +1.3.3 (2010-07-30) +================== - fix issue113: assertion representation problem with triple-quoted strings (and possibly other cases) @@ -1886,8 +3494,8 @@ Bug fixes: (thanks Armin Ronacher for reporting) - remove trailing whitespace in all py/text distribution files -1.3.2 -===== +1.3.2 (2010-07-08) +================== **New features** @@ -1959,8 +3567,8 @@ Bug fixes: - fix homedir detection on Windows - ship distribute_setup.py version 0.6.13 -1.3.1 -===== +1.3.1 (2010-05-25) +================== **New features** @@ -2029,8 +3637,8 @@ Bug fixes: (and internally be more careful when presenting unexpected byte sequences) -1.3.0 -===== +1.3.0 (2010-05-05) +================== - deprecate --report option in favour of a new shorter and easier to remember -r option: it takes a string argument consisting of any @@ -2061,7 +3669,7 @@ Bug fixes: - extend and refine xfail mechanism: ``@py.test.mark.xfail(run=False)`` do not run the decorated test ``@py.test.mark.xfail(reason="...")`` prints the reason string in xfail summaries - specifiying ``--runxfail`` on command line virtually ignores xfail markers + specifying ``--runxfail`` on command line virtually ignores xfail markers - expose (previously internal) commonly useful methods: py.io.get_terminal_with() -> return terminal width @@ -2094,8 +3702,8 @@ Bug fixes: - added links to the new capturelog and coverage plugins -1.2.0 -===== +1.2.0 (2010-01-18) +================== - refined usage and options for "py.cleanup":: @@ -2133,8 +3741,8 @@ Bug fixes: - fix plugin links -1.1.1 -===== +1.1.1 (2009-11-24) +================== - moved dist/looponfailing from py.test core into a new separately released pytest-xdist plugin. @@ -2217,8 +3825,8 @@ Bug fixes: - fix docs, fix internal bin/ script generation -1.1.0 -===== +1.1.0 (2009-11-05) +================== - introduce automatic plugin registration via 'pytest11' entrypoints via setuptools' pkg_resources.iter_entry_points @@ -2286,7 +3894,7 @@ Bug fixes: * add the ability to specify a path for py.lookup to search in -* fix a funcarg cached_setup bug probably only occuring +* fix a funcarg cached_setup bug probably only occurring in distributed testing and "module" scope with teardown. * many fixes and changes for making the code base python3 compatible, @@ -2321,16 +3929,16 @@ Bug fixes: * simplified internal localpath implementation -1.0.2 -===== +1.0.2 (2009-08-27) +================== * fixing packaging issues, triggered by fedora redhat packaging, also added doc, examples and contrib dirs to the tarball. * added a documentation link to the new django plugin. -1.0.1 -===== +1.0.1 (2009-08-19) +================== * added a 'pytest_nose' plugin which handles nose.SkipTest, nose-style function/method/generator setup/teardown and @@ -2363,14 +3971,14 @@ Bug fixes: * simplified multicall mechanism and plugin architecture, renamed some internal methods and argnames -1.0.0 -===== +1.0.0 (2009-08-04) +================== * more terse reporting try to show filesystem path relatively to current dir * improve xfail output a bit -1.0.0b9 -======= +1.0.0b9 (2009-07-31) +==================== * cleanly handle and report final teardown of test setup @@ -2403,8 +4011,8 @@ Bug fixes: * item.repr_failure(excinfo) instead of item.repr_failure(excinfo, outerr) -1.0.0b8 -======= +1.0.0b8 (2009-07-22) +==================== * pytest_unittest-plugin is now enabled by default @@ -2457,8 +4065,8 @@ Bug fixes: * make __name__ == "__channelexec__" for remote_exec code -1.0.0b3 -======= +1.0.0b3 (2009-06-19) +==================== * plugin classes are removed: one now defines hooks directly in conftest.py or global pytest_*.py @@ -2552,10 +4160,10 @@ serve as a reference for developers. * fixed issue with 2.5 type representations in py.test [45483, 45484] * made that internal reporting issues displaying is done atomically in py.test [45518] -* made that non-existing files are igored by the py.lookup script [45519] +* made that non-existing files are ignored by the py.lookup script [45519] * improved exception name creation in py.test [45535] * made that less threads are used in execnet [merge in 45539] -* removed lock required for atomical reporting issue displaying in py.test +* removed lock required for atomic reporting issue displaying in py.test [45545] * removed globals from execnet [45541, 45547] * refactored cleanup mechanics, made that setDaemon is set to 1 to make atexit diff --git a/tests/wpt/web-platform-tests/tools/pytest/CONTRIBUTING.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/CONTRIBUTING.rst similarity index 59% rename from tests/wpt/web-platform-tests/tools/pytest/CONTRIBUTING.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/CONTRIBUTING.rst index 75ee3ec32d3..d85a894b910 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/CONTRIBUTING.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/CONTRIBUTING.rst @@ -34,13 +34,13 @@ If you are reporting a bug, please include: * Your operating system name and version. * Any details about your local setup that might be helpful in troubleshooting, - specifically Python interpreter version, - installed libraries and pytest version. + specifically the Python interpreter version, installed libraries, and pytest + version. * Detailed steps to reproduce the bug. -If you can write a demonstration test that currently fails but should pass (xfail), -that is a very useful commit to make as well, even if you can't find how -to fix the bug yet. +If you can write a demonstration test that currently fails but should pass +(xfail), that is a very useful commit to make as well, even if you cannot +fix the bug itself. .. _fixbugs: @@ -48,8 +48,8 @@ to fix the bug yet. Fix bugs -------- -Look through the GitHub issues for bugs. Here is sample filter you can use: -https://github.com/pytest-dev/pytest/labels/bug +Look through the GitHub issues for bugs. Here is a filter you can use: +https://github.com/pytest-dev/pytest/labels/type%3A%20bug :ref:`Talk ` to developers to find out how you can fix specific bugs. @@ -60,8 +60,7 @@ Don't forget to check the issue trackers of your favourite plugins, too! Implement features ------------------ -Look through the GitHub issues for enhancements. Here is sample filter you -can use: +Look through the GitHub issues for enhancements. Here is a filter you can use: https://github.com/pytest-dev/pytest/labels/enhancement :ref:`Talk ` to developers to find out how you can implement specific @@ -70,17 +69,26 @@ features. Write documentation ------------------- -pytest could always use more documentation. What exactly is needed? +Pytest could always use more documentation. What exactly is needed? * More complementary documentation. Have you perhaps found something unclear? * Documentation translations. We currently have only English. * Docstrings. There can never be too many of them. * Blog posts, articles and such -- they're all very appreciated. -You can also edit documentation files directly in the Github web interface -without needing to make a fork and local copy. This can be convenient for -small fixes. +You can also edit documentation files directly in the GitHub web interface, +without using a local copy. This can be convenient for small fixes. +.. note:: + Build the documentation locally with the following command: + + .. code:: bash + + $ tox -e docs + + The built documentation should be available in the ``doc/en/_build/``. + + Where 'en' refers to the documentation language. .. _submitplugin: @@ -95,13 +103,14 @@ in repositories living under the ``pytest-dev`` organisations: - `pytest-dev on Bitbucket `_ All pytest-dev Contributors team members have write access to all contained -repositories. pytest core and plugins are generally developed +repositories. Pytest core and plugins are generally developed using `pull requests`_ to respective repositories. The objectives of the ``pytest-dev`` organisation are: * Having a central location for popular pytest plugins -* Sharing some of the maintenance responsibility (in case a maintainer no longer whishes to maintain a plugin) +* Sharing some of the maintenance responsibility (in case a maintainer no + longer wishes to maintain a plugin) You can submit your plugin by subscribing to the `pytest-dev mail list `_ and writing a @@ -111,7 +120,7 @@ the following: - PyPI presence with a ``setup.py`` that contains a license, ``pytest-`` prefixed name, version number, authors, short and long description. -- a ``tox.ini`` for running tests using `tox `_. +- a ``tox.ini`` for running tests using `tox `_. - a ``README.txt`` describing how to use the plugin and on which platforms it runs. @@ -121,33 +130,26 @@ the following: - an issue tracker for bug reports and enhancement requests. +- a `changelog `_ + If no contributor strongly objects and two agree, the repository can then be transferred to the ``pytest-dev`` organisation. Here's a rundown of how a repository transfer usually proceeds (using a repository named ``joedoe/pytest-xyz`` as example): -* One of the ``pytest-dev`` administrators creates: - - - ``pytest-xyz-admin`` team, with full administration rights to - ``pytest-dev/pytest-xyz``. - - ``pytest-xyz-developers`` team, with write access to - ``pytest-dev/pytest-xyz``. - -* ``joedoe`` is invited to the ``pytest-xyz-admin`` team; - -* After accepting the invitation, ``joedoe`` transfers the repository from its - original location to ``pytest-dev/pytest-xyz`` (A nice feature is that GitHub handles URL redirection from - the old to the new location automatically). - -* ``joedoe`` is free to add any other collaborators to the - ``pytest-xyz-admin`` or ``pytest-xyz-developers`` team as desired. +* ``joedoe`` transfers repository ownership to ``pytest-dev`` administrator ``calvin``. +* ``calvin`` creates ``pytest-xyz-admin`` and ``pytest-xyz-developers`` teams, inviting ``joedoe`` to both as **maintainer**. +* ``calvin`` transfers repository to ``pytest-dev`` and configures team access: + + - ``pytest-xyz-admin`` **admin** access; + - ``pytest-xyz-developers`` **write** access; The ``pytest-dev/Contributors`` team has write access to all projects, and every project administrator is in it. We recommend that each plugin has at least three people who have the right to release to PyPI. -Repository owners can be assured that no ``pytest-dev`` administrator will ever make +Repository owners can rest assured that no ``pytest-dev`` administrator will ever make releases of your repository or take ownership in any way, except in rare cases where someone becomes unresponsive after months of contact attempts. As stated, the objective is to share maintenance and avoid "plugin-abandon". @@ -156,23 +158,41 @@ As stated, the objective is to share maintenance and avoid "plugin-abandon". .. _`pull requests`: .. _pull-requests: -Preparing Pull Requests on GitHub ---------------------------------- +Preparing Pull Requests +----------------------- -There's an excellent tutorial on how Pull Requests work in the -`GitHub Help Center `_ +Short version +~~~~~~~~~~~~~ + +#. Fork the repository; +#. Target ``master`` for bugfixes and doc changes; +#. Target ``features`` for new features or functionality changes. +#. Follow **PEP-8**. There's a ``tox`` command to help fixing it: ``tox -e fix-lint``. +#. Tests are run using ``tox``:: + + tox -e linting,py27,py36 + + The test environments above are usually enough to cover most cases locally. + +#. Write a ``changelog`` entry: ``changelog/2574.bugfix``, use issue id number + and one of ``bugfix``, ``removal``, ``feature``, ``vendor``, ``doc`` or + ``trivial`` for the issue type. +#. Unless your change is a trivial or a documentation fix (e.g., a typo or reword of a small section) please + add yourself to the ``AUTHORS`` file, in alphabetical order; -.. note:: - What is a "pull request"? It informs project's core developers about the - changes you want to review and merge. Pull requests are stored on - `GitHub servers `_. - Once you send pull request, we can discuss it's potential modifications and - even add more commits to it later on. +Long version +~~~~~~~~~~~~ -There's an excellent tutorial on how Pull Requests work in the -`GitHub Help Center `_, -but here is a simple overview: +What is a "pull request"? It informs the project's core developers about the +changes you want to review and merge. Pull requests are stored on +`GitHub servers `_. +Once you send a pull request, we can discuss its potential modifications and +even add more commits to it later on. There's an excellent tutorial on how Pull +Requests work in the +`GitHub Help Center `_. + +Here is a simple overview, with pytest-specific bits: #. Fork the `pytest GitHub repository `__. It's @@ -208,38 +228,43 @@ but here is a simple overview: #. Run all the tests - You need to have Python 2.7 and 3.5 available in your system. Now + You need to have Python 2.7 and 3.6 available in your system. Now running tests is as simple as issuing this command:: - $ python runtox.py -e linting,py27,py35 + $ tox -e linting,py27,py36 - This command will run tests via the "tox" tool against Python 2.7 and 3.5 - and also perform "lint" coding-style checks. ``runtox.py`` is - a thin wrapper around ``tox`` which installs from a development package - index where newer (not yet released to pypi) versions of dependencies - (especially ``py``) might be present. + This command will run tests via the "tox" tool against Python 2.7 and 3.6 + and also perform "lint" coding-style checks. -#. You can now edit your local working copy. +#. You can now edit your local working copy. Please follow PEP-8. You can now make the changes you want and run the tests again as necessary. - To run tests on py27 and pass options to pytest (e.g. enter pdb on failure) - to pytest you can do:: + If you have too much linting errors, try running:: - $ python runtox.py -e py27 -- --pdb + $ tox -e fix-lint - or to only run tests in a particular test module on py35:: + To fix pep8 related errors. - $ python runtox.py -e py35 -- testing/test_config.py + You can pass different options to ``tox``. For example, to run tests on Python 2.7 and pass options to pytest + (e.g. enter pdb on failure) to pytest you can do:: + + $ tox -e py27 -- --pdb + + Or to only run tests in a particular test module on Python 3.6:: + + $ tox -e py36 -- testing/test_config.py #. Commit and push once your tests pass and you are happy with your change(s):: $ git commit -a -m "" $ git push -u - Make sure you add a CHANGELOG message, and add yourself to AUTHORS. If you - are unsure about either of these steps, submit your pull request and we'll - help you fix it up. +#. Create a new changelog entry in ``changelog``. The file should be named ``.``, + where *issueid* is the number of the issue related to the change and *type* is one of + ``bugfix``, ``removal``, ``feature``, ``vendor``, ``doc`` or ``trivial``. + +#. Add yourself to ``AUTHORS`` file if not there yet, in alphabetical order. #. Finally, submit a pull request through the GitHub website using this data:: @@ -248,6 +273,6 @@ but here is a simple overview: base-fork: pytest-dev/pytest base: master # if it's a bugfix - base: feature # if it's a feature + base: features # if it's a feature diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/HOWTORELEASE.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/HOWTORELEASE.rst new file mode 100644 index 00000000000..48a3461d4bc --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/HOWTORELEASE.rst @@ -0,0 +1,65 @@ +Release Procedure +----------------- + +Our current policy for releasing is to aim for a bugfix every few weeks and a minor release every 2-3 months. The idea +is to get fixes and new features out instead of trying to cram a ton of features into a release and by consequence +taking a lot of time to make a new one. + +.. important:: + + pytest releases must be prepared on **Linux** because the docs and examples expect + to be executed in that platform. + +#. Install development dependencies in a virtual environment with:: + + pip3 install -r tasks/requirements.txt + +#. Create a branch ``release-X.Y.Z`` with the version for the release. + + * **patch releases**: from the latest ``master``; + + * **minor releases**: from the latest ``features``; then merge with the latest ``master``; + + Ensure your are in a clean work tree. + +#. Generate docs, changelog, announcements and upload a package to + your ``devpi`` staging server:: + + invoke generate.pre-release --password + + If ``--password`` is not given, it is assumed the user is already logged in ``devpi``. + If you don't have an account, please ask for one. + +#. Open a PR for this branch targeting ``master``. + +#. Test the package + + * **Manual method** + + Run from multiple machines:: + + devpi use https://devpi.net/USER/dev + devpi test pytest==VERSION + + Check that tests pass for relevant combinations with:: + + devpi list pytest + + * **CI servers** + + Configure a repository as per-instructions on + devpi-cloud-test_ to test the package on Travis_ and AppVeyor_. + All test environments should pass. + +#. Publish to PyPI:: + + invoke generate.publish-release + + where PYPI_NAME is the name of pypi.python.org as configured in your ``~/.pypirc`` + file `for devpi `_. + +#. After a minor/major release, merge ``release-X.Y.Z`` into ``master`` and push (or open a PR). + +.. _devpi-cloud-test: https://github.com/obestwalter/devpi-cloud-test +.. _AppVeyor: https://www.appveyor.com/ +.. _Travis: https://travis-ci.org diff --git a/tests/wpt/web-platform-tests/tools/pytest/LICENSE b/tests/wpt/web-platform-tests/tools/third_party/pytest/LICENSE similarity index 95% rename from tests/wpt/web-platform-tests/tools/pytest/LICENSE rename to tests/wpt/web-platform-tests/tools/third_party/pytest/LICENSE index 9e27bd78419..629df45ac40 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/LICENSE +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2004-2016 Holger Krekel and others +Copyright (c) 2004-2017 Holger Krekel and others Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/README.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/README.rst new file mode 100644 index 00000000000..3630dd4c62a --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/README.rst @@ -0,0 +1,109 @@ +.. image:: http://docs.pytest.org/en/latest/_static/pytest1.png + :target: http://docs.pytest.org + :align: center + :alt: pytest + +------ + +.. image:: https://img.shields.io/pypi/v/pytest.svg + :target: https://pypi.python.org/pypi/pytest + +.. image:: https://anaconda.org/conda-forge/pytest/badges/version.svg + :target: https://anaconda.org/conda-forge/pytest + +.. image:: https://img.shields.io/pypi/pyversions/pytest.svg + :target: https://pypi.python.org/pypi/pytest + +.. image:: https://img.shields.io/coveralls/pytest-dev/pytest/master.svg + :target: https://coveralls.io/r/pytest-dev/pytest + +.. image:: https://travis-ci.org/pytest-dev/pytest.svg?branch=master + :target: https://travis-ci.org/pytest-dev/pytest + +.. image:: https://ci.appveyor.com/api/projects/status/mrgbjaua7t33pg6b?svg=true + :target: https://ci.appveyor.com/project/pytestbot/pytest + +The ``pytest`` framework makes it easy to write small tests, yet +scales to support complex functional testing for applications and libraries. + +An example of a simple test: + +.. code-block:: python + + # content of test_sample.py + def inc(x): + return x + 1 + + def test_answer(): + assert inc(3) == 5 + + +To execute it:: + + $ pytest + ============================= test session starts ============================= + collected 1 items + + test_sample.py F + + ================================== FAILURES =================================== + _________________________________ test_answer _________________________________ + + def test_answer(): + > assert inc(3) == 5 + E assert 4 == 5 + E + where 4 = inc(3) + + test_sample.py:5: AssertionError + ========================== 1 failed in 0.04 seconds =========================== + + +Due to ``pytest``'s detailed assertion introspection, only plain ``assert`` statements are used. See `getting-started `_ for more examples. + + +Features +-------- + +- Detailed info on failing `assert statements `_ (no need to remember ``self.assert*`` names); + +- `Auto-discovery + `_ + of test modules and functions; + +- `Modular fixtures `_ for + managing small or parametrized long-lived test resources; + +- Can run `unittest `_ (or trial), + `nose `_ test suites out of the box; + +- Python 2.7, Python 3.4+, PyPy 2.3, Jython 2.5 (untested); + +- Rich plugin architecture, with over 315+ `external plugins `_ and thriving community; + + +Documentation +------------- + +For full documentation, including installation, tutorials and PDF documents, please see http://docs.pytest.org. + + +Bugs/Requests +------------- + +Please use the `GitHub issue tracker `_ to submit bugs or request features. + + +Changelog +--------- + +Consult the `Changelog `__ page for fixes and enhancements of each version. + + +License +------- + +Copyright Holger Krekel and others, 2004-2017. + +Distributed under the terms of the `MIT`_ license, pytest is free and open source software. + +.. _`MIT`: https://github.com/pytest-dev/pytest/blob/master/LICENSE diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/__init__.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/__init__.py new file mode 100644 index 00000000000..6e41f0504e4 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/__init__.py @@ -0,0 +1,8 @@ +__all__ = ['__version__'] + +try: + from ._version import version as __version__ +except ImportError: + # broken installation, we don't even try + # unknown only works because we do poor mans version compare + __version__ = 'unknown' diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/_argcomplete.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/_argcomplete.py similarity index 91% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/_argcomplete.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/_argcomplete.py index 955855a9648..0625a75f9f1 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/_argcomplete.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/_argcomplete.py @@ -4,9 +4,6 @@ needs argcomplete>=0.5.6 for python 3.2/3.3 (older versions fail to find the magic string, so _ARGCOMPLETE env. var is never set, and this does not need special code. -argcomplete does not support python 2.5 (although the changes for that -are minor). - Function try_argcomplete(parser) should be called directly before the call to ArgumentParser.parse_args(). @@ -57,26 +54,29 @@ If things do not work right away: which should throw a KeyError: 'COMPLINE' (which is properly set by the global argcomplete script). """ - +from __future__ import absolute_import, division, print_function import sys import os from glob import glob + class FastFilesCompleter: 'Fast file completer class' + def __init__(self, directories=True): self.directories = directories def __call__(self, prefix, **kwargs): """only called on non option completions""" - if os.path.sep in prefix[1:]: # + if os.path.sep in prefix[1:]: prefix_dir = len(os.path.dirname(prefix) + os.path.sep) else: prefix_dir = 0 completion = [] globbed = [] if '*' not in prefix and '?' not in prefix: - if prefix[-1] == os.path.sep: # we are on unix, otherwise no bash + # we are on unix, otherwise no bash + if not prefix or prefix[-1] == os.path.sep: globbed.extend(glob(prefix + '.*')) prefix += '*' globbed.extend(glob(prefix)) @@ -87,6 +87,7 @@ class FastFilesCompleter: completion.append(x[prefix_dir:]) return completion + if os.environ.get('_ARGCOMPLETE'): try: import argcomplete.completers @@ -95,7 +96,8 @@ if os.environ.get('_ARGCOMPLETE'): filescompleter = FastFilesCompleter() def try_argcomplete(parser): - argcomplete.autocomplete(parser) + argcomplete.autocomplete(parser, always_complete_options=False) else: - def try_argcomplete(parser): pass + def try_argcomplete(parser): + pass filescompleter = None diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/_code/__init__.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/_code/__init__.py similarity index 80% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/_code/__init__.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/_code/__init__.py index c046b9716ca..815c13b42c2 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/_code/__init__.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/_code/__init__.py @@ -1,12 +1,10 @@ """ python inspection/code generation API """ +from __future__ import absolute_import, division, print_function from .code import Code # noqa from .code import ExceptionInfo # noqa from .code import Frame # noqa from .code import Traceback # noqa from .code import getrawcode # noqa -from .code import patch_builtins # noqa -from .code import unpatch_builtins # noqa from .source import Source # noqa from .source import compile_ as compile # noqa from .source import getfslineno # noqa - diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/_code/_py2traceback.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/_code/_py2traceback.py similarity index 96% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/_code/_py2traceback.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/_code/_py2traceback.py index a830d9899ae..5aacf0a428d 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/_code/_py2traceback.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/_code/_py2traceback.py @@ -2,8 +2,10 @@ # CHANGES: # - some_str is replaced, trying to create unicode strings # +from __future__ import absolute_import, division, print_function import types + def format_exception_only(etype, value): """Format the exception part of a traceback. @@ -29,7 +31,7 @@ def format_exception_only(etype, value): # would throw another exception and mask the original problem. if (isinstance(etype, BaseException) or isinstance(etype, types.InstanceType) or - etype is None or type(etype) is str): + etype is None or type(etype) is str): return [_format_final_exc_line(etype, value)] stype = etype.__name__ @@ -61,6 +63,7 @@ def format_exception_only(etype, value): lines.append(_format_final_exc_line(stype, value)) return lines + def _format_final_exc_line(etype, value): """Return a list of a single line -- normal case for format_exception_only""" valuestr = _some_str(value) @@ -70,6 +73,7 @@ def _format_final_exc_line(etype, value): line = "%s: %s\n" % (etype, valuestr) return line + def _some_str(value): try: return unicode(value) diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/_code/code.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/_code/code.py similarity index 72% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/_code/code.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/_code/code.py index bc68aac5548..3fb232bd430 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/_code/code.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/_code/code.py @@ -1,19 +1,22 @@ +from __future__ import absolute_import, division, print_function import sys from inspect import CO_VARARGS, CO_VARKEYWORDS +import re +from weakref import ref +from _pytest.compat import _PY2, _PY3, PY35, safe_str import py - builtin_repr = repr -reprlib = py.builtin._tryimport('repr', 'reprlib') - -if sys.version_info[0] >= 3: +if _PY3: from traceback import format_exception_only else: from ._py2traceback import format_exception_only + class Code(object): """ wrapper around Python code objects """ + def __init__(self, rawcode): if not hasattr(rawcode, "co_filename"): rawcode = getrawcode(rawcode) @@ -22,12 +25,14 @@ class Code(object): self.firstlineno = rawcode.co_firstlineno - 1 self.name = rawcode.co_name except AttributeError: - raise TypeError("not a code object: %r" %(rawcode,)) + raise TypeError("not a code object: %r" % (rawcode,)) self.raw = rawcode def __eq__(self, other): return self.raw == other.raw + __hash__ = None + def __ne__(self, other): return not self == other @@ -35,12 +40,16 @@ class Code(object): def path(self): """ return a path object pointing to source code (note that it might not point to an actually existing file). """ - p = py.path.local(self.raw.co_filename) - # maybe don't try this checking - if not p.check(): + try: + p = py.path.local(self.raw.co_filename) + # maybe don't try this checking + if not p.check(): + raise OSError("py.path check failed.") + except OSError: # XXX maybe try harder like the weird logic # in the standard lib [linecache.updatecache] does? p = self.raw.co_filename + return p @property @@ -72,6 +81,7 @@ class Code(object): argcount += raw.co_flags & CO_VARKEYWORDS return raw.co_varnames[:argcount] + class Frame(object): """Wrapper around a Python frame holding f_locals and f_globals in which expressions can be evaluated.""" @@ -109,7 +119,7 @@ class Frame(object): """ f_locals = self.f_locals.copy() f_locals.update(vars) - py.builtin.exec_(code, self.f_globals, f_locals ) + py.builtin.exec_(code, self.f_globals, f_locals) def repr(self, object): """ return a 'safe' (non-recursive, one-line) string repr for 'object' @@ -133,13 +143,15 @@ class Frame(object): pass # this can occur when using Psyco return retval + class TracebackEntry(object): """ a single entry in a traceback """ _repr_style = None exprinfo = None - def __init__(self, rawentry): + def __init__(self, rawentry, excinfo=None): + self._excinfo = excinfo self._rawentry = rawentry self.lineno = rawentry.tb_lineno - 1 @@ -157,7 +169,7 @@ class TracebackEntry(object): return self.lineno - self.frame.code.firstlineno def __repr__(self): - return "" %(self.frame.code.path, self.lineno+1) + return "" % (self.frame.code.path, self.lineno + 1) @property def statement(self): @@ -174,18 +186,6 @@ class TracebackEntry(object): return self.frame.f_locals locals = property(getlocals, None, None, "locals of underlaying frame") - def reinterpret(self): - """Reinterpret the failing statement and returns a detailed information - about what operations are performed.""" - from _pytest.assertion.reinterpret import reinterpret - if self.exprinfo is None: - source = py.builtin._totext(self.statement).strip() - x = reinterpret(source, self.frame, should_fail=True) - if not py.builtin._istext(x): - raise TypeError("interpret returned non-string %r" % (x,)) - self.exprinfo = x - return self.exprinfo - def getfirstlinesource(self): # on Jython this firstlineno can be -1 apparently return max(self.frame.code.firstlineno, 0) @@ -220,16 +220,24 @@ class TracebackEntry(object): """ return True if the current frame has a var __tracebackhide__ resolving to True + If __tracebackhide__ is a callable, it gets called with the + ExceptionInfo instance and can decide whether to hide the traceback. + mostly for internal use """ try: - return self.frame.f_locals['__tracebackhide__'] + tbh = self.frame.f_locals['__tracebackhide__'] except KeyError: try: - return self.frame.f_globals['__tracebackhide__'] + tbh = self.frame.f_globals['__tracebackhide__'] except KeyError: return False + if callable(tbh): + return tbh(None if self._excinfo is None else self._excinfo()) + else: + return tbh + def __str__(self): try: fn = str(self.path) @@ -240,25 +248,28 @@ class TracebackEntry(object): line = str(self.statement).lstrip() except KeyboardInterrupt: raise - except: + except: # noqa line = "???" - return " File %r:%d in %s\n %s\n" %(fn, self.lineno+1, name, line) + return " File %r:%d in %s\n %s\n" % (fn, self.lineno + 1, name, line) def name(self): return self.frame.code.raw.co_name name = property(name, None, None, "co_name of underlaying code") + class Traceback(list): """ Traceback objects encapsulate and offer higher level access to Traceback entries. """ Entry = TracebackEntry - def __init__(self, tb): - """ initialize from given python traceback object. """ + + def __init__(self, tb, excinfo=None): + """ initialize from given python traceback object and ExceptionInfo """ + self._excinfo = excinfo if hasattr(tb, 'tb_next'): def f(cur): while cur is not None: - yield self.Entry(cur) + yield self.Entry(cur, excinfo=excinfo) cur = cur.tb_next list.__init__(self, f(tb)) else: @@ -281,8 +292,8 @@ class Traceback(list): (excludepath is None or not hasattr(codepath, 'relto') or not codepath.relto(excludepath)) and (lineno is None or x.lineno == lineno) and - (firstlineno is None or x.frame.code.firstlineno == firstlineno)): - return Traceback(x._rawentry) + (firstlineno is None or x.frame.code.firstlineno == firstlineno)): + return Traceback(x._rawentry, self._excinfo) return self def __getitem__(self, key): @@ -294,27 +305,27 @@ class Traceback(list): def filter(self, fn=lambda x: not x.ishidden()): """ return a Traceback instance with certain items removed - fn is a function that gets a single argument, a TracebackItem + fn is a function that gets a single argument, a TracebackEntry instance, and should return True when the item should be added to the Traceback, False when not - by default this removes all the TracebackItems which are hidden + by default this removes all the TracebackEntries which are hidden (see ishidden() above) """ - return Traceback(filter(fn, self)) + return Traceback(filter(fn, self), self._excinfo) def getcrashentry(self): """ return last non-hidden traceback entry that lead to the exception of a traceback. """ - for i in range(-1, -len(self)-1, -1): + for i in range(-1, -len(self) - 1, -1): entry = self[i] if not entry.ishidden(): return entry return self[-1] def recursionindex(self): - """ return the index of the frame/TracebackItem where recursion + """ return the index of the frame/TracebackEntry where recursion originates if appropriate, None if no recursion occurred """ cache = {} @@ -322,29 +333,33 @@ class Traceback(list): # id for the code.raw is needed to work around # the strange metaprogramming in the decorator lib from pypi # which generates code objects that have hash/value equality - #XXX needs a test + # XXX needs a test key = entry.frame.code.path, id(entry.frame.code.raw), entry.lineno - #print "checking for recursion at", key - l = cache.setdefault(key, []) - if l: + # print "checking for recursion at", key + values = cache.setdefault(key, []) + if values: f = entry.frame loc = f.f_locals - for otherloc in l: + for otherloc in values: if f.is_true(f.eval(co_equal, - __recursioncache_locals_1=loc, - __recursioncache_locals_2=otherloc)): + __recursioncache_locals_1=loc, + __recursioncache_locals_2=otherloc)): return i - l.append(entry.frame.f_locals) + values.append(entry.frame.f_locals) return None + co_equal = compile('__recursioncache_locals_1 == __recursioncache_locals_2', '?', 'eval') + class ExceptionInfo(object): """ wraps sys.exc_info() objects and offers help for navigating the traceback. """ _striptext = '' + _assert_start_repr = "AssertionError(u\'assert " if _PY2 else "AssertionError(\'assert " + def __init__(self, tup=None, exprinfo=None): import _pytest._code if tup is None: @@ -352,8 +367,8 @@ class ExceptionInfo(object): if exprinfo is None and isinstance(tup[1], AssertionError): exprinfo = getattr(tup[1], 'msg', None) if exprinfo is None: - exprinfo = str(tup[1]) - if exprinfo and exprinfo.startswith('assert '): + exprinfo = py.io.saferepr(tup[1]) + if exprinfo and exprinfo.startswith(self._assert_start_repr): self._striptext = 'AssertionError: ' self._excinfo = tup #: the exception class @@ -365,7 +380,7 @@ class ExceptionInfo(object): #: the exception type name self.typename = self.type.__name__ #: the exception traceback (_pytest._code.Traceback instance) - self.traceback = _pytest._code.Traceback(self.tb) + self.traceback = _pytest._code.Traceback(self.tb, excinfo=ref(self)) def __repr__(self): return "" % (self.typename, len(self.traceback)) @@ -394,10 +409,10 @@ class ExceptionInfo(object): exconly = self.exconly(tryshort=True) entry = self.traceback.getcrashentry() path, lineno = entry.frame.code.raw.co_filename, entry.lineno - return ReprFileLocation(path, lineno+1, exconly) + return ReprFileLocation(path, lineno + 1, exconly) def getrepr(self, showlocals=False, style="long", - abspath=False, tbfilter=True, funcargs=False): + abspath=False, tbfilter=True, funcargs=False): """ return str()able representation of this exception info. showlocals: show locals per traceback entry style: long|short|no|native traceback style @@ -414,7 +429,7 @@ class ExceptionInfo(object): )), self._getreprcrash()) fmt = FormattedExcinfo(showlocals=showlocals, style=style, - abspath=abspath, tbfilter=tbfilter, funcargs=funcargs) + abspath=abspath, tbfilter=tbfilter, funcargs=funcargs) return fmt.repr_excinfo(self) def __str__(self): @@ -427,6 +442,19 @@ class ExceptionInfo(object): loc = ReprFileLocation(entry.path, entry.lineno + 1, self.exconly()) return unicode(loc) + def match(self, regexp): + """ + Match the regular expression 'regexp' on the string representation of + the exception. If it matches then True is returned (so that it is + possible to write 'assert excinfo.match()'). If it doesn't match an + AssertionError is raised. + """ + __tracebackhide__ = True + if not re.search(regexp, str(self.value)): + assert 0, "Pattern '{0!s}' not found in '{1!s}'".format( + regexp, self.value) + return True + class FormattedExcinfo(object): """ presenting information about failing Functions and Generators. """ @@ -445,15 +473,15 @@ class FormattedExcinfo(object): def _getindent(self, source): # figure out indent for given source try: - s = str(source.getstatement(len(source)-1)) + s = str(source.getstatement(len(source) - 1)) except KeyboardInterrupt: raise - except: + except: # noqa try: s = str(source[-1]) except KeyboardInterrupt: raise - except: + except: # noqa return 0 return 4 + (len(s) - len(s.lstrip())) @@ -489,7 +517,7 @@ class FormattedExcinfo(object): for line in source.lines[:line_index]: lines.append(space_prefix + line) lines.append(self.flow_marker + " " + source.lines[line_index]) - for line in source.lines[line_index+1:]: + for line in source.lines[line_index + 1:]: lines.append(space_prefix + line) if excinfo is not None: indent = 4 if short else self._getindent(source) @@ -522,10 +550,10 @@ class FormattedExcinfo(object): # _repr() function, which is only reprlib.Repr in # disguise, so is very configurable. str_repr = self._saferepr(value) - #if len(str_repr) < 70 or not isinstance(value, + # if len(str_repr) < 70 or not isinstance(value, # (list, tuple, dict)): - lines.append("%-10s = %s" %(name, str_repr)) - #else: + lines.append("%-10s = %s" % (name, str_repr)) + # else: # self._line("%-10s =\\" % (name,)) # # XXX # py.std.pprint.pprint(value, stream=self.excinfowriter) @@ -551,14 +579,14 @@ class FormattedExcinfo(object): s = self.get_source(source, line_index, excinfo, short=short) lines.extend(s) if short: - message = "in %s" %(entry.name) + message = "in %s" % (entry.name) else: message = excinfo and excinfo.typename or "" path = self._makepath(entry.path) - filelocrepr = ReprFileLocation(path, entry.lineno+1, message) + filelocrepr = ReprFileLocation(path, entry.lineno + 1, message) localsrepr = None if not short: - localsrepr = self.repr_locals(entry.locals) + localsrepr = self.repr_locals(entry.locals) return ReprEntry(lines, reprargs, localsrepr, filelocrepr, style) if excinfo: lines.extend(self.get_exconly(excinfo, indent=4)) @@ -578,31 +606,91 @@ class FormattedExcinfo(object): traceback = excinfo.traceback if self.tbfilter: traceback = traceback.filter() - recursionindex = None - if excinfo.errisinstance(RuntimeError): - if "maximum recursion depth exceeded" in str(excinfo.value): - recursionindex = traceback.recursionindex() + + if is_recursion_error(excinfo): + traceback, extraline = self._truncate_recursive_traceback(traceback) + else: + extraline = None + last = traceback[-1] entries = [] - extraline = None for index, entry in enumerate(traceback): einfo = (last == entry) and excinfo or None reprentry = self.repr_traceback_entry(entry, einfo) entries.append(reprentry) - if index == recursionindex: - extraline = "!!! Recursion detected (same locals & position)" - break return ReprTraceback(entries, extraline, style=self.style) - def repr_excinfo(self, excinfo): - reprtraceback = self.repr_traceback(excinfo) - reprcrash = excinfo._getreprcrash() - return ReprExceptionInfo(reprtraceback, reprcrash) + def _truncate_recursive_traceback(self, traceback): + """ + Truncate the given recursive traceback trying to find the starting point + of the recursion. -class TerminalRepr: + The detection is done by going through each traceback entry and finding the + point in which the locals of the frame are equal to the locals of a previous frame (see ``recursionindex()``. + + Handle the situation where the recursion process might raise an exception (for example + comparing numpy arrays using equality raises a TypeError), in which case we do our best to + warn the user of the error and show a limited traceback. + """ + try: + recursionindex = traceback.recursionindex() + except Exception as e: + max_frames = 10 + extraline = ( + '!!! Recursion error detected, but an error occurred locating the origin of recursion.\n' + ' The following exception happened when comparing locals in the stack frame:\n' + ' {exc_type}: {exc_msg}\n' + ' Displaying first and last {max_frames} stack frames out of {total}.' + ).format(exc_type=type(e).__name__, exc_msg=safe_str(e), max_frames=max_frames, total=len(traceback)) + traceback = traceback[:max_frames] + traceback[-max_frames:] + else: + if recursionindex is not None: + extraline = "!!! Recursion detected (same locals & position)" + traceback = traceback[:recursionindex + 1] + else: + extraline = None + + return traceback, extraline + + def repr_excinfo(self, excinfo): + if _PY2: + reprtraceback = self.repr_traceback(excinfo) + reprcrash = excinfo._getreprcrash() + + return ReprExceptionInfo(reprtraceback, reprcrash) + else: + repr_chain = [] + e = excinfo.value + descr = None + while e is not None: + if excinfo: + reprtraceback = self.repr_traceback(excinfo) + reprcrash = excinfo._getreprcrash() + else: + # fallback to native repr if the exception doesn't have a traceback: + # ExceptionInfo objects require a full traceback to work + reprtraceback = ReprTracebackNative(py.std.traceback.format_exception(type(e), e, None)) + reprcrash = None + + repr_chain += [(reprtraceback, reprcrash, descr)] + if e.__cause__ is not None: + e = e.__cause__ + excinfo = ExceptionInfo((type(e), e, e.__traceback__)) if e.__traceback__ else None + descr = 'The above exception was the direct cause of the following exception:' + elif (e.__context__ is not None and not e.__suppress_context__): + e = e.__context__ + excinfo = ExceptionInfo((type(e), e, e.__traceback__)) if e.__traceback__ else None + descr = 'During handling of the above exception, another exception occurred:' + else: + e = None + repr_chain.reverse() + return ExceptionChainRepr(repr_chain) + + +class TerminalRepr(object): def __str__(self): s = self.__unicode__() - if sys.version_info[0] < 3: + if _PY2: s = s.encode('utf-8') return s @@ -615,24 +703,51 @@ class TerminalRepr: return io.getvalue().strip() def __repr__(self): - return "<%s instance at %0x>" %(self.__class__, id(self)) + return "<%s instance at %0x>" % (self.__class__, id(self)) -class ReprExceptionInfo(TerminalRepr): - def __init__(self, reprtraceback, reprcrash): - self.reprtraceback = reprtraceback - self.reprcrash = reprcrash +class ExceptionRepr(TerminalRepr): + def __init__(self): self.sections = [] def addsection(self, name, content, sep="-"): self.sections.append((name, content, sep)) def toterminal(self, tw): - self.reprtraceback.toterminal(tw) for name, content, sep in self.sections: tw.sep(sep, name) tw.line(content) + +class ExceptionChainRepr(ExceptionRepr): + def __init__(self, chain): + super(ExceptionChainRepr, self).__init__() + self.chain = chain + # reprcrash and reprtraceback of the outermost (the newest) exception + # in the chain + self.reprtraceback = chain[-1][0] + self.reprcrash = chain[-1][1] + + def toterminal(self, tw): + for element in self.chain: + element[0].toterminal(tw) + if element[2] is not None: + tw.line("") + tw.line(element[2], yellow=True) + super(ExceptionChainRepr, self).toterminal(tw) + + +class ReprExceptionInfo(ExceptionRepr): + def __init__(self, reprtraceback, reprcrash): + super(ReprExceptionInfo, self).__init__() + self.reprtraceback = reprtraceback + self.reprcrash = reprcrash + + def toterminal(self, tw): + self.reprtraceback.toterminal(tw) + super(ReprExceptionInfo, self).toterminal(tw) + + class ReprTraceback(TerminalRepr): entrysep = "_ " @@ -648,7 +763,7 @@ class ReprTraceback(TerminalRepr): tw.line("") entry.toterminal(tw) if i < len(self.reprentries) - 1: - next_entry = self.reprentries[i+1] + next_entry = self.reprentries[i + 1] if entry.style == "long" or \ entry.style == "short" and next_entry.style == "long": tw.sep(self.entrysep) @@ -656,12 +771,14 @@ class ReprTraceback(TerminalRepr): if self.extraline: tw.line(self.extraline) + class ReprTracebackNative(ReprTraceback): def __init__(self, tblines): self.style = "native" self.reprentries = [ReprEntryNative(tblines)] self.extraline = None + class ReprEntryNative(TerminalRepr): style = "native" @@ -671,6 +788,7 @@ class ReprEntryNative(TerminalRepr): def toterminal(self, tw): tw.write("".join(self.lines)) + class ReprEntry(TerminalRepr): localssep = "_ " @@ -687,7 +805,7 @@ class ReprEntry(TerminalRepr): for line in self.lines: red = line.startswith("E ") tw.line(line, bold=True, red=red) - #tw.line("") + # tw.line("") return if self.reprfuncargs: self.reprfuncargs.toterminal(tw) @@ -695,7 +813,7 @@ class ReprEntry(TerminalRepr): red = line.startswith("E ") tw.line(line, bold=True, red=red) if self.reprlocals: - #tw.sep(self.localssep, "Locals") + # tw.sep(self.localssep, "Locals") tw.line("") self.reprlocals.toterminal(tw) if self.reprfileloc: @@ -708,6 +826,7 @@ class ReprEntry(TerminalRepr): self.reprlocals, self.reprfileloc) + class ReprFileLocation(TerminalRepr): def __init__(self, path, lineno, message): self.path = str(path) @@ -721,7 +840,9 @@ class ReprFileLocation(TerminalRepr): i = msg.find("\n") if i != -1: msg = msg[:i] - tw.line("%s:%s: %s" %(self.path, self.lineno, msg)) + tw.write(self.path, bold=True, red=True) + tw.line(":%s: %s" % (self.lineno, msg)) + class ReprLocals(TerminalRepr): def __init__(self, lines): @@ -731,6 +852,7 @@ class ReprLocals(TerminalRepr): for line in self.lines: tw.line(line) + class ReprFuncArgs(TerminalRepr): def __init__(self, args): self.args = args @@ -739,11 +861,11 @@ class ReprFuncArgs(TerminalRepr): if self.args: linesofar = "" for name, value in self.args: - ns = "%s = %s" %(name, value) + ns = "%s = %s" % (safe_str(name), safe_str(value)) if len(ns) + len(linesofar) + 2 > tw.fullwidth: if linesofar: tw.line(linesofar) - linesofar = ns + linesofar = ns else: if linesofar: linesofar += ", " + ns @@ -754,29 +876,6 @@ class ReprFuncArgs(TerminalRepr): tw.line("") - -oldbuiltins = {} - -def patch_builtins(assertion=True, compile=True): - """ put compile and AssertionError builtins to Python's builtins. """ - if assertion: - from _pytest.assertion import reinterpret - l = oldbuiltins.setdefault('AssertionError', []) - l.append(py.builtin.builtins.AssertionError) - py.builtin.builtins.AssertionError = reinterpret.AssertionError - if compile: - import _pytest._code - l = oldbuiltins.setdefault('compile', []) - l.append(py.builtin.builtins.compile) - py.builtin.builtins.compile = _pytest._code.compile - -def unpatch_builtins(assertion=True, compile=True): - """ remove compile and AssertionError builtins from Python builtins. """ - if assertion: - py.builtin.builtins.AssertionError = oldbuiltins['AssertionError'].pop() - if compile: - py.builtin.builtins.compile = oldbuiltins['compile'].pop() - def getrawcode(obj, trycall=True): """ return code object for given function. """ try: @@ -793,3 +892,15 @@ def getrawcode(obj, trycall=True): return x return obj + +if PY35: # RecursionError introduced in 3.5 + def is_recursion_error(excinfo): + return excinfo.errisinstance(RecursionError) # noqa +else: + def is_recursion_error(excinfo): + if not excinfo.errisinstance(RuntimeError): + return False + try: + return "maximum recursion depth exceeded" in str(excinfo.value) + except UnicodeError: + return False diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/_code/source.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/_code/source.py similarity index 85% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/_code/source.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/_code/source.py index a1521f8a212..2638c598b74 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/_code/source.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/_code/source.py @@ -1,10 +1,11 @@ -from __future__ import generators +from __future__ import absolute_import, division, generators, print_function from bisect import bisect_right import sys -import inspect, tokenize +import six +import inspect +import tokenize import py -from types import ModuleType cpy_compile = compile try: @@ -20,6 +21,7 @@ class Source(object): possibly deindenting it. """ _compilecounter = 0 + def __init__(self, *parts, **kwargs): self.lines = lines = [] de = kwargs.get('deindent', True) @@ -31,7 +33,7 @@ class Source(object): partlines = part.lines elif isinstance(part, (tuple, list)): partlines = [x.rstrip("\n") for x in part] - elif isinstance(part, py.builtin._basestring): + elif isinstance(part, six.string_types): partlines = part.split('\n') if rstrip: while partlines: @@ -52,22 +54,21 @@ class Source(object): return str(self) == other return False + __hash__ = None + def __getitem__(self, key): if isinstance(key, int): return self.lines[key] else: if key.step not in (None, 1): raise IndexError("cannot slice a Source with a step") - return self.__getslice__(key.start, key.stop) + newsource = Source() + newsource.lines = self.lines[key.start:key.stop] + return newsource def __len__(self): return len(self.lines) - def __getslice__(self, start, end): - newsource = Source() - newsource.lines = self.lines[start:end] - return newsource - def strip(self): """ return new source object with trailing and leading blank lines removed. @@ -75,7 +76,7 @@ class Source(object): start, end = 0, len(self) while start < end and not self.lines[start].strip(): start += 1 - while end > start and not self.lines[end-1].strip(): + while end > start and not self.lines[end - 1].strip(): end -= 1 source = Source() source.lines[:] = self.lines[start:end] @@ -88,8 +89,8 @@ class Source(object): before = Source(before) after = Source(after) newsource = Source() - lines = [ (indent + line) for line in self.lines] - newsource.lines = before.lines + lines + after.lines + lines = [(indent + line) for line in self.lines] + newsource.lines = before.lines + lines + after.lines return newsource def indent(self, indent=' ' * 4): @@ -97,7 +98,7 @@ class Source(object): all lines indented by the given indent-string. """ newsource = Source() - newsource.lines = [(indent+line) for line in self.lines] + newsource.lines = [(indent + line) for line in self.lines] return newsource def getstatement(self, lineno, assertion=False): @@ -136,7 +137,8 @@ class Source(object): try: import parser except ImportError: - syntax_checker = lambda x: compile(x, 'asd', 'exec') + def syntax_checker(x): + return compile(x, 'asd', 'exec') else: syntax_checker = parser.suite @@ -145,8 +147,8 @@ class Source(object): else: source = str(self) try: - #compile(source+'\n', "x", "exec") - syntax_checker(source+'\n') + # compile(source+'\n', "x", "exec") + syntax_checker(source + '\n') except KeyboardInterrupt: raise except Exception: @@ -166,8 +168,8 @@ class Source(object): """ if not filename or py.path.local(filename).check(file=0): if _genframe is None: - _genframe = sys._getframe(1) # the caller - fn,lineno = _genframe.f_code.co_filename, _genframe.f_lineno + _genframe = sys._getframe(1) # the caller + fn, lineno = _genframe.f_code.co_filename, _genframe.f_lineno base = "<%d-codegen " % self._compilecounter self.__class__._compilecounter += 1 if not filename: @@ -182,7 +184,7 @@ class Source(object): # re-represent syntax errors from parsing python strings msglines = self.lines[:ex.lineno] if ex.offset: - msglines.append(" "*ex.offset + '^') + msglines.append(" " * ex.offset + '^') msglines.append("(code was compiled probably from here: %s)" % filename) newex = SyntaxError('\n'.join(msglines)) newex.offset = ex.offset @@ -193,14 +195,6 @@ class Source(object): if flag & _AST_FLAG: return co lines = [(x + "\n") for x in self.lines] - if sys.version_info[0] >= 3: - # XXX py3's inspect.getsourcefile() checks for a module - # and a pep302 __loader__ ... we don't have a module - # at code compile-time so we need to fake it here - m = ModuleType("_pycodecompile_pseudo_module") - py.std.inspect.modulesbyfile[filename] = None - py.std.sys.modules[None] = m - m.__loader__ = 1 py.std.linecache.cache[filename] = (1, None, lines, filename) return co @@ -208,8 +202,8 @@ class Source(object): # public API shortcut functions # -def compile_(source, filename=None, mode='exec', flags= - generators.compiler_flag, dont_inherit=0): + +def compile_(source, filename=None, mode='exec', flags=generators.compiler_flag, dont_inherit=0): """ compile the given source to a raw code object, and maintain an internal cache which allows later retrieval of the source code for the code object @@ -218,7 +212,7 @@ def compile_(source, filename=None, mode='exec', flags= if _ast is not None and isinstance(source, _ast.AST): # XXX should Source support having AST? return cpy_compile(source, filename, mode, flags, dont_inherit) - _genframe = sys._getframe(1) # the caller + _genframe = sys._getframe(1) # the caller s = Source(source) co = s.compile(filename, mode, flags, _genframe=_genframe) return co @@ -255,17 +249,19 @@ def getfslineno(obj): # helper functions # + def findsource(obj): try: sourcelines, lineno = py.std.inspect.findsource(obj) except py.builtin._sysex: raise - except: + except: # noqa return None, -1 source = Source() source.lines = [line.rstrip() for line in sourcelines] return source, lineno + def getsource(obj, **kwargs): import _pytest._code obj = _pytest._code.getrawcode(obj) @@ -276,19 +272,21 @@ def getsource(obj, **kwargs): assert isinstance(strsrc, str) return Source(strsrc, **kwargs) + def deindent(lines, offset=None): if offset is None: for line in lines: line = line.expandtabs() s = line.lstrip() if s: - offset = len(line)-len(s) + offset = len(line) - len(s) break else: offset = 0 if offset == 0: return list(lines) newlines = [] + def readline_generator(lines): for line in lines: yield line + '\n' @@ -300,11 +298,11 @@ def deindent(lines, offset=None): try: for _, _, (sline, _), (eline, _), _ in tokenize.generate_tokens(lambda: next(it)): if sline > len(lines): - break # End of input reached + break # End of input reached if sline > len(newlines): line = lines[sline - 1].expandtabs() if line.lstrip() and line[:offset].isspace(): - line = line[offset:] # Deindent + line = line[offset:] # Deindent newlines.append(line) for i in range(sline, eline): @@ -322,30 +320,28 @@ def get_statement_startend2(lineno, node): import ast # flatten all statements and except handlers into one lineno-list # AST's line numbers start indexing at 1 - l = [] + values = [] for x in ast.walk(node): if isinstance(x, _ast.stmt) or isinstance(x, _ast.ExceptHandler): - l.append(x.lineno - 1) + values.append(x.lineno - 1) for name in "finalbody", "orelse": val = getattr(x, name, None) if val: # treat the finally/orelse part as its own statement - l.append(val[0].lineno - 1 - 1) - l.sort() - insert_index = bisect_right(l, lineno) - start = l[insert_index - 1] - if insert_index >= len(l): + values.append(val[0].lineno - 1 - 1) + values.sort() + insert_index = bisect_right(values, lineno) + start = values[insert_index - 1] + if insert_index >= len(values): end = None else: - end = l[insert_index] + end = values[insert_index] return start, end def getstatementrange_ast(lineno, source, assertion=False, astnode=None): if astnode is None: content = str(source) - if sys.version_info < (2,7): - content += "\n" try: astnode = compile(content, "source", "exec", 1024) # 1024 for AST except ValueError: @@ -400,7 +396,7 @@ def getstatementrange_old(lineno, source, assertion=False): raise IndexError("likely a subclass") if "assert" not in line and "raise" not in line: continue - trylines = source.lines[start:lineno+1] + trylines = source.lines[start:lineno + 1] # quick hack to prepare parsing an indented line with # compile_command() (which errors on "return" outside defs) trylines.insert(0, 'def xxx():') @@ -412,10 +408,8 @@ def getstatementrange_old(lineno, source, assertion=False): continue # 2. find the end of the statement - for end in range(lineno+1, len(source)+1): + for end in range(lineno + 1, len(source) + 1): trysource = source[start:end] if trysource.isparseable(): return start, end raise SyntaxError("no valid source range around line %d " % (lineno,)) - - diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/assertion/__init__.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/assertion/__init__.py new file mode 100644 index 00000000000..a48e98c85aa --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/assertion/__init__.py @@ -0,0 +1,146 @@ +""" +support for presenting detailed information in failing assertions. +""" +from __future__ import absolute_import, division, print_function +import sys +import six + +from _pytest.assertion import util +from _pytest.assertion import rewrite +from _pytest.assertion import truncate + + +def pytest_addoption(parser): + group = parser.getgroup("debugconfig") + group.addoption('--assert', + action="store", + dest="assertmode", + choices=("rewrite", "plain",), + default="rewrite", + metavar="MODE", + help="""Control assertion debugging tools. 'plain' + performs no assertion debugging. 'rewrite' + (the default) rewrites assert statements in + test modules on import to provide assert + expression information.""") + + +def register_assert_rewrite(*names): + """Register one or more module names to be rewritten on import. + + This function will make sure that this module or all modules inside + the package will get their assert statements rewritten. + Thus you should make sure to call this before the module is + actually imported, usually in your __init__.py if you are a plugin + using a package. + + :raise TypeError: if the given module names are not strings. + """ + for name in names: + if not isinstance(name, str): + msg = 'expected module names as *args, got {0} instead' + raise TypeError(msg.format(repr(names))) + for hook in sys.meta_path: + if isinstance(hook, rewrite.AssertionRewritingHook): + importhook = hook + break + else: + importhook = DummyRewriteHook() + importhook.mark_rewrite(*names) + + +class DummyRewriteHook(object): + """A no-op import hook for when rewriting is disabled.""" + + def mark_rewrite(self, *names): + pass + + +class AssertionState: + """State for the assertion plugin.""" + + def __init__(self, config, mode): + self.mode = mode + self.trace = config.trace.root.get("assertion") + self.hook = None + + +def install_importhook(config): + """Try to install the rewrite hook, raise SystemError if it fails.""" + # Jython has an AST bug that make the assertion rewriting hook malfunction. + if (sys.platform.startswith('java')): + raise SystemError('rewrite not supported') + + config._assertstate = AssertionState(config, 'rewrite') + config._assertstate.hook = hook = rewrite.AssertionRewritingHook(config) + sys.meta_path.insert(0, hook) + config._assertstate.trace('installed rewrite import hook') + + def undo(): + hook = config._assertstate.hook + if hook is not None and hook in sys.meta_path: + sys.meta_path.remove(hook) + + config.add_cleanup(undo) + return hook + + +def pytest_collection(session): + # this hook is only called when test modules are collected + # so for example not in the master process of pytest-xdist + # (which does not collect test modules) + assertstate = getattr(session.config, '_assertstate', None) + if assertstate: + if assertstate.hook is not None: + assertstate.hook.set_session(session) + + +def pytest_runtest_setup(item): + """Setup the pytest_assertrepr_compare hook + + The newinterpret and rewrite modules will use util._reprcompare if + it exists to use custom reporting via the + pytest_assertrepr_compare hook. This sets up this custom + comparison for the test. + """ + def callbinrepr(op, left, right): + """Call the pytest_assertrepr_compare hook and prepare the result + + This uses the first result from the hook and then ensures the + following: + * Overly verbose explanations are truncated unless configured otherwise + (eg. if running in verbose mode). + * Embedded newlines are escaped to help util.format_explanation() + later. + * If the rewrite mode is used embedded %-characters are replaced + to protect later % formatting. + + The result can be formatted by util.format_explanation() for + pretty printing. + """ + hook_result = item.ihook.pytest_assertrepr_compare( + config=item.config, op=op, left=left, right=right) + for new_expl in hook_result: + if new_expl: + new_expl = truncate.truncate_if_required(new_expl, item) + new_expl = [line.replace("\n", "\\n") for line in new_expl] + res = six.text_type("\n~").join(new_expl) + if item.config.getvalue("assertmode") == "rewrite": + res = res.replace("%", "%%") + return res + util._reprcompare = callbinrepr + + +def pytest_runtest_teardown(item): + util._reprcompare = None + + +def pytest_sessionfinish(session): + assertstate = getattr(session.config, '_assertstate', None) + if assertstate: + if assertstate.hook is not None: + assertstate.hook.set_session(None) + + +# Expose this plugin's implementation for the pytest_assertrepr_compare hook +pytest_assertrepr_compare = util.assertrepr_compare diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/assertion/rewrite.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/assertion/rewrite.py similarity index 86% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/assertion/rewrite.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/assertion/rewrite.py index 14b8e49db2b..f64358f490b 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/assertion/rewrite.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/assertion/rewrite.py @@ -1,12 +1,14 @@ """Rewrite assertion AST to produce nice error messages""" - +from __future__ import absolute_import, division, print_function import ast +import _ast import errno import itertools import imp import marshal import os import re +import six import struct import sys import types @@ -32,32 +34,32 @@ else: PYC_EXT = ".py" + (__debug__ and "c" or "o") PYC_TAIL = "." + PYTEST_TAG + PYC_EXT -REWRITE_NEWLINES = sys.version_info[:2] != (2, 7) and sys.version_info < (3, 2) ASCII_IS_DEFAULT_ENCODING = sys.version_info[0] < 3 -if sys.version_info >= (3,5): +if sys.version_info >= (3, 5): ast_Call = ast.Call else: - ast_Call = lambda a,b,c: ast.Call(a, b, c, None, None) + def ast_Call(a, b, c): + return ast.Call(a, b, c, None, None) class AssertionRewritingHook(object): """PEP302 Import hook which rewrites asserts.""" - def __init__(self): + def __init__(self, config): + self.config = config + self.fnpats = config.getini("python_files") self.session = None self.modules = {} + self._rewritten_names = set() self._register_with_pkg_resources() + self._must_rewrite = set() def set_session(self, session): - self.fnpats = session.config.getini("python_files") self.session = session def find_module(self, name, path=None): - if self.session is None: - return None - sess = self.session - state = sess.config._assertstate + state = self.config._assertstate state.trace("find_module called for: %s" % name) names = name.rsplit(".", 1) lastname = names[-1] @@ -78,7 +80,12 @@ class AssertionRewritingHook(object): tp = desc[2] if tp == imp.PY_COMPILED: if hasattr(imp, "source_from_cache"): - fn = imp.source_from_cache(fn) + try: + fn = imp.source_from_cache(fn) + except ValueError: + # Python 3 doesn't like orphaned but still-importable + # .pyc files. + fn = fn[:-1] else: fn = fn[:-1] elif tp != imp.PY_SOURCE: @@ -86,24 +93,13 @@ class AssertionRewritingHook(object): return None else: fn = os.path.join(pth, name.rpartition(".")[2] + ".py") + fn_pypath = py.path.local(fn) - # Is this a test file? - if not sess.isinitpath(fn): - # We have to be very careful here because imports in this code can - # trigger a cycle. - self.session = None - try: - for pat in self.fnpats: - if fn_pypath.fnmatch(pat): - state.trace("matched test file %r" % (fn,)) - break - else: - return None - finally: - self.session = sess - else: - state.trace("matched test file (was specified on cmdline): %r" % - (fn,)) + if not self._should_rewrite(name, fn_pypath, state): + return None + + self._rewritten_names.add(name) + # The requested module looks like a test file, so rewrite it. This is # the most magical part of the process: load the source, rewrite the # asserts, and load the rewritten source. We also cache the rewritten @@ -140,7 +136,7 @@ class AssertionRewritingHook(object): co = _read_pyc(fn_pypath, pyc, state.trace) if co is None: state.trace("rewriting %r" % (fn,)) - source_stat, co = _rewrite_test(state, fn_pypath) + source_stat, co = _rewrite_test(self.config, fn_pypath) if co is None: # Probably a SyntaxError in the test. return None @@ -151,6 +147,51 @@ class AssertionRewritingHook(object): self.modules[name] = co, pyc return self + def _should_rewrite(self, name, fn_pypath, state): + # always rewrite conftest files + fn = str(fn_pypath) + if fn_pypath.basename == 'conftest.py': + state.trace("rewriting conftest file: %r" % (fn,)) + return True + + if self.session is not None: + if self.session.isinitpath(fn): + state.trace("matched test file (was specified on cmdline): %r" % + (fn,)) + return True + + # modules not passed explicitly on the command line are only + # rewritten if they match the naming convention for test files + for pat in self.fnpats: + if fn_pypath.fnmatch(pat): + state.trace("matched test file %r" % (fn,)) + return True + + for marked in self._must_rewrite: + if name == marked or name.startswith(marked + '.'): + state.trace("matched marked file %r (from %r)" % (name, marked)) + return True + + return False + + def mark_rewrite(self, *names): + """Mark import names as needing to be rewritten. + + The named module or package as well as any nested modules will + be rewritten on import. + """ + already_imported = set(names).intersection(set(sys.modules)) + if already_imported: + for name in already_imported: + if name not in self._rewritten_names: + self._warn_already_imported(name) + self._must_rewrite.update(names) + + def _warn_already_imported(self, name): + self.config.warn( + 'P1', + 'Module already imported so cannot be rewritten: %s' % name) + def load_module(self, name): # If there is an existing module object named 'fullname' in # sys.modules, the loader must use that existing module. (Otherwise, @@ -169,13 +210,12 @@ class AssertionRewritingHook(object): mod.__cached__ = pyc mod.__loader__ = self py.builtin.exec_(co, mod.__dict__) - except: - del sys.modules[name] + except: # noqa + if name in sys.modules: + del sys.modules[name] raise return sys.modules[name] - - def is_package(self, name): try: fd, fn, desc = imp.find_module(name) @@ -220,7 +260,7 @@ def _write_pyc(state, co, source_stat, pyc): fp = open(pyc, "wb") except IOError: err = sys.exc_info()[1].errno - state.trace("error writing pyc file at %s: errno=%s" %(pyc, err)) + state.trace("error writing pyc file at %s: errno=%s" % (pyc, err)) # we ignore any failure to write the cache file # there are many reasons, permission-denied, __pycache__ being a # file etc. @@ -235,14 +275,17 @@ def _write_pyc(state, co, source_stat, pyc): fp.close() return True + RN = "\r\n".encode("utf-8") N = "\n".encode("utf-8") cookie_re = re.compile(r"^[ \t\f]*#.*coding[:=][ \t]*[-\w.]+") BOM_UTF8 = '\xef\xbb\xbf' -def _rewrite_test(state, fn): + +def _rewrite_test(config, fn): """Try to read and rewrite *fn* and return the code object.""" + state = config._assertstate try: stat = fn.stat() source = fn.read("rb") @@ -264,7 +307,7 @@ def _rewrite_test(state, fn): end2 = source.find("\n", end1 + 1) if (not source.startswith(BOM_UTF8) and cookie_re.match(source[0:end1]) is None and - cookie_re.match(source[end1 + 1:end2]) is None): + cookie_re.match(source[end1 + 1:end2]) is None): if hasattr(state, "_indecode"): # encodings imported us again, so don't rewrite. return None, None @@ -277,19 +320,15 @@ def _rewrite_test(state, fn): return None, None finally: del state._indecode - # On Python versions which are not 2.7 and less than or equal to 3.1, the - # parser expects *nix newlines. - if REWRITE_NEWLINES: - source = source.replace(RN, N) + N try: tree = ast.parse(source) except SyntaxError: # Let this pop up again in the real import. state.trace("failed to parse: %r" % (fn,)) return None, None - rewrite_asserts(tree) + rewrite_asserts(tree, fn, config) try: - co = compile(tree, fn.strpath, "exec") + co = compile(tree, fn.strpath, "exec", dont_inherit=True) except SyntaxError: # It's possible that this error is from some bug in the # assertion rewriting, but I don't know of a fast way to tell. @@ -297,6 +336,7 @@ def _rewrite_test(state, fn): return None, None return stat, co + def _make_rewritten_pyc(state, source_stat, pyc, co): """Try to dump rewritten code to *pyc*.""" if sys.platform.startswith("win"): @@ -310,6 +350,7 @@ def _make_rewritten_pyc(state, source_stat, pyc, co): if _write_pyc(state, co, source_stat, proc_pyc): os.rename(proc_pyc, pyc) + def _read_pyc(source, pyc, trace=lambda x: None): """Possibly read a pytest pyc containing rewritten code. @@ -343,9 +384,9 @@ def _read_pyc(source, pyc, trace=lambda x: None): return co -def rewrite_asserts(mod): +def rewrite_asserts(mod, module_path=None, config=None): """Rewrite the assert statements in mod.""" - AssertionRewriter().run(mod) + AssertionRewriter(module_path, config).run(mod) def _saferepr(obj): @@ -360,14 +401,15 @@ def _saferepr(obj): """ repr = py.io.saferepr(obj) - if py.builtin._istext(repr): - t = py.builtin.text + if isinstance(repr, six.text_type): + t = six.text_type else: - t = py.builtin.bytes + t = six.binary_type return repr.replace(t("\n"), t("\\n")) -from _pytest.assertion.util import format_explanation as _format_explanation # noqa +from _pytest.assertion.util import format_explanation as _format_explanation # noqa + def _format_assertmsg(obj): """Format the custom assertion message given. @@ -381,32 +423,35 @@ def _format_assertmsg(obj): # contains a newline it gets escaped, however if an object has a # .__repr__() which contains newlines it does not get escaped. # However in either case we want to preserve the newline. - if py.builtin._istext(obj) or py.builtin._isbytes(obj): + if isinstance(obj, six.text_type) or isinstance(obj, six.binary_type): s = obj is_repr = False else: s = py.io.saferepr(obj) is_repr = True - if py.builtin._istext(s): - t = py.builtin.text + if isinstance(s, six.text_type): + t = six.text_type else: - t = py.builtin.bytes + t = six.binary_type s = s.replace(t("\n"), t("\n~")).replace(t("%"), t("%%")) if is_repr: s = s.replace(t("\\n"), t("\n~")) return s + def _should_repr_global_name(obj): - return not hasattr(obj, "__name__") and not py.builtin.callable(obj) + return not hasattr(obj, "__name__") and not callable(obj) + def _format_boolop(explanations, is_or): explanation = "(" + (is_or and " or " or " and ").join(explanations) + ")" - if py.builtin._istext(explanation): - t = py.builtin.text + if isinstance(explanation, six.text_type): + t = six.text_type else: - t = py.builtin.bytes + t = six.binary_type return explanation.replace(t('%'), t('%%')) + def _call_reprcompare(ops, results, expls, each_obj): for i, res, expl in zip(range(len(ops)), results, expls): try: @@ -440,7 +485,7 @@ binop_map = { ast.Mult: "*", ast.Div: "/", ast.FloorDiv: "//", - ast.Mod: "%%", # escaped for string formatting + ast.Mod: "%%", # escaped for string formatting ast.Eq: "==", ast.NotEq: "!=", ast.Lt: "<", @@ -484,7 +529,7 @@ class AssertionRewriter(ast.NodeVisitor): """Assertion rewriting implementation. The main entrypoint is to call .run() with an ast.Module instance, - this will then find all the assert statements and re-write them to + this will then find all the assert statements and rewrite them to provide intermediate values and a detailed assertion error. See http://pybites.blogspot.be/2011/07/behind-scenes-of-pytests-new-assertion.html for an overview of how this works. @@ -493,7 +538,7 @@ class AssertionRewriter(ast.NodeVisitor): statements in an ast.Module and for each ast.Assert statement it finds call .visit() with it. Then .visit_Assert() takes over and is responsible for creating new ast statements to replace the - original assert statement: it re-writes the test of an assertion + original assert statement: it rewrites the test of an assertion to provide intermediate values and replace it with an if statement which raises an assertion error with a detailed explanation in case the expression is false. @@ -532,6 +577,11 @@ class AssertionRewriter(ast.NodeVisitor): """ + def __init__(self, module_path, config): + super(AssertionRewriter, self).__init__() + self.module_path = module_path + self.config = config + def run(self, mod): """Find all assert statements in *mod* and rewrite them.""" if not mod.body: @@ -541,23 +591,26 @@ class AssertionRewriter(ast.NodeVisitor): # docstrings and __future__ imports. aliases = [ast.alias(py.builtin.builtins.__name__, "@py_builtins"), ast.alias("_pytest.assertion.rewrite", "@pytest_ar")] - expect_docstring = True + doc = getattr(mod, "docstring", None) + expect_docstring = doc is None + if doc is not None and self.is_rewrite_disabled(doc): + return pos = 0 - lineno = 0 + lineno = 1 for item in mod.body: if (expect_docstring and isinstance(item, ast.Expr) and isinstance(item.value, ast.Str)): doc = item.value.s - if "PYTEST_DONT_REWRITE" in doc: - # The module has disabled assertion rewriting. + if self.is_rewrite_disabled(doc): return - lineno += len(doc) - 1 expect_docstring = False elif (not isinstance(item, ast.ImportFrom) or item.level > 0 or item.module != "__future__"): lineno = item.lineno break pos += 1 + else: + lineno = item.lineno imports = [ast.Import([alias], lineno=lineno, col_offset=0) for alias in aliases] mod.body[pos:pos] = imports @@ -583,6 +636,9 @@ class AssertionRewriter(ast.NodeVisitor): not isinstance(field, ast.expr)): nodes.append(field) + def is_rewrite_disabled(self, docstring): + return "PYTEST_DONT_REWRITE" in docstring + def variable(self): """Get a new variable.""" # Use a character invalid in python identifiers to avoid clashing. @@ -666,12 +722,16 @@ class AssertionRewriter(ast.NodeVisitor): def visit_Assert(self, assert_): """Return the AST statements to replace the ast.Assert instance. - This re-writes the test of an assertion to provide + This rewrites the test of an assertion to provide intermediate values and replace it with an if statement which raises an assertion error with a detailed explanation in case the expression is false. """ + if isinstance(assert_.test, ast.Tuple) and self.config is not None: + fslocation = (self.module_path, assert_.lineno) + self.config.warn('R1', 'assertion is always true, perhaps ' + 'remove parentheses?', fslocation=fslocation) self.statements = [] self.variables = [] self.variable_counter = itertools.count() @@ -735,7 +795,7 @@ class AssertionRewriter(ast.NodeVisitor): if i: fail_inner = [] # cond is set in a prior loop iteration below - self.on_failure.append(ast.If(cond, fail_inner, [])) # noqa + self.on_failure.append(ast.If(cond, fail_inner, [])) # noqa self.on_failure = fail_inner self.push_format_context() res, expl = self.visit(v) @@ -787,7 +847,7 @@ class AssertionRewriter(ast.NodeVisitor): new_kwargs.append(ast.keyword(keyword.arg, res)) if keyword.arg: arg_expls.append(keyword.arg + "=" + expl) - else: ## **args have `arg` keywords with an .arg of None + else: # **args have `arg` keywords with an .arg of None arg_expls.append("**" + expl) expl = "%s(%s)" % (func_expl, ', '.join(arg_expls)) @@ -841,7 +901,6 @@ class AssertionRewriter(ast.NodeVisitor): else: visit_Call = visit_Call_legacy - def visit_Attribute(self, attr): if not isinstance(attr.ctx, ast.Load): return self.generic_visit(attr) @@ -855,6 +914,8 @@ class AssertionRewriter(ast.NodeVisitor): def visit_Compare(self, comp): self.push_format_context() left_res, left_expl = self.visit(comp.left) + if isinstance(comp.left, (_ast.Compare, _ast.BoolOp)): + left_expl = "({0})".format(left_expl) res_variables = [self.variable() for i in range(len(comp.ops))] load_names = [ast.Name(v, ast.Load()) for v in res_variables] store_names = [ast.Name(v, ast.Store()) for v in res_variables] @@ -864,6 +925,8 @@ class AssertionRewriter(ast.NodeVisitor): results = [left_res] for i, op, next_operand in it: next_res, next_expl = self.visit(next_operand) + if isinstance(next_operand, (_ast.Compare, _ast.BoolOp)): + next_expl = "({0})".format(next_expl) results.append(next_res) sym = binop_map[op.__class__] syms.append(ast.Str(sym)) diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/assertion/truncate.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/assertion/truncate.py new file mode 100644 index 00000000000..2ed12e2e5a9 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/assertion/truncate.py @@ -0,0 +1,102 @@ +""" +Utilities for truncating assertion output. + +Current default behaviour is to truncate assertion explanations at +~8 terminal lines, unless running in "-vv" mode or running on CI. +""" +from __future__ import absolute_import, division, print_function +import os + +import six + + +DEFAULT_MAX_LINES = 8 +DEFAULT_MAX_CHARS = 8 * 80 +USAGE_MSG = "use '-vv' to show" + + +def truncate_if_required(explanation, item, max_length=None): + """ + Truncate this assertion explanation if the given test item is eligible. + """ + if _should_truncate_item(item): + return _truncate_explanation(explanation) + return explanation + + +def _should_truncate_item(item): + """ + Whether or not this test item is eligible for truncation. + """ + verbose = item.config.option.verbose + return verbose < 2 and not _running_on_ci() + + +def _running_on_ci(): + """Check if we're currently running on a CI system.""" + env_vars = ['CI', 'BUILD_NUMBER'] + return any(var in os.environ for var in env_vars) + + +def _truncate_explanation(input_lines, max_lines=None, max_chars=None): + """ + Truncate given list of strings that makes up the assertion explanation. + + Truncates to either 8 lines, or 640 characters - whichever the input reaches + first. The remaining lines will be replaced by a usage message. + """ + + if max_lines is None: + max_lines = DEFAULT_MAX_LINES + if max_chars is None: + max_chars = DEFAULT_MAX_CHARS + + # Check if truncation required + input_char_count = len("".join(input_lines)) + if len(input_lines) <= max_lines and input_char_count <= max_chars: + return input_lines + + # Truncate first to max_lines, and then truncate to max_chars if max_chars + # is exceeded. + truncated_explanation = input_lines[:max_lines] + truncated_explanation = _truncate_by_char_count(truncated_explanation, max_chars) + + # Add ellipsis to final line + truncated_explanation[-1] = truncated_explanation[-1] + "..." + + # Append useful message to explanation + truncated_line_count = len(input_lines) - len(truncated_explanation) + truncated_line_count += 1 # Account for the part-truncated final line + msg = '...Full output truncated' + if truncated_line_count == 1: + msg += ' ({0} line hidden)'.format(truncated_line_count) + else: + msg += ' ({0} lines hidden)'.format(truncated_line_count) + msg += ", {0}" .format(USAGE_MSG) + truncated_explanation.extend([ + six.text_type(""), + six.text_type(msg), + ]) + return truncated_explanation + + +def _truncate_by_char_count(input_lines, max_chars): + # Check if truncation required + if len("".join(input_lines)) <= max_chars: + return input_lines + + # Find point at which input length exceeds total allowed length + iterated_char_count = 0 + for iterated_index, input_line in enumerate(input_lines): + if iterated_char_count + len(input_line) > max_chars: + break + iterated_char_count += len(input_line) + + # Create truncated explanation with modified final line + truncated_result = input_lines[:iterated_index] + final_line = input_lines[iterated_index] + if final_line: + final_line_truncate_point = max_chars - iterated_char_count + final_line = final_line[:final_line_truncate_point] + truncated_result.append(final_line) + return truncated_result diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/assertion/util.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/assertion/util.py similarity index 82% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/assertion/util.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/assertion/util.py index f2f23efea27..511d98ef1fd 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/assertion/util.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/assertion/util.py @@ -1,15 +1,17 @@ """Utilities for assertion debugging""" +from __future__ import absolute_import, division, print_function import pprint import _pytest._code import py +import six try: from collections import Sequence except ImportError: Sequence = list -BuiltinAssertionError = py.builtin.builtins.AssertionError -u = py.builtin._totext + +u = six.text_type # The _reprcompare attribute on the util module is used by the new assertion # interpretation code and assertion rewriter to detect this plugin was @@ -38,44 +40,11 @@ def format_explanation(explanation): displaying diffs. """ explanation = ecu(explanation) - explanation = _collapse_false(explanation) lines = _split_explanation(explanation) result = _format_lines(lines) return u('\n').join(result) -def _collapse_false(explanation): - """Collapse expansions of False - - So this strips out any "assert False\n{where False = ...\n}" - blocks. - """ - where = 0 - while True: - start = where = explanation.find("False\n{False = ", where) - if where == -1: - break - level = 0 - prev_c = explanation[start] - for i, c in enumerate(explanation[start:]): - if prev_c + c == "\n{": - level += 1 - elif prev_c + c == "\n}": - level -= 1 - if not level: - break - prev_c = c - else: - raise AssertionError("unbalanced braces: %r" % (explanation,)) - end = start + i - where = end - if explanation[end - 1] == '\n': - explanation = (explanation[:start] + explanation[start+15:end-1] + - explanation[end+1:]) - where -= 17 - return explanation - - def _split_explanation(explanation): """Return a list of individual lines in the explanation @@ -85,11 +54,11 @@ def _split_explanation(explanation): """ raw_lines = (explanation or u('')).split('\n') lines = [raw_lines[0]] - for l in raw_lines[1:]: - if l and l[0] in ['{', '}', '~', '>']: - lines.append(l) + for values in raw_lines[1:]: + if values and values[0] in ['{', '}', '~', '>']: + lines.append(values) else: - lines[-1] += '\\n' + l + lines[-1] += '\\n' + values return lines @@ -114,7 +83,7 @@ def _format_lines(lines): stack.append(len(result)) stackcnt[-1] += 1 stackcnt.append(0) - result.append(u(' +') + u(' ')*(len(stack)-1) + s + line[1:]) + result.append(u(' +') + u(' ') * (len(stack) - 1) + s + line[1:]) elif line.startswith('}'): stack.pop() stackcnt.pop() @@ -123,7 +92,7 @@ def _format_lines(lines): assert line[0] in ['~', '>'] stack[-1] += 1 indent = len(stack) if line.startswith('~') else len(stack) - 1 - result.append(u(' ')*indent + line[1:]) + result.append(u(' ') * indent + line[1:]) assert len(stack) == 1 return result @@ -138,16 +107,22 @@ except NameError: def assertrepr_compare(config, op, left, right): """Return specialised explanations for some operators/operands""" width = 80 - 15 - len(op) - 2 # 15 chars indentation, 1 space around op - left_repr = py.io.saferepr(left, maxsize=int(width/2)) - right_repr = py.io.saferepr(right, maxsize=width-len(left_repr)) + left_repr = py.io.saferepr(left, maxsize=int(width // 2)) + right_repr = py.io.saferepr(right, maxsize=width - len(left_repr)) summary = u('%s %s %s') % (ecu(left_repr), op, ecu(right_repr)) - issequence = lambda x: (isinstance(x, (list, tuple, Sequence)) and - not isinstance(x, basestring)) - istext = lambda x: isinstance(x, basestring) - isdict = lambda x: isinstance(x, dict) - isset = lambda x: isinstance(x, (set, frozenset)) + def issequence(x): + return (isinstance(x, (list, tuple, Sequence)) and not isinstance(x, basestring)) + + def istext(x): + return isinstance(x, basestring) + + def isdict(x): + return isinstance(x, dict) + + def isset(x): + return isinstance(x, (set, frozenset)) def isiterable(obj): try: @@ -200,9 +175,9 @@ def _diff_text(left, right, verbose=False): """ from difflib import ndiff explanation = [] - if isinstance(left, py.builtin.bytes): + if isinstance(left, six.binary_type): left = u(repr(left)[1:-1]).replace(r'\n', '\n') - if isinstance(right, py.builtin.bytes): + if isinstance(right, six.binary_type): right = u(repr(right)[1:-1]).replace(r'\n', '\n') if not verbose: i = 0 # just in case left or right has zero length @@ -225,9 +200,10 @@ def _diff_text(left, right, verbose=False): 'characters in diff, use -v to show') % i] left = left[:-i] right = right[:-i] + keepends = True explanation += [line.strip('\n') - for line in ndiff(left.splitlines(), - right.splitlines())] + for line in ndiff(left.splitlines(keepends), + right.splitlines(keepends))] return explanation @@ -288,8 +264,8 @@ def _compare_eq_dict(left, right, verbose=False): explanation = [] common = set(left).intersection(set(right)) same = dict((k, left[k]) for k in common if left[k] == right[k]) - if same and not verbose: - explanation += [u('Omitting %s identical items, use -v to show') % + if same and verbose < 2: + explanation += [u('Omitting %s identical items, use -vv to show') % len(same)] elif same: explanation += [u('Common items:')] @@ -316,7 +292,7 @@ def _compare_eq_dict(left, right, verbose=False): def _notin_text(term, text, verbose=False): index = text.find(term) head = text[:index] - tail = text[index+len(term):] + tail = text[index + len(term):] correct_text = head + tail diff = _diff_text(correct_text, text, verbose) newdiff = [u('%s is contained here:') % py.io.saferepr(term, maxsize=42)] diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/cacheprovider.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/cacheprovider.py similarity index 81% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/cacheprovider.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/cacheprovider.py index 0657001f2d4..c537c14472b 100755 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/cacheprovider.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/cacheprovider.py @@ -1,20 +1,21 @@ """ merged implementation of the cache provider -the name cache was not choosen to ensure pluggy automatically +the name cache was not chosen to ensure pluggy automatically ignores the external pytest-cache """ - +from __future__ import absolute_import, division, print_function import py import pytest import json +import os from os.path import sep as _sep, altsep as _altsep class Cache(object): def __init__(self, config): self.config = config - self._cachedir = config.rootdir.join(".cache") + self._cachedir = Cache.cache_dir_from_config(config) self.trace = config.trace.root.get("cache") if config.getvalue("cacheclear"): self.trace("clearing cachedir") @@ -22,6 +23,16 @@ class Cache(object): self._cachedir.remove() self._cachedir.mkdir() + @staticmethod + def cache_dir_from_config(config): + cache_dir = config.getini("cache_dir") + cache_dir = os.path.expanduser(cache_dir) + cache_dir = os.path.expandvars(cache_dir) + if os.path.isabs(cache_dir): + return py.path.local(cache_dir) + else: + return config.rootdir.join(cache_dir) + def makedir(self, name): """ return a directory path object with the given name. If the directory does not yet exist, it will be created. You can use it @@ -89,31 +100,31 @@ class Cache(object): class LFPlugin: """ Plugin which implements the --lf (run last-failing) option """ + def __init__(self, config): self.config = config active_keys = 'lf', 'failedfirst' self.active = any(config.getvalue(key) for key in active_keys) - if self.active: - self.lastfailed = config.cache.get("cache/lastfailed", {}) - else: - self.lastfailed = {} + self.lastfailed = config.cache.get("cache/lastfailed", {}) + self._previously_failed_count = None - def pytest_report_header(self): + def pytest_report_collectionfinish(self): if self.active: - if not self.lastfailed: + if not self._previously_failed_count: mode = "run all (no recorded failures)" else: - mode = "rerun last %d failures%s" % ( - len(self.lastfailed), - " first" if self.config.getvalue("failedfirst") else "") + noun = 'failure' if self._previously_failed_count == 1 else 'failures' + suffix = " first" if self.config.getvalue("failedfirst") else "" + mode = "rerun previous {count} {noun}{suffix}".format( + count=self._previously_failed_count, suffix=suffix, noun=noun + ) return "run-last-failure: %s" % mode def pytest_runtest_logreport(self, report): - if report.failed and "xfail" not in report.keywords: + if (report.when == 'call' and report.passed) or report.skipped: + self.lastfailed.pop(report.nodeid, None) + elif report.failed: self.lastfailed[report.nodeid] = True - elif not report.failed: - if report.when == "call": - self.lastfailed.pop(report.nodeid, None) def pytest_collectreport(self, report): passed = report.outcome in ('passed', 'skipped') @@ -135,22 +146,24 @@ class LFPlugin: previously_failed.append(item) else: previously_passed.append(item) - if not previously_failed and previously_passed: + self._previously_failed_count = len(previously_failed) + if not previously_failed: # running a subset of all tests with recorded failures outside # of the set of tests currently executing - pass - elif self.config.getvalue("failedfirst"): - items[:] = previously_failed + previously_passed - else: + return + if self.config.getvalue("lf"): items[:] = previously_failed config.hook.pytest_deselected(items=previously_passed) + else: + items[:] = previously_failed + previously_passed def pytest_sessionfinish(self, session): config = self.config if config.getvalue("cacheshow") or hasattr(config, "slaveinput"): return - prev_failed = config.cache.get("cache/lastfailed", None) is not None - if (session.testscollected and prev_failed) or self.lastfailed: + + saved_lastfailed = config.cache.get("cache/lastfailed", {}) + if saved_lastfailed != self.lastfailed: config.cache.set("cache/lastfailed", self.lastfailed) @@ -171,6 +184,9 @@ def pytest_addoption(parser): group.addoption( '--cache-clear', action='store_true', dest="cacheclear", help="remove all cache contents at start of test run.") + parser.addini( + "cache_dir", default='.cache', + help="cache directory path.") def pytest_cmdline_main(config): @@ -179,7 +195,6 @@ def pytest_cmdline_main(config): return wrap_session(config, cacheshow) - @pytest.hookimpl(tryfirst=True) def pytest_configure(config): config.cache = Cache(config) @@ -219,12 +234,12 @@ def cacheshow(config, session): basedir = config.cache._cachedir vdir = basedir.join("v") tw.sep("-", "cache values") - for valpath in vdir.visit(lambda x: x.isfile()): + for valpath in sorted(vdir.visit(lambda x: x.isfile())): key = valpath.relto(vdir).replace(valpath.sep, "/") val = config.cache.get(key, dummy) if val is dummy: tw.line("%s contains unreadable content, " - "will be ignored" % key) + "will be ignored" % key) else: tw.line("%s contains:" % key) stream = py.io.TextIO() @@ -235,8 +250,8 @@ def cacheshow(config, session): ddir = basedir.join("d") if ddir.isdir() and ddir.listdir(): tw.sep("-", "cache directories") - for p in basedir.join("d").visit(): - #if p.check(dir=1): + for p in sorted(basedir.join("d").visit()): + # if p.check(dir=1): # print("%s/" % p.relto(basedir)) if p.isfile(): key = p.relto(basedir) diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/capture.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/capture.py new file mode 100644 index 00000000000..f2ebe38c8c0 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/capture.py @@ -0,0 +1,683 @@ +""" +per-test stdout/stderr capturing mechanism. + +""" +from __future__ import absolute_import, division, print_function + +import collections +import contextlib +import sys +import os +import io +from io import UnsupportedOperation +from tempfile import TemporaryFile + +import six +import pytest +from _pytest.compat import CaptureIO + + +patchsysdict = {0: 'stdin', 1: 'stdout', 2: 'stderr'} + + +def pytest_addoption(parser): + group = parser.getgroup("general") + group._addoption( + '--capture', action="store", + default="fd" if hasattr(os, "dup") else "sys", + metavar="method", choices=['fd', 'sys', 'no'], + help="per-test capturing method: one of fd|sys|no.") + group._addoption( + '-s', action="store_const", const="no", dest="capture", + help="shortcut for --capture=no.") + + +@pytest.hookimpl(hookwrapper=True) +def pytest_load_initial_conftests(early_config, parser, args): + ns = early_config.known_args_namespace + if ns.capture == "fd": + _py36_windowsconsoleio_workaround(sys.stdout) + _colorama_workaround() + _readline_workaround() + pluginmanager = early_config.pluginmanager + capman = CaptureManager(ns.capture) + pluginmanager.register(capman, "capturemanager") + + # make sure that capturemanager is properly reset at final shutdown + early_config.add_cleanup(capman.stop_global_capturing) + + # make sure logging does not raise exceptions at the end + def silence_logging_at_shutdown(): + if "logging" in sys.modules: + sys.modules["logging"].raiseExceptions = False + early_config.add_cleanup(silence_logging_at_shutdown) + + # finally trigger conftest loading but while capturing (issue93) + capman.start_global_capturing() + outcome = yield + out, err = capman.suspend_global_capture() + if outcome.excinfo is not None: + sys.stdout.write(out) + sys.stderr.write(err) + + +class CaptureManager: + """ + Capture plugin, manages that the appropriate capture method is enabled/disabled during collection and each + test phase (setup, call, teardown). After each of those points, the captured output is obtained and + attached to the collection/runtest report. + + There are two levels of capture: + * global: which is enabled by default and can be suppressed by the ``-s`` option. This is always enabled/disabled + during collection and each test phase. + * fixture: when a test function or one of its fixture depend on the ``capsys`` or ``capfd`` fixtures. In this + case special handling is needed to ensure the fixtures take precedence over the global capture. + """ + + def __init__(self, method): + self._method = method + self._global_capturing = None + + def _getcapture(self, method): + if method == "fd": + return MultiCapture(out=True, err=True, Capture=FDCapture) + elif method == "sys": + return MultiCapture(out=True, err=True, Capture=SysCapture) + elif method == "no": + return MultiCapture(out=False, err=False, in_=False) + else: + raise ValueError("unknown capturing method: %r" % method) + + def start_global_capturing(self): + assert self._global_capturing is None + self._global_capturing = self._getcapture(self._method) + self._global_capturing.start_capturing() + + def stop_global_capturing(self): + if self._global_capturing is not None: + self._global_capturing.pop_outerr_to_orig() + self._global_capturing.stop_capturing() + self._global_capturing = None + + def resume_global_capture(self): + self._global_capturing.resume_capturing() + + def suspend_global_capture(self, item=None, in_=False): + if item is not None: + self.deactivate_fixture(item) + cap = getattr(self, "_global_capturing", None) + if cap is not None: + try: + outerr = cap.readouterr() + finally: + cap.suspend_capturing(in_=in_) + return outerr + + def activate_fixture(self, item): + """If the current item is using ``capsys`` or ``capfd``, activate them so they take precedence over + the global capture. + """ + fixture = getattr(item, "_capture_fixture", None) + if fixture is not None: + fixture._start() + + def deactivate_fixture(self, item): + """Deactivates the ``capsys`` or ``capfd`` fixture of this item, if any.""" + fixture = getattr(item, "_capture_fixture", None) + if fixture is not None: + fixture.close() + + @pytest.hookimpl(hookwrapper=True) + def pytest_make_collect_report(self, collector): + if isinstance(collector, pytest.File): + self.resume_global_capture() + outcome = yield + out, err = self.suspend_global_capture() + rep = outcome.get_result() + if out: + rep.sections.append(("Captured stdout", out)) + if err: + rep.sections.append(("Captured stderr", err)) + else: + yield + + @pytest.hookimpl(hookwrapper=True) + def pytest_runtest_setup(self, item): + self.resume_global_capture() + # no need to activate a capture fixture because they activate themselves during creation; this + # only makes sense when a fixture uses a capture fixture, otherwise the capture fixture will + # be activated during pytest_runtest_call + yield + self.suspend_capture_item(item, "setup") + + @pytest.hookimpl(hookwrapper=True) + def pytest_runtest_call(self, item): + self.resume_global_capture() + # it is important to activate this fixture during the call phase so it overwrites the "global" + # capture + self.activate_fixture(item) + yield + self.suspend_capture_item(item, "call") + + @pytest.hookimpl(hookwrapper=True) + def pytest_runtest_teardown(self, item): + self.resume_global_capture() + self.activate_fixture(item) + yield + self.suspend_capture_item(item, "teardown") + + @pytest.hookimpl(tryfirst=True) + def pytest_keyboard_interrupt(self, excinfo): + self.stop_global_capturing() + + @pytest.hookimpl(tryfirst=True) + def pytest_internalerror(self, excinfo): + self.stop_global_capturing() + + def suspend_capture_item(self, item, when, in_=False): + out, err = self.suspend_global_capture(item, in_=in_) + item.add_report_section(when, "stdout", out) + item.add_report_section(when, "stderr", err) + + +capture_fixtures = {'capfd', 'capfdbinary', 'capsys', 'capsysbinary'} + + +def _ensure_only_one_capture_fixture(request, name): + fixtures = set(request.fixturenames) & capture_fixtures - set((name,)) + if fixtures: + fixtures = sorted(fixtures) + fixtures = fixtures[0] if len(fixtures) == 1 else fixtures + raise request.raiseerror( + "cannot use {0} and {1} at the same time".format( + fixtures, name, + ), + ) + + +@pytest.fixture +def capsys(request): + """Enable capturing of writes to sys.stdout/sys.stderr and make + captured output available via ``capsys.readouterr()`` method calls + which return a ``(out, err)`` tuple. ``out`` and ``err`` will be ``text`` + objects. + """ + _ensure_only_one_capture_fixture(request, 'capsys') + with _install_capture_fixture_on_item(request, SysCapture) as fixture: + yield fixture + + +@pytest.fixture +def capsysbinary(request): + """Enable capturing of writes to sys.stdout/sys.stderr and make + captured output available via ``capsys.readouterr()`` method calls + which return a ``(out, err)`` tuple. ``out`` and ``err`` will be ``bytes`` + objects. + """ + _ensure_only_one_capture_fixture(request, 'capsysbinary') + # Currently, the implementation uses the python3 specific `.buffer` + # property of CaptureIO. + if sys.version_info < (3,): + raise request.raiseerror('capsysbinary is only supported on python 3') + with _install_capture_fixture_on_item(request, SysCaptureBinary) as fixture: + yield fixture + + +@pytest.fixture +def capfd(request): + """Enable capturing of writes to file descriptors 1 and 2 and make + captured output available via ``capfd.readouterr()`` method calls + which return a ``(out, err)`` tuple. ``out`` and ``err`` will be ``text`` + objects. + """ + _ensure_only_one_capture_fixture(request, 'capfd') + if not hasattr(os, 'dup'): + pytest.skip("capfd fixture needs os.dup function which is not available in this system") + with _install_capture_fixture_on_item(request, FDCapture) as fixture: + yield fixture + + +@pytest.fixture +def capfdbinary(request): + """Enable capturing of write to file descriptors 1 and 2 and make + captured output available via ``capfdbinary.readouterr`` method calls + which return a ``(out, err)`` tuple. ``out`` and ``err`` will be + ``bytes`` objects. + """ + _ensure_only_one_capture_fixture(request, 'capfdbinary') + if not hasattr(os, 'dup'): + pytest.skip("capfdbinary fixture needs os.dup function which is not available in this system") + with _install_capture_fixture_on_item(request, FDCaptureBinary) as fixture: + yield fixture + + +@contextlib.contextmanager +def _install_capture_fixture_on_item(request, capture_class): + """ + Context manager which creates a ``CaptureFixture`` instance and "installs" it on + the item/node of the given request. Used by ``capsys`` and ``capfd``. + + The CaptureFixture is added as attribute of the item because it needs to accessed + by ``CaptureManager`` during its ``pytest_runtest_*`` hooks. + """ + request.node._capture_fixture = fixture = CaptureFixture(capture_class, request) + capmanager = request.config.pluginmanager.getplugin('capturemanager') + # need to active this fixture right away in case it is being used by another fixture (setup phase) + # if this fixture is being used only by a test function (call phase), then we wouldn't need this + # activation, but it doesn't hurt + capmanager.activate_fixture(request.node) + yield fixture + fixture.close() + del request.node._capture_fixture + + +class CaptureFixture: + def __init__(self, captureclass, request): + self.captureclass = captureclass + self.request = request + + def _start(self): + self._capture = MultiCapture(out=True, err=True, in_=False, + Capture=self.captureclass) + self._capture.start_capturing() + + def close(self): + cap = self.__dict__.pop("_capture", None) + if cap is not None: + self._outerr = cap.pop_outerr_to_orig() + cap.stop_capturing() + + def readouterr(self): + try: + return self._capture.readouterr() + except AttributeError: + return self._outerr + + @contextlib.contextmanager + def disabled(self): + self._capture.suspend_capturing() + capmanager = self.request.config.pluginmanager.getplugin('capturemanager') + capmanager.suspend_global_capture(item=None, in_=False) + try: + yield + finally: + capmanager.resume_global_capture() + self._capture.resume_capturing() + + +def safe_text_dupfile(f, mode, default_encoding="UTF8"): + """ return a open text file object that's a duplicate of f on the + FD-level if possible. + """ + encoding = getattr(f, "encoding", None) + try: + fd = f.fileno() + except Exception: + if "b" not in getattr(f, "mode", "") and hasattr(f, "encoding"): + # we seem to have a text stream, let's just use it + return f + else: + newfd = os.dup(fd) + if "b" not in mode: + mode += "b" + f = os.fdopen(newfd, mode, 0) # no buffering + return EncodedFile(f, encoding or default_encoding) + + +class EncodedFile(object): + errors = "strict" # possibly needed by py3 code (issue555) + + def __init__(self, buffer, encoding): + self.buffer = buffer + self.encoding = encoding + + def write(self, obj): + if isinstance(obj, six.text_type): + obj = obj.encode(self.encoding, "replace") + self.buffer.write(obj) + + def writelines(self, linelist): + data = ''.join(linelist) + self.write(data) + + @property + def name(self): + """Ensure that file.name is a string.""" + return repr(self.buffer) + + def __getattr__(self, name): + return getattr(object.__getattribute__(self, "buffer"), name) + + +CaptureResult = collections.namedtuple("CaptureResult", ["out", "err"]) + + +class MultiCapture(object): + out = err = in_ = None + + def __init__(self, out=True, err=True, in_=True, Capture=None): + if in_: + self.in_ = Capture(0) + if out: + self.out = Capture(1) + if err: + self.err = Capture(2) + + def start_capturing(self): + if self.in_: + self.in_.start() + if self.out: + self.out.start() + if self.err: + self.err.start() + + def pop_outerr_to_orig(self): + """ pop current snapshot out/err capture and flush to orig streams. """ + out, err = self.readouterr() + if out: + self.out.writeorg(out) + if err: + self.err.writeorg(err) + return out, err + + def suspend_capturing(self, in_=False): + if self.out: + self.out.suspend() + if self.err: + self.err.suspend() + if in_ and self.in_: + self.in_.suspend() + self._in_suspended = True + + def resume_capturing(self): + if self.out: + self.out.resume() + if self.err: + self.err.resume() + if hasattr(self, "_in_suspended"): + self.in_.resume() + del self._in_suspended + + def stop_capturing(self): + """ stop capturing and reset capturing streams """ + if hasattr(self, '_reset'): + raise ValueError("was already stopped") + self._reset = True + if self.out: + self.out.done() + if self.err: + self.err.done() + if self.in_: + self.in_.done() + + def readouterr(self): + """ return snapshot unicode value of stdout/stderr capturings. """ + return CaptureResult(self.out.snap() if self.out is not None else "", + self.err.snap() if self.err is not None else "") + + +class NoCapture: + __init__ = start = done = suspend = resume = lambda *args: None + + +class FDCaptureBinary: + """Capture IO to/from a given os-level filedescriptor. + + snap() produces `bytes` + """ + + def __init__(self, targetfd, tmpfile=None): + self.targetfd = targetfd + try: + self.targetfd_save = os.dup(self.targetfd) + except OSError: + self.start = lambda: None + self.done = lambda: None + else: + if targetfd == 0: + assert not tmpfile, "cannot set tmpfile with stdin" + tmpfile = open(os.devnull, "r") + self.syscapture = SysCapture(targetfd) + else: + if tmpfile is None: + f = TemporaryFile() + with f: + tmpfile = safe_text_dupfile(f, mode="wb+") + if targetfd in patchsysdict: + self.syscapture = SysCapture(targetfd, tmpfile) + else: + self.syscapture = NoCapture() + self.tmpfile = tmpfile + self.tmpfile_fd = tmpfile.fileno() + + def __repr__(self): + return "" % (self.targetfd, self.targetfd_save) + + def start(self): + """ Start capturing on targetfd using memorized tmpfile. """ + try: + os.fstat(self.targetfd_save) + except (AttributeError, OSError): + raise ValueError("saved filedescriptor not valid anymore") + os.dup2(self.tmpfile_fd, self.targetfd) + self.syscapture.start() + + def snap(self): + self.tmpfile.seek(0) + res = self.tmpfile.read() + self.tmpfile.seek(0) + self.tmpfile.truncate() + return res + + def done(self): + """ stop capturing, restore streams, return original capture file, + seeked to position zero. """ + targetfd_save = self.__dict__.pop("targetfd_save") + os.dup2(targetfd_save, self.targetfd) + os.close(targetfd_save) + self.syscapture.done() + self.tmpfile.close() + + def suspend(self): + self.syscapture.suspend() + os.dup2(self.targetfd_save, self.targetfd) + + def resume(self): + self.syscapture.resume() + os.dup2(self.tmpfile_fd, self.targetfd) + + def writeorg(self, data): + """ write to original file descriptor. """ + if isinstance(data, six.text_type): + data = data.encode("utf8") # XXX use encoding of original stream + os.write(self.targetfd_save, data) + + +class FDCapture(FDCaptureBinary): + """Capture IO to/from a given os-level filedescriptor. + + snap() produces text + """ + def snap(self): + res = FDCaptureBinary.snap(self) + enc = getattr(self.tmpfile, "encoding", None) + if enc and isinstance(res, bytes): + res = six.text_type(res, enc, "replace") + return res + + +class SysCapture: + def __init__(self, fd, tmpfile=None): + name = patchsysdict[fd] + self._old = getattr(sys, name) + self.name = name + if tmpfile is None: + if name == "stdin": + tmpfile = DontReadFromInput() + else: + tmpfile = CaptureIO() + self.tmpfile = tmpfile + + def start(self): + setattr(sys, self.name, self.tmpfile) + + def snap(self): + res = self.tmpfile.getvalue() + self.tmpfile.seek(0) + self.tmpfile.truncate() + return res + + def done(self): + setattr(sys, self.name, self._old) + del self._old + self.tmpfile.close() + + def suspend(self): + setattr(sys, self.name, self._old) + + def resume(self): + setattr(sys, self.name, self.tmpfile) + + def writeorg(self, data): + self._old.write(data) + self._old.flush() + + +class SysCaptureBinary(SysCapture): + def snap(self): + res = self.tmpfile.buffer.getvalue() + self.tmpfile.seek(0) + self.tmpfile.truncate() + return res + + +class DontReadFromInput: + """Temporary stub class. Ideally when stdin is accessed, the + capturing should be turned off, with possibly all data captured + so far sent to the screen. This should be configurable, though, + because in automated test runs it is better to crash than + hang indefinitely. + """ + + encoding = None + + def read(self, *args): + raise IOError("reading from stdin while output is captured") + readline = read + readlines = read + __iter__ = read + + def fileno(self): + raise UnsupportedOperation("redirected stdin is pseudofile, " + "has no fileno()") + + def isatty(self): + return False + + def close(self): + pass + + @property + def buffer(self): + if sys.version_info >= (3, 0): + return self + else: + raise AttributeError('redirected stdin has no attribute buffer') + + +def _colorama_workaround(): + """ + Ensure colorama is imported so that it attaches to the correct stdio + handles on Windows. + + colorama uses the terminal on import time. So if something does the + first import of colorama while I/O capture is active, colorama will + fail in various ways. + """ + + if not sys.platform.startswith('win32'): + return + try: + import colorama # noqa + except ImportError: + pass + + +def _readline_workaround(): + """ + Ensure readline is imported so that it attaches to the correct stdio + handles on Windows. + + Pdb uses readline support where available--when not running from the Python + prompt, the readline module is not imported until running the pdb REPL. If + running pytest with the --pdb option this means the readline module is not + imported until after I/O capture has been started. + + This is a problem for pyreadline, which is often used to implement readline + support on Windows, as it does not attach to the correct handles for stdout + and/or stdin if they have been redirected by the FDCapture mechanism. This + workaround ensures that readline is imported before I/O capture is setup so + that it can attach to the actual stdin/out for the console. + + See https://github.com/pytest-dev/pytest/pull/1281 + """ + + if not sys.platform.startswith('win32'): + return + try: + import readline # noqa + except ImportError: + pass + + +def _py36_windowsconsoleio_workaround(stream): + """ + Python 3.6 implemented unicode console handling for Windows. This works + by reading/writing to the raw console handle using + ``{Read,Write}ConsoleW``. + + The problem is that we are going to ``dup2`` over the stdio file + descriptors when doing ``FDCapture`` and this will ``CloseHandle`` the + handles used by Python to write to the console. Though there is still some + weirdness and the console handle seems to only be closed randomly and not + on the first call to ``CloseHandle``, or maybe it gets reopened with the + same handle value when we suspend capturing. + + The workaround in this case will reopen stdio with a different fd which + also means a different handle by replicating the logic in + "Py_lifecycle.c:initstdio/create_stdio". + + :param stream: in practice ``sys.stdout`` or ``sys.stderr``, but given + here as parameter for unittesting purposes. + + See https://github.com/pytest-dev/py/issues/103 + """ + if not sys.platform.startswith('win32') or sys.version_info[:2] < (3, 6): + return + + # bail out if ``stream`` doesn't seem like a proper ``io`` stream (#2666) + if not hasattr(stream, 'buffer'): + return + + buffered = hasattr(stream.buffer, 'raw') + raw_stdout = stream.buffer.raw if buffered else stream.buffer + + if not isinstance(raw_stdout, io._WindowsConsoleIO): + return + + def _reopen_stdio(f, mode): + if not buffered and mode[0] == 'w': + buffering = 0 + else: + buffering = -1 + + return io.TextIOWrapper( + open(os.dup(f.fileno()), mode, buffering), + f.encoding, + f.errors, + f.newlines, + f.line_buffering) + + sys.__stdin__ = sys.stdin = _reopen_stdio(sys.stdin, 'rb') + sys.__stdout__ = sys.stdout = _reopen_stdio(sys.stdout, 'wb') + sys.__stderr__ = sys.stderr = _reopen_stdio(sys.stderr, 'wb') diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/compat.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/compat.py new file mode 100644 index 00000000000..7560fbec397 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/compat.py @@ -0,0 +1,322 @@ +""" +python version compatibility code +""" +from __future__ import absolute_import, division, print_function + +import codecs +import functools +import inspect +import re +import sys + +import py + +import _pytest +from _pytest.outcomes import TEST_OUTCOME + +try: + import enum +except ImportError: # pragma: no cover + # Only available in Python 3.4+ or as a backport + enum = None + + +_PY3 = sys.version_info > (3, 0) +_PY2 = not _PY3 + + +if _PY3: + from inspect import signature, Parameter as Parameter +else: + from funcsigs import signature, Parameter as Parameter + + +NoneType = type(None) +NOTSET = object() + +PY35 = sys.version_info[:2] >= (3, 5) +PY36 = sys.version_info[:2] >= (3, 6) +MODULE_NOT_FOUND_ERROR = 'ModuleNotFoundError' if PY36 else 'ImportError' + + +def _format_args(func): + return str(signature(func)) + + +isfunction = inspect.isfunction +isclass = inspect.isclass +# used to work around a python2 exception info leak +exc_clear = getattr(sys, 'exc_clear', lambda: None) +# The type of re.compile objects is not exposed in Python. +REGEX_TYPE = type(re.compile('')) + + +def is_generator(func): + genfunc = inspect.isgeneratorfunction(func) + return genfunc and not iscoroutinefunction(func) + + +def iscoroutinefunction(func): + """Return True if func is a decorated coroutine function. + + Note: copied and modified from Python 3.5's builtin couroutines.py to avoid import asyncio directly, + which in turns also initializes the "logging" module as side-effect (see issue #8). + """ + return (getattr(func, '_is_coroutine', False) or + (hasattr(inspect, 'iscoroutinefunction') and inspect.iscoroutinefunction(func))) + + +def getlocation(function, curdir): + fn = py.path.local(inspect.getfile(function)) + lineno = py.builtin._getcode(function).co_firstlineno + if fn.relto(curdir): + fn = fn.relto(curdir) + return "%s:%d" % (fn, lineno + 1) + + +def num_mock_patch_args(function): + """ return number of arguments used up by mock arguments (if any) """ + patchings = getattr(function, "patchings", None) + if not patchings: + return 0 + mock = sys.modules.get("mock", sys.modules.get("unittest.mock", None)) + if mock is not None: + return len([p for p in patchings + if not p.attribute_name and p.new is mock.DEFAULT]) + return len(patchings) + + +def getfuncargnames(function, is_method=False, cls=None): + """Returns the names of a function's mandatory arguments. + + This should return the names of all function arguments that: + * Aren't bound to an instance or type as in instance or class methods. + * Don't have default values. + * Aren't bound with functools.partial. + * Aren't replaced with mocks. + + The is_method and cls arguments indicate that the function should + be treated as a bound method even though it's not unless, only in + the case of cls, the function is a static method. + + @RonnyPfannschmidt: This function should be refactored when we + revisit fixtures. The fixture mechanism should ask the node for + the fixture names, and not try to obtain directly from the + function object well after collection has occurred. + + """ + # The parameters attribute of a Signature object contains an + # ordered mapping of parameter names to Parameter instances. This + # creates a tuple of the names of the parameters that don't have + # defaults. + arg_names = tuple(p.name for p in signature(function).parameters.values() + if (p.kind is Parameter.POSITIONAL_OR_KEYWORD or + p.kind is Parameter.KEYWORD_ONLY) and + p.default is Parameter.empty) + # If this function should be treated as a bound method even though + # it's passed as an unbound method or function, remove the first + # parameter name. + if (is_method or + (cls and not isinstance(cls.__dict__.get(function.__name__, None), + staticmethod))): + arg_names = arg_names[1:] + # Remove any names that will be replaced with mocks. + if hasattr(function, "__wrapped__"): + arg_names = arg_names[num_mock_patch_args(function):] + return arg_names + + +if _PY3: + STRING_TYPES = bytes, str + UNICODE_TYPES = str, + + if PY35: + def _bytes_to_ascii(val): + return val.decode('ascii', 'backslashreplace') + else: + def _bytes_to_ascii(val): + if val: + # source: http://goo.gl/bGsnwC + encoded_bytes, _ = codecs.escape_encode(val) + return encoded_bytes.decode('ascii') + else: + # empty bytes crashes codecs.escape_encode (#1087) + return '' + + def ascii_escaped(val): + """If val is pure ascii, returns it as a str(). Otherwise, escapes + bytes objects into a sequence of escaped bytes: + + b'\xc3\xb4\xc5\xd6' -> u'\\xc3\\xb4\\xc5\\xd6' + + and escapes unicode objects into a sequence of escaped unicode + ids, e.g.: + + '4\\nV\\U00043efa\\x0eMXWB\\x1e\\u3028\\u15fd\\xcd\\U0007d944' + + note: + the obvious "v.decode('unicode-escape')" will return + valid utf-8 unicode if it finds them in bytes, but we + want to return escaped bytes for any byte, even if they match + a utf-8 string. + + """ + if isinstance(val, bytes): + return _bytes_to_ascii(val) + else: + return val.encode('unicode_escape').decode('ascii') +else: + STRING_TYPES = bytes, str, unicode + UNICODE_TYPES = unicode, + + def ascii_escaped(val): + """In py2 bytes and str are the same type, so return if it's a bytes + object, return it unchanged if it is a full ascii string, + otherwise escape it into its binary form. + + If it's a unicode string, change the unicode characters into + unicode escapes. + + """ + if isinstance(val, bytes): + try: + return val.encode('ascii') + except UnicodeDecodeError: + return val.encode('string-escape') + else: + return val.encode('unicode-escape') + + +def get_real_func(obj): + """ gets the real function object of the (possibly) wrapped object by + functools.wraps or functools.partial. + """ + start_obj = obj + for i in range(100): + new_obj = getattr(obj, '__wrapped__', None) + if new_obj is None: + break + obj = new_obj + else: + raise ValueError( + ("could not find real function of {start}" + "\nstopped at {current}").format( + start=py.io.saferepr(start_obj), + current=py.io.saferepr(obj))) + if isinstance(obj, functools.partial): + obj = obj.func + return obj + + +def getfslineno(obj): + # xxx let decorators etc specify a sane ordering + obj = get_real_func(obj) + if hasattr(obj, 'place_as'): + obj = obj.place_as + fslineno = _pytest._code.getfslineno(obj) + assert isinstance(fslineno[1], int), obj + return fslineno + + +def getimfunc(func): + try: + return func.__func__ + except AttributeError: + return func + + +def safe_getattr(object, name, default): + """ Like getattr but return default upon any Exception or any OutcomeException. + + Attribute access can potentially fail for 'evil' Python objects. + See issue #214. + It catches OutcomeException because of #2490 (issue #580), new outcomes are derived from BaseException + instead of Exception (for more details check #2707) + """ + try: + return getattr(object, name, default) + except TEST_OUTCOME: + return default + + +def _is_unittest_unexpected_success_a_failure(): + """Return if the test suite should fail if a @expectedFailure unittest test PASSES. + + From https://docs.python.org/3/library/unittest.html?highlight=unittest#unittest.TestResult.wasSuccessful: + Changed in version 3.4: Returns False if there were any + unexpectedSuccesses from tests marked with the expectedFailure() decorator. + """ + return sys.version_info >= (3, 4) + + +if _PY3: + def safe_str(v): + """returns v as string""" + return str(v) +else: + def safe_str(v): + """returns v as string, converting to ascii if necessary""" + try: + return str(v) + except UnicodeError: + if not isinstance(v, unicode): + v = unicode(v) + errors = 'replace' + return v.encode('utf-8', errors) + + +COLLECT_FAKEMODULE_ATTRIBUTES = ( + 'Collector', + 'Module', + 'Generator', + 'Function', + 'Instance', + 'Session', + 'Item', + 'Class', + 'File', + '_fillfuncargs', +) + + +def _setup_collect_fakemodule(): + from types import ModuleType + import pytest + pytest.collect = ModuleType('pytest.collect') + pytest.collect.__all__ = [] # used for setns + for attr in COLLECT_FAKEMODULE_ATTRIBUTES: + setattr(pytest.collect, attr, getattr(pytest, attr)) + + +if _PY2: + # Without this the test_dupfile_on_textio will fail, otherwise CaptureIO could directly inherit from StringIO. + from py.io import TextIO + + class CaptureIO(TextIO): + + @property + def encoding(self): + return getattr(self, '_encoding', 'UTF-8') + +else: + import io + + class CaptureIO(io.TextIOWrapper): + def __init__(self): + super(CaptureIO, self).__init__( + io.BytesIO(), + encoding='UTF-8', newline='', write_through=True, + ) + + def getvalue(self): + return self.buffer.getvalue().decode('UTF-8') + + +class FuncargnamesCompatAttr(object): + """ helper class so that Metafunc, Function and FixtureRequest + don't need to each define the "funcargnames" compatibility attribute. + """ + @property + def funcargnames(self): + """ alias attribute for ``fixturenames`` for pre-2.3 compatibility""" + return self.fixturenames diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/config.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/config.py similarity index 71% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/config.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/config.py index fb7b1774f68..499c8079d41 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/config.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/config.py @@ -1,16 +1,21 @@ """ command line options, ini-file and conftest.py processing. """ +from __future__ import absolute_import, division, print_function import argparse import shlex import traceback import types import warnings +import six import py # DON't import pytest here because it causes import cycle troubles -import sys, os +import sys +import os import _pytest._code import _pytest.hookspec # the extension point definitions -from _pytest._pluggy import PluginManager, HookimplMarker, HookspecMarker +import _pytest.assertion +from pluggy import PluginManager, HookimplMarker, HookspecMarker +from _pytest.compat import safe_str hookimpl = HookimplMarker("pytest") hookspec = HookspecMarker("pytest") @@ -25,6 +30,12 @@ class ConftestImportFailure(Exception): self.path = path self.excinfo = excinfo + def __str__(self): + etype, evalue, etb = self.excinfo + formatted = traceback.format_tb(etb) + # The level of the tracebacks we want to print is hand crafted :( + return repr(evalue) + '\n' + ''.join(formatted[2:]) + def main(args=None, plugins=None): """ return exit code, after performing an in-process test run. @@ -45,39 +56,63 @@ def main(args=None, plugins=None): return 4 else: try: - config.pluginmanager.check_pending() return config.hook.pytest_cmdline_main(config=config) finally: config._ensure_unconfigure() except UsageError as e: for msg in e.args: - sys.stderr.write("ERROR: %s\n" %(msg,)) + sys.stderr.write("ERROR: %s\n" % (msg,)) return 4 + class cmdline: # compatibility namespace main = staticmethod(main) + class UsageError(Exception): """ error in pytest usage or invocation""" -_preinit = [] + +class PrintHelp(Exception): + """Raised when pytest should print it's help to skip the rest of the + argument parsing and validation.""" + pass + + +def filename_arg(path, optname): + """ Argparse type validator for filename arguments. + + :path: path of filename + :optname: name of the option + """ + if os.path.isdir(path): + raise UsageError("{0} must be a filename, given: {1}".format(optname, path)) + return path + + +def directory_arg(path, optname): + """Argparse type validator for directory arguments. + + :path: path of directory + :optname: name of the option + """ + if not os.path.isdir(path): + raise UsageError("{0} must be a directory, given: {1}".format(optname, path)) + return path + default_plugins = ( - "mark main terminal runner python pdb unittest capture skipping " - "tmpdir monkeypatch recwarn pastebin helpconfig nose assertion genscript " - "junitxml resultlog doctest cacheprovider").split() + "mark main terminal runner python fixtures debugging unittest capture skipping " + "tmpdir monkeypatch recwarn pastebin helpconfig nose assertion " + "junitxml resultlog doctest cacheprovider freeze_support " + "setuponly setupplan warnings logging").split() + builtin_plugins = set(default_plugins) builtin_plugins.add("pytester") -def _preloadplugins(): - assert not _preinit - _preinit.append(get_config()) - def get_config(): - if _preinit: - return _preinit.pop(0) # subsequent calls to main will create a fresh instance pluginmanager = PytestPluginManager() config = Config(pluginmanager) @@ -85,6 +120,7 @@ def get_config(): pluginmanager.import_plugin(spec) return config + def get_plugin_manager(): """ Obtain a new instance of the @@ -96,7 +132,9 @@ def get_plugin_manager(): """ return get_config().pluginmanager + def _prepareconfig(args=None, plugins=None): + warning = None if args is None: args = sys.argv[1:] elif isinstance(args, py.path.local): @@ -104,18 +142,22 @@ def _prepareconfig(args=None, plugins=None): elif not isinstance(args, (tuple, list)): if not isinstance(args, str): raise ValueError("not a string or argument list: %r" % (args,)) - args = shlex.split(args) + args = shlex.split(args, posix=sys.platform != "win32") + from _pytest import deprecated + warning = deprecated.MAIN_STR_ARGS config = get_config() pluginmanager = config.pluginmanager try: if plugins: for plugin in plugins: - if isinstance(plugin, py.builtin._basestring): + if isinstance(plugin, six.string_types): pluginmanager.consider_pluginarg(plugin) else: pluginmanager.register(plugin) + if warning: + config.warn('C1', warning) return pluginmanager.hook.pytest_cmdline_parse( - pluginmanager=pluginmanager, args=args) + pluginmanager=pluginmanager, args=args) except BaseException: config._ensure_unconfigure() raise @@ -123,13 +165,14 @@ def _prepareconfig(args=None, plugins=None): class PytestPluginManager(PluginManager): """ - Overwrites :py:class:`pluggy.PluginManager` to add pytest-specific + Overwrites :py:class:`pluggy.PluginManager ` to add pytest-specific functionality: * loading plugins from the command line, ``PYTEST_PLUGIN`` env variable and ``pytest_plugins`` global variables found in plugins being loaded; * ``conftest.py`` loading during start-up; """ + def __init__(self): super(PytestPluginManager, self).__init__("pytest", implprefix="pytest_") self._conftest_plugins = set() @@ -139,6 +182,7 @@ class PytestPluginManager(PluginManager): self._conftestpath2mod = {} self._confcutdir = None self._noconftest = False + self._duplicatepaths = set() self.add_hookspecs(_pytest.hookspec) self.register(self) @@ -152,11 +196,15 @@ class PytestPluginManager(PluginManager): self.trace.root.setwriter(err.write) self.enable_tracing() + # Config._consider_importhook will set a real object if required. + self.rewrite_hook = _pytest.assertion.DummyRewriteHook() + def addhooks(self, module_or_class): """ .. deprecated:: 2.8 - Use :py:meth:`pluggy.PluginManager.add_hookspecs` instead. + Use :py:meth:`pluggy.PluginManager.add_hookspecs ` + instead. """ warning = dict(code="I2", fslocation=_pytest._code.getfslineno(sys._getframe(1)), @@ -185,7 +233,7 @@ class PytestPluginManager(PluginManager): def parse_hookspec_opts(self, module_or_class, name): opts = super(PytestPluginManager, self).parse_hookspec_opts( - module_or_class, name) + module_or_class, name) if opts is None: method = getattr(module_or_class, name) if name.startswith("pytest_"): @@ -193,22 +241,18 @@ class PytestPluginManager(PluginManager): "historic": hasattr(method, "historic")} return opts - def _verify_hook(self, hook, hookmethod): - super(PytestPluginManager, self)._verify_hook(hook, hookmethod) - if "__multicall__" in hookmethod.argnames: - fslineno = _pytest._code.getfslineno(hookmethod.function) - warning = dict(code="I1", - fslocation=fslineno, - nodeid=None, - message="%r hook uses deprecated __multicall__ " - "argument" % (hook.name)) - self._warn(warning) - def register(self, plugin, name=None): + if name == 'pytest_catchlog': + self._warn('pytest-catchlog plugin has been merged into the core, ' + 'please remove it from your requirements.') + return ret = super(PytestPluginManager, self).register(plugin, name) if ret: self.hook.pytest_plugin_registered.call_historic( - kwargs=dict(plugin=plugin, manager=self)) + kwargs=dict(plugin=plugin, manager=self)) + + if isinstance(plugin, types.ModuleType): + self.consider_module(plugin) return ret def getplugin(self, name): @@ -223,11 +267,11 @@ class PytestPluginManager(PluginManager): # XXX now that the pluginmanager exposes hookimpl(tryfirst...) # we should remove tryfirst/trylast as markers config.addinivalue_line("markers", - "tryfirst: mark a hook implementation function such that the " - "plugin machinery will try to call it first/as early as possible.") + "tryfirst: mark a hook implementation function such that the " + "plugin machinery will try to call it first/as early as possible.") config.addinivalue_line("markers", - "trylast: mark a hook implementation function such that the " - "plugin machinery will try to call it last/as late as possible.") + "trylast: mark a hook implementation function such that the " + "plugin machinery will try to call it last/as late as possible.") def _warn(self, message): kwargs = message if isinstance(message, dict) else { @@ -251,7 +295,7 @@ class PytestPluginManager(PluginManager): """ current = py.path.local() self._confcutdir = current.join(namespace.confcutdir, abs=True) \ - if namespace.confcutdir else None + if namespace.confcutdir else None self._noconftest = namespace.noconftest testpaths = namespace.file_or_dir foundanchor = False @@ -262,7 +306,7 @@ class PytestPluginManager(PluginManager): if i != -1: path = path[:i] anchor = current.join(path, abs=1) - if exists(anchor): # we found some file object + if exists(anchor): # we found some file object self._try_load_conftest(anchor) foundanchor = True if not foundanchor: @@ -329,7 +373,7 @@ class PytestPluginManager(PluginManager): if path and path.relto(dirpath) or path == dirpath: assert mod not in mods mods.append(mod) - self.trace("loaded conftestmodule %r" %(mod)) + self.trace("loaded conftestmodule %r" % (mod)) self.consider_conftest(mod) return mod @@ -339,7 +383,7 @@ class PytestPluginManager(PluginManager): # def consider_preparse(self, args): - for opt1,opt2 in zip(args, args[1:]): + for opt1, opt2 in zip(args, args[1:]): if opt1 == "-p": self.consider_pluginarg(opt2) @@ -353,52 +397,68 @@ class PytestPluginManager(PluginManager): self.import_plugin(arg) def consider_conftest(self, conftestmodule): - if self.register(conftestmodule, name=conftestmodule.__file__): - self.consider_module(conftestmodule) + self.register(conftestmodule, name=conftestmodule.__file__) def consider_env(self): self._import_plugin_specs(os.environ.get("PYTEST_PLUGINS")) def consider_module(self, mod): - self._import_plugin_specs(getattr(mod, "pytest_plugins", None)) + self._import_plugin_specs(getattr(mod, 'pytest_plugins', [])) def _import_plugin_specs(self, spec): - if spec: - if isinstance(spec, str): - spec = spec.split(",") - for import_spec in spec: - self.import_plugin(import_spec) + plugins = _get_plugin_specs_as_list(spec) + for import_spec in plugins: + self.import_plugin(import_spec) def import_plugin(self, modname): # most often modname refers to builtin modules, e.g. "pytester", # "terminal" or "capture". Those plugins are registered under their # basename for historic purposes but must be imported with the # _pytest prefix. - assert isinstance(modname, str) - if self.get_plugin(modname) is not None: + assert isinstance(modname, (six.text_type, str)), "module name as text required, got %r" % modname + modname = str(modname) + if self.is_blocked(modname) or self.get_plugin(modname) is not None: return if modname in builtin_plugins: importspec = "_pytest." + modname else: importspec = modname + self.rewrite_hook.mark_rewrite(importspec) try: __import__(importspec) except ImportError as e: - new_exc = ImportError('Error importing plugin "%s": %s' % (modname, e)) - # copy over name and path attributes - for attr in ('name', 'path'): - if hasattr(e, attr): - setattr(new_exc, attr, getattr(e, attr)) - raise new_exc + new_exc_type = ImportError + new_exc_message = 'Error importing plugin "%s": %s' % (modname, safe_str(e.args[0])) + new_exc = new_exc_type(new_exc_message) + + six.reraise(new_exc_type, new_exc, sys.exc_info()[2]) + except Exception as e: import pytest if not hasattr(pytest, 'skip') or not isinstance(e, pytest.skip.Exception): raise - self._warn("skipped plugin %r: %s" %((modname, e.msg))) + self._warn("skipped plugin %r: %s" % ((modname, e.msg))) else: mod = sys.modules[importspec] self.register(mod, modname) - self.consider_module(mod) + + +def _get_plugin_specs_as_list(specs): + """ + Parses a list of "plugin specs" and returns a list of plugin names. + + Plugin specs can be given as a list of strings separated by "," or already as a list/tuple in + which case it is returned as a list. Specs can also be `None` in which case an + empty list is returned. + """ + if specs is not None: + if isinstance(specs, str): + specs = specs.split(',') if specs else [] + if not isinstance(specs, (list, tuple)): + raise UsageError("Plugin specs must be a ','-separated string or a " + "list/tuple of strings for plugin names. Given: %r" % specs) + return list(specs) + return [] class Parser: @@ -442,7 +502,7 @@ class Parser: for i, grp in enumerate(self._groups): if grp.name == after: break - self._groups.insert(i+1, group) + self._groups.insert(i + 1, group) return group def addoption(self, *opts, **attrs): @@ -480,7 +540,7 @@ class Parser: a = option.attrs() arggroup.add_argument(*n, **a) # bash like autocompletion for dirs (appending '/') - optparser.add_argument(FILE_OR_DIR, nargs='*').completer=filescompleter + optparser.add_argument(FILE_OR_DIR, nargs='*').completer = filescompleter return optparser def parse_setoption(self, args, option, namespace=None): @@ -537,13 +597,18 @@ class ArgumentError(Exception): class Argument: - """class that mimics the necessary behaviour of optparse.Option """ + """class that mimics the necessary behaviour of optparse.Option + + its currently a least effort implementation + and ignoring choices and integer prefixes + https://docs.python.org/3/library/optparse.html#optparse-standard-option-types + """ _typ_map = { 'int': int, 'string': str, - } - # enable after some grace period for plugin writers - TYPE_WARN = False + 'float': float, + 'complex': complex, + } def __init__(self, *names, **attrs): """store parms in private vars for use in add_argument""" @@ -551,44 +616,37 @@ class Argument: self._short_opts = [] self._long_opts = [] self.dest = attrs.get('dest') - if self.TYPE_WARN: - try: - help = attrs['help'] - if '%default' in help: - warnings.warn( - 'pytest now uses argparse. "%default" should be' - ' changed to "%(default)s" ', - FutureWarning, - stacklevel=3) - except KeyError: - pass + if '%default' in (attrs.get('help') or ''): + warnings.warn( + 'pytest now uses argparse. "%default" should be' + ' changed to "%(default)s" ', + DeprecationWarning, + stacklevel=3) try: typ = attrs['type'] except KeyError: pass else: # this might raise a keyerror as well, don't want to catch that - if isinstance(typ, py.builtin._basestring): + if isinstance(typ, six.string_types): if typ == 'choice': - if self.TYPE_WARN: - warnings.warn( - 'type argument to addoption() is a string %r.' - ' For parsearg this is optional and when supplied ' - ' should be a type.' - ' (options: %s)' % (typ, names), - FutureWarning, - stacklevel=3) + warnings.warn( + 'type argument to addoption() is a string %r.' + ' For parsearg this is optional and when supplied' + ' should be a type.' + ' (options: %s)' % (typ, names), + DeprecationWarning, + stacklevel=3) # argparse expects a type here take it from # the type of the first element attrs['type'] = type(attrs['choices'][0]) else: - if self.TYPE_WARN: - warnings.warn( - 'type argument to addoption() is a string %r.' - ' For parsearg this should be a type.' - ' (options: %s)' % (typ, names), - FutureWarning, - stacklevel=3) + warnings.warn( + 'type argument to addoption() is a string %r.' + ' For parsearg this should be a type.' + ' (options: %s)' % (typ, names), + DeprecationWarning, + stacklevel=3) attrs['type'] = Argument._typ_map[typ] # used in test_parseopt -> test_parse_defaultgetter self.type = attrs['type'] @@ -626,7 +684,7 @@ class Argument: if self._attrs.get('help'): a = self._attrs['help'] a = a.replace('%default', '%(default)s') - #a = a.replace('%prog', '%(prog)s') + # a = a.replace('%prog', '%(prog)s') self._attrs['help'] = a return self._attrs @@ -655,20 +713,17 @@ class Argument: self._long_opts.append(opt) def __repr__(self): - retval = 'Argument(' + args = [] if self._short_opts: - retval += '_short_opts: ' + repr(self._short_opts) + ', ' + args += ['_short_opts: ' + repr(self._short_opts)] if self._long_opts: - retval += '_long_opts: ' + repr(self._long_opts) + ', ' - retval += 'dest: ' + repr(self.dest) + ', ' + args += ['_long_opts: ' + repr(self._long_opts)] + args += ['dest: ' + repr(self.dest)] if hasattr(self, 'type'): - retval += 'type: ' + repr(self.type) + ', ' + args += ['type: ' + repr(self.type)] if hasattr(self, 'default'): - retval += 'default: ' + repr(self.default) + ', ' - if retval[-2:] == ', ': # always long enough to test ("Argument(" ) - retval = retval[:-2] - retval += ')' - return retval + args += ['default: ' + repr(self.default)] + return 'Argument({0})'.format(', '.join(args)) class OptionGroup: @@ -686,6 +741,10 @@ class OptionGroup: results in help showing '--two-words' only, but --twowords gets accepted **and** the automatic destination is in args.twowords """ + conflict = set(optnames).intersection( + name for opt in self.options for name in opt.names()) + if conflict: + raise ValueError("option names %s already added" % conflict) option = Argument(*optnames, **attrs) self._addoption_instance(option, shortupper=False) @@ -709,7 +768,7 @@ class MyOptionParser(argparse.ArgumentParser): extra_info = {} self._parser = parser argparse.ArgumentParser.__init__(self, usage=parser._usage, - add_help=False, formatter_class=DropShorterLongHelpFormatter) + add_help=False, formatter_class=DropShorterLongHelpFormatter) # extra_info is a dict of (param -> value) to display if there's # an usage error to provide more contextual information to the user self.extra_info = extra_info @@ -737,9 +796,10 @@ class DropShorterLongHelpFormatter(argparse.HelpFormatter): - shortcut if there are only two options and one of them is a short one - cache result on action object as this is called at least 2 times """ + def _format_action_invocation(self, action): orgstr = argparse.HelpFormatter._format_action_invocation(self, action) - if orgstr and orgstr[0] != '-': # only optional arguments + if orgstr and orgstr[0] != '-': # only optional arguments return orgstr res = getattr(action, '_formatted_action_invocation', None) if res: @@ -750,7 +810,7 @@ class DropShorterLongHelpFormatter(argparse.HelpFormatter): action._formatted_action_invocation = orgstr return orgstr return_list = [] - option_map = getattr(action, 'map_long_option', {}) + option_map = getattr(action, 'map_long_option', {}) if option_map is None: option_map = {} short_long = {} @@ -768,38 +828,56 @@ class DropShorterLongHelpFormatter(argparse.HelpFormatter): short_long[shortened] = xxoption # now short_long has been filled out to the longest with dashes # **and** we keep the right option ordering from add_argument - for option in options: # + for option in options: if len(option) == 2 or option[2] == ' ': return_list.append(option) if option[2:] == short_long.get(option.replace('-', '')): - return_list.append(option.replace(' ', '=')) + return_list.append(option.replace(' ', '=', 1)) action._formatted_action_invocation = ', '.join(return_list) return action._formatted_action_invocation - def _ensure_removed_sysmodule(modname): try: del sys.modules[modname] except KeyError: pass + class CmdOptions(object): """ holds cmdline options as attributes.""" + def __init__(self, values=()): self.__dict__.update(values) + def __repr__(self): - return "" %(self.__dict__,) + return "" % (self.__dict__,) + def copy(self): return CmdOptions(self.__dict__) + class Notset: def __repr__(self): return "" + notset = Notset() FILE_OR_DIR = 'file_or_dir' + +def _iter_rewritable_modules(package_files): + for fn in package_files: + is_simple_module = '/' not in fn and fn.endswith('.py') + is_package = fn.count('/') == 1 and fn.endswith('__init__.py') + if is_simple_module: + module_name, _ = os.path.splitext(fn) + yield module_name + elif is_package: + package_name = os.path.dirname(fn) + yield package_name + + class Config(object): """ access to configuration values, pluginmanager and plugin hooks. """ @@ -817,14 +895,17 @@ class Config(object): self.trace = self.pluginmanager.trace.root.get("config") self.hook = self.pluginmanager.hook self._inicache = {} + self._override_ini = () self._opt2dest = {} self._cleanup = [] self._warn = self.pluginmanager._warn self.pluginmanager.register(self, "pytestconfig") self._configured = False + def do_setns(dic): import pytest setns(pytest, dic) + self.hook.pytest_namespace.call_historic(do_setns, {}) self.hook.pytest_addoption.call_historic(kwargs=dict(parser=self._parser)) @@ -847,11 +928,11 @@ class Config(object): fin = self._cleanup.pop() fin() - def warn(self, code, message, fslocation=None): + def warn(self, code, message, fslocation=None, nodeid=None): """ generate a warning for this test session. """ self.hook.pytest_logwarning.call_historic(kwargs=dict( code=code, message=message, - fslocation=fslocation, nodeid=None)) + fslocation=fslocation, nodeid=nodeid)) def get_terminal_writer(self): return self.pluginmanager.get_plugin("terminalreporter")._tw @@ -867,14 +948,14 @@ class Config(object): else: style = "native" excrepr = excinfo.getrepr(funcargs=True, - showlocals=getattr(option, 'showlocals', False), - style=style, - ) + showlocals=getattr(option, 'showlocals', False), + style=style, + ) res = self.hook.pytest_internalerror(excrepr=excrepr, excinfo=excinfo) - if not py.builtin.any(res): + if not any(res): for line in str(excrepr).split("\n"): - sys.stderr.write("INTERNALERROR> %s\n" %line) + sys.stderr.write("INTERNALERROR> %s\n" % line) sys.stderr.flush() def cwd_relative_nodeid(self, nodeid): @@ -908,25 +989,85 @@ class Config(object): def _initini(self, args): ns, unknown_args = self._parser.parse_known_and_unknown_args(args, namespace=self.option.copy()) - r = determine_setup(ns.inifilename, ns.file_or_dir + unknown_args) + r = determine_setup(ns.inifilename, ns.file_or_dir + unknown_args, warnfunc=self.warn) self.rootdir, self.inifile, self.inicfg = r self._parser.extra_info['rootdir'] = self.rootdir self._parser.extra_info['inifile'] = self.inifile self.invocation_dir = py.path.local() self._parser.addini('addopts', 'extra command line options', 'args') self._parser.addini('minversion', 'minimally required pytest version') + self._override_ini = ns.override_ini or () + + def _consider_importhook(self, args): + """Install the PEP 302 import hook if using assertion rewriting. + + Needs to parse the --assert= option from the commandline + and find all the installed plugins to mark them for rewriting + by the importhook. + """ + ns, unknown_args = self._parser.parse_known_and_unknown_args(args) + mode = ns.assertmode + if mode == 'rewrite': + try: + hook = _pytest.assertion.install_importhook(self) + except SystemError: + mode = 'plain' + else: + self._mark_plugins_for_rewrite(hook) + self._warn_about_missing_assertion(mode) + + def _mark_plugins_for_rewrite(self, hook): + """ + Given an importhook, mark for rewrite any top-level + modules or packages in the distribution package for + all pytest plugins. + """ + import pkg_resources + self.pluginmanager.rewrite_hook = hook + + # 'RECORD' available for plugins installed normally (pip install) + # 'SOURCES.txt' available for plugins installed in dev mode (pip install -e) + # for installed plugins 'SOURCES.txt' returns an empty list, and vice-versa + # so it shouldn't be an issue + metadata_files = 'RECORD', 'SOURCES.txt' + + package_files = ( + entry.split(',')[0] + for entrypoint in pkg_resources.iter_entry_points('pytest11') + for metadata in metadata_files + for entry in entrypoint.dist._get_metadata(metadata) + ) + + for name in _iter_rewritable_modules(package_files): + hook.mark_rewrite(name) + + def _warn_about_missing_assertion(self, mode): + try: + assert False + except AssertionError: + pass + else: + if mode == 'plain': + sys.stderr.write("WARNING: ASSERTIONS ARE NOT EXECUTED" + " and FAILING TESTS WILL PASS. Are you" + " using python -O?") + else: + sys.stderr.write("WARNING: assertions not in test modules or" + " plugins will be ignored" + " because assert statements are not executed " + "by the underlying Python interpreter " + "(are you using python -O?)\n") def _preparse(self, args, addopts=True): - self._initini(args) if addopts: args[:] = shlex.split(os.environ.get('PYTEST_ADDOPTS', '')) + args + self._initini(args) + if addopts: args[:] = self.getini("addopts") + args self._checkversion() + self._consider_importhook(args) self.pluginmanager.consider_preparse(args) - try: - self.pluginmanager.load_setuptools_entrypoints("pytest11") - except ImportError as e: - self.warn("I2", "could not load setuptools entry import: %s" % (e,)) + self.pluginmanager.load_setuptools_entrypoints('pytest11') self.pluginmanager.consider_env() self.known_args_namespace = ns = self._parser.parse_known_args(args, namespace=self.option.copy()) if self.known_args_namespace.confcutdir is None and self.inifile: @@ -934,7 +1075,7 @@ class Config(object): self.known_args_namespace.confcutdir = confcutdir try: self.hook.pytest_load_initial_conftests(early_config=self, - args=args, parser=self._parser) + args=args, parser=self._parser) except ConftestImportFailure: e = sys.exc_info()[1] if ns.help or ns.version: @@ -952,28 +1093,32 @@ class Config(object): myver = pytest.__version__.split(".") if myver < ver: raise pytest.UsageError( - "%s:%d: requires pytest-%s, actual pytest-%s'" %( - self.inicfg.config.path, self.inicfg.lineof('minversion'), - minver, pytest.__version__)) + "%s:%d: requires pytest-%s, actual pytest-%s'" % ( + self.inicfg.config.path, self.inicfg.lineof('minversion'), + minver, pytest.__version__)) def parse(self, args, addopts=True): # parse given cmdline arguments into this config object. assert not hasattr(self, 'args'), ( - "can only parse cmdline args at most once per Config object") + "can only parse cmdline args at most once per Config object") self._origargs = args self.hook.pytest_addhooks.call_historic( - kwargs=dict(pluginmanager=self.pluginmanager)) + kwargs=dict(pluginmanager=self.pluginmanager)) self._preparse(args, addopts=addopts) # XXX deprecated hook: self.hook.pytest_cmdline_preparse(config=self, args=args) - args = self._parser.parse_setoption(args, self.option, namespace=self.option) - if not args: - cwd = os.getcwd() - if cwd == self.rootdir: - args = self.getini('testpaths') + self._parser.after_preparse = True + try: + args = self._parser.parse_setoption(args, self.option, namespace=self.option) if not args: - args = [cwd] - self.args = args + cwd = os.getcwd() + if cwd == self.rootdir: + args = self.getini('testpaths') + if not args: + args = [cwd] + self.args = args + except PrintHelp: + pass def addinivalue_line(self, name, line): """ add a line to an ini-file option. The option must have been @@ -981,12 +1126,12 @@ class Config(object): the first line in its value. """ x = self.getini(name) assert isinstance(x, list) - x.append(line) # modifies the cached list inline + x.append(line) # modifies the cached list inline def getini(self, name): """ return configuration value from an :ref:`ini file `. If the specified name hasn't been registered through a prior - :py:func:`parser.addini ` + :py:func:`parser.addini <_pytest.config.Parser.addini>` call (usually from a plugin), a ValueError is raised. """ try: return self._inicache[name] @@ -998,21 +1143,23 @@ class Config(object): try: description, type, default = self._parser._inidict[name] except KeyError: - raise ValueError("unknown configuration value: %r" %(name,)) - try: - value = self.inicfg[name] - except KeyError: - if default is not None: - return default - if type is None: - return '' - return [] + raise ValueError("unknown configuration value: %r" % (name,)) + value = self._get_override_ini_value(name) + if value is None: + try: + value = self.inicfg[name] + except KeyError: + if default is not None: + return default + if type is None: + return '' + return [] if type == "pathlist": dp = py.path.local(self.inicfg.config.path).dirpath() - l = [] + values = [] for relpath in shlex.split(value): - l.append(dp.join(relpath, abs=True)) - return l + values.append(dp.join(relpath, abs=True)) + return values elif type == "args": return shlex.split(value) elif type == "linelist": @@ -1029,13 +1176,29 @@ class Config(object): except KeyError: return None modpath = py.path.local(mod.__file__).dirpath() - l = [] + values = [] for relroot in relroots: if not isinstance(relroot, py.path.local): relroot = relroot.replace("/", py.path.local.sep) relroot = modpath.join(relroot, abs=True) - l.append(relroot) - return l + values.append(relroot) + return values + + def _get_override_ini_value(self, name): + value = None + # override_ini is a list of list, to support both -o foo1=bar1 foo2=bar2 and + # and -o foo1=bar1 -o foo2=bar2 options + # always use the last item if multiple value set for same ini-name, + # e.g. -o foo=bar1 -o foo=bar2 will set foo to bar2 + for ini_config_list in self._override_ini: + for ini_config in ini_config_list: + try: + (key, user_ini_value) = ini_config.split("=", 1) + except ValueError: + raise UsageError("-o/--override-ini expects option=value style.") + if key == name: + value = user_ini_value + return value def getoption(self, name, default=notset, skip=False): """ return command line option value. @@ -1057,7 +1220,7 @@ class Config(object): return default if skip: import pytest - pytest.skip("no %r option found" %(name,)) + pytest.skip("no %r option found" % (name,)) raise ValueError("no option named %r" % (name,)) def getvalue(self, name, path=None): @@ -1068,13 +1231,26 @@ class Config(object): """ (deprecated, use getoption(skip=True)) """ return self.getoption(name, skip=True) + def exists(path, ignore=EnvironmentError): try: return path.check() except ignore: return False -def getcfg(args, inibasenames): + +def getcfg(args, warnfunc=None): + """ + Search the list of arguments for a valid ini-file for pytest, + and return a tuple of (rootdir, inifile, cfg-dict). + + note: warnfunc is an optional function used to warn + about ini-files that use deprecated features. + This parameter should be removed when pytest + adopts standard deprecation warnings (#1804). + """ + from _pytest.deprecated import SETUP_CFG_PYTEST + inibasenames = ["pytest.ini", "tox.ini", "setup.cfg"] args = [x for x in args if not str(x).startswith("-")] if not args: args = [py.path.local()] @@ -1086,57 +1262,89 @@ def getcfg(args, inibasenames): if exists(p): iniconfig = py.iniconfig.IniConfig(p) if 'pytest' in iniconfig.sections: + if inibasename == 'setup.cfg' and warnfunc: + warnfunc('C1', SETUP_CFG_PYTEST) return base, p, iniconfig['pytest'] + if inibasename == 'setup.cfg' and 'tool:pytest' in iniconfig.sections: + return base, p, iniconfig['tool:pytest'] elif inibasename == "pytest.ini": # allowed to be empty return base, p, {} return None, None, None -def get_common_ancestor(args): - # args are what we get after early command line parsing (usually - # strings, but can be py.path.local objects as well) +def get_common_ancestor(paths): common_ancestor = None - for arg in args: - if str(arg)[0] == "-": + for path in paths: + if not path.exists(): continue - p = py.path.local(arg) if common_ancestor is None: - common_ancestor = p + common_ancestor = path else: - if p.relto(common_ancestor) or p == common_ancestor: + if path.relto(common_ancestor) or path == common_ancestor: continue - elif common_ancestor.relto(p): - common_ancestor = p + elif common_ancestor.relto(path): + common_ancestor = path else: - shared = p.common(common_ancestor) + shared = path.common(common_ancestor) if shared is not None: common_ancestor = shared if common_ancestor is None: common_ancestor = py.path.local() - elif not common_ancestor.isdir(): + elif common_ancestor.isfile(): common_ancestor = common_ancestor.dirpath() return common_ancestor -def determine_setup(inifile, args): +def get_dirs_from_args(args): + def is_option(x): + return str(x).startswith('-') + + def get_file_part_from_node_id(x): + return str(x).split('::')[0] + + def get_dir_from_path(path): + if path.isdir(): + return path + return py.path.local(path.dirname) + + # These look like paths but may not exist + possible_paths = ( + py.path.local(get_file_part_from_node_id(arg)) + for arg in args + if not is_option(arg) + ) + + return [ + get_dir_from_path(path) + for path in possible_paths + if path.exists() + ] + + +def determine_setup(inifile, args, warnfunc=None): + dirs = get_dirs_from_args(args) if inifile: iniconfig = py.iniconfig.IniConfig(inifile) try: inicfg = iniconfig["pytest"] except KeyError: inicfg = None - rootdir = get_common_ancestor(args) + rootdir = get_common_ancestor(dirs) else: - ancestor = get_common_ancestor(args) - rootdir, inifile, inicfg = getcfg( - [ancestor], ["pytest.ini", "tox.ini", "setup.cfg"]) + ancestor = get_common_ancestor(dirs) + rootdir, inifile, inicfg = getcfg([ancestor], warnfunc=warnfunc) if rootdir is None: for rootdir in ancestor.parts(reverse=True): if rootdir.join("setup.py").exists(): break else: - rootdir = ancestor + rootdir, inifile, inicfg = getcfg(dirs, warnfunc=warnfunc) + if rootdir is None: + rootdir = get_common_ancestor([py.path.local(), ancestor]) + is_fs_root = os.path.splitdrive(str(rootdir))[1] == '/' + if is_fs_root: + rootdir = ancestor return rootdir, inifile, inicfg or {} @@ -1156,7 +1364,7 @@ def setns(obj, dic): else: setattr(obj, name, value) obj.__all__.append(name) - #if obj != pytest: + # if obj != pytest: # pytest.__all__.append(name) setattr(pytest, name, value) diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/pdb.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/debugging.py similarity index 66% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/pdb.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/debugging.py index 84c920d172c..d7dca780956 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/pdb.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/debugging.py @@ -1,65 +1,79 @@ """ interactive debugging with PDB, the Python Debugger. """ -from __future__ import absolute_import +from __future__ import absolute_import, division, print_function import pdb import sys -import pytest - def pytest_addoption(parser): group = parser.getgroup("general") - group._addoption('--pdb', - action="store_true", dest="usepdb", default=False, - help="start the interactive Python debugger on errors.") + group._addoption( + '--pdb', dest="usepdb", action="store_true", + help="start the interactive Python debugger on errors.") + group._addoption( + '--pdbcls', dest="usepdb_cls", metavar="modulename:classname", + help="start a custom interactive Python debugger on errors. " + "For example: --pdbcls=IPython.terminal.debugger:TerminalPdb") -def pytest_namespace(): - return {'set_trace': pytestPDB().set_trace} def pytest_configure(config): + if config.getvalue("usepdb_cls"): + modname, classname = config.getvalue("usepdb_cls").split(":") + __import__(modname) + pdb_cls = getattr(sys.modules[modname], classname) + else: + pdb_cls = pdb.Pdb + if config.getvalue("usepdb"): config.pluginmanager.register(PdbInvoke(), 'pdbinvoke') old = (pdb.set_trace, pytestPDB._pluginmanager) + def fin(): pdb.set_trace, pytestPDB._pluginmanager = old pytestPDB._config = None - pdb.set_trace = pytest.set_trace + pytestPDB._pdb_cls = pdb.Pdb + + pdb.set_trace = pytestPDB.set_trace pytestPDB._pluginmanager = config.pluginmanager pytestPDB._config = config + pytestPDB._pdb_cls = pdb_cls config._cleanup.append(fin) + class pytestPDB: """ Pseudo PDB that defers to the real pdb. """ _pluginmanager = None _config = None + _pdb_cls = pdb.Pdb - def set_trace(self): + @classmethod + def set_trace(cls): """ invoke PDB set_trace debugging, dropping any IO capturing. """ import _pytest.config frame = sys._getframe().f_back - if self._pluginmanager is not None: - capman = self._pluginmanager.getplugin("capturemanager") + if cls._pluginmanager is not None: + capman = cls._pluginmanager.getplugin("capturemanager") if capman: - capman.suspendcapture(in_=True) - tw = _pytest.config.create_terminal_writer(self._config) + capman.suspend_global_capture(in_=True) + tw = _pytest.config.create_terminal_writer(cls._config) tw.line() tw.sep(">", "PDB set_trace (IO-capturing turned off)") - self._pluginmanager.hook.pytest_enter_pdb(config=self._config) - pdb.Pdb().set_trace(frame) + cls._pluginmanager.hook.pytest_enter_pdb(config=cls._config) + cls._pdb_cls().set_trace(frame) class PdbInvoke: def pytest_exception_interact(self, node, call, report): capman = node.config.pluginmanager.getplugin("capturemanager") if capman: - out, err = capman.suspendcapture(in_=True) + out, err = capman.suspend_global_capture(in_=True) sys.stdout.write(out) sys.stdout.write(err) _enter_pdb(node, call.excinfo, report) def pytest_internalerror(self, excrepr, excinfo): for line in str(excrepr).split("\n"): - sys.stderr.write("INTERNALERROR> %s\n" %line) + sys.stderr.write("INTERNALERROR> %s\n" % line) sys.stderr.flush() tb = _postmortem_traceback(excinfo) post_mortem(tb) @@ -98,7 +112,7 @@ def _find_last_non_hidden_frame(stack): def post_mortem(t): - class Pdb(pdb.Pdb): + class Pdb(pytestPDB._pdb_cls): def get_stack(self, f, t): stack, i = pdb.Pdb.get_stack(self, f, t) if f is None: diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/deprecated.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/deprecated.py new file mode 100644 index 00000000000..9c0fbeca7bc --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/deprecated.py @@ -0,0 +1,52 @@ +""" +This module contains deprecation messages and bits of code used elsewhere in the codebase +that is planned to be removed in the next pytest release. + +Keeping it in a central location makes it easy to track what is deprecated and should +be removed when the time comes. +""" +from __future__ import absolute_import, division, print_function + + +class RemovedInPytest4Warning(DeprecationWarning): + """warning class for features removed in pytest 4.0""" + + +MAIN_STR_ARGS = 'passing a string to pytest.main() is deprecated, ' \ + 'pass a list of arguments instead.' + +YIELD_TESTS = 'yield tests are deprecated, and scheduled to be removed in pytest 4.0' + +FUNCARG_PREFIX = ( + '{name}: declaring fixtures using "pytest_funcarg__" prefix is deprecated ' + 'and scheduled to be removed in pytest 4.0. ' + 'Please remove the prefix and use the @pytest.fixture decorator instead.') + +SETUP_CFG_PYTEST = '[pytest] section in setup.cfg files is deprecated, use [tool:pytest] instead.' + +GETFUNCARGVALUE = "use of getfuncargvalue is deprecated, use getfixturevalue" + +RESULT_LOG = ( + '--result-log is deprecated and scheduled for removal in pytest 4.0.\n' + 'See https://docs.pytest.org/en/latest/usage.html#creating-resultlog-format-files for more information.' +) + +MARK_INFO_ATTRIBUTE = RemovedInPytest4Warning( + "MarkInfo objects are deprecated as they contain the merged marks" +) + +MARK_PARAMETERSET_UNPACKING = RemovedInPytest4Warning( + "Applying marks directly to parameters is deprecated," + " please use pytest.param(..., marks=...) instead.\n" + "For more details, see: https://docs.pytest.org/en/latest/parametrize.html" +) + +COLLECTOR_MAKEITEM = RemovedInPytest4Warning( + "pycollector makeitem was removed " + "as it is an accidentially leaked internal api" +) + +METAFUNC_ADD_CALL = ( + "Metafunc.addcall is deprecated and scheduled to be removed in pytest 4.0.\n" + "Please use Metafunc.parametrize instead." +) diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/doctest.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/doctest.py similarity index 67% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/doctest.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/doctest.py index a57f7a4949e..bba90e551c5 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/doctest.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/doctest.py @@ -1,41 +1,68 @@ """ discover and run doctests in modules and test files.""" -from __future__ import absolute_import +from __future__ import absolute_import, division, print_function import traceback import pytest -from _pytest._code.code import TerminalRepr, ReprFileLocation, ExceptionInfo -from _pytest.python import FixtureRequest +from _pytest._code.code import ExceptionInfo, ReprFileLocation, TerminalRepr +from _pytest.fixtures import FixtureRequest +DOCTEST_REPORT_CHOICE_NONE = 'none' +DOCTEST_REPORT_CHOICE_CDIFF = 'cdiff' +DOCTEST_REPORT_CHOICE_NDIFF = 'ndiff' +DOCTEST_REPORT_CHOICE_UDIFF = 'udiff' +DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE = 'only_first_failure' + +DOCTEST_REPORT_CHOICES = ( + DOCTEST_REPORT_CHOICE_NONE, + DOCTEST_REPORT_CHOICE_CDIFF, + DOCTEST_REPORT_CHOICE_NDIFF, + DOCTEST_REPORT_CHOICE_UDIFF, + DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE, +) + def pytest_addoption(parser): parser.addini('doctest_optionflags', 'option flags for doctests', - type="args", default=["ELLIPSIS"]) + type="args", default=["ELLIPSIS"]) + parser.addini("doctest_encoding", 'encoding used for doctest files', default="utf-8") group = parser.getgroup("collect") group.addoption("--doctest-modules", - action="store_true", default=False, - help="run doctests in all .py modules", - dest="doctestmodules") + action="store_true", default=False, + help="run doctests in all .py modules", + dest="doctestmodules") + group.addoption("--doctest-report", + type=str.lower, default="udiff", + help="choose another output format for diffs on doctest failure", + choices=DOCTEST_REPORT_CHOICES, + dest="doctestreport") group.addoption("--doctest-glob", - action="append", default=[], metavar="pat", - help="doctests file matching pattern, default: test*.txt", - dest="doctestglob") + action="append", default=[], metavar="pat", + help="doctests file matching pattern, default: test*.txt", + dest="doctestglob") group.addoption("--doctest-ignore-import-errors", - action="store_true", default=False, - help="ignore doctest ImportErrors", - dest="doctest_ignore_import_errors") + action="store_true", default=False, + help="ignore doctest ImportErrors", + dest="doctest_ignore_import_errors") def pytest_collect_file(path, parent): config = parent.config if path.ext == ".py": - if config.option.doctestmodules: + if config.option.doctestmodules and not _is_setup_py(config, path, parent): return DoctestModule(path, parent) elif _is_doctest(config, path, parent): return DoctestTextfile(path, parent) +def _is_setup_py(config, path, parent): + if path.basename != "setup.py": + return False + contents = path.read() + return 'setuptools' in contents or 'distutils' in contents + + def _is_doctest(config, path, parent): if path.ext in ('.txt', '.rst') and parent.session.isinitpath(path): return True @@ -59,7 +86,6 @@ class ReprFailDoctest(TerminalRepr): class DoctestItem(pytest.Item): - def __init__(self, name, parent, runner=None, dtest=None): super(DoctestItem, self).__init__(name, parent) self.runner = runner @@ -70,7 +96,9 @@ class DoctestItem(pytest.Item): def setup(self): if self.dtest is not None: self.fixture_request = _setup_fixtures(self) - globs = dict(getfixture=self.fixture_request.getfuncargvalue) + globs = dict(getfixture=self.fixture_request.getfixturevalue) + for name, value in self.fixture_request.getfixturevalue('doctest_namespace').items(): + globs[name] = value self.dtest.globs.update(globs) def runtest(self): @@ -92,14 +120,14 @@ class DoctestItem(pytest.Item): message = excinfo.type.__name__ reprlocation = ReprFileLocation(filename, lineno, message) checker = _get_checker() - REPORT_UDIFF = doctest.REPORT_UDIFF + report_choice = _get_report_choice(self.config.getoption("doctestreport")) if lineno is not None: lines = doctestfailure.test.docstring.splitlines(False) # add line numbers to the left of the error message lines = ["%03d %s" % (i + test.lineno + 1, x) for (i, x) in enumerate(lines)] # trim docstring error lines to 10 - lines = lines[example.lineno - 9:example.lineno + 1] + lines = lines[max(example.lineno - 9, 0):example.lineno + 1] else: lines = ['EXAMPLE LOCATION UNKNOWN, not showing all tests of that example'] indent = '>>>' @@ -108,18 +136,18 @@ class DoctestItem(pytest.Item): indent = '...' if excinfo.errisinstance(doctest.DocTestFailure): lines += checker.output_difference(example, - doctestfailure.got, REPORT_UDIFF).split("\n") + doctestfailure.got, report_choice).split("\n") else: inner_excinfo = ExceptionInfo(excinfo.value.exc_info) lines += ["UNEXPECTED EXCEPTION: %s" % - repr(inner_excinfo.value)] + repr(inner_excinfo.value)] lines += traceback.format_exception(*excinfo.value.exc_info) return ReprFailDoctest(reprlocation, lines) else: return super(DoctestItem, self).repr_failure(excinfo) def reportinfo(self): - return self.fspath, None, "[doctest] %s" % self.name + return self.fspath, self.dtest.lineno, "[doctest] %s" % self.name def _get_flag_lookup(): @@ -144,29 +172,29 @@ def get_optionflags(parent): return flag_acc -class DoctestTextfile(DoctestItem, pytest.Module): +class DoctestTextfile(pytest.Module): + obj = None - def runtest(self): + def collect(self): import doctest - fixture_request = _setup_fixtures(self) # inspired by doctest.testfile; ideally we would use it directly, # but it doesn't support passing a custom checker - text = self.fspath.read() + encoding = self.config.getini("doctest_encoding") + text = self.fspath.read_text(encoding) filename = str(self.fspath) name = self.fspath.basename - globs = dict(getfixture=fixture_request.getfuncargvalue) - if '__name__' not in globs: - globs['__name__'] = '__main__' + globs = {'__name__': '__main__'} optionflags = get_optionflags(self) runner = doctest.DebugRunner(verbose=0, optionflags=optionflags, checker=_get_checker()) + _fix_spoof_python2(runner, encoding) parser = doctest.DocTestParser() test = parser.get_doctest(text, globs, name, filename, 0) - _check_all_skipped(test) - runner.run(test) + if test.examples: + yield DoctestItem(test.name, self, runner, test) def _check_all_skipped(test): @@ -197,6 +225,7 @@ class DoctestModule(pytest.Module): optionflags = get_optionflags(self) runner = doctest.DebugRunner(verbose=0, optionflags=optionflags, checker=_get_checker()) + for test in finder.find(module, module.__name__): if test.examples: # skip empty doctests yield DoctestItem(test.name, self, runner, test) @@ -288,3 +317,53 @@ def _get_allow_bytes_flag(): """ import doctest return doctest.register_optionflag('ALLOW_BYTES') + + +def _get_report_choice(key): + """ + This function returns the actual `doctest` module flag value, we want to do it as late as possible to avoid + importing `doctest` and all its dependencies when parsing options, as it adds overhead and breaks tests. + """ + import doctest + + return { + DOCTEST_REPORT_CHOICE_UDIFF: doctest.REPORT_UDIFF, + DOCTEST_REPORT_CHOICE_CDIFF: doctest.REPORT_CDIFF, + DOCTEST_REPORT_CHOICE_NDIFF: doctest.REPORT_NDIFF, + DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE: doctest.REPORT_ONLY_FIRST_FAILURE, + DOCTEST_REPORT_CHOICE_NONE: 0, + }[key] + + +def _fix_spoof_python2(runner, encoding): + """ + Installs a "SpoofOut" into the given DebugRunner so it properly deals with unicode output. This + should patch only doctests for text files because they don't have a way to declare their + encoding. Doctests in docstrings from Python modules don't have the same problem given that + Python already decoded the strings. + + This fixes the problem related in issue #2434. + """ + from _pytest.compat import _PY2 + if not _PY2: + return + + from doctest import _SpoofOut + + class UnicodeSpoof(_SpoofOut): + + def getvalue(self): + result = _SpoofOut.getvalue(self) + if encoding: + result = result.decode(encoding) + return result + + runner._fakeout = UnicodeSpoof() + + +@pytest.fixture(scope='session') +def doctest_namespace(): + """ + Inject names into the doctest namespace. + """ + return dict() diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/fixtures.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/fixtures.py new file mode 100644 index 00000000000..e09ffaddba7 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/fixtures.py @@ -0,0 +1,1147 @@ +from __future__ import absolute_import, division, print_function + +import functools +import inspect +import sys +import warnings +from collections import OrderedDict + +import attr +import py +from py._code.code import FormattedExcinfo + +import _pytest +from _pytest import nodes +from _pytest._code.code import TerminalRepr +from _pytest.compat import ( + NOTSET, exc_clear, _format_args, + getfslineno, get_real_func, + is_generator, isclass, getimfunc, + getlocation, getfuncargnames, + safe_getattr, + FuncargnamesCompatAttr, +) +from _pytest.outcomes import fail, TEST_OUTCOME + + +def pytest_sessionstart(session): + import _pytest.python + + scopename2class.update({ + 'class': _pytest.python.Class, + 'module': _pytest.python.Module, + 'function': _pytest.main.Item, + 'session': _pytest.main.Session, + }) + session._fixturemanager = FixtureManager(session) + + +scopename2class = {} + + +scope2props = dict(session=()) +scope2props["module"] = ("fspath", "module") +scope2props["class"] = scope2props["module"] + ("cls",) +scope2props["instance"] = scope2props["class"] + ("instance", ) +scope2props["function"] = scope2props["instance"] + ("function", "keywords") + + +def scopeproperty(name=None, doc=None): + def decoratescope(func): + scopename = name or func.__name__ + + def provide(self): + if func.__name__ in scope2props[self.scope]: + return func(self) + raise AttributeError("%s not available in %s-scoped context" % ( + scopename, self.scope)) + + return property(provide, None, None, func.__doc__) + return decoratescope + + +def get_scope_node(node, scope): + cls = scopename2class.get(scope) + if cls is None: + raise ValueError("unknown scope") + return node.getparent(cls) + + +def add_funcarg_pseudo_fixture_def(collector, metafunc, fixturemanager): + # this function will transform all collected calls to a functions + # if they use direct funcargs (i.e. direct parametrization) + # because we want later test execution to be able to rely on + # an existing FixtureDef structure for all arguments. + # XXX we can probably avoid this algorithm if we modify CallSpec2 + # to directly care for creating the fixturedefs within its methods. + if not metafunc._calls[0].funcargs: + return # this function call does not have direct parametrization + # collect funcargs of all callspecs into a list of values + arg2params = {} + arg2scope = {} + for callspec in metafunc._calls: + for argname, argvalue in callspec.funcargs.items(): + assert argname not in callspec.params + callspec.params[argname] = argvalue + arg2params_list = arg2params.setdefault(argname, []) + callspec.indices[argname] = len(arg2params_list) + arg2params_list.append(argvalue) + if argname not in arg2scope: + scopenum = callspec._arg2scopenum.get(argname, + scopenum_function) + arg2scope[argname] = scopes[scopenum] + callspec.funcargs.clear() + + # register artificial FixtureDef's so that later at test execution + # time we can rely on a proper FixtureDef to exist for fixture setup. + arg2fixturedefs = metafunc._arg2fixturedefs + for argname, valuelist in arg2params.items(): + # if we have a scope that is higher than function we need + # to make sure we only ever create an according fixturedef on + # a per-scope basis. We thus store and cache the fixturedef on the + # node related to the scope. + scope = arg2scope[argname] + node = None + if scope != "function": + node = get_scope_node(collector, scope) + if node is None: + assert scope == "class" and isinstance(collector, _pytest.python.Module) + # use module-level collector for class-scope (for now) + node = collector + if node and argname in node._name2pseudofixturedef: + arg2fixturedefs[argname] = [node._name2pseudofixturedef[argname]] + else: + fixturedef = FixtureDef(fixturemanager, '', argname, + get_direct_param_fixture_func, + arg2scope[argname], + valuelist, False, False) + arg2fixturedefs[argname] = [fixturedef] + if node is not None: + node._name2pseudofixturedef[argname] = fixturedef + + +def getfixturemarker(obj): + """ return fixturemarker or None if it doesn't exist or raised + exceptions.""" + try: + return getattr(obj, "_pytestfixturefunction", None) + except TEST_OUTCOME: + # some objects raise errors like request (from flask import request) + # we don't expect them to be fixture functions + return None + + +def get_parametrized_fixture_keys(item, scopenum): + """ return list of keys for all parametrized arguments which match + the specified scope. """ + assert scopenum < scopenum_function # function + try: + cs = item.callspec + except AttributeError: + pass + else: + # cs.indices.items() is random order of argnames. Need to + # sort this so that different calls to + # get_parametrized_fixture_keys will be deterministic. + for argname, param_index in sorted(cs.indices.items()): + if cs._arg2scopenum[argname] != scopenum: + continue + if scopenum == 0: # session + key = (argname, param_index) + elif scopenum == 1: # module + key = (argname, param_index, item.fspath) + elif scopenum == 2: # class + key = (argname, param_index, item.fspath, item.cls) + yield key + + +# algorithm for sorting on a per-parametrized resource setup basis +# it is called for scopenum==0 (session) first and performs sorting +# down to the lower scopes such as to minimize number of "high scope" +# setups and teardowns + +def reorder_items(items): + argkeys_cache = {} + for scopenum in range(0, scopenum_function): + argkeys_cache[scopenum] = d = {} + for item in items: + keys = OrderedDict.fromkeys(get_parametrized_fixture_keys(item, scopenum)) + if keys: + d[item] = keys + return reorder_items_atscope(items, set(), argkeys_cache, 0) + + +def reorder_items_atscope(items, ignore, argkeys_cache, scopenum): + if scopenum >= scopenum_function or len(items) < 3: + return items + items_done = [] + while 1: + items_before, items_same, items_other, newignore = \ + slice_items(items, ignore, argkeys_cache[scopenum]) + items_before = reorder_items_atscope( + items_before, ignore, argkeys_cache, scopenum + 1) + if items_same is None: + # nothing to reorder in this scope + assert items_other is None + return items_done + items_before + items_done.extend(items_before) + items = items_same + items_other + ignore = newignore + + +def slice_items(items, ignore, scoped_argkeys_cache): + # we pick the first item which uses a fixture instance in the + # requested scope and which we haven't seen yet. We slice the input + # items list into a list of items_nomatch, items_same and + # items_other + if scoped_argkeys_cache: # do we need to do work at all? + it = iter(items) + # first find a slicing key + for i, item in enumerate(it): + argkeys = scoped_argkeys_cache.get(item) + if argkeys is not None: + newargkeys = OrderedDict.fromkeys(k for k in argkeys if k not in ignore) + if newargkeys: # found a slicing key + slicing_argkey, _ = newargkeys.popitem() + items_before = items[:i] + items_same = [item] + items_other = [] + # now slice the remainder of the list + for item in it: + argkeys = scoped_argkeys_cache.get(item) + if argkeys and slicing_argkey in argkeys and \ + slicing_argkey not in ignore: + items_same.append(item) + else: + items_other.append(item) + newignore = ignore.copy() + newignore.add(slicing_argkey) + return (items_before, items_same, items_other, newignore) + return items, None, None, None + + +def fillfixtures(function): + """ fill missing funcargs for a test function. """ + try: + request = function._request + except AttributeError: + # XXX this special code path is only expected to execute + # with the oejskit plugin. It uses classes with funcargs + # and we thus have to work a bit to allow this. + fm = function.session._fixturemanager + fi = fm.getfixtureinfo(function.parent, function.obj, None) + function._fixtureinfo = fi + request = function._request = FixtureRequest(function) + request._fillfixtures() + # prune out funcargs for jstests + newfuncargs = {} + for name in fi.argnames: + newfuncargs[name] = function.funcargs[name] + function.funcargs = newfuncargs + else: + request._fillfixtures() + + +def get_direct_param_fixture_func(request): + return request.param + + +class FuncFixtureInfo: + def __init__(self, argnames, names_closure, name2fixturedefs): + self.argnames = argnames + self.names_closure = names_closure + self.name2fixturedefs = name2fixturedefs + + +class FixtureRequest(FuncargnamesCompatAttr): + """ A request for a fixture from a test or fixture function. + + A request object gives access to the requesting test context + and has an optional ``param`` attribute in case + the fixture is parametrized indirectly. + """ + + def __init__(self, pyfuncitem): + self._pyfuncitem = pyfuncitem + #: fixture for which this request is being performed + self.fixturename = None + #: Scope string, one of "function", "class", "module", "session" + self.scope = "function" + self._fixture_values = {} # argname -> fixture value + self._fixture_defs = {} # argname -> FixtureDef + fixtureinfo = pyfuncitem._fixtureinfo + self._arg2fixturedefs = fixtureinfo.name2fixturedefs.copy() + self._arg2index = {} + self._fixturemanager = pyfuncitem.session._fixturemanager + + @property + def fixturenames(self): + # backward incompatible note: now a readonly property + return list(self._pyfuncitem._fixtureinfo.names_closure) + + @property + def node(self): + """ underlying collection node (depends on current request scope)""" + return self._getscopeitem(self.scope) + + def _getnextfixturedef(self, argname): + fixturedefs = self._arg2fixturedefs.get(argname, None) + if fixturedefs is None: + # we arrive here because of a a dynamic call to + # getfixturevalue(argname) usage which was naturally + # not known at parsing/collection time + parentid = self._pyfuncitem.parent.nodeid + fixturedefs = self._fixturemanager.getfixturedefs(argname, parentid) + self._arg2fixturedefs[argname] = fixturedefs + # fixturedefs list is immutable so we maintain a decreasing index + index = self._arg2index.get(argname, 0) - 1 + if fixturedefs is None or (-index > len(fixturedefs)): + raise FixtureLookupError(argname, self) + self._arg2index[argname] = index + return fixturedefs[index] + + @property + def config(self): + """ the pytest config object associated with this request. """ + return self._pyfuncitem.config + + @scopeproperty() + def function(self): + """ test function object if the request has a per-function scope. """ + return self._pyfuncitem.obj + + @scopeproperty("class") + def cls(self): + """ class (can be None) where the test function was collected. """ + clscol = self._pyfuncitem.getparent(_pytest.python.Class) + if clscol: + return clscol.obj + + @property + def instance(self): + """ instance (can be None) on which test function was collected. """ + # unittest support hack, see _pytest.unittest.TestCaseFunction + try: + return self._pyfuncitem._testcase + except AttributeError: + function = getattr(self, "function", None) + if function is not None: + return py.builtin._getimself(function) + + @scopeproperty() + def module(self): + """ python module object where the test function was collected. """ + return self._pyfuncitem.getparent(_pytest.python.Module).obj + + @scopeproperty() + def fspath(self): + """ the file system path of the test module which collected this test. """ + return self._pyfuncitem.fspath + + @property + def keywords(self): + """ keywords/markers dictionary for the underlying node. """ + return self.node.keywords + + @property + def session(self): + """ pytest session object. """ + return self._pyfuncitem.session + + def addfinalizer(self, finalizer): + """ add finalizer/teardown function to be called after the + last test within the requesting test context finished + execution. """ + # XXX usually this method is shadowed by fixturedef specific ones + self._addfinalizer(finalizer, scope=self.scope) + + def _addfinalizer(self, finalizer, scope): + colitem = self._getscopeitem(scope) + self._pyfuncitem.session._setupstate.addfinalizer( + finalizer=finalizer, colitem=colitem) + + def applymarker(self, marker): + """ Apply a marker to a single test function invocation. + This method is useful if you don't want to have a keyword/marker + on all function invocations. + + :arg marker: a :py:class:`_pytest.mark.MarkDecorator` object + created by a call to ``pytest.mark.NAME(...)``. + """ + try: + self.node.keywords[marker.markname] = marker + except AttributeError: + raise ValueError(marker) + + def raiseerror(self, msg): + """ raise a FixtureLookupError with the given message. """ + raise self._fixturemanager.FixtureLookupError(None, self, msg) + + def _fillfixtures(self): + item = self._pyfuncitem + fixturenames = getattr(item, "fixturenames", self.fixturenames) + for argname in fixturenames: + if argname not in item.funcargs: + item.funcargs[argname] = self.getfixturevalue(argname) + + def cached_setup(self, setup, teardown=None, scope="module", extrakey=None): + """ (deprecated) Return a testing resource managed by ``setup`` & + ``teardown`` calls. ``scope`` and ``extrakey`` determine when the + ``teardown`` function will be called so that subsequent calls to + ``setup`` would recreate the resource. With pytest-2.3 you often + do not need ``cached_setup()`` as you can directly declare a scope + on a fixture function and register a finalizer through + ``request.addfinalizer()``. + + :arg teardown: function receiving a previously setup resource. + :arg setup: a no-argument function creating a resource. + :arg scope: a string value out of ``function``, ``class``, ``module`` + or ``session`` indicating the caching lifecycle of the resource. + :arg extrakey: added to internal caching key of (funcargname, scope). + """ + if not hasattr(self.config, '_setupcache'): + self.config._setupcache = {} # XXX weakref? + cachekey = (self.fixturename, self._getscopeitem(scope), extrakey) + cache = self.config._setupcache + try: + val = cache[cachekey] + except KeyError: + self._check_scope(self.fixturename, self.scope, scope) + val = setup() + cache[cachekey] = val + if teardown is not None: + def finalizer(): + del cache[cachekey] + teardown(val) + self._addfinalizer(finalizer, scope=scope) + return val + + def getfixturevalue(self, argname): + """ Dynamically run a named fixture function. + + Declaring fixtures via function argument is recommended where possible. + But if you can only decide whether to use another fixture at test + setup time, you may use this function to retrieve it inside a fixture + or test function body. + """ + return self._get_active_fixturedef(argname).cached_result[0] + + def getfuncargvalue(self, argname): + """ Deprecated, use getfixturevalue. """ + from _pytest import deprecated + warnings.warn( + deprecated.GETFUNCARGVALUE, + DeprecationWarning, + stacklevel=2) + return self.getfixturevalue(argname) + + def _get_active_fixturedef(self, argname): + try: + return self._fixture_defs[argname] + except KeyError: + try: + fixturedef = self._getnextfixturedef(argname) + except FixtureLookupError: + if argname == "request": + class PseudoFixtureDef: + cached_result = (self, [0], None) + scope = "function" + return PseudoFixtureDef + raise + # remove indent to prevent the python3 exception + # from leaking into the call + result = self._getfixturevalue(fixturedef) + self._fixture_values[argname] = result + self._fixture_defs[argname] = fixturedef + return fixturedef + + def _get_fixturestack(self): + current = self + values = [] + while 1: + fixturedef = getattr(current, "_fixturedef", None) + if fixturedef is None: + values.reverse() + return values + values.append(fixturedef) + current = current._parent_request + + def _getfixturevalue(self, fixturedef): + # prepare a subrequest object before calling fixture function + # (latter managed by fixturedef) + argname = fixturedef.argname + funcitem = self._pyfuncitem + scope = fixturedef.scope + try: + param = funcitem.callspec.getparam(argname) + except (AttributeError, ValueError): + param = NOTSET + param_index = 0 + if fixturedef.params is not None: + frame = inspect.stack()[3] + frameinfo = inspect.getframeinfo(frame[0]) + source_path = frameinfo.filename + source_lineno = frameinfo.lineno + source_path = py.path.local(source_path) + if source_path.relto(funcitem.config.rootdir): + source_path = source_path.relto(funcitem.config.rootdir) + msg = ( + "The requested fixture has no parameter defined for the " + "current test.\n\nRequested fixture '{0}' defined in:\n{1}" + "\n\nRequested here:\n{2}:{3}".format( + fixturedef.argname, + getlocation(fixturedef.func, funcitem.config.rootdir), + source_path, + source_lineno, + ) + ) + fail(msg) + else: + # indices might not be set if old-style metafunc.addcall() was used + param_index = funcitem.callspec.indices.get(argname, 0) + # if a parametrize invocation set a scope it will override + # the static scope defined with the fixture function + paramscopenum = funcitem.callspec._arg2scopenum.get(argname) + if paramscopenum is not None: + scope = scopes[paramscopenum] + + subrequest = SubRequest(self, scope, param, param_index, fixturedef) + + # check if a higher-level scoped fixture accesses a lower level one + subrequest._check_scope(argname, self.scope, scope) + + # clear sys.exc_info before invoking the fixture (python bug?) + # if its not explicitly cleared it will leak into the call + exc_clear() + try: + # call the fixture function + val = fixturedef.execute(request=subrequest) + finally: + # if fixture function failed it might have registered finalizers + self.session._setupstate.addfinalizer(functools.partial(fixturedef.finish, request=subrequest), + subrequest.node) + return val + + def _check_scope(self, argname, invoking_scope, requested_scope): + if argname == "request": + return + if scopemismatch(invoking_scope, requested_scope): + # try to report something helpful + lines = self._factorytraceback() + fail("ScopeMismatch: You tried to access the %r scoped " + "fixture %r with a %r scoped request object, " + "involved factories\n%s" % ( + (requested_scope, argname, invoking_scope, "\n".join(lines))), + pytrace=False) + + def _factorytraceback(self): + lines = [] + for fixturedef in self._get_fixturestack(): + factory = fixturedef.func + fs, lineno = getfslineno(factory) + p = self._pyfuncitem.session.fspath.bestrelpath(fs) + args = _format_args(factory) + lines.append("%s:%d: def %s%s" % ( + p, lineno, factory.__name__, args)) + return lines + + def _getscopeitem(self, scope): + if scope == "function": + # this might also be a non-function Item despite its attribute name + return self._pyfuncitem + node = get_scope_node(self._pyfuncitem, scope) + if node is None and scope == "class": + # fallback to function item itself + node = self._pyfuncitem + assert node, 'Could not obtain a node for scope "{}" for function {!r}'.format(scope, self._pyfuncitem) + return node + + def __repr__(self): + return "" % (self.node) + + +class SubRequest(FixtureRequest): + """ a sub request for handling getting a fixture from a + test function/fixture. """ + + def __init__(self, request, scope, param, param_index, fixturedef): + self._parent_request = request + self.fixturename = fixturedef.argname + if param is not NOTSET: + self.param = param + self.param_index = param_index + self.scope = scope + self._fixturedef = fixturedef + self._pyfuncitem = request._pyfuncitem + self._fixture_values = request._fixture_values + self._fixture_defs = request._fixture_defs + self._arg2fixturedefs = request._arg2fixturedefs + self._arg2index = request._arg2index + self._fixturemanager = request._fixturemanager + + def __repr__(self): + return "" % (self.fixturename, self._pyfuncitem) + + def addfinalizer(self, finalizer): + self._fixturedef.addfinalizer(finalizer) + + +class ScopeMismatchError(Exception): + """ A fixture function tries to use a different fixture function which + which has a lower scope (e.g. a Session one calls a function one) + """ + + +scopes = "session module class function".split() +scopenum_function = scopes.index("function") + + +def scopemismatch(currentscope, newscope): + return scopes.index(newscope) > scopes.index(currentscope) + + +def scope2index(scope, descr, where=None): + """Look up the index of ``scope`` and raise a descriptive value error + if not defined. + """ + try: + return scopes.index(scope) + except ValueError: + raise ValueError( + "{0} {1}has an unsupported scope value '{2}'".format( + descr, 'from {0} '.format(where) if where else '', + scope) + ) + + +class FixtureLookupError(LookupError): + """ could not return a requested Fixture (missing or invalid). """ + + def __init__(self, argname, request, msg=None): + self.argname = argname + self.request = request + self.fixturestack = request._get_fixturestack() + self.msg = msg + + def formatrepr(self): + tblines = [] + addline = tblines.append + stack = [self.request._pyfuncitem.obj] + stack.extend(map(lambda x: x.func, self.fixturestack)) + msg = self.msg + if msg is not None: + # the last fixture raise an error, let's present + # it at the requesting side + stack = stack[:-1] + for function in stack: + fspath, lineno = getfslineno(function) + try: + lines, _ = inspect.getsourcelines(get_real_func(function)) + except (IOError, IndexError, TypeError): + error_msg = "file %s, line %s: source code not available" + addline(error_msg % (fspath, lineno + 1)) + else: + addline("file %s, line %s" % (fspath, lineno + 1)) + for i, line in enumerate(lines): + line = line.rstrip() + addline(" " + line) + if line.lstrip().startswith('def'): + break + + if msg is None: + fm = self.request._fixturemanager + available = [] + parentid = self.request._pyfuncitem.parent.nodeid + for name, fixturedefs in fm._arg2fixturedefs.items(): + faclist = list(fm._matchfactories(fixturedefs, parentid)) + if faclist and name not in available: + available.append(name) + msg = "fixture %r not found" % (self.argname,) + msg += "\n available fixtures: %s" % (", ".join(sorted(available)),) + msg += "\n use 'pytest --fixtures [testpath]' for help on them." + + return FixtureLookupErrorRepr(fspath, lineno, tblines, msg, self.argname) + + +class FixtureLookupErrorRepr(TerminalRepr): + def __init__(self, filename, firstlineno, tblines, errorstring, argname): + self.tblines = tblines + self.errorstring = errorstring + self.filename = filename + self.firstlineno = firstlineno + self.argname = argname + + def toterminal(self, tw): + # tw.line("FixtureLookupError: %s" %(self.argname), red=True) + for tbline in self.tblines: + tw.line(tbline.rstrip()) + lines = self.errorstring.split("\n") + if lines: + tw.line('{0} {1}'.format(FormattedExcinfo.fail_marker, + lines[0].strip()), red=True) + for line in lines[1:]: + tw.line('{0} {1}'.format(FormattedExcinfo.flow_marker, + line.strip()), red=True) + tw.line() + tw.line("%s:%d" % (self.filename, self.firstlineno + 1)) + + +def fail_fixturefunc(fixturefunc, msg): + fs, lineno = getfslineno(fixturefunc) + location = "%s:%s" % (fs, lineno + 1) + source = _pytest._code.Source(fixturefunc) + fail(msg + ":\n\n" + str(source.indent()) + "\n" + location, + pytrace=False) + + +def call_fixture_func(fixturefunc, request, kwargs): + yieldctx = is_generator(fixturefunc) + if yieldctx: + it = fixturefunc(**kwargs) + res = next(it) + + def teardown(): + try: + next(it) + except StopIteration: + pass + else: + fail_fixturefunc(fixturefunc, + "yield_fixture function has more than one 'yield'") + + request.addfinalizer(teardown) + else: + res = fixturefunc(**kwargs) + return res + + +class FixtureDef: + """ A container for a factory definition. """ + + def __init__(self, fixturemanager, baseid, argname, func, scope, params, + unittest=False, ids=None): + self._fixturemanager = fixturemanager + self.baseid = baseid or '' + self.has_location = baseid is not None + self.func = func + self.argname = argname + self.scope = scope + self.scopenum = scope2index( + scope or "function", + descr='fixture {0}'.format(func.__name__), + where=baseid + ) + self.params = params + self.argnames = getfuncargnames(func, is_method=unittest) + self.unittest = unittest + self.ids = ids + self._finalizers = [] + + def addfinalizer(self, finalizer): + self._finalizers.append(finalizer) + + def finish(self, request): + exceptions = [] + try: + while self._finalizers: + try: + func = self._finalizers.pop() + func() + except: # noqa + exceptions.append(sys.exc_info()) + if exceptions: + e = exceptions[0] + del exceptions # ensure we don't keep all frames alive because of the traceback + py.builtin._reraise(*e) + + finally: + hook = self._fixturemanager.session.gethookproxy(request.node.fspath) + hook.pytest_fixture_post_finalizer(fixturedef=self, request=request) + # even if finalization fails, we invalidate + # the cached fixture value and remove + # all finalizers because they may be bound methods which will + # keep instances alive + if hasattr(self, "cached_result"): + del self.cached_result + self._finalizers = [] + + def execute(self, request): + # get required arguments and register our own finish() + # with their finalization + for argname in self.argnames: + fixturedef = request._get_active_fixturedef(argname) + if argname != "request": + fixturedef.addfinalizer(functools.partial(self.finish, request=request)) + + my_cache_key = request.param_index + cached_result = getattr(self, "cached_result", None) + if cached_result is not None: + result, cache_key, err = cached_result + if my_cache_key == cache_key: + if err is not None: + py.builtin._reraise(*err) + else: + return result + # we have a previous but differently parametrized fixture instance + # so we need to tear it down before creating a new one + self.finish(request) + assert not hasattr(self, "cached_result") + + hook = self._fixturemanager.session.gethookproxy(request.node.fspath) + return hook.pytest_fixture_setup(fixturedef=self, request=request) + + def __repr__(self): + return ("" % + (self.argname, self.scope, self.baseid)) + + +def pytest_fixture_setup(fixturedef, request): + """ Execution of fixture setup. """ + kwargs = {} + for argname in fixturedef.argnames: + fixdef = request._get_active_fixturedef(argname) + result, arg_cache_key, exc = fixdef.cached_result + request._check_scope(argname, request.scope, fixdef.scope) + kwargs[argname] = result + + fixturefunc = fixturedef.func + if fixturedef.unittest: + if request.instance is not None: + # bind the unbound method to the TestCase instance + fixturefunc = fixturedef.func.__get__(request.instance) + else: + # the fixture function needs to be bound to the actual + # request.instance so that code working with "fixturedef" behaves + # as expected. + if request.instance is not None: + fixturefunc = getimfunc(fixturedef.func) + if fixturefunc != fixturedef.func: + fixturefunc = fixturefunc.__get__(request.instance) + my_cache_key = request.param_index + try: + result = call_fixture_func(fixturefunc, request, kwargs) + except TEST_OUTCOME: + fixturedef.cached_result = (None, my_cache_key, sys.exc_info()) + raise + fixturedef.cached_result = (result, my_cache_key, None) + return result + + +def _ensure_immutable_ids(ids): + if ids is None: + return + if callable(ids): + return ids + return tuple(ids) + + +@attr.s(frozen=True) +class FixtureFunctionMarker(object): + scope = attr.ib() + params = attr.ib(convert=attr.converters.optional(tuple)) + autouse = attr.ib(default=False) + ids = attr.ib(default=None, convert=_ensure_immutable_ids) + name = attr.ib(default=None) + + def __call__(self, function): + if isclass(function): + raise ValueError( + "class fixtures not supported (may be in the future)") + function._pytestfixturefunction = self + return function + + +def fixture(scope="function", params=None, autouse=False, ids=None, name=None): + """ (return a) decorator to mark a fixture factory function. + + This decorator can be used (with or without parameters) to define a + fixture function. The name of the fixture function can later be + referenced to cause its invocation ahead of running tests: test + modules or classes can use the pytest.mark.usefixtures(fixturename) + marker. Test functions can directly use fixture names as input + arguments in which case the fixture instance returned from the fixture + function will be injected. + + :arg scope: the scope for which this fixture is shared, one of + "function" (default), "class", "module" or "session". + + :arg params: an optional list of parameters which will cause multiple + invocations of the fixture function and all of the tests + using it. + + :arg autouse: if True, the fixture func is activated for all tests that + can see it. If False (the default) then an explicit + reference is needed to activate the fixture. + + :arg ids: list of string ids each corresponding to the params + so that they are part of the test id. If no ids are provided + they will be generated automatically from the params. + + :arg name: the name of the fixture. This defaults to the name of the + decorated function. If a fixture is used in the same module in + which it is defined, the function name of the fixture will be + shadowed by the function arg that requests the fixture; one way + to resolve this is to name the decorated function + ``fixture_`` and then use + ``@pytest.fixture(name='')``. + + Fixtures can optionally provide their values to test functions using a ``yield`` statement, + instead of ``return``. In this case, the code block after the ``yield`` statement is executed + as teardown code regardless of the test outcome. A fixture function must yield exactly once. + """ + if callable(scope) and params is None and autouse is False: + # direct decoration + return FixtureFunctionMarker( + "function", params, autouse, name=name)(scope) + if params is not None and not isinstance(params, (list, tuple)): + params = list(params) + return FixtureFunctionMarker(scope, params, autouse, ids=ids, name=name) + + +def yield_fixture(scope="function", params=None, autouse=False, ids=None, name=None): + """ (return a) decorator to mark a yield-fixture factory function. + + .. deprecated:: 3.0 + Use :py:func:`pytest.fixture` directly instead. + """ + if callable(scope) and params is None and not autouse: + # direct decoration + return FixtureFunctionMarker( + "function", params, autouse, ids=ids, name=name)(scope) + else: + return FixtureFunctionMarker(scope, params, autouse, ids=ids, name=name) + + +defaultfuncargprefixmarker = fixture() + + +@fixture(scope="session") +def pytestconfig(request): + """ the pytest config object with access to command line opts.""" + return request.config + + +class FixtureManager: + """ + pytest fixtures definitions and information is stored and managed + from this class. + + During collection fm.parsefactories() is called multiple times to parse + fixture function definitions into FixtureDef objects and internal + data structures. + + During collection of test functions, metafunc-mechanics instantiate + a FuncFixtureInfo object which is cached per node/func-name. + This FuncFixtureInfo object is later retrieved by Function nodes + which themselves offer a fixturenames attribute. + + The FuncFixtureInfo object holds information about fixtures and FixtureDefs + relevant for a particular function. An initial list of fixtures is + assembled like this: + + - ini-defined usefixtures + - autouse-marked fixtures along the collection chain up from the function + - usefixtures markers at module/class/function level + - test function funcargs + + Subsequently the funcfixtureinfo.fixturenames attribute is computed + as the closure of the fixtures needed to setup the initial fixtures, + i. e. fixtures needed by fixture functions themselves are appended + to the fixturenames list. + + Upon the test-setup phases all fixturenames are instantiated, retrieved + by a lookup of their FuncFixtureInfo. + """ + + _argprefix = "pytest_funcarg__" + FixtureLookupError = FixtureLookupError + FixtureLookupErrorRepr = FixtureLookupErrorRepr + + def __init__(self, session): + self.session = session + self.config = session.config + self._arg2fixturedefs = {} + self._holderobjseen = set() + self._arg2finish = {} + self._nodeid_and_autousenames = [("", self.config.getini("usefixtures"))] + session.config.pluginmanager.register(self, "funcmanage") + + def getfixtureinfo(self, node, func, cls, funcargs=True): + if funcargs and not hasattr(node, "nofuncargs"): + argnames = getfuncargnames(func, cls=cls) + else: + argnames = () + usefixtures = getattr(func, "usefixtures", None) + initialnames = argnames + if usefixtures is not None: + initialnames = usefixtures.args + initialnames + fm = node.session._fixturemanager + names_closure, arg2fixturedefs = fm.getfixtureclosure(initialnames, + node) + return FuncFixtureInfo(argnames, names_closure, arg2fixturedefs) + + def pytest_plugin_registered(self, plugin): + nodeid = None + try: + p = py.path.local(plugin.__file__) + except AttributeError: + pass + else: + # construct the base nodeid which is later used to check + # what fixtures are visible for particular tests (as denoted + # by their test id) + if p.basename.startswith("conftest.py"): + nodeid = p.dirpath().relto(self.config.rootdir) + if p.sep != nodes.SEP: + nodeid = nodeid.replace(p.sep, nodes.SEP) + self.parsefactories(plugin, nodeid) + + def _getautousenames(self, nodeid): + """ return a tuple of fixture names to be used. """ + autousenames = [] + for baseid, basenames in self._nodeid_and_autousenames: + if nodeid.startswith(baseid): + if baseid: + i = len(baseid) + nextchar = nodeid[i:i + 1] + if nextchar and nextchar not in ":/": + continue + autousenames.extend(basenames) + # make sure autousenames are sorted by scope, scopenum 0 is session + autousenames.sort( + key=lambda x: self._arg2fixturedefs[x][-1].scopenum) + return autousenames + + def getfixtureclosure(self, fixturenames, parentnode): + # collect the closure of all fixtures , starting with the given + # fixturenames as the initial set. As we have to visit all + # factory definitions anyway, we also return a arg2fixturedefs + # mapping so that the caller can reuse it and does not have + # to re-discover fixturedefs again for each fixturename + # (discovering matching fixtures for a given name/node is expensive) + + parentid = parentnode.nodeid + fixturenames_closure = self._getautousenames(parentid) + + def merge(otherlist): + for arg in otherlist: + if arg not in fixturenames_closure: + fixturenames_closure.append(arg) + + merge(fixturenames) + arg2fixturedefs = {} + lastlen = -1 + while lastlen != len(fixturenames_closure): + lastlen = len(fixturenames_closure) + for argname in fixturenames_closure: + if argname in arg2fixturedefs: + continue + fixturedefs = self.getfixturedefs(argname, parentid) + if fixturedefs: + arg2fixturedefs[argname] = fixturedefs + merge(fixturedefs[-1].argnames) + return fixturenames_closure, arg2fixturedefs + + def pytest_generate_tests(self, metafunc): + for argname in metafunc.fixturenames: + faclist = metafunc._arg2fixturedefs.get(argname) + if faclist: + fixturedef = faclist[-1] + if fixturedef.params is not None: + parametrize_func = getattr(metafunc.function, 'parametrize', None) + func_params = getattr(parametrize_func, 'args', [[None]]) + func_kwargs = getattr(parametrize_func, 'kwargs', {}) + # skip directly parametrized arguments + if "argnames" in func_kwargs: + argnames = parametrize_func.kwargs["argnames"] + else: + argnames = func_params[0] + if not isinstance(argnames, (tuple, list)): + argnames = [x.strip() for x in argnames.split(",") if x.strip()] + if argname not in func_params and argname not in argnames: + metafunc.parametrize(argname, fixturedef.params, + indirect=True, scope=fixturedef.scope, + ids=fixturedef.ids) + else: + continue # will raise FixtureLookupError at setup time + + def pytest_collection_modifyitems(self, items): + # separate parametrized setups + items[:] = reorder_items(items) + + def parsefactories(self, node_or_obj, nodeid=NOTSET, unittest=False): + if nodeid is not NOTSET: + holderobj = node_or_obj + else: + holderobj = node_or_obj.obj + nodeid = node_or_obj.nodeid + if holderobj in self._holderobjseen: + return + self._holderobjseen.add(holderobj) + autousenames = [] + for name in dir(holderobj): + # The attribute can be an arbitrary descriptor, so the attribute + # access below can raise. safe_getatt() ignores such exceptions. + obj = safe_getattr(holderobj, name, None) + # fixture functions have a pytest_funcarg__ prefix (pre-2.3 style) + # or are "@pytest.fixture" marked + marker = getfixturemarker(obj) + if marker is None: + if not name.startswith(self._argprefix): + continue + if not callable(obj): + continue + marker = defaultfuncargprefixmarker + from _pytest import deprecated + self.config.warn('C1', deprecated.FUNCARG_PREFIX.format(name=name), nodeid=nodeid) + name = name[len(self._argprefix):] + elif not isinstance(marker, FixtureFunctionMarker): + # magic globals with __getattr__ might have got us a wrong + # fixture attribute + continue + else: + if marker.name: + name = marker.name + msg = 'fixtures cannot have "pytest_funcarg__" prefix ' \ + 'and be decorated with @pytest.fixture:\n%s' % name + assert not name.startswith(self._argprefix), msg + + fixture_def = FixtureDef(self, nodeid, name, obj, + marker.scope, marker.params, + unittest=unittest, ids=marker.ids) + + faclist = self._arg2fixturedefs.setdefault(name, []) + if fixture_def.has_location: + faclist.append(fixture_def) + else: + # fixturedefs with no location are at the front + # so this inserts the current fixturedef after the + # existing fixturedefs from external plugins but + # before the fixturedefs provided in conftests. + i = len([f for f in faclist if not f.has_location]) + faclist.insert(i, fixture_def) + if marker.autouse: + autousenames.append(name) + + if autousenames: + self._nodeid_and_autousenames.append((nodeid or '', autousenames)) + + def getfixturedefs(self, argname, nodeid): + """ + Gets a list of fixtures which are applicable to the given node id. + + :param str argname: name of the fixture to search for + :param str nodeid: full node id of the requesting test. + :return: list[FixtureDef] + """ + try: + fixturedefs = self._arg2fixturedefs[argname] + except KeyError: + return None + else: + return tuple(self._matchfactories(fixturedefs, nodeid)) + + def _matchfactories(self, fixturedefs, nodeid): + for fixturedef in fixturedefs: + if nodes.ischildnode(fixturedef.baseid, nodeid): + yield fixturedef diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/freeze_support.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/freeze_support.py new file mode 100644 index 00000000000..97147a88250 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/freeze_support.py @@ -0,0 +1,43 @@ +""" +Provides a function to report all internal modules for using freezing tools +pytest +""" +from __future__ import absolute_import, division, print_function + + +def freeze_includes(): + """ + Returns a list of module names used by py.test that should be + included by cx_freeze. + """ + import py + import _pytest + result = list(_iter_all_modules(py)) + result += list(_iter_all_modules(_pytest)) + return result + + +def _iter_all_modules(package, prefix=''): + """ + Iterates over the names of all modules that can be found in the given + package, recursively. + Example: + _iter_all_modules(_pytest) -> + ['_pytest.assertion.newinterpret', + '_pytest.capture', + '_pytest.core', + ... + ] + """ + import os + import pkgutil + if type(package) is not str: + path, prefix = package.__path__[0], package.__name__ + '.' + else: + path = package + for _, name, is_package in pkgutil.iter_modules([path]): + if is_package: + for m in _iter_all_modules(os.path.join(path, name), prefix=name + '.'): + yield prefix + m + else: + yield prefix + name diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/helpconfig.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/helpconfig.py similarity index 56% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/helpconfig.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/helpconfig.py index 1df0c56ac7b..e744637f866 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/helpconfig.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/helpconfig.py @@ -1,25 +1,65 @@ """ version info, help messages, tracing configuration. """ +from __future__ import absolute_import, division, print_function + import py import pytest -import os, sys +from _pytest.config import PrintHelp +import os +import sys +from argparse import Action + + +class HelpAction(Action): + """This is an argparse Action that will raise an exception in + order to skip the rest of the argument parsing when --help is passed. + This prevents argparse from quitting due to missing required arguments + when any are defined, for example by ``pytest_addoption``. + This is similar to the way that the builtin argparse --help option is + implemented by raising SystemExit. + """ + + def __init__(self, + option_strings, + dest=None, + default=False, + help=None): + super(HelpAction, self).__init__( + option_strings=option_strings, + dest=dest, + const=True, + default=default, + nargs=0, + help=help) + + def __call__(self, parser, namespace, values, option_string=None): + setattr(namespace, self.dest, self.const) + + # We should only skip the rest of the parsing after preparse is done + if getattr(parser._parser, 'after_preparse', False): + raise PrintHelp + def pytest_addoption(parser): group = parser.getgroup('debugconfig') group.addoption('--version', action="store_true", - help="display pytest lib version and import information.") - group._addoption("-h", "--help", action="store_true", dest="help", - help="show help message and configuration info") - group._addoption('-p', action="append", dest="plugins", default = [], - metavar="name", - help="early-load given plugin (multi-allowed). " - "To avoid loading of plugins, use the `no:` prefix, e.g. " - "`no:doctest`.") + help="display pytest lib version and import information.") + group._addoption("-h", "--help", action=HelpAction, dest="help", + help="show help message and configuration info") + group._addoption('-p', action="append", dest="plugins", default=[], + metavar="name", + help="early-load given plugin (multi-allowed). " + "To avoid loading of plugins, use the `no:` prefix, e.g. " + "`no:doctest`.") group.addoption('--traceconfig', '--trace-config', - action="store_true", default=False, - help="trace considerations of conftest.py files."), + action="store_true", default=False, + help="trace considerations of conftest.py files."), group.addoption('--debug', - action="store_true", dest="debug", default=False, - help="store internal tracing debug information in 'pytestdebug.log'.") + action="store_true", dest="debug", default=False, + help="store internal tracing debug information in 'pytestdebug.log'.") + group._addoption( + '-o', '--override-ini', nargs='*', dest="override_ini", + action="append", + help="override config option with option=value style, e.g. `-o xfail_strict=True`.") @pytest.hookimpl(hookwrapper=True) @@ -30,26 +70,29 @@ def pytest_cmdline_parse(): path = os.path.abspath("pytestdebug.log") debugfile = open(path, 'w') debugfile.write("versions pytest-%s, py-%s, " - "python-%s\ncwd=%s\nargs=%s\n\n" %( - pytest.__version__, py.__version__, - ".".join(map(str, sys.version_info)), - os.getcwd(), config._origargs)) + "python-%s\ncwd=%s\nargs=%s\n\n" % ( + pytest.__version__, py.__version__, + ".".join(map(str, sys.version_info)), + os.getcwd(), config._origargs)) config.trace.root.setwriter(debugfile.write) undo_tracing = config.pluginmanager.enable_tracing() sys.stderr.write("writing pytestdebug information to %s\n" % path) + def unset_tracing(): debugfile.close() sys.stderr.write("wrote pytestdebug information to %s\n" % debugfile.name) config.trace.root.setwriter(None) undo_tracing() + config.add_cleanup(unset_tracing) + def pytest_cmdline_main(config): if config.option.version: p = py.path.local(pytest.__file__) sys.stderr.write("This is pytest version %s, imported from %s\n" % - (pytest.__version__, p)) + (pytest.__version__, p)) plugininfo = getpluginversioninfo(config) if plugininfo: for line in plugininfo: @@ -61,15 +104,15 @@ def pytest_cmdline_main(config): config._ensure_unconfigure() return 0 + def showhelp(config): reporter = config.pluginmanager.get_plugin('terminalreporter') tw = reporter._tw tw.write(config._parser.optparser.format_help()) tw.line() tw.line() - #tw.sep( "=", "config file settings") - tw.line("[pytest] ini-options in the next " - "pytest.ini|tox.ini|setup.cfg file:") + tw.line("[pytest] ini-options in the first " + "pytest.ini|tox.ini|setup.cfg file found:") tw.line() for name in config._parser._ininames: @@ -77,7 +120,7 @@ def showhelp(config): if type is None: type = "string" spec = "%s (%s)" % (name, type) - line = " %-24s %s" %(spec, help) + line = " %-24s %s" % (spec, help) tw.line(line[:tw.fullwidth]) tw.line() @@ -92,8 +135,8 @@ def showhelp(config): tw.line() tw.line() - tw.line("to see available markers type: py.test --markers") - tw.line("to see available fixtures type: py.test --fixtures") + tw.line("to see available markers type: pytest --markers") + tw.line("to see available fixtures type: pytest --fixtures") tw.line("(shown according to specified file_or_dir or current dir " "if not specified)") @@ -106,6 +149,7 @@ conftest_options = [ ('pytest_plugins', 'list of plugin names to load'), ] + def getpluginversioninfo(config): lines = [] plugininfo = config.pluginmanager.list_plugin_distinfo() @@ -117,11 +161,12 @@ def getpluginversioninfo(config): lines.append(" " + content) return lines + def pytest_report_header(config): lines = [] if config.option.debug or config.option.traceconfig: lines.append("using: pytest-%s pylib-%s" % - (pytest.__version__,py.__version__)) + (pytest.__version__, py.__version__)) verinfo = getpluginversioninfo(config) if verinfo: @@ -135,5 +180,5 @@ def pytest_report_header(config): r = plugin.__file__ else: r = repr(plugin) - lines.append(" %-20s: %s" %(name, r)) + lines.append(" %-20s: %s" % (name, r)) return lines diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/hookspec.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/hookspec.py similarity index 72% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/hookspec.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/hookspec.py index 60e9b47d262..440bf99d375 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/hookspec.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/hookspec.py @@ -1,6 +1,6 @@ """ hook specifications for pytest plugins, invoked from main.py and builtin plugins. """ -from _pytest._pluggy import HookspecMarker +from pluggy import HookspecMarker hookspec = HookspecMarker("pytest") @@ -8,6 +8,7 @@ hookspec = HookspecMarker("pytest") # Initialization hooks called for every plugin # ------------------------------------------------------------------------- + @hookspec(historic=True) def pytest_addhooks(pluginmanager): """called at plugin registration time to allow adding new hooks via a call to @@ -16,11 +17,14 @@ def pytest_addhooks(pluginmanager): @hookspec(historic=True) def pytest_namespace(): - """return dict of name->object to be made globally available in + """ + DEPRECATED: this hook causes direct monkeypatching on pytest, its use is strongly discouraged + return dict of name->object to be made globally available in the pytest namespace. This hook is called at plugin registration time. """ + @hookspec(historic=True) def pytest_plugin_registered(plugin, manager): """ a new pytest plugin got registered. """ @@ -34,7 +38,7 @@ def pytest_addoption(parser): .. note:: This function should be implemented only in plugins or ``conftest.py`` - files situated at the tests root directory due to how py.test + files situated at the tests root directory due to how pytest :ref:`discovers plugins during startup `. :arg parser: To add command line options, call @@ -56,11 +60,20 @@ def pytest_addoption(parser): via (deprecated) ``pytest.config``. """ + @hookspec(historic=True) def pytest_configure(config): - """ called after command line options have been parsed - and all plugins and initial conftest files been loaded. - This hook is called for every plugin. + """ + Allows plugins and conftest files to perform initial configuration. + + This hook is called for every plugin and initial conftest file + after command line options have been parsed. + + After that, the hook is called for other conftest files as they are + imported. + + :arg config: pytest config object + :type config: _pytest.config.Config """ # ------------------------------------------------------------------------- @@ -69,17 +82,25 @@ def pytest_configure(config): # discoverable conftest.py local plugins. # ------------------------------------------------------------------------- + @hookspec(firstresult=True) def pytest_cmdline_parse(pluginmanager, args): - """return initialized config object, parsing the specified args. """ + """return initialized config object, parsing the specified args. + + Stops at first non-None result, see :ref:`firstresult` """ + def pytest_cmdline_preparse(config, args): """(deprecated) modify command line arguments before option parsing. """ + @hookspec(firstresult=True) def pytest_cmdline_main(config): """ called for performing the main command line action. The default - implementation will invoke the configure hooks and runtest_mainloop. """ + implementation will invoke the configure hooks and runtest_mainloop. + + Stops at first non-None result, see :ref:`firstresult` """ + def pytest_load_initial_conftests(early_config, parser, args): """ implements the loading of initial conftest files ahead @@ -92,82 +113,124 @@ def pytest_load_initial_conftests(early_config, parser, args): @hookspec(firstresult=True) def pytest_collection(session): - """ perform the collection protocol for the given session. """ + """ perform the collection protocol for the given session. + + Stops at first non-None result, see :ref:`firstresult` """ + def pytest_collection_modifyitems(session, config, items): """ called after collection has been performed, may filter or re-order the items in-place.""" + def pytest_collection_finish(session): """ called after collection has been performed and modified. """ + @hookspec(firstresult=True) def pytest_ignore_collect(path, config): """ return True to prevent considering this path for collection. This hook is consulted for all files and directories prior to calling more specific hooks. + + Stops at first non-None result, see :ref:`firstresult` """ + @hookspec(firstresult=True) def pytest_collect_directory(path, parent): - """ called before traversing a directory for collection files. """ + """ called before traversing a directory for collection files. + + Stops at first non-None result, see :ref:`firstresult` """ + def pytest_collect_file(path, parent): """ return collection Node or None for the given path. Any new node needs to have the specified ``parent`` as a parent.""" # logging hooks for collection + + def pytest_collectstart(collector): """ collector starts collecting. """ + def pytest_itemcollected(item): """ we just collected a test item. """ + def pytest_collectreport(report): """ collector finished collecting. """ + def pytest_deselected(items): """ called for test items deselected by keyword. """ + @hookspec(firstresult=True) def pytest_make_collect_report(collector): - """ perform ``collector.collect()`` and return a CollectReport. """ + """ perform ``collector.collect()`` and return a CollectReport. + + Stops at first non-None result, see :ref:`firstresult` """ # ------------------------------------------------------------------------- # Python test function related hooks # ------------------------------------------------------------------------- + @hookspec(firstresult=True) def pytest_pycollect_makemodule(path, parent): """ return a Module collector or None for the given path. This hook will be called for each matching test module path. The pytest_collect_file hook needs to be used if you want to create test modules for files that do not match as a test module. - """ + + Stops at first non-None result, see :ref:`firstresult` """ + @hookspec(firstresult=True) def pytest_pycollect_makeitem(collector, name, obj): - """ return custom item/collector for a python object in a module, or None. """ + """ return custom item/collector for a python object in a module, or None. + + Stops at first non-None result, see :ref:`firstresult` """ + @hookspec(firstresult=True) def pytest_pyfunc_call(pyfuncitem): - """ call underlying test function. """ + """ call underlying test function. + + Stops at first non-None result, see :ref:`firstresult` """ + def pytest_generate_tests(metafunc): """ generate (multiple) parametrized calls to a test function.""" + +@hookspec(firstresult=True) +def pytest_make_parametrize_id(config, val, argname): + """Return a user-friendly string representation of the given ``val`` that will be used + by @pytest.mark.parametrize calls. Return None if the hook doesn't know about ``val``. + The parameter name is available as ``argname``, if required. + + Stops at first non-None result, see :ref:`firstresult` """ + # ------------------------------------------------------------------------- # generic runtest related hooks # ------------------------------------------------------------------------- + @hookspec(firstresult=True) def pytest_runtestloop(session): """ called for performing the main runtest loop - (after collection finished). """ + (after collection finished). + + Stops at first non-None result, see :ref:`firstresult` """ + def pytest_itemstart(item, node): """ (deprecated, use pytest_runtest_logstart). """ + @hookspec(firstresult=True) def pytest_runtest_protocol(item, nextitem): """ implements the runtest_setup/call/teardown protocol for @@ -181,17 +244,23 @@ def pytest_runtest_protocol(item, nextitem): :py:func:`pytest_runtest_teardown`. :return boolean: True if no further hook implementations should be invoked. - """ + + + Stops at first non-None result, see :ref:`firstresult` """ + def pytest_runtest_logstart(nodeid, location): """ signal the start of running a single test item. """ + def pytest_runtest_setup(item): """ called before ``pytest_runtest_call(item)``. """ + def pytest_runtest_call(item): """ called to execute the test ``item``. """ + def pytest_runtest_teardown(item, nextitem): """ called after ``pytest_runtest_call``. @@ -201,33 +270,56 @@ def pytest_runtest_teardown(item, nextitem): so that nextitem only needs to call setup-functions. """ + @hookspec(firstresult=True) def pytest_runtest_makereport(item, call): """ return a :py:class:`_pytest.runner.TestReport` object - for the given :py:class:`pytest.Item` and + for the given :py:class:`pytest.Item <_pytest.main.Item>` and :py:class:`_pytest.runner.CallInfo`. - """ + + Stops at first non-None result, see :ref:`firstresult` """ + def pytest_runtest_logreport(report): """ process a test setup/call/teardown report relating to the respective phase of executing a test. """ +# ------------------------------------------------------------------------- +# Fixture related hooks +# ------------------------------------------------------------------------- + + +@hookspec(firstresult=True) +def pytest_fixture_setup(fixturedef, request): + """ performs fixture setup execution. + + Stops at first non-None result, see :ref:`firstresult` """ + + +def pytest_fixture_post_finalizer(fixturedef, request): + """ called after fixture teardown, but before the cache is cleared so + the fixture result cache ``fixturedef.cached_result`` can + still be accessed.""" + # ------------------------------------------------------------------------- # test session related hooks # ------------------------------------------------------------------------- + def pytest_sessionstart(session): """ before session.main() is called. """ + def pytest_sessionfinish(session, exitstatus): """ whole test run finishes. """ + def pytest_unconfigure(config): """ called before test process is exited. """ # ------------------------------------------------------------------------- -# hooks for customising the assert methods +# hooks for customizing the assert methods # ------------------------------------------------------------------------- def pytest_assertrepr_compare(config, op, left, right): @@ -236,21 +328,50 @@ def pytest_assertrepr_compare(config, op, left, right): Return None for no custom explanation, otherwise return a list of strings. The strings will be joined by newlines but any newlines *in* a string will be escaped. Note that all but the first line will - be indented sligthly, the intention is for the first line to be a summary. + be indented slightly, the intention is for the first line to be a summary. """ # ------------------------------------------------------------------------- # hooks for influencing reporting (invoked from _pytest_terminal) # ------------------------------------------------------------------------- + def pytest_report_header(config, startdir): - """ return a string to be displayed as header info for terminal reporting.""" + """ return a string or list of strings to be displayed as header info for terminal reporting. + + :param config: the pytest config object. + :param startdir: py.path object with the starting dir + + .. note:: + + This function should be implemented only in plugins or ``conftest.py`` + files situated at the tests root directory due to how pytest + :ref:`discovers plugins during startup `. + """ + + +def pytest_report_collectionfinish(config, startdir, items): + """ + .. versionadded:: 3.2 + + return a string or list of strings to be displayed after collection has finished successfully. + + This strings will be displayed after the standard "collected X items" message. + + :param config: the pytest config object. + :param startdir: py.path object with the starting dir + :param items: list of pytest items that are going to be executed; this list should not be modified. + """ + @hookspec(firstresult=True) def pytest_report_teststatus(report): - """ return result-category, shortletter and verbose word for reporting.""" + """ return result-category, shortletter and verbose word for reporting. -def pytest_terminal_summary(terminalreporter): + Stops at first non-None result, see :ref:`firstresult` """ + + +def pytest_terminal_summary(terminalreporter, exitstatus): """ add additional section in terminal summary reporting. """ @@ -264,20 +385,26 @@ def pytest_logwarning(message, code, nodeid, fslocation): # doctest hooks # ------------------------------------------------------------------------- + @hookspec(firstresult=True) def pytest_doctest_prepare_content(content): - """ return processed content for a given doctest""" + """ return processed content for a given doctest + + Stops at first non-None result, see :ref:`firstresult` """ # ------------------------------------------------------------------------- # error handling and internal debugging hooks # ------------------------------------------------------------------------- + def pytest_internalerror(excrepr, excinfo): """ called for internal errors. """ + def pytest_keyboard_interrupt(excinfo): """ called for keyboard interrupt. """ + def pytest_exception_interact(node, call, report): """called when an exception was raised which can potentially be interactively handled. @@ -286,6 +413,7 @@ def pytest_exception_interact(node, call, report): that is not an internal exception like ``skip.Exception``. """ + def pytest_enter_pdb(config): """ called upon pdb.set_trace(), can be used by plugins to take special action just before the python debugger enters in interactive mode. diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/junitxml.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/junitxml.py similarity index 74% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/junitxml.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/junitxml.py index 660d718a6a8..7fb40dc3548 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/junitxml.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/junitxml.py @@ -4,16 +4,21 @@ Based on initial code from Ross Lawley. -""" -# Output conforms to https://github.com/jenkinsci/xunit-plugin/blob/master/ -# src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd/junit-10.xsd +Output conforms to https://github.com/jenkinsci/xunit-plugin/blob/master/ +src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd/junit-10.xsd +""" +from __future__ import absolute_import, division, print_function + +import functools import py import os import re import sys import time import pytest +from _pytest import nodes +from _pytest.config import filename_arg # Python 2.X and 3.X compatibility if sys.version_info[0] < 3: @@ -27,6 +32,7 @@ else: class Junit(py.xml.Namespace): pass + # We need to get the subset of the invalid unicode ranges according to # XML 1.0 which are valid in this python build. Hence we calculate # this dynamically instead of hardcoding it. The spec range of valid @@ -102,6 +108,8 @@ class _NodeReporter(object): } if testreport.location[1] is not None: attrs["line"] = testreport.location[1] + if hasattr(testreport, "url"): + attrs["url"] = testreport.url self.attrs = attrs def to_xml(self): @@ -116,19 +124,15 @@ class _NodeReporter(object): node = kind(data, message=message) self.append(node) - def _write_captured_output(self, report): + def write_captured_output(self, report): for capname in ('out', 'err'): - allcontent = "" - for name, content in report.get_sections("Captured std%s" % - capname): - allcontent += content - if allcontent: + content = getattr(report, 'capstd' + capname) + if content: tag = getattr(Junit, 'system-' + capname) - self.append(tag(bin_xml_escape(allcontent))) + self.append(tag(bin_xml_escape(content))) def append_pass(self, report): self.add_stats('passed') - self._write_captured_output(report) def append_failure(self, report): # msg = str(report.longrepr.reprtraceback.extraline) @@ -147,7 +151,6 @@ class _NodeReporter(object): fail = Junit.failure(message=message) fail.append(bin_xml_escape(report.longrepr)) self.append(fail) - self._write_captured_output(report) def append_collect_error(self, report): # msg = str(report.longrepr.reprtraceback.extraline) @@ -159,9 +162,12 @@ class _NodeReporter(object): Junit.skipped, "collection skipped", report.longrepr) def append_error(self, report): + if getattr(report, 'when', None) == 'teardown': + msg = "test teardown failure" + else: + msg = "test setup failure" self._add_simple( - Junit.error, "test setup failure", report.longrepr) - self._write_captured_output(report) + Junit.error, msg, report.longrepr) def append_skipped(self, report): if hasattr(report, "wasxfail"): @@ -176,7 +182,7 @@ class _NodeReporter(object): Junit.skipped("%s:%s: %s" % (filename, lineno, skipreason), type="pytest.skip", message=skipreason)) - self._write_captured_output(report) + self.write_captured_output(report) def finalize(self): data = self.to_xml().unicode(indent=0) @@ -186,8 +192,8 @@ class _NodeReporter(object): @pytest.fixture def record_xml_property(request): - """Fixture that adds extra xml properties to the tag for the calling test. - The fixture is callable with (name, value), with value being automatically + """Add extra xml properties to the tag for the calling test. + The fixture is callable with ``(name, value)``, with value being automatically xml-encoded. """ request.node.warn( @@ -212,6 +218,7 @@ def pytest_addoption(parser): action="store", dest="xmlpath", metavar="path", + type=functools.partial(filename_arg, optname="--junitxml"), default=None, help="create junit-xml style report file at given path.") group.addoption( @@ -220,13 +227,14 @@ def pytest_addoption(parser): metavar="str", default=None, help="prepend prefix to classnames in junit-xml output") + parser.addini("junit_suite_name", "Test suite name for JUnit report", default="pytest") def pytest_configure(config): xmlpath = config.option.xmlpath # prevent opening xmllog on slave nodes (xdist) if xmlpath and not hasattr(config, 'slaveinput'): - config._xml = LogXML(xmlpath, config.option.junitprefix) + config._xml = LogXML(xmlpath, config.option.junitprefix, config.getini("junit_suite_name")) config.pluginmanager.register(config._xml) @@ -245,7 +253,7 @@ def mangle_test_address(address): except ValueError: pass # convert file path to dotted path - names[0] = names[0].replace("/", '.') + names[0] = names[0].replace(nodes.SEP, '.') names[0] = _py_ext_re.sub("", names[0]) # put any params back names[-1] += possible_open_bracket + params @@ -253,10 +261,11 @@ def mangle_test_address(address): class LogXML(object): - def __init__(self, logfile, prefix): + def __init__(self, logfile, prefix, suite_name="pytest"): logfile = os.path.expanduser(os.path.expandvars(logfile)) self.logfile = os.path.normpath(os.path.abspath(logfile)) self.prefix = prefix + self.suite_name = suite_name self.stats = dict.fromkeys([ 'error', 'passed', @@ -265,6 +274,10 @@ class LogXML(object): ], 0) self.node_reporters = {} # nodeid -> _NodeReporter self.node_reporters_ordered = [] + self.global_properties = [] + # List of reports that failed on call but teardown is pending. + self.open_reports = [] + self.cnt_double_fail_tests = 0 def finalize(self, report): nodeid = getattr(report, 'nodeid', report) @@ -284,9 +297,12 @@ class LogXML(object): if key in self.node_reporters: # TODO: breasks for --dist=each return self.node_reporters[key] + reporter = _NodeReporter(nodeid, self) + self.node_reporters[key] = reporter self.node_reporters_ordered.append(reporter) + return reporter def add_stats(self, key): @@ -321,14 +337,33 @@ class LogXML(object): -> teardown node2 -> teardown node1 """ + close_report = None if report.passed: if report.when == "call": # ignore setup/teardown reporter = self._opentestcase(report) reporter.append_pass(report) elif report.failed: + if report.when == "teardown": + # The following vars are needed when xdist plugin is used + report_wid = getattr(report, "worker_id", None) + report_ii = getattr(report, "item_index", None) + close_report = next( + (rep for rep in self.open_reports + if (rep.nodeid == report.nodeid and + getattr(rep, "item_index", None) == report_ii and + getattr(rep, "worker_id", None) == report_wid + ) + ), None) + if close_report: + # We need to open new testcase in case we have failure in + # call and error in teardown in order to follow junit + # schema + self.finalize(close_report) + self.cnt_double_fail_tests += 1 reporter = self._opentestcase(report) if report.when == "call": reporter.append_failure(report) + self.open_reports.append(report) else: reporter.append_error(report) elif report.skipped: @@ -336,7 +371,20 @@ class LogXML(object): reporter.append_skipped(report) self.update_testcase_duration(report) if report.when == "teardown": + reporter = self._opentestcase(report) + reporter.write_captured_output(report) self.finalize(report) + report_wid = getattr(report, "worker_id", None) + report_ii = getattr(report, "item_index", None) + close_report = next( + (rep for rep in self.open_reports + if (rep.nodeid == report.nodeid and + getattr(rep, "item_index", None) == report_ii and + getattr(rep, "worker_id", None) == report_wid + ) + ), None) + if close_report: + self.open_reports.remove(close_report) def update_testcase_duration(self, report): """accumulates total duration for nodeid from given report and updates @@ -369,12 +417,15 @@ class LogXML(object): suite_stop_time = time.time() suite_time_delta = suite_stop_time - self.suite_start_time - numtests = self.stats['passed'] + self.stats['failure'] - + numtests = (self.stats['passed'] + self.stats['failure'] + + self.stats['skipped'] + self.stats['error'] - + self.cnt_double_fail_tests) logfile.write('') + logfile.write(Junit.testsuite( + self._get_global_properties_node(), [x.to_xml() for x in self.node_reporters_ordered], - name="pytest", + name=self.suite_name, errors=self.stats['error'], failures=self.stats['failure'], skips=self.stats['skipped'], @@ -385,3 +436,18 @@ class LogXML(object): def pytest_terminal_summary(self, terminalreporter): terminalreporter.write_sep("-", "generated xml file: %s" % (self.logfile)) + + def add_global_property(self, name, value): + self.global_properties.append((str(name), bin_xml_escape(value))) + + def _get_global_properties_node(self): + """Return a Junit node containing custom properties, if any. + """ + if self.global_properties: + return Junit.properties( + [ + Junit.property(name=name, value=value) + for name, value in self.global_properties + ] + ) + return '' diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/logging.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/logging.py new file mode 100644 index 00000000000..ed4db25ad44 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/logging.py @@ -0,0 +1,337 @@ +from __future__ import absolute_import, division, print_function + +import logging +from contextlib import closing, contextmanager +import sys +import six + +import pytest +import py + + +DEFAULT_LOG_FORMAT = '%(filename)-25s %(lineno)4d %(levelname)-8s %(message)s' +DEFAULT_LOG_DATE_FORMAT = '%H:%M:%S' + + +def get_option_ini(config, *names): + for name in names: + ret = config.getoption(name) # 'default' arg won't work as expected + if ret is None: + ret = config.getini(name) + if ret: + return ret + + +def pytest_addoption(parser): + """Add options to control log capturing.""" + group = parser.getgroup('logging') + + def add_option_ini(option, dest, default=None, type=None, **kwargs): + parser.addini(dest, default=default, type=type, + help='default value for ' + option) + group.addoption(option, dest=dest, **kwargs) + + add_option_ini( + '--no-print-logs', + dest='log_print', action='store_const', const=False, default=True, + type='bool', + help='disable printing caught logs on failed tests.') + add_option_ini( + '--log-level', + dest='log_level', default=None, + help='logging level used by the logging module') + add_option_ini( + '--log-format', + dest='log_format', default=DEFAULT_LOG_FORMAT, + help='log format as used by the logging module.') + add_option_ini( + '--log-date-format', + dest='log_date_format', default=DEFAULT_LOG_DATE_FORMAT, + help='log date format as used by the logging module.') + add_option_ini( + '--log-cli-level', + dest='log_cli_level', default=None, + help='cli logging level.') + add_option_ini( + '--log-cli-format', + dest='log_cli_format', default=None, + help='log format as used by the logging module.') + add_option_ini( + '--log-cli-date-format', + dest='log_cli_date_format', default=None, + help='log date format as used by the logging module.') + add_option_ini( + '--log-file', + dest='log_file', default=None, + help='path to a file when logging will be written to.') + add_option_ini( + '--log-file-level', + dest='log_file_level', default=None, + help='log file logging level.') + add_option_ini( + '--log-file-format', + dest='log_file_format', default=DEFAULT_LOG_FORMAT, + help='log format as used by the logging module.') + add_option_ini( + '--log-file-date-format', + dest='log_file_date_format', default=DEFAULT_LOG_DATE_FORMAT, + help='log date format as used by the logging module.') + + +@contextmanager +def logging_using_handler(handler, logger=None): + """Context manager that safely registers a given handler.""" + logger = logger or logging.getLogger(logger) + + if handler in logger.handlers: # reentrancy + # Adding the same handler twice would confuse logging system. + # Just don't do that. + yield + else: + logger.addHandler(handler) + try: + yield + finally: + logger.removeHandler(handler) + + +@contextmanager +def catching_logs(handler, formatter=None, + level=logging.NOTSET, logger=None): + """Context manager that prepares the whole logging machinery properly.""" + logger = logger or logging.getLogger(logger) + + if formatter is not None: + handler.setFormatter(formatter) + handler.setLevel(level) + + with logging_using_handler(handler, logger): + orig_level = logger.level + logger.setLevel(min(orig_level, level)) + try: + yield handler + finally: + logger.setLevel(orig_level) + + +class LogCaptureHandler(logging.StreamHandler): + """A logging handler that stores log records and the log text.""" + + def __init__(self): + """Creates a new log handler.""" + logging.StreamHandler.__init__(self, py.io.TextIO()) + self.records = [] + + def emit(self, record): + """Keep the log records in a list in addition to the log text.""" + self.records.append(record) + logging.StreamHandler.emit(self, record) + + +class LogCaptureFixture(object): + """Provides access and control of log capturing.""" + + def __init__(self, item): + """Creates a new funcarg.""" + self._item = item + + @property + def handler(self): + return self._item.catch_log_handler + + @property + def text(self): + """Returns the log text.""" + return self.handler.stream.getvalue() + + @property + def records(self): + """Returns the list of log records.""" + return self.handler.records + + @property + def record_tuples(self): + """Returns a list of a striped down version of log records intended + for use in assertion comparison. + + The format of the tuple is: + + (logger_name, log_level, message) + """ + return [(r.name, r.levelno, r.getMessage()) for r in self.records] + + def clear(self): + """Reset the list of log records.""" + self.handler.records = [] + + def set_level(self, level, logger=None): + """Sets the level for capturing of logs. + + By default, the level is set on the handler used to capture + logs. Specify a logger name to instead set the level of any + logger. + """ + if logger is None: + logger = self.handler + else: + logger = logging.getLogger(logger) + logger.setLevel(level) + + @contextmanager + def at_level(self, level, logger=None): + """Context manager that sets the level for capturing of logs. + + By default, the level is set on the handler used to capture + logs. Specify a logger name to instead set the level of any + logger. + """ + if logger is None: + logger = self.handler + else: + logger = logging.getLogger(logger) + + orig_level = logger.level + logger.setLevel(level) + try: + yield + finally: + logger.setLevel(orig_level) + + +@pytest.fixture +def caplog(request): + """Access and control log capturing. + + Captured logs are available through the following methods:: + + * caplog.text() -> string containing formatted log output + * caplog.records() -> list of logging.LogRecord instances + * caplog.record_tuples() -> list of (logger_name, level, message) tuples + """ + return LogCaptureFixture(request.node) + + +def get_actual_log_level(config, *setting_names): + """Return the actual logging level.""" + + for setting_name in setting_names: + log_level = config.getoption(setting_name) + if log_level is None: + log_level = config.getini(setting_name) + if log_level: + break + else: + return + + if isinstance(log_level, six.string_types): + log_level = log_level.upper() + try: + return int(getattr(logging, log_level, log_level)) + except ValueError: + # Python logging does not recognise this as a logging level + raise pytest.UsageError( + "'{0}' is not recognized as a logging level name for " + "'{1}'. Please consider passing the " + "logging level num instead.".format( + log_level, + setting_name)) + + +def pytest_configure(config): + config.pluginmanager.register(LoggingPlugin(config), + 'logging-plugin') + + +class LoggingPlugin(object): + """Attaches to the logging module and captures log messages for each test. + """ + + def __init__(self, config): + """Creates a new plugin to capture log messages. + + The formatter can be safely shared across all handlers so + create a single one for the entire test session here. + """ + self.log_cli_level = get_actual_log_level( + config, 'log_cli_level', 'log_level') or logging.WARNING + + self.print_logs = get_option_ini(config, 'log_print') + self.formatter = logging.Formatter( + get_option_ini(config, 'log_format'), + get_option_ini(config, 'log_date_format')) + + log_cli_handler = logging.StreamHandler(sys.stderr) + log_cli_format = get_option_ini( + config, 'log_cli_format', 'log_format') + log_cli_date_format = get_option_ini( + config, 'log_cli_date_format', 'log_date_format') + log_cli_formatter = logging.Formatter( + log_cli_format, + datefmt=log_cli_date_format) + self.log_cli_handler = log_cli_handler # needed for a single unittest + self.live_logs = catching_logs(log_cli_handler, + formatter=log_cli_formatter, + level=self.log_cli_level) + + log_file = get_option_ini(config, 'log_file') + if log_file: + self.log_file_level = get_actual_log_level( + config, 'log_file_level') or logging.WARNING + + log_file_format = get_option_ini( + config, 'log_file_format', 'log_format') + log_file_date_format = get_option_ini( + config, 'log_file_date_format', 'log_date_format') + self.log_file_handler = logging.FileHandler( + log_file, + # Each pytest runtests session will write to a clean logfile + mode='w') + log_file_formatter = logging.Formatter( + log_file_format, + datefmt=log_file_date_format) + self.log_file_handler.setFormatter(log_file_formatter) + else: + self.log_file_handler = None + + @contextmanager + def _runtest_for(self, item, when): + """Implements the internals of pytest_runtest_xxx() hook.""" + with catching_logs(LogCaptureHandler(), + formatter=self.formatter) as log_handler: + item.catch_log_handler = log_handler + try: + yield # run test + finally: + del item.catch_log_handler + + if self.print_logs: + # Add a captured log section to the report. + log = log_handler.stream.getvalue().strip() + item.add_report_section(when, 'log', log) + + @pytest.hookimpl(hookwrapper=True) + def pytest_runtest_setup(self, item): + with self._runtest_for(item, 'setup'): + yield + + @pytest.hookimpl(hookwrapper=True) + def pytest_runtest_call(self, item): + with self._runtest_for(item, 'call'): + yield + + @pytest.hookimpl(hookwrapper=True) + def pytest_runtest_teardown(self, item): + with self._runtest_for(item, 'teardown'): + yield + + @pytest.hookimpl(hookwrapper=True) + def pytest_runtestloop(self, session): + """Runs all collected test items.""" + with self.live_logs: + if self.log_file_handler is not None: + with closing(self.log_file_handler): + with catching_logs(self.log_file_handler, + level=self.log_file_level): + yield # run all the tests + else: + yield # run all the tests diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/main.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/main.py similarity index 67% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/main.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/main.py index 8654d7af627..25554098dac 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/main.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/main.py @@ -1,18 +1,22 @@ """ core implementation of testing process: init, session, runtest loop. """ -import imp +from __future__ import absolute_import, division, print_function + +import functools import os -import re +import six import sys import _pytest +from _pytest import nodes import _pytest._code import py -import pytest try: from collections import MutableMapping as MappingMixin except ImportError: from UserDict import DictMixin as MappingMixin +from _pytest.config import directory_arg, UsageError, hookimpl +from _pytest.outcomes import exit from _pytest.runner import collect_one_node tracebackcutdir = py.path.local(_pytest.__file__).dirpath() @@ -25,60 +29,65 @@ EXIT_INTERNALERROR = 3 EXIT_USAGEERROR = 4 EXIT_NOTESTSCOLLECTED = 5 -name_re = re.compile("^[a-zA-Z_]\w*$") def pytest_addoption(parser): parser.addini("norecursedirs", "directory patterns to avoid for recursion", - type="args", default=['.*', 'CVS', '_darcs', '{arch}', '*.egg']) - parser.addini("testpaths", "directories to search for tests when no files or directories are given in the command line.", - type="args", default=[]) - #parser.addini("dirpatterns", + type="args", default=['.*', 'build', 'dist', 'CVS', '_darcs', '{arch}', '*.egg', 'venv']) + parser.addini("testpaths", "directories to search for tests when no files or directories are given in the " + "command line.", + type="args", default=[]) + # parser.addini("dirpatterns", # "patterns specifying possible locations of test files", # type="linelist", default=["**/test_*.txt", # "**/test_*.py", "**/*_test.py"] - #) + # ) group = parser.getgroup("general", "running and selection options") - group._addoption('-x', '--exitfirst', action="store_true", default=False, - dest="exitfirst", - help="exit instantly on first error or failed test."), + group._addoption('-x', '--exitfirst', action="store_const", + dest="maxfail", const=1, + help="exit instantly on first error or failed test."), group._addoption('--maxfail', metavar="num", - action="store", type=int, dest="maxfail", default=0, - help="exit after first num failures or errors.") + action="store", type=int, dest="maxfail", default=0, + help="exit after first num failures or errors.") group._addoption('--strict', action="store_true", - help="run pytest in strict mode, warnings become errors.") + help="marks not registered in configuration file raise errors.") group._addoption("-c", metavar="file", type=str, dest="inifilename", - help="load configuration from `file` instead of trying to locate one of the implicit configuration files.") + help="load configuration from `file` instead of trying to locate one of the implicit " + "configuration files.") + group._addoption("--continue-on-collection-errors", action="store_true", + default=False, dest="continue_on_collection_errors", + help="Force test execution even if collection errors occur.") group = parser.getgroup("collect", "collection") group.addoption('--collectonly', '--collect-only', action="store_true", - help="only collect tests, don't execute them."), + help="only collect tests, don't execute them."), group.addoption('--pyargs', action="store_true", - help="try to interpret all arguments as python packages.") + help="try to interpret all arguments as python packages.") group.addoption("--ignore", action="append", metavar="path", - help="ignore path during collection (multi-allowed).") + help="ignore path during collection (multi-allowed).") # when changing this to --conf-cut-dir, config.py Conftest.setinitial # needs upgrading as well group.addoption('--confcutdir', dest="confcutdir", default=None, - metavar="dir", - help="only load conftest.py's relative to specified dir.") + metavar="dir", type=functools.partial(directory_arg, optname="--confcutdir"), + help="only load conftest.py's relative to specified dir.") group.addoption('--noconftest', action="store_true", - dest="noconftest", default=False, - help="Don't load any conftest.py files.") + dest="noconftest", default=False, + help="Don't load any conftest.py files.") + group.addoption('--keepduplicates', '--keep-duplicates', action="store_true", + dest="keepduplicates", default=False, + help="Keep duplicate tests.") + group.addoption('--collect-in-virtualenv', action='store_true', + dest='collect_in_virtualenv', default=False, + help="Don't ignore tests in a local virtualenv directory") group = parser.getgroup("debugconfig", - "test session debugging and configuration") + "test session debugging and configuration") group.addoption('--basetemp', dest="basetemp", default=None, metavar="dir", - help="base temporary directory for this test run.") + help="base temporary directory for this test run.") -def pytest_namespace(): - collect = dict(Item=Item, Collector=Collector, File=File, Session=Session) - return dict(collect=collect) - def pytest_configure(config): - pytest.config = config # compatibiltiy - if config.option.exitfirst: - config.option.maxfail = 1 + __import__('pytest').config = config # compatibiltiy + def wrap_session(config, doit): """Skeleton command line program""" @@ -92,13 +101,18 @@ def wrap_session(config, doit): config.hook.pytest_sessionstart(session=session) initstate = 2 session.exitstatus = doit(config, session) or 0 - except pytest.UsageError: + except UsageError: raise + except Failed: + session.exitstatus = EXIT_TESTSFAILED except KeyboardInterrupt: excinfo = _pytest._code.ExceptionInfo() + if initstate < 2 and isinstance(excinfo.value, exit.Exception): + sys.stderr.write('{0}: {1}\n'.format( + excinfo.typename, excinfo.value.msg)) config.hook.pytest_keyboard_interrupt(excinfo=excinfo) session.exitstatus = EXIT_INTERRUPTED - except: + except: # noqa excinfo = _pytest._code.ExceptionInfo() config.notify_exception(excinfo, config.option) session.exitstatus = EXIT_INTERNALERROR @@ -115,9 +129,11 @@ def wrap_session(config, doit): config._ensure_unconfigure() return session.exitstatus + def pytest_cmdline_main(config): return wrap_session(config, _main) + def _main(config, session): """ default command line protocol for initialization, session, running tests and reporting. """ @@ -129,37 +145,66 @@ def _main(config, session): elif session.testscollected == 0: return EXIT_NOTESTSCOLLECTED + def pytest_collection(session): return session.perform_collect() + def pytest_runtestloop(session): + if (session.testsfailed and + not session.config.option.continue_on_collection_errors): + raise session.Interrupted( + "%d errors during collection" % session.testsfailed) + if session.config.option.collectonly: return True - def getnextitem(i): - # this is a function to avoid python2 - # keeping sys.exc_info set when calling into a test - # python2 keeps sys.exc_info till the frame is left - try: - return session.items[i+1] - except IndexError: - return None - for i, item in enumerate(session.items): - nextitem = getnextitem(i) + nextitem = session.items[i + 1] if i + 1 < len(session.items) else None item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem) + if session.shouldfail: + raise session.Failed(session.shouldfail) if session.shouldstop: raise session.Interrupted(session.shouldstop) return True + +def _in_venv(path): + """Attempts to detect if ``path`` is the root of a Virtual Environment by + checking for the existence of the appropriate activate script""" + bindir = path.join('Scripts' if sys.platform.startswith('win') else 'bin') + if not bindir.exists(): + return False + activates = ('activate', 'activate.csh', 'activate.fish', + 'Activate', 'Activate.bat', 'Activate.ps1') + return any([fname.basename in activates for fname in bindir.listdir()]) + + def pytest_ignore_collect(path, config): - p = path.dirpath() - ignore_paths = config._getconftest_pathlist("collect_ignore", path=p) + ignore_paths = config._getconftest_pathlist("collect_ignore", path=path.dirpath()) ignore_paths = ignore_paths or [] excludeopt = config.getoption("ignore") if excludeopt: ignore_paths.extend([py.path.local(x) for x in excludeopt]) - return path in ignore_paths + + if py.path.local(path) in ignore_paths: + return True + + allow_in_venv = config.getoption("collect_in_virtualenv") + if _in_venv(path) and not allow_in_venv: + return True + + # Skip duplicate paths. + keepduplicates = config.getoption("keepduplicates") + duplicate_paths = config.pluginmanager._duplicatepaths + if not keepduplicates: + if path in duplicate_paths: + return True + else: + duplicate_paths.add(path) + + return False + class FSHookProxy: def __init__(self, fspath, pm, remove_mods): @@ -172,12 +217,22 @@ class FSHookProxy: self.__dict__[name] = x return x -def compatproperty(name): - def fget(self): - # deprecated - use pytest.name - return getattr(pytest, name) - return property(fget) +class _CompatProperty(object): + def __init__(self, name): + self.name = name + + def __get__(self, obj, owner): + if obj is None: + return self + + # TODO: reenable in the features branch + # warnings.warn( + # "usage of {owner!r}.{name} is deprecated, please use pytest.{name} instead".format( + # name=self.name, owner=type(owner).__name__), + # PendingDeprecationWarning, stacklevel=2) + return getattr(__import__('pytest'), self.name) + class NodeKeywords(MappingMixin): def __init__(self, node): @@ -249,24 +304,28 @@ class Node(object): """ fspath sensitive hook proxy used to call pytest hooks""" return self.session.gethookproxy(self.fspath) - Module = compatproperty("Module") - Class = compatproperty("Class") - Instance = compatproperty("Instance") - Function = compatproperty("Function") - File = compatproperty("File") - Item = compatproperty("Item") + Module = _CompatProperty("Module") + Class = _CompatProperty("Class") + Instance = _CompatProperty("Instance") + Function = _CompatProperty("Function") + File = _CompatProperty("File") + Item = _CompatProperty("Item") def _getcustomclass(self, name): - cls = getattr(self, name) - if cls != getattr(pytest, name): - py.log._apiwarn("2.0", "use of node.%s is deprecated, " - "use pytest_pycollect_makeitem(...) to create custom " - "collection nodes" % name) + maybe_compatprop = getattr(type(self), name) + if isinstance(maybe_compatprop, _CompatProperty): + return getattr(__import__('pytest'), name) + else: + cls = getattr(self, name) + # TODO: reenable in the features branch + # warnings.warn("use of node.%s is deprecated, " + # "use pytest_pycollect_makeitem(...) to create custom " + # "collection nodes" % name, category=DeprecationWarning) return cls def __repr__(self): - return "<%s %r>" %(self.__class__.__name__, - getattr(self, 'name', None)) + return "<%s %r>" % (self.__class__.__name__, + getattr(self, 'name', None)) def warn(self, code, message): """ generate a warning with the given code and message for this @@ -275,9 +334,6 @@ class Node(object): fslocation = getattr(self, "location", None) if fslocation is None: fslocation = getattr(self, "fspath", None) - else: - fslocation = "%s:%s" % fslocation[:2] - self.ihook.pytest_logwarning.call_historic(kwargs=dict( code=code, message=message, nodeid=self.nodeid, fslocation=fslocation)) @@ -304,24 +360,6 @@ class Node(object): def teardown(self): pass - def _memoizedcall(self, attrname, function): - exattrname = "_ex_" + attrname - failure = getattr(self, exattrname, None) - if failure is not None: - py.builtin._reraise(failure[0], failure[1], failure[2]) - if hasattr(self, attrname): - return getattr(self, attrname) - try: - res = function() - except py.builtin._sysex: - raise - except: - failure = sys.exc_info() - setattr(self, exattrname, failure) - raise - setattr(self, attrname, res) - return res - def listchain(self): """ return list of all parent collectors up to self, starting from root of collection tree. """ @@ -338,9 +376,9 @@ class Node(object): ``marker`` can be a string or pytest.mark.* instance. """ - from _pytest.mark import MarkDecorator - if isinstance(marker, py.builtin._basestring): - marker = MarkDecorator(marker) + from _pytest.mark import MarkDecorator, MARK_GEN + if isinstance(marker, six.string_types): + marker = getattr(MARK_GEN, marker) elif not isinstance(marker, MarkDecorator): raise ValueError("is not a string or pytest.mark.* Marker") self.keywords[marker.name] = marker @@ -390,9 +428,12 @@ class Node(object): return excinfo.value.formatrepr() tbfilter = True if self.config.option.fulltrace: - style="long" + style = "long" else: + tb = _pytest._code.Traceback([excinfo.traceback[-1]]) self._prunetraceback(excinfo) + if len(excinfo.traceback) == 0: + excinfo.traceback = tb tbfilter = False # prunetraceback already does it if style == "auto": style = "long" @@ -403,12 +444,19 @@ class Node(object): else: style = "long" - return excinfo.getrepr(funcargs=True, + try: + os.getcwd() + abspath = False + except OSError: + abspath = True + + return excinfo.getrepr(funcargs=True, abspath=abspath, showlocals=self.config.option.showlocals, style=style, tbfilter=tbfilter) repr_failure = _repr_failure_py + class Collector(Node): """ Collector instances create children through collect() and thus iteratively build a tree. @@ -430,10 +478,6 @@ class Collector(Node): return str(exc.args[0]) return self._repr_failure_py(excinfo, style="short") - def _memocollect(self): - """ internal helper method to cache results of calling collect(). """ - return self._memoizedcall('_collected', lambda: list(self.collect())) - def _prunetraceback(self, excinfo): if hasattr(self, 'fspath'): traceback = excinfo.traceback @@ -442,27 +486,38 @@ class Collector(Node): ntraceback = ntraceback.cut(excludepath=tracebackcutdir) excinfo.traceback = ntraceback.filter() + class FSCollector(Collector): def __init__(self, fspath, parent=None, config=None, session=None): - fspath = py.path.local(fspath) # xxx only for test_resultlog.py? + fspath = py.path.local(fspath) # xxx only for test_resultlog.py? name = fspath.basename if parent is not None: rel = fspath.relto(parent.fspath) if rel: name = rel - name = name.replace(os.sep, "/") + name = name.replace(os.sep, nodes.SEP) super(FSCollector, self).__init__(name, parent, config, session) self.fspath = fspath + def _check_initialpaths_for_relpath(self): + for initialpath in self.session._initialpaths: + if self.fspath.common(initialpath) == initialpath: + return self.fspath.relto(initialpath.dirname) + def _makeid(self): relpath = self.fspath.relto(self.config.rootdir) - if os.sep != "/": - relpath = relpath.replace(os.sep, "/") + + if not relpath: + relpath = self._check_initialpaths_for_relpath() + if os.sep != nodes.SEP: + relpath = relpath.replace(os.sep, nodes.SEP) return relpath + class File(FSCollector): """ base class for collecting tests from a file. """ + class Item(Node): """ a basic test invocation item. Note that for a single function there might be multiple test invocation items. @@ -474,6 +529,21 @@ class Item(Node): self._report_sections = [] def add_report_section(self, when, key, content): + """ + Adds a new report section, similar to what's done internally to add stdout and + stderr captured output:: + + item.add_report_section("call", "stdout", "report section contents") + + :param str when: + One of the possible capture states, ``"setup"``, ``"call"``, ``"teardown"``. + :param str key: + Name of the section, can be customized at will. Pytest uses ``"stdout"`` and + ``"stderr"`` internally. + + :param str content: + The full contents as a string. + """ if content: self._report_sections.append((when, key, content)) @@ -497,23 +567,31 @@ class Item(Node): self._location = location return location + class NoMatch(Exception): """ raised if matching cannot locate a matching names. """ + class Interrupted(KeyboardInterrupt): """ signals an interrupted test run. """ - __module__ = 'builtins' # for py3 + __module__ = 'builtins' # for py3 + + +class Failed(Exception): + """ signals an stop as failed test run. """ + class Session(FSCollector): Interrupted = Interrupted + Failed = Failed def __init__(self, config): FSCollector.__init__(self, config.rootdir, parent=None, config=config, session=self) - self._fs2hookproxy = {} self.testsfailed = 0 self.testscollected = 0 self.shouldstop = False + self.shouldfail = False self.trace = config.trace.root.get("collection") self._norecursepatterns = config.getini("norecursedirs") self.startdir = py.path.local() @@ -522,18 +600,20 @@ class Session(FSCollector): def _makeid(self): return "" - @pytest.hookimpl(tryfirst=True) + @hookimpl(tryfirst=True) def pytest_collectstart(self): + if self.shouldfail: + raise self.Failed(self.shouldfail) if self.shouldstop: raise self.Interrupted(self.shouldstop) - @pytest.hookimpl(tryfirst=True) + @hookimpl(tryfirst=True) def pytest_runtest_logreport(self, report): if report.failed and not hasattr(report, 'wasxfail'): self.testsfailed += 1 maxfail = self.config.getvalue("maxfail") if maxfail and self.testsfailed >= maxfail: - self.shouldstop = "stopping after %d failures" % ( + self.shouldfail = "stopping after %d failures" % ( self.testsfailed) pytest_collectreport = pytest_runtest_logreport @@ -541,30 +621,26 @@ class Session(FSCollector): return path in self._initialpaths def gethookproxy(self, fspath): - try: - return self._fs2hookproxy[fspath] - except KeyError: - # check if we have the common case of running - # hooks with all conftest.py filesall conftest.py - pm = self.config.pluginmanager - my_conftestmodules = pm._getconftestmodules(fspath) - remove_mods = pm._conftest_plugins.difference(my_conftestmodules) - if remove_mods: - # one or more conftests are not in use at this fspath - proxy = FSHookProxy(fspath, pm, remove_mods) - else: - # all plugis are active for this fspath - proxy = self.config.hook - - self._fs2hookproxy[fspath] = proxy - return proxy + # check if we have the common case of running + # hooks with all conftest.py filesall conftest.py + pm = self.config.pluginmanager + my_conftestmodules = pm._getconftestmodules(fspath) + remove_mods = pm._conftest_plugins.difference(my_conftestmodules) + if remove_mods: + # one or more conftests are not in use at this fspath + proxy = FSHookProxy(fspath, pm, remove_mods) + else: + # all plugis are active for this fspath + proxy = self.config.hook + return proxy def perform_collect(self, args=None, genitems=True): hook = self.config.hook try: items = self._perform_collect(args, genitems) + self.config.pluginmanager.check_pending() hook.pytest_collection_modifyitems(session=self, - config=self.config, items=items) + config=self.config, items=items) finally: hook.pytest_collection_finish(session=self) self.testscollected = len(items) @@ -591,8 +667,8 @@ class Session(FSCollector): for arg, exc in self._notfound: line = "(no name %r in any of %r)" % (arg, exc.args[0]) errors.append("not found: %s\n%s" % (arg, line)) - #XXX: test this - raise pytest.UsageError(*errors) + # XXX: test this + raise UsageError(*errors) if not genitems: return rep.result else: @@ -620,7 +696,7 @@ class Session(FSCollector): names = self._parsearg(arg) path = names.pop(0) if path.check(dir=1): - assert not names, "invalid arg %r" %(arg,) + assert not names, "invalid arg %r" % (arg,) for path in path.visit(fil=lambda x: x.check(file=1), rec=self._recurse, bf=True, sort=True): for x in self._collectfile(path): @@ -649,44 +725,41 @@ class Session(FSCollector): return True def _tryconvertpyarg(self, x): - mod = None - path = [os.path.abspath('.')] + sys.path - for name in x.split('.'): - # ignore anything that's not a proper name here - # else something like --pyargs will mess up '.' - # since imp.find_module will actually sometimes work for it - # but it's supposed to be considered a filesystem path - # not a package - if name_re.match(name) is None: - return x - try: - fd, mod, type_ = imp.find_module(name, path) - except ImportError: - return x - else: - if fd is not None: - fd.close() + """Convert a dotted module name to path. - if type_[2] != imp.PKG_DIRECTORY: - path = [os.path.dirname(mod)] - else: - path = [mod] - return mod + """ + import pkgutil + try: + loader = pkgutil.find_loader(x) + except ImportError: + return x + if loader is None: + return x + # This method is sometimes invoked when AssertionRewritingHook, which + # does not define a get_filename method, is already in place: + try: + path = loader.get_filename(x) + except AttributeError: + # Retrieve path from AssertionRewritingHook: + path = loader.modules[x][0].co_filename + if loader.is_package(x): + path = os.path.dirname(path) + return path def _parsearg(self, arg): """ return (fspath, names) tuple after checking the file exists. """ - arg = str(arg) - if self.config.option.pyargs: - arg = self._tryconvertpyarg(arg) parts = str(arg).split("::") + if self.config.option.pyargs: + parts[0] = self._tryconvertpyarg(parts[0]) relpath = parts[0].replace("/", os.sep) path = self.config.invocation_dir.join(relpath, abs=True) if not path.check(): if self.config.option.pyargs: - msg = "file or package not found: " + raise UsageError( + "file or package not found: " + arg + + " (missing __init__.py?)") else: - msg = "file not found: " - raise pytest.UsageError(msg + arg) + raise UsageError("file not found: " + arg) parts[0] = path return parts @@ -709,11 +782,11 @@ class Session(FSCollector): nextnames = names[1:] resultnodes = [] for node in matching: - if isinstance(node, pytest.Item): + if isinstance(node, Item): if not names: resultnodes.append(node) continue - assert isinstance(node, pytest.Collector) + assert isinstance(node, Collector) rep = collect_one_node(node) if rep.passed: has_matched = False @@ -726,16 +799,20 @@ class Session(FSCollector): if not has_matched and len(rep.result) == 1 and x.name == "()": nextnames.insert(0, name) resultnodes.extend(self.matchnodes([x], nextnames)) - node.ihook.pytest_collectreport(report=rep) + else: + # report collection failures here to avoid failing to run some test + # specified in the command line because the module could not be + # imported (#134) + node.ihook.pytest_collectreport(report=rep) return resultnodes def genitems(self, node): self.trace("genitems", node) - if isinstance(node, pytest.Item): + if isinstance(node, Item): node.ihook.pytest_itemcollected(item=node) yield node else: - assert isinstance(node, pytest.Collector) + assert isinstance(node, Collector) rep = collect_one_node(node) if rep.passed: for subnode in rep.result: diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/mark.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/mark.py similarity index 50% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/mark.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/mark.py index 1a763540240..3f1f01b1a2e 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/mark.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/mark.py @@ -1,5 +1,97 @@ """ generic mechanism for marking and selecting python functions. """ +from __future__ import absolute_import, division, print_function + import inspect +import warnings +import attr +from collections import namedtuple +from operator import attrgetter +from six.moves import map +from .deprecated import MARK_PARAMETERSET_UNPACKING +from .compat import NOTSET, getfslineno + + +def alias(name, warning=None): + getter = attrgetter(name) + + def warned(self): + warnings.warn(warning, stacklevel=2) + return getter(self) + + return property(getter if warning is None else warned, doc='alias for ' + name) + + +class ParameterSet(namedtuple('ParameterSet', 'values, marks, id')): + @classmethod + def param(cls, *values, **kw): + marks = kw.pop('marks', ()) + if isinstance(marks, MarkDecorator): + marks = marks, + else: + assert isinstance(marks, (tuple, list, set)) + + def param_extract_id(id=None): + return id + + id = param_extract_id(**kw) + return cls(values, marks, id) + + @classmethod + def extract_from(cls, parameterset, legacy_force_tuple=False): + """ + :param parameterset: + a legacy style parameterset that may or may not be a tuple, + and may or may not be wrapped into a mess of mark objects + + :param legacy_force_tuple: + enforce tuple wrapping so single argument tuple values + don't get decomposed and break tests + + """ + + if isinstance(parameterset, cls): + return parameterset + if not isinstance(parameterset, MarkDecorator) and legacy_force_tuple: + return cls.param(parameterset) + + newmarks = [] + argval = parameterset + while isinstance(argval, MarkDecorator): + newmarks.append(MarkDecorator(Mark( + argval.markname, argval.args[:-1], argval.kwargs))) + argval = argval.args[-1] + assert not isinstance(argval, ParameterSet) + if legacy_force_tuple: + argval = argval, + + if newmarks: + warnings.warn(MARK_PARAMETERSET_UNPACKING) + + return cls(argval, marks=newmarks, id=None) + + @classmethod + def _for_parameterize(cls, argnames, argvalues, function): + if not isinstance(argnames, (tuple, list)): + argnames = [x.strip() for x in argnames.split(",") if x.strip()] + force_tuple = len(argnames) == 1 + else: + force_tuple = False + parameters = [ + ParameterSet.extract_from(x, legacy_force_tuple=force_tuple) + for x in argvalues] + del argvalues + + if not parameters: + fs, lineno = getfslineno(function) + reason = "got empty parameter set %r, function %s at %s:%d" % ( + argnames, function.__name__, fs, lineno) + mark = MARK_GEN.skip(reason=reason) + parameters.append(ParameterSet( + values=(NOTSET,) * len(argnames), + marks=[mark], + id=None, + )) + return argnames, parameters class MarkerError(Exception): @@ -7,8 +99,8 @@ class MarkerError(Exception): """Error in use of a pytest marker/attribute.""" -def pytest_namespace(): - return {'mark': MarkGenerator()} +def param(*values, **kw): + return ParameterSet.param(*values, **kw) def pytest_addoption(parser): @@ -19,9 +111,10 @@ def pytest_addoption(parser): help="only run tests which match the given substring expression. " "An expression is a python evaluatable expression " "where all names are substring-matched against test names " - "and their parent classes. Example: -k 'test_method or test " + "and their parent classes. Example: -k 'test_method or test_" "other' matches all test functions and classes whose name " - "contains 'test_method' or 'test_other'. " + "contains 'test_method' or 'test_other', while -k 'not test_method' " + "matches those that don't contain 'test_method' in their names. " "Additionally keywords are matched to classes and functions " "containing extra names in their 'extra_keyword_matches' set, " "as well as functions which have names assigned directly to them." @@ -48,23 +141,27 @@ def pytest_cmdline_main(config): config._do_configure() tw = _pytest.config.create_terminal_writer(config) for line in config.getini("markers"): - name, rest = line.split(":", 1) + parts = line.split(":", 1) + name = parts[0] + rest = parts[1] if len(parts) == 2 else '' tw.write("@pytest.mark.%s:" % name, bold=True) tw.line(rest) tw.line() config._ensure_unconfigure() return 0 + + pytest_cmdline_main.tryfirst = True def pytest_collection_modifyitems(items, config): - keywordexpr = config.option.keyword + keywordexpr = config.option.keyword.lstrip() matchexpr = config.option.markexpr if not keywordexpr and not matchexpr: return # pytest used to allow "-" for negating # but today we just allow "-" at the beginning, use "not" instead - # we probably remove "-" alltogether soon + # we probably remove "-" altogether soon if keywordexpr.startswith("-"): keywordexpr = "not " + keywordexpr[1:] selectuntil = False @@ -91,24 +188,30 @@ def pytest_collection_modifyitems(items, config): items[:] = remaining -class MarkMapping: +@attr.s +class MarkMapping(object): """Provides a local mapping for markers where item access resolves to True if the marker is present. """ - def __init__(self, keywords): - mymarks = set() + + own_mark_names = attr.ib() + + @classmethod + def from_keywords(cls, keywords): + mark_names = set() for key, value in keywords.items(): if isinstance(value, MarkInfo) or isinstance(value, MarkDecorator): - mymarks.add(key) - self._mymarks = mymarks + mark_names.add(key) + return cls(mark_names) def __getitem__(self, name): - return name in self._mymarks + return name in self.own_mark_names -class KeywordMapping: +class KeywordMapping(object): """Provides a local mapping for keywords. Given a list of names, map any substring of one of these names to True. """ + def __init__(self, names): self._names = names @@ -121,7 +224,7 @@ class KeywordMapping: def matchmark(colitem, markexpr): """Tries to match on any marker names, attached to the given colitem.""" - return eval(markexpr, {}, MarkMapping(colitem.keywords)) + return eval(markexpr, {}, MarkMapping.from_keywords(colitem.keywords)) def matchkeyword(colitem, keywordexpr): @@ -160,9 +263,13 @@ def matchkeyword(colitem, keywordexpr): def pytest_configure(config): - import pytest + config._old_mark_config = MARK_GEN._config if config.option.strict: - pytest.mark._config = config + MARK_GEN._config = config + + +def pytest_unconfigure(config): + MARK_GEN._config = getattr(config, '_old_mark_config', None) class MarkGenerator: @@ -176,13 +283,14 @@ class MarkGenerator: will set a 'slowtest' :class:`MarkInfo` object on the ``test_function`` object. """ + _config = None def __getattr__(self, name): if name[0] == "_": raise AttributeError("Marker name must NOT start with underscore") - if hasattr(self, '_config'): + if self._config is not None: self._check(name) - return MarkDecorator(name) + return MarkDecorator(Mark(name, (), {})) def _check(self, name): try: @@ -190,19 +298,36 @@ class MarkGenerator: return except AttributeError: pass - self._markers = l = set() + self._markers = values = set() for line in self._config.getini("markers"): - beginning = line.split(":", 1) - x = beginning[0].split("(", 1)[0] - l.add(x) + marker = line.split(":", 1)[0] + marker = marker.rstrip() + x = marker.split("(", 1)[0] + values.add(x) if name not in self._markers: raise AttributeError("%r not a registered marker" % (name,)) + def istestfunc(func): return hasattr(func, "__call__") and \ getattr(func, "__name__", "") != "" -class MarkDecorator: + +@attr.s(frozen=True) +class Mark(object): + name = attr.ib() + args = attr.ib() + kwargs = attr.ib() + + def combined_with(self, other): + assert self.name == other.name + return Mark( + self.name, self.args + other.args, + dict(self.kwargs, **other.kwargs)) + + +@attr.s +class MarkDecorator(object): """ A decorator for test functions and test classes. When applied it will create :class:`MarkInfo` objects which may be :ref:`retrieved by hooks as item keywords `. @@ -235,19 +360,33 @@ class MarkDecorator: additional keyword or positional arguments. """ - def __init__(self, name, args=None, kwargs=None): - self.name = name - self.args = args or () - self.kwargs = kwargs or {} + + mark = attr.ib(validator=attr.validators.instance_of(Mark)) + + name = alias('mark.name') + args = alias('mark.args') + kwargs = alias('mark.kwargs') @property def markname(self): - return self.name # for backward-compat (2.4.1 had this attr) + return self.name # for backward-compat (2.4.1 had this attr) + + def __eq__(self, other): + return self.mark == other.mark if isinstance(other, MarkDecorator) else False def __repr__(self): - d = self.__dict__.copy() - name = d.pop('name') - return "" % (name, d) + return "" % (self.mark,) + + def with_args(self, *args, **kwargs): + """ return a MarkDecorator with extra arguments added + + unlike call this can be used even if the sole argument is a callable/class + + :return: MarkDecorator + """ + + mark = Mark(self.name, args, kwargs) + return self.__class__(self.mark.combined_with(mark)) def __call__(self, *args, **kwargs): """ if passed a single callable argument: decorate it with mark info. @@ -257,55 +396,101 @@ class MarkDecorator: is_class = inspect.isclass(func) if len(args) == 1 and (istestfunc(func) or is_class): if is_class: - if hasattr(func, 'pytestmark'): - mark_list = func.pytestmark - if not isinstance(mark_list, list): - mark_list = [mark_list] - # always work on a copy to avoid updating pytestmark - # from a superclass by accident - mark_list = mark_list + [self] - func.pytestmark = mark_list - else: - func.pytestmark = [self] + store_mark(func, self.mark) else: - holder = getattr(func, self.name, None) - if holder is None: - holder = MarkInfo( - self.name, self.args, self.kwargs - ) - setattr(func, self.name, holder) - else: - holder.add(self.args, self.kwargs) + store_legacy_markinfo(func, self.mark) + store_mark(func, self.mark) return func - kw = self.kwargs.copy() - kw.update(kwargs) - args = self.args + args - return self.__class__(self.name, args=args, kwargs=kw) + return self.with_args(*args, **kwargs) -class MarkInfo: +def get_unpacked_marks(obj): + """ + obtain the unpacked marks that are stored on a object + """ + mark_list = getattr(obj, 'pytestmark', []) + + if not isinstance(mark_list, list): + mark_list = [mark_list] + return [ + getattr(mark, 'mark', mark) # unpack MarkDecorator + for mark in mark_list + ] + + +def store_mark(obj, mark): + """store a Mark on a object + this is used to implement the Mark declarations/decorators correctly + """ + assert isinstance(mark, Mark), mark + # always reassign name to avoid updating pytestmark + # in a reference that was only borrowed + obj.pytestmark = get_unpacked_marks(obj) + [mark] + + +def store_legacy_markinfo(func, mark): + """create the legacy MarkInfo objects and put them onto the function + """ + if not isinstance(mark, Mark): + raise TypeError("got {mark!r} instead of a Mark".format(mark=mark)) + holder = getattr(func, mark.name, None) + if holder is None: + holder = MarkInfo(mark) + setattr(func, mark.name, holder) + else: + holder.add_mark(mark) + + +class MarkInfo(object): """ Marking object created by :class:`MarkDecorator` instances. """ - def __init__(self, name, args, kwargs): - #: name of attribute - self.name = name - #: positional argument list, empty if none specified - self.args = args - #: keyword argument dictionary, empty if nothing specified - self.kwargs = kwargs.copy() - self._arglist = [(args, kwargs.copy())] + + def __init__(self, mark): + assert isinstance(mark, Mark), repr(mark) + self.combined = mark + self._marks = [mark] + + name = alias('combined.name') + args = alias('combined.args') + kwargs = alias('combined.kwargs') def __repr__(self): - return "" % ( - self.name, self.args, self.kwargs - ) + return "".format(self.combined) - def add(self, args, kwargs): + def add_mark(self, mark): """ add a MarkInfo with the given args and kwargs. """ - self._arglist.append((args, kwargs)) - self.args += args - self.kwargs.update(kwargs) + self._marks.append(mark) + self.combined = self.combined.combined_with(mark) def __iter__(self): """ yield MarkInfo objects each relating to a marking-call. """ - for args, kwargs in self._arglist: - yield MarkInfo(self.name, args, kwargs) + return map(MarkInfo, self._marks) + + +MARK_GEN = MarkGenerator() + + +def _marked(func, mark): + """ Returns True if :func: is already marked with :mark:, False otherwise. + This can happen if marker is applied to class and the test file is + invoked more than once. + """ + try: + func_mark = getattr(func, mark.name) + except AttributeError: + return False + return mark.args == func_mark.args and mark.kwargs == func_mark.kwargs + + +def transfer_markers(funcobj, cls, mod): + """ + this function transfers class level markers and module level markers + into function level markinfo objects + + this is the main reason why marks are so broken + the resolution will involve phasing out function level MarkInfo objects + + """ + for obj in (cls, mod): + for mark in get_unpacked_marks(obj): + if not _marked(funcobj, mark): + store_legacy_markinfo(funcobj, mark) diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/monkeypatch.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/monkeypatch.py similarity index 91% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/monkeypatch.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/monkeypatch.py index d4c169d37a9..40ae560f070 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/monkeypatch.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/monkeypatch.py @@ -1,15 +1,18 @@ """ monkeypatching and mocking functionality. """ +from __future__ import absolute_import, division, print_function -import os, sys +import os +import sys import re - -from py.builtin import _basestring +import six +from _pytest.fixtures import fixture RE_IMPORT_ERROR_NAME = re.compile("^No module named (.*)$") -def pytest_funcarg__monkeypatch(request): - """The returned ``monkeypatch`` funcarg provides these +@fixture +def monkeypatch(): + """The returned ``monkeypatch`` fixture provides these helper methods to modify objects, dictionaries or os.environ:: monkeypatch.setattr(obj, name, value, raising=True) @@ -22,13 +25,13 @@ def pytest_funcarg__monkeypatch(request): monkeypatch.chdir(path) All modifications will be undone after the requesting - test function has finished. The ``raising`` + test function or fixture has finished. The ``raising`` parameter determines if a KeyError or AttributeError will be raised if the set/deletion operation has no target. """ - mpatch = monkeypatch() - request.addfinalizer(mpatch.undo) - return mpatch + mpatch = MonkeyPatch() + yield mpatch + mpatch.undo() def resolve(name): @@ -67,15 +70,15 @@ def annotated_getattr(obj, name, ann): obj = getattr(obj, name) except AttributeError: raise AttributeError( - '%r object at %s has no attribute %r' % ( - type(obj).__name__, ann, name - ) + '%r object at %s has no attribute %r' % ( + type(obj).__name__, ann, name + ) ) return obj def derive_importpath(import_path, raising): - if not isinstance(import_path, _basestring) or "." not in import_path: + if not isinstance(import_path, six.string_types) or "." not in import_path: raise TypeError("must be absolute import path string, not %r" % (import_path,)) module, attr = import_path.rsplit('.', 1) @@ -93,8 +96,9 @@ class Notset: notset = Notset() -class monkeypatch: - """ Object keeping a record of setattr/item/env/syspath changes. """ +class MonkeyPatch: + """ Object returned by the ``monkeypatch`` fixture keeping a record of setattr/item/env/syspath changes. + """ def __init__(self): self._setattr = [] @@ -120,7 +124,7 @@ class monkeypatch: import inspect if value is notset: - if not isinstance(target, _basestring): + if not isinstance(target, six.string_types): raise TypeError("use setattr(target, name, value) or " "setattr(target, value) with target being a dotted " "import string") @@ -150,7 +154,7 @@ class monkeypatch: """ __tracebackhide__ = True if name is notset: - if not isinstance(target, _basestring): + if not isinstance(target, six.string_types): raise TypeError("use delattr(target, name) or " "delattr(target) with target being a dotted " "import string") @@ -220,10 +224,10 @@ class monkeypatch: """ Undo previous changes. This call consumes the undo stack. Calling it a second time has no effect unless you do more monkeypatching after the undo call. - + There is generally no need to call `undo()`, since it is called automatically during tear-down. - + Note that the same `monkeypatch` fixture is used across a single test function invocation. If `monkeypatch` is used both by the test function itself and one of the test fixtures, diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/nodes.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/nodes.py new file mode 100644 index 00000000000..ad3af2ce67c --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/nodes.py @@ -0,0 +1,37 @@ +SEP = "/" + + +def _splitnode(nodeid): + """Split a nodeid into constituent 'parts'. + + Node IDs are strings, and can be things like: + '' + 'testing/code' + 'testing/code/test_excinfo.py' + 'testing/code/test_excinfo.py::TestFormattedExcinfo::()' + + Return values are lists e.g. + [] + ['testing', 'code'] + ['testing', 'code', 'test_excinfo.py'] + ['testing', 'code', 'test_excinfo.py', 'TestFormattedExcinfo', '()'] + """ + if nodeid == '': + # If there is no root node at all, return an empty list so the caller's logic can remain sane + return [] + parts = nodeid.split(SEP) + # Replace single last element 'test_foo.py::Bar::()' with multiple elements 'test_foo.py', 'Bar', '()' + parts[-1:] = parts[-1].split("::") + return parts + + +def ischildnode(baseid, nodeid): + """Return True if the nodeid is a child node of the baseid. + + E.g. 'foo/bar::Baz::()' is a child of 'foo', 'foo/bar' and 'foo/bar::Baz', but not of 'foo/blorp' + """ + base_parts = _splitnode(baseid) + node_parts = _splitnode(nodeid) + if len(node_parts) < len(base_parts): + return False + return node_parts[:len(base_parts)] == base_parts diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/nose.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/nose.py similarity index 74% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/nose.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/nose.py index 03874686860..c81542eadf3 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/nose.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/nose.py @@ -1,10 +1,10 @@ """ run test suites written for nose. """ +from __future__ import absolute_import, division, print_function import sys -import py -import pytest -from _pytest import unittest +from _pytest import unittest, runner, python +from _pytest.config import hookimpl def get_skip_exceptions(): @@ -19,52 +19,53 @@ def get_skip_exceptions(): def pytest_runtest_makereport(item, call): if call.excinfo and call.excinfo.errisinstance(get_skip_exceptions()): # let's substitute the excinfo with a pytest.skip one - call2 = call.__class__(lambda: - pytest.skip(str(call.excinfo.value)), call.when) + call2 = call.__class__( + lambda: runner.skip(str(call.excinfo.value)), call.when) call.excinfo = call2.excinfo -@pytest.hookimpl(trylast=True) +@hookimpl(trylast=True) def pytest_runtest_setup(item): if is_potential_nosetest(item): - if isinstance(item.parent, pytest.Generator): + if isinstance(item.parent, python.Generator): gen = item.parent if not hasattr(gen, '_nosegensetup'): call_optional(gen.obj, 'setup') - if isinstance(gen.parent, pytest.Instance): + if isinstance(gen.parent, python.Instance): call_optional(gen.parent.obj, 'setup') gen._nosegensetup = True if not call_optional(item.obj, 'setup'): # call module level setup if there is no object level one call_optional(item.parent.obj, 'setup') - #XXX this implies we only call teardown when setup worked + # XXX this implies we only call teardown when setup worked item.session._setupstate.addfinalizer((lambda: teardown_nose(item)), item) + def teardown_nose(item): if is_potential_nosetest(item): if not call_optional(item.obj, 'teardown'): call_optional(item.parent.obj, 'teardown') - #if hasattr(item.parent, '_nosegensetup'): + # if hasattr(item.parent, '_nosegensetup'): # #call_optional(item._nosegensetup, 'teardown') # del item.parent._nosegensetup def pytest_make_collect_report(collector): - if isinstance(collector, pytest.Generator): + if isinstance(collector, python.Generator): call_optional(collector.obj, 'setup') def is_potential_nosetest(item): # extra check needed since we do not do nose style setup/teardown # on direct unittest style classes - return isinstance(item, pytest.Function) and \ + return isinstance(item, python.Function) and \ not isinstance(item, unittest.TestCaseFunction) def call_optional(obj, name): method = getattr(obj, name, None) isfixture = hasattr(method, "_pytestfixturefunction") - if method is not None and not isfixture and py.builtin.callable(method): + if method is not None and not isfixture and callable(method): # If there's any problems allow the exception to raise rather than # silently ignoring them method() diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/outcomes.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/outcomes.py new file mode 100644 index 00000000000..7f0c18fa6c1 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/outcomes.py @@ -0,0 +1,147 @@ +""" +exception classes and constants handling test outcomes +as well as functions creating them +""" +from __future__ import absolute_import, division, print_function +import py +import sys + + +class OutcomeException(BaseException): + """ OutcomeException and its subclass instances indicate and + contain info about test and collection outcomes. + """ + def __init__(self, msg=None, pytrace=True): + BaseException.__init__(self, msg) + self.msg = msg + self.pytrace = pytrace + + def __repr__(self): + if self.msg: + val = self.msg + if isinstance(val, bytes): + val = py._builtin._totext(val, errors='replace') + return val + return "<%s instance>" % (self.__class__.__name__,) + __str__ = __repr__ + + +TEST_OUTCOME = (OutcomeException, Exception) + + +class Skipped(OutcomeException): + # XXX hackish: on 3k we fake to live in the builtins + # in order to have Skipped exception printing shorter/nicer + __module__ = 'builtins' + + def __init__(self, msg=None, pytrace=True, allow_module_level=False): + OutcomeException.__init__(self, msg=msg, pytrace=pytrace) + self.allow_module_level = allow_module_level + + +class Failed(OutcomeException): + """ raised from an explicit call to pytest.fail() """ + __module__ = 'builtins' + + +class Exit(KeyboardInterrupt): + """ raised for immediate program exits (no tracebacks/summaries)""" + def __init__(self, msg="unknown reason"): + self.msg = msg + KeyboardInterrupt.__init__(self, msg) + +# exposed helper methods + + +def exit(msg): + """ exit testing process as if KeyboardInterrupt was triggered. """ + __tracebackhide__ = True + raise Exit(msg) + + +exit.Exception = Exit + + +def skip(msg="", **kwargs): + """ skip an executing test with the given message. Note: it's usually + better to use the pytest.mark.skipif marker to declare a test to be + skipped under certain conditions like mismatching platforms or + dependencies. See the pytest_skipping plugin for details. + + :kwarg bool allow_module_level: allows this function to be called at + module level, skipping the rest of the module. Default to False. + """ + __tracebackhide__ = True + allow_module_level = kwargs.pop('allow_module_level', False) + if kwargs: + keys = [k for k in kwargs.keys()] + raise TypeError('unexpected keyword arguments: {0}'.format(keys)) + raise Skipped(msg=msg, allow_module_level=allow_module_level) + + +skip.Exception = Skipped + + +def fail(msg="", pytrace=True): + """ explicitly fail an currently-executing test with the given Message. + + :arg pytrace: if false the msg represents the full failure information + and no python traceback will be reported. + """ + __tracebackhide__ = True + raise Failed(msg=msg, pytrace=pytrace) + + +fail.Exception = Failed + + +class XFailed(fail.Exception): + """ raised from an explicit call to pytest.xfail() """ + + +def xfail(reason=""): + """ xfail an executing test or setup functions with the given reason.""" + __tracebackhide__ = True + raise XFailed(reason) + + +xfail.Exception = XFailed + + +def importorskip(modname, minversion=None): + """ return imported module if it has at least "minversion" as its + __version__ attribute. If no minversion is specified the a skip + is only triggered if the module can not be imported. + """ + import warnings + __tracebackhide__ = True + compile(modname, '', 'eval') # to catch syntaxerrors + should_skip = False + + with warnings.catch_warnings(): + # make sure to ignore ImportWarnings that might happen because + # of existing directories with the same name we're trying to + # import but without a __init__.py file + warnings.simplefilter('ignore') + try: + __import__(modname) + except ImportError: + # Do not raise chained exception here(#1485) + should_skip = True + if should_skip: + raise Skipped("could not import %r" % (modname,), allow_module_level=True) + mod = sys.modules[modname] + if minversion is None: + return mod + verattr = getattr(mod, '__version__', None) + if minversion is not None: + try: + from pkg_resources import parse_version as pv + except ImportError: + raise Skipped("we have a required version for %r but can not import " + "pkg_resources to parse version strings." % (modname,), + allow_module_level=True) + if verattr is None or pv(verattr) < pv(minversion): + raise Skipped("module %r has __version__ %r, required is: %r" % ( + modname, verattr, minversion), allow_module_level=True) + return mod diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/pastebin.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/pastebin.py similarity index 89% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/pastebin.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/pastebin.py index 4ec62d02280..b588b021b12 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/pastebin.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/pastebin.py @@ -1,5 +1,8 @@ """ submit failure or test session information to a pastebin service. """ +from __future__ import absolute_import, division, print_function + import pytest +import six import sys import tempfile @@ -7,13 +10,13 @@ import tempfile def pytest_addoption(parser): group = parser.getgroup("terminal reporting") group._addoption('--pastebin', metavar="mode", - action='store', dest="pastebin", default=None, - choices=['failed', 'all'], - help="send failed|all info to bpaste.net pastebin service.") + action='store', dest="pastebin", default=None, + choices=['failed', 'all'], + help="send failed|all info to bpaste.net pastebin service.") + @pytest.hookimpl(trylast=True) def pytest_configure(config): - import py if config.option.pastebin == "all": tr = config.pluginmanager.getplugin('terminalreporter') # if no terminal reporter plugin is present, nothing we can do here; @@ -23,13 +26,16 @@ def pytest_configure(config): # pastebin file will be utf-8 encoded binary file config._pastebinfile = tempfile.TemporaryFile('w+b') oldwrite = tr._tw.write + def tee_write(s, **kwargs): oldwrite(s, **kwargs) - if py.builtin._istext(s): + if isinstance(s, six.text_type): s = s.encode('utf-8') config._pastebinfile.write(s) + tr._tw.write = tee_write + def pytest_unconfigure(config): if hasattr(config, '_pastebinfile'): # get terminal contents and delete file @@ -45,6 +51,7 @@ def pytest_unconfigure(config): pastebinurl = create_new_paste(sessionlog) tr.write_line("pastebin session-log: %s\n" % pastebinurl) + def create_new_paste(contents): """ Creates a new paste using bpaste.net service. @@ -72,6 +79,7 @@ def create_new_paste(contents): else: return 'bad response: ' + response + def pytest_terminal_summary(terminalreporter): import _pytest.config if terminalreporter.config.option.pastebin != "failed": @@ -89,4 +97,4 @@ def pytest_terminal_summary(terminalreporter): s = tw.stringio.getvalue() assert len(s) pastebinurl = create_new_paste(s) - tr.write_line("%s --> %s" %(msg, pastebinurl)) + tr.write_line("%s --> %s" % (msg, pastebinurl)) diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/pytester.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/pytester.py similarity index 76% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/pytester.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/pytester.py index faed7f581c9..f2dd5994f1b 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/pytester.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/pytester.py @@ -1,44 +1,44 @@ """ (disabled by default) support for testing pytest and pytest plugins. """ +from __future__ import absolute_import, division, print_function + import codecs import gc import os import platform import re import subprocess +import six import sys import time import traceback from fnmatch import fnmatch -from py.builtin import print_ +from weakref import WeakKeyDictionary +from _pytest.capture import MultiCapture, SysCapture from _pytest._code import Source import py import pytest from _pytest.main import Session, EXIT_OK +from _pytest.assertion.rewrite import AssertionRewritingHook + + +PYTEST_FULLPATH = os.path.abspath(pytest.__file__.rstrip("oc")).replace("$py.class", ".py") def pytest_addoption(parser): # group = parser.getgroup("pytester", "pytester (self-tests) options") parser.addoption('--lsof', - action="store_true", dest="lsof", default=False, - help=("run FD checks if lsof is available")) + action="store_true", dest="lsof", default=False, + help=("run FD checks if lsof is available")) parser.addoption('--runpytest', default="inprocess", dest="runpytest", - choices=("inprocess", "subprocess", ), - help=("run pytest sub runs in tests using an 'inprocess' " - "or 'subprocess' (python -m main) method")) + choices=("inprocess", "subprocess", ), + help=("run pytest sub runs in tests using an 'inprocess' " + "or 'subprocess' (python -m main) method")) def pytest_configure(config): - # This might be called multiple times. Only take the first. - global _pytest_fullpath - try: - _pytest_fullpath - except NameError: - _pytest_fullpath = os.path.abspath(pytest.__file__.rstrip("oc")) - _pytest_fullpath = _pytest_fullpath.replace("$py.class", ".py") - if config.getvalue("lsof"): checker = LsofFdLeakChecker() if checker.matching_platform(): @@ -58,7 +58,7 @@ class LsofFdLeakChecker(object): def _parse_lsof_output(self, out): def isopen(line): return line.startswith('f') and ("deleted" not in line and - 'mem' not in line and "txt" not in line and 'cwd' not in line) + 'mem' not in line and "txt" not in line and 'cwd' not in line) open_files = [] @@ -84,7 +84,7 @@ class LsofFdLeakChecker(object): return True @pytest.hookimpl(hookwrapper=True, tryfirst=True) - def pytest_runtest_item(self, item): + def pytest_runtest_protocol(self, item): lines1 = self.get_open_files() yield if hasattr(sys, "pypy_version_info"): @@ -103,40 +103,42 @@ class LsofFdLeakChecker(object): error.extend([str(f) for f in lines2]) error.append(error[0]) error.append("*** function %s:%s: %s " % item.location) - pytest.fail("\n".join(error), pytrace=False) + error.append("See issue #2366") + item.warn('', "\n".join(error)) # XXX copied from execnet's conftest.py - needs to be merged winpymap = { 'python2.7': r'C:\Python27\python.exe', - 'python2.6': r'C:\Python26\python.exe', - 'python3.1': r'C:\Python31\python.exe', - 'python3.2': r'C:\Python32\python.exe', - 'python3.3': r'C:\Python33\python.exe', 'python3.4': r'C:\Python34\python.exe', 'python3.5': r'C:\Python35\python.exe', + 'python3.6': r'C:\Python36\python.exe', } + def getexecutable(name, cache={}): try: return cache[name] except KeyError: executable = py.path.local.sysfind(name) if executable: + import subprocess + popen = subprocess.Popen([str(executable), "--version"], + universal_newlines=True, stderr=subprocess.PIPE) + out, err = popen.communicate() if name == "jython": - import subprocess - popen = subprocess.Popen([str(executable), "--version"], - universal_newlines=True, stderr=subprocess.PIPE) - out, err = popen.communicate() if not err or "2.5" not in err: executable = None if "2.5.2" in err: - executable = None # http://bugs.jython.org/issue1790 + executable = None # http://bugs.jython.org/issue1790 + elif popen.returncode != 0: + # Handle pyenv's 127. + executable = None cache[name] = executable return executable -@pytest.fixture(params=['python2.6', 'python2.7', 'python3.3', "python3.4", - 'pypy', 'pypy3']) + +@pytest.fixture(params=['python2.7', 'python3.4', 'pypy', 'pypy3']) def anypython(request): name = request.param executable = getexecutable(name) @@ -151,6 +153,8 @@ def anypython(request): return executable # used at least by pytest-xdist plugin + + @pytest.fixture def _pytest(request): """ Return a helper which offers a gethookrecorder(hook) @@ -159,6 +163,7 @@ def _pytest(request): """ return PytestArg(request) + class PytestArg: def __init__(self, request): self.request = request @@ -169,9 +174,9 @@ class PytestArg: return hookrecorder -def get_public_names(l): - """Only return names from iterator l without a leading underscore.""" - return [x for x in l if x[0] != "_"] +def get_public_names(values): + """Only return names from iterator values without a leading underscore.""" + return [x for x in values if x[0] != "_"] class ParsedCall: @@ -182,7 +187,7 @@ class ParsedCall: def __repr__(self): d = self.__dict__.copy() del d['_name'] - return "" %(self._name, d) + return "" % (self._name, d) class HookRecorder: @@ -222,15 +227,15 @@ class HookRecorder: name, check = entries.pop(0) for ind, call in enumerate(self.calls[i:]): if call._name == name: - print_("NAMEMATCH", name, call) + print("NAMEMATCH", name, call) if eval(check, backlocals, call.__dict__): - print_("CHECKERMATCH", repr(check), "->", call) + print("CHECKERMATCH", repr(check), "->", call) else: - print_("NOCHECKERMATCH", repr(check), "-", call) + print("NOCHECKERMATCH", repr(check), "-", call) continue i += ind + 1 break - print_("NONAMEMATCH", name, "with", call) + print("NONAMEMATCH", name, "with", call) else: pytest.fail("could not find %r check %r" % (name, check)) @@ -245,9 +250,9 @@ class HookRecorder: pytest.fail("\n".join(lines)) def getcall(self, name): - l = self.getcalls(name) - assert len(l) == 1, (name, l) - return l[0] + values = self.getcalls(name) + assert len(values) == 1, (name, values) + return values[0] # functionality for test reports @@ -256,9 +261,9 @@ class HookRecorder: return [x.report for x in self.getcalls(names)] def matchreport(self, inamepart="", - names="pytest_runtest_logreport pytest_collectreport", when=None): + names="pytest_runtest_logreport pytest_collectreport", when=None): """ return a testreport whose dotted import path matches """ - l = [] + values = [] for rep in self.getreports(names=names): try: if not when and rep.when != "call" and rep.passed: @@ -269,14 +274,14 @@ class HookRecorder: if when and getattr(rep, 'when', None) != when: continue if not inamepart or inamepart in rep.nodeid.split("::"): - l.append(rep) - if not l: + values.append(rep) + if not values: raise ValueError("could not find test report matching %r: " "no test reports at all!" % (inamepart,)) - if len(l) > 1: + if len(values) > 1: raise ValueError( - "found 2 or more testreports matching %r: %s" %(inamepart, l)) - return l[0] + "found 2 or more testreports matching %r: %s" % (inamepart, values)) + return values[0] def getfailures(self, names='pytest_runtest_logreport pytest_collectreport'): @@ -290,7 +295,7 @@ class HookRecorder: skipped = [] failed = [] for rep in self.getreports( - "pytest_collectreport pytest_runtest_logreport"): + "pytest_collectreport pytest_runtest_logreport"): if rep.passed: if getattr(rep, "when", None) == "call": passed.append(rep) @@ -318,7 +323,8 @@ def linecomp(request): return LineComp() -def pytest_funcarg__LineMatcher(request): +@pytest.fixture(name='LineMatcher') +def LineMatcher_fixture(request): return LineMatcher @@ -327,7 +333,9 @@ def testdir(request, tmpdir_factory): return Testdir(request, tmpdir_factory) -rex_outcome = re.compile("(\d+) ([\w-]+)") +rex_outcome = re.compile(r"(\d+) ([\w-]+)") + + class RunResult: """The result of running a command. @@ -343,6 +351,7 @@ class RunResult: :duration: Duration in seconds. """ + def __init__(self, ret, outlines, errlines, duration): self.ret = ret self.outlines = outlines @@ -362,22 +371,26 @@ class RunResult: for num, cat in outcomes: d[cat] = int(num) return d + raise ValueError("Pytest terminal report not found") - def assert_outcomes(self, passed=0, skipped=0, failed=0): + def assert_outcomes(self, passed=0, skipped=0, failed=0, error=0): """ assert that the specified outcomes appear with the respective numbers (0 means it didn't occur) in the text output from a test run.""" d = self.parseoutcomes() - assert passed == d.get("passed", 0) - assert skipped == d.get("skipped", 0) - assert failed == d.get("failed", 0) - + obtained = { + 'passed': d.get('passed', 0), + 'skipped': d.get('skipped', 0), + 'failed': d.get('failed', 0), + 'error': d.get('error', 0), + } + assert obtained == dict(passed=passed, skipped=skipped, failed=failed, error=error) class Testdir: - """Temporary test directory with tools to test/run py.test itself. + """Temporary test directory with tools to test/run pytest itself. This is based on the ``tmpdir`` fixture but provides a number of - methods which aid with testing py.test itself. Unless + methods which aid with testing pytest itself. Unless :py:meth:`chdir` is used all methods will use :py:attr:`tmpdir` as current working directory. @@ -396,20 +409,13 @@ class Testdir: def __init__(self, request, tmpdir_factory): self.request = request - # XXX remove duplication with tmpdir plugin - basetmp = tmpdir_factory.ensuretemp("testdir") + self._mod_collections = WeakKeyDictionary() name = request.function.__name__ - for i in range(100): - try: - tmpdir = basetmp.mkdir(name + str(i)) - except py.error.EEXIST: - continue - break - self.tmpdir = tmpdir + self.tmpdir = tmpdir_factory.mktemp(name, numbered=True) self.plugins = [] self._savesyspath = (list(sys.path), list(sys.meta_path)) self._savemodulekeys = set(sys.modules) - self.chdir() # always chdir + self.chdir() # always chdir self.request.addfinalizer(self.finalize) method = self.request.config.getoption("--runpytest") if method == "inprocess": @@ -441,9 +447,10 @@ class Testdir: the module is re-imported. """ for name in set(sys.modules).difference(self._savemodulekeys): - # it seems zope.interfaces is keeping some state - # (used by twisted related tests) - if name != "zope.interface": + # some zope modules used by twisted-related tests keeps internal + # state and can't be deleted; we had some trouble in the past + # with zope.interface for example + if not name.startswith("zope"): del sys.modules[name] def make_hook_recorder(self, pluginmanager): @@ -463,26 +470,24 @@ class Testdir: if not hasattr(self, '_olddir'): self._olddir = old - def _makefile(self, ext, args, kwargs): + def _makefile(self, ext, args, kwargs, encoding='utf-8'): items = list(kwargs.items()) + + def to_text(s): + return s.decode(encoding) if isinstance(s, bytes) else six.text_type(s) + if args: - source = py.builtin._totext("\n").join( - map(py.builtin._totext, args)) + py.builtin._totext("\n") + source = u"\n".join(to_text(x) for x in args) basename = self.request.function.__name__ items.insert(0, (basename, source)) + ret = None - for name, value in items: - p = self.tmpdir.join(name).new(ext=ext) + for basename, value in items: + p = self.tmpdir.join(basename).new(ext=ext) + p.dirpath().ensure_dir() source = Source(value) - def my_totext(s, encoding="utf-8"): - if py.builtin._isbytes(s): - s = py.builtin._totext(s, encoding=encoding) - return s - source_unicode = "\n".join([my_totext(line) for line in source.lines]) - source = py.builtin._totext(source_unicode) - content = source.strip().encode("utf-8") # + "\n" - #content = content.rstrip() + "\n" - p.write(content, "wb") + source = u"\n".join(to_text(line) for line in source.lines) + p.write(source.strip().encode(encoding), "wb") if ret is None: ret = p return ret @@ -557,7 +562,7 @@ class Testdir: def mkpydir(self, name): """Create a new python package. - This creates a (sub)direcotry with an empty ``__init__.py`` + This creates a (sub)directory with an empty ``__init__.py`` file so that is recognised as a python package. """ @@ -566,6 +571,7 @@ class Testdir: return p Session = Session + def getnode(self, config, arg): """Return the collection node of a file. @@ -588,7 +594,7 @@ class Testdir: """Return the collection node of a file. This is like :py:meth:`getnode` but uses - :py:meth:`parseconfigure` to create the (configured) py.test + :py:meth:`parseconfigure` to create the (configured) pytest Config instance. :param path: A :py:class:`py.path.local` instance of the file. @@ -646,17 +652,17 @@ class Testdir: """ p = self.makepyfile(source) - l = list(cmdlineargs) + [p] - return self.inline_run(*l) + values = list(cmdlineargs) + [p] + return self.inline_run(*values) def inline_genitems(self, *args): """Run ``pytest.main(['--collectonly'])`` in-process. - Retuns a tuple of the collected items and a + Returns a tuple of the collected items and a :py:class:`HookRecorder` instance. This runs the :py:func:`pytest.main` function to run all of - py.test inside the test process itself like + pytest inside the test process itself like :py:meth:`inline_run`. However the return value is a tuple of the collection items and a :py:class:`HookRecorder` instance. @@ -669,7 +675,7 @@ class Testdir: """Run ``pytest.main()`` in-process, returning a HookRecorder. This runs the :py:func:`pytest.main` function to run all of - py.test inside the test process itself. This means it can + pytest inside the test process itself. This means it can return a :py:class:`HookRecorder` instance which gives more detailed results from then run then can be done by matching stdout/stderr from :py:meth:`runpytest`. @@ -681,9 +687,21 @@ class Testdir: ``pytest.main()`` instance should use. :return: A :py:class:`HookRecorder` instance. - """ + # When running py.test inline any plugins active in the main + # test process are already imported. So this disables the + # warning which will trigger to say they can no longer be + # rewritten, which is fine as they are already rewritten. + orig_warn = AssertionRewritingHook._warn_already_imported + + def revert(): + AssertionRewritingHook._warn_already_imported = orig_warn + + self.request.addfinalizer(revert) + AssertionRewritingHook._warn_already_imported = lambda *a: None + rec = [] + class Collect: def pytest_configure(x, config): rec.append(self.make_hook_recorder(config.pluginmanager)) @@ -713,25 +731,30 @@ class Testdir: if kwargs.get("syspathinsert"): self.syspathinsert() now = time.time() - capture = py.io.StdCapture() + capture = MultiCapture(Capture=SysCapture) + capture.start_capturing() try: try: reprec = self.inline_run(*args, **kwargs) except SystemExit as e: + class reprec: ret = e.args[0] + except Exception: traceback.print_exc() + class reprec: ret = 3 finally: - out, err = capture.reset() + out, err = capture.readouterr() + capture.stop_capturing() sys.stdout.write(out) sys.stderr.write(err) res = RunResult(reprec.ret, out.split("\n"), err.split("\n"), - time.time()-now) + time.time() - now) res.reprec = reprec return res @@ -747,17 +770,17 @@ class Testdir: args = [str(x) for x in args] for x in args: if str(x).startswith('--basetemp'): - #print ("basedtemp exists: %s" %(args,)) + # print("basedtemp exists: %s" %(args,)) break else: args.append("--basetemp=%s" % self.tmpdir.dirpath('basetemp')) - #print ("added basetemp: %s" %(args,)) + # print("added basetemp: %s" %(args,)) return args def parseconfig(self, *args): - """Return a new py.test Config instance from given commandline args. + """Return a new pytest Config instance from given commandline args. - This invokes the py.test bootstrapping code in _pytest.config + This invokes the pytest bootstrapping code in _pytest.config to create a new :py:class:`_pytest.core.PluginManager` and call the pytest_cmdline_parse hook to create new :py:class:`_pytest.config.Config` instance. @@ -777,7 +800,7 @@ class Testdir: return config def parseconfigure(self, *args): - """Return a new py.test configured Config instance. + """Return a new pytest configured Config instance. This returns a new :py:class:`_pytest.config.Config` instance like :py:meth:`parseconfig`, but also calls the @@ -789,10 +812,10 @@ class Testdir: self.request.addfinalizer(config._ensure_unconfigure) return config - def getitem(self, source, funcname="test_func"): + def getitem(self, source, funcname="test_func"): """Return the test item for a test function. - This writes the source to a python file and runs py.test's + This writes the source to a python file and runs pytest's collection on the resulting module, returning the test item for the requested function name. @@ -806,13 +829,13 @@ class Testdir: for item in items: if item.name == funcname: return item - assert 0, "%r item not found in module:\n%s\nitems: %s" %( + assert 0, "%r item not found in module:\n%s\nitems: %s" % ( funcname, source, items) - def getitems(self, source): + def getitems(self, source): """Return all test items collected from the module. - This writes the source to a python file and runs py.test's + This writes the source to a python file and runs pytest's collection on the resulting module, returning all test items contained within. @@ -820,11 +843,11 @@ class Testdir: modcol = self.getmodulecol(source) return self.genitems([modcol]) - def getmodulecol(self, source, configargs=(), withinit=False): + def getmodulecol(self, source, configargs=(), withinit=False): """Return the module collection node for ``source``. This writes ``source`` to a file using :py:meth:`makepyfile` - and then runs the py.test collection on it, returning the + and then runs the pytest collection on it, returning the collection node for the test module. :param source: The source code of the module to collect. @@ -833,15 +856,16 @@ class Testdir: :py:meth:`parseconfigure`. :param withinit: Whether to also write a ``__init__.py`` file - to the temporarly directory to ensure it is a package. + to the temporary directory to ensure it is a package. """ kw = {self.request.function.__name__: Source(source).strip()} path = self.makepyfile(**kw) if withinit: - self.makepyfile(__init__ = "#") + self.makepyfile(__init__="#") self.config = config = self.parseconfigure(path, *configargs) node = self.getnode(config, path) + return node def collect_by_name(self, modcol, name): @@ -856,7 +880,9 @@ class Testdir: :param name: The name of the node to return. """ - for colitem in modcol._memocollect(): + if modcol not in self._mod_collections: + self._mod_collections[modcol] = list(modcol.collect()) + for colitem in self._mod_collections[modcol]: if colitem.name == name: return colitem @@ -873,8 +899,11 @@ class Testdir: env['PYTHONPATH'] = os.pathsep.join(filter(None, [ str(os.getcwd()), env.get('PYTHONPATH', '')])) kw['env'] = env - return subprocess.Popen(cmdargs, - stdout=stdout, stderr=stderr, **kw) + + popen = subprocess.Popen(cmdargs, stdin=subprocess.PIPE, stdout=stdout, stderr=stderr, **kw) + popen.stdin.close() + + return popen def run(self, *cmdargs): """Run a command with arguments. @@ -891,14 +920,14 @@ class Testdir: cmdargs = [str(x) for x in cmdargs] p1 = self.tmpdir.join("stdout") p2 = self.tmpdir.join("stderr") - print_("running:", ' '.join(cmdargs)) - print_(" in:", str(py.path.local())) + print("running:", ' '.join(cmdargs)) + print(" in:", str(py.path.local())) f1 = codecs.open(str(p1), "w", encoding="utf8") f2 = codecs.open(str(p2), "w", encoding="utf8") try: now = time.time() popen = self.popen(cmdargs, stdout=f1, stderr=f2, - close_fds=(sys.platform != "win32")) + close_fds=(sys.platform != "win32")) ret = popen.wait() finally: f1.close() @@ -913,19 +942,19 @@ class Testdir: f2.close() self._dump_lines(out, sys.stdout) self._dump_lines(err, sys.stderr) - return RunResult(ret, out, err, time.time()-now) + return RunResult(ret, out, err, time.time() - now) def _dump_lines(self, lines, fp): try: for line in lines: - py.builtin.print_(line, file=fp) + print(line, file=fp) except UnicodeEncodeError: print("couldn't print to %s because of encoding" % (fp,)) def _getpytestargs(self): # we cannot use "(sys.executable,script)" - # because on windows the script is e.g. a py.test.exe - return (sys.executable, _pytest_fullpath,) # noqa + # because on windows the script is e.g. a pytest.exe + return (sys.executable, PYTEST_FULLPATH) # noqa def runpython(self, script): """Run a python script using sys.executable as interpreter. @@ -939,7 +968,7 @@ class Testdir: return self.run(sys.executable, "-c", command) def runpytest_subprocess(self, *args, **kwargs): - """Run py.test as a subprocess with given arguments. + """Run pytest as a subprocess with given arguments. Any plugins added to the :py:attr:`plugins` list will added using the ``-p`` command line option. Addtionally @@ -952,12 +981,12 @@ class Testdir: """ p = py.path.local.make_numbered_dir(prefix="runpytest-", - keep=None, rootdir=self.tmpdir) + keep=None, rootdir=self.tmpdir) args = ('--basetemp=%s' % p, ) + args - #for x in args: + # for x in args: # if '--confcutdir' in str(x): # break - #else: + # else: # pass # args = ('--confcutdir=.',) + args plugins = [x for x in self.plugins if isinstance(x, str)] @@ -967,15 +996,15 @@ class Testdir: return self.run(*args) def spawn_pytest(self, string, expect_timeout=10.0): - """Run py.test using pexpect. + """Run pytest using pexpect. - This makes sure to use the right py.test and sets up the + This makes sure to use the right pytest and sets up the temporary directory locations. The pexpect child is returned. """ - basetemp = self.tmpdir.mkdir("pexpect") + basetemp = self.tmpdir.mkdir("temp-pexpect") invoke = " ".join(map(str, self._getpytestargs())) cmd = "%s --basetemp=%s %s" % (invoke, basetemp, string) return self.spawn(cmd, expect_timeout=expect_timeout) @@ -988,8 +1017,6 @@ class Testdir: pexpect = pytest.importorskip("pexpect", "3.0") if hasattr(sys, 'pypy_version_info') and '64' in platform.machine(): pytest.skip("pypy-64 bit not supported") - if sys.platform == "darwin": - pytest.xfail("pexpect does not work reliably on darwin?!") if sys.platform.startswith("freebsd"): pytest.xfail("pexpect does not work reliably on freebsd") logfile = self.tmpdir.join("spawn.out").open("wb") @@ -998,12 +1025,13 @@ class Testdir: child.timeout = expect_timeout return child + def getdecoded(out): - try: - return out.decode("utf-8") - except UnicodeDecodeError: - return "INTERNAL not-utf8-decodeable, truncated string:\n%s" % ( - py.io.saferepr(out),) + try: + return out.decode("utf-8") + except UnicodeDecodeError: + return "INTERNAL not-utf8-decodeable, truncated string:\n%s" % ( + py.io.saferepr(out),) class LineComp: @@ -1033,8 +1061,9 @@ class LineMatcher: """ - def __init__(self, lines): + def __init__(self, lines): self.lines = lines + self._log_output = [] def str(self): """Return the entire original text.""" @@ -1048,6 +1077,23 @@ class LineMatcher: return lines2 def fnmatch_lines_random(self, lines2): + """Check lines exist in the output using ``fnmatch.fnmatch``, in any order. + + The argument is a list of lines which have to occur in the + output, in any order. + """ + self._match_lines_random(lines2, fnmatch) + + def re_match_lines_random(self, lines2): + """Check lines exist in the output using ``re.match``, in any order. + + The argument is a list of lines which have to occur in the + output, in any order. + + """ + self._match_lines_random(lines2, lambda name, pat: re.match(pat, name)) + + def _match_lines_random(self, lines2, match_func): """Check lines exist in the output. The argument is a list of lines which have to occur in the @@ -1057,11 +1103,12 @@ class LineMatcher: lines2 = self._getlines(lines2) for line in lines2: for x in self.lines: - if line == x or fnmatch(x, line): - print_("matched: ", repr(line)) + if line == x or match_func(x, line): + self._log("matched: ", repr(line)) break else: - raise ValueError("line %r not found in output" % line) + self._log("line %r not found in output" % line) + raise ValueError(self._log_text) def get_lines_after(self, fnline): """Return all lines following the given line in the text. @@ -1070,20 +1117,49 @@ class LineMatcher: """ for i, line in enumerate(self.lines): if fnline == line or fnmatch(line, fnline): - return self.lines[i+1:] + return self.lines[i + 1:] raise ValueError("line %r not found in output" % fnline) + def _log(self, *args): + self._log_output.append(' '.join((str(x) for x in args))) + + @property + def _log_text(self): + return '\n'.join(self._log_output) + def fnmatch_lines(self, lines2): - """Search the text for matching lines. + """Search captured text for matching lines using ``fnmatch.fnmatch``. The argument is a list of lines which have to match and can - use glob wildcards. If they do not match an pytest.fail() is + use glob wildcards. If they do not match a pytest.fail() is called. The matches and non-matches are also printed on stdout. """ - def show(arg1, arg2): - py.builtin.print_(arg1, arg2, file=sys.stderr) + self._match_lines(lines2, fnmatch, 'fnmatch') + + def re_match_lines(self, lines2): + """Search captured text for matching lines using ``re.match``. + + The argument is a list of lines which have to match using ``re.match``. + If they do not match a pytest.fail() is called. + + The matches and non-matches are also printed on + stdout. + """ + self._match_lines(lines2, lambda name, pat: re.match(pat, name), 're.match') + + def _match_lines(self, lines2, match_func, match_nickname): + """Underlying implementation of ``fnmatch_lines`` and ``re_match_lines``. + + :param list[str] lines2: list of string patterns to match. The actual format depends on + ``match_func``. + :param match_func: a callable ``match_func(line, pattern)`` where line is the captured + line from stdout/stderr and pattern is the matching pattern. + + :param str match_nickname: the nickname for the match function that will be logged + to stdout when a match occurs. + """ lines2 = self._getlines(lines2) lines1 = self.lines[:] nextline = None @@ -1094,17 +1170,18 @@ class LineMatcher: while lines1: nextline = lines1.pop(0) if line == nextline: - show("exact match:", repr(line)) + self._log("exact match:", repr(line)) break - elif fnmatch(nextline, line): - show("fnmatch:", repr(line)) - show(" with:", repr(nextline)) + elif match_func(nextline, line): + self._log("%s:" % match_nickname, repr(line)) + self._log(" with:", repr(nextline)) break else: if not nomatchprinted: - show("nomatch:", repr(line)) + self._log("nomatch:", repr(line)) nomatchprinted = True - show(" and:", repr(nextline)) + self._log(" and:", repr(nextline)) extralines.append(nextline) else: - pytest.fail("remains unmatched: %r, see stderr" % (line,)) + self._log("remains unmatched: %r" % (line,)) + pytest.fail(self._log_text) diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/python.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/python.py new file mode 100644 index 00000000000..650171a9e9c --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/python.py @@ -0,0 +1,1175 @@ +""" Python test discovery, setup and run of test functions. """ +from __future__ import absolute_import, division, print_function + +import fnmatch +import inspect +import sys +import os +import collections +import warnings +from textwrap import dedent +from itertools import count + + +import py +import six +from _pytest.mark import MarkerError +from _pytest.config import hookimpl + +import _pytest +import pluggy +from _pytest import fixtures +from _pytest import main +from _pytest import deprecated +from _pytest.compat import ( + isclass, isfunction, is_generator, ascii_escaped, + REGEX_TYPE, STRING_TYPES, NoneType, NOTSET, + get_real_func, getfslineno, safe_getattr, + safe_str, getlocation, enum, +) +from _pytest.outcomes import fail +from _pytest.mark import transfer_markers + +cutdir1 = py.path.local(pluggy.__file__.rstrip("oc")) +cutdir2 = py.path.local(_pytest.__file__).dirpath() +cutdir3 = py.path.local(py.__file__).dirpath() + + +def filter_traceback(entry): + """Return True if a TracebackEntry instance should be removed from tracebacks: + * dynamically generated code (no code to show up for it); + * internal traceback from pytest or its internal libraries, py and pluggy. + """ + # entry.path might sometimes return a str object when the entry + # points to dynamically generated code + # see https://bitbucket.org/pytest-dev/py/issues/71 + raw_filename = entry.frame.code.raw.co_filename + is_generated = '<' in raw_filename and '>' in raw_filename + if is_generated: + return False + # entry.path might point to an inexisting file, in which case it will + # alsso return a str object. see #1133 + p = py.path.local(entry.path) + return p != cutdir1 and not p.relto(cutdir2) and not p.relto(cutdir3) + + +def pyobj_property(name): + def get(self): + node = self.getparent(getattr(__import__('pytest'), name)) + if node is not None: + return node.obj + doc = "python %s object this node was collected from (can be None)." % ( + name.lower(),) + return property(get, None, None, doc) + + +def pytest_addoption(parser): + group = parser.getgroup("general") + group.addoption('--fixtures', '--funcargs', + action="store_true", dest="showfixtures", default=False, + help="show available fixtures, sorted by plugin appearance") + group.addoption( + '--fixtures-per-test', + action="store_true", + dest="show_fixtures_per_test", + default=False, + help="show fixtures per test", + ) + parser.addini("usefixtures", type="args", default=[], + help="list of default fixtures to be used with this project") + parser.addini("python_files", type="args", + default=['test_*.py', '*_test.py'], + help="glob-style file patterns for Python test module discovery") + parser.addini("python_classes", type="args", default=["Test", ], + help="prefixes or glob names for Python test class discovery") + parser.addini("python_functions", type="args", default=["test", ], + help="prefixes or glob names for Python test function and " + "method discovery") + + group.addoption("--import-mode", default="prepend", + choices=["prepend", "append"], dest="importmode", + help="prepend/append to sys.path when importing test modules, " + "default is to prepend.") + + +def pytest_cmdline_main(config): + if config.option.showfixtures: + showfixtures(config) + return 0 + if config.option.show_fixtures_per_test: + show_fixtures_per_test(config) + return 0 + + +def pytest_generate_tests(metafunc): + # those alternative spellings are common - raise a specific error to alert + # the user + alt_spellings = ['parameterize', 'parametrise', 'parameterise'] + for attr in alt_spellings: + if hasattr(metafunc.function, attr): + msg = "{0} has '{1}', spelling should be 'parametrize'" + raise MarkerError(msg.format(metafunc.function.__name__, attr)) + try: + markers = metafunc.function.parametrize + except AttributeError: + return + for marker in markers: + metafunc.parametrize(*marker.args, **marker.kwargs) + + +def pytest_configure(config): + config.addinivalue_line("markers", + "parametrize(argnames, argvalues): call a test function multiple " + "times passing in different arguments in turn. argvalues generally " + "needs to be a list of values if argnames specifies only one name " + "or a list of tuples of values if argnames specifies multiple names. " + "Example: @parametrize('arg1', [1,2]) would lead to two calls of the " + "decorated test function, one with arg1=1 and another with arg1=2." + "see http://pytest.org/latest/parametrize.html for more info and " + "examples." + ) + config.addinivalue_line("markers", + "usefixtures(fixturename1, fixturename2, ...): mark tests as needing " + "all of the specified fixtures. see http://pytest.org/latest/fixture.html#usefixtures " + ) + + +@hookimpl(trylast=True) +def pytest_pyfunc_call(pyfuncitem): + testfunction = pyfuncitem.obj + if pyfuncitem._isyieldedfunction(): + testfunction(*pyfuncitem._args) + else: + funcargs = pyfuncitem.funcargs + testargs = {} + for arg in pyfuncitem._fixtureinfo.argnames: + testargs[arg] = funcargs[arg] + testfunction(**testargs) + return True + + +def pytest_collect_file(path, parent): + ext = path.ext + if ext == ".py": + if not parent.session.isinitpath(path): + for pat in parent.config.getini('python_files'): + if path.fnmatch(pat): + break + else: + return + ihook = parent.session.gethookproxy(path) + return ihook.pytest_pycollect_makemodule(path=path, parent=parent) + + +def pytest_pycollect_makemodule(path, parent): + return Module(path, parent) + + +@hookimpl(hookwrapper=True) +def pytest_pycollect_makeitem(collector, name, obj): + outcome = yield + res = outcome.get_result() + if res is not None: + return + # nothing was collected elsewhere, let's do it here + if isclass(obj): + if collector.istestclass(obj, name): + Class = collector._getcustomclass("Class") + outcome.force_result(Class(name, parent=collector)) + elif collector.istestfunction(obj, name): + # mock seems to store unbound methods (issue473), normalize it + obj = getattr(obj, "__func__", obj) + # We need to try and unwrap the function if it's a functools.partial + # or a funtools.wrapped. + # We musn't if it's been wrapped with mock.patch (python 2 only) + if not (isfunction(obj) or isfunction(get_real_func(obj))): + collector.warn(code="C2", message="cannot collect %r because it is not a function." + % name, ) + elif getattr(obj, "__test__", True): + if is_generator(obj): + res = Generator(name, parent=collector) + else: + res = list(collector._genfunctions(name, obj)) + outcome.force_result(res) + + +def pytest_make_parametrize_id(config, val, argname=None): + return None + + +class PyobjContext(object): + module = pyobj_property("Module") + cls = pyobj_property("Class") + instance = pyobj_property("Instance") + + +class PyobjMixin(PyobjContext): + def obj(): + def fget(self): + obj = getattr(self, '_obj', None) + if obj is None: + self._obj = obj = self._getobj() + return obj + + def fset(self, value): + self._obj = value + + return property(fget, fset, None, "underlying python object") + + obj = obj() + + def _getobj(self): + return getattr(self.parent.obj, self.name) + + def getmodpath(self, stopatmodule=True, includemodule=False): + """ return python path relative to the containing module. """ + chain = self.listchain() + chain.reverse() + parts = [] + for node in chain: + if isinstance(node, Instance): + continue + name = node.name + if isinstance(node, Module): + name = os.path.splitext(name)[0] + if stopatmodule: + if includemodule: + parts.append(name) + break + parts.append(name) + parts.reverse() + s = ".".join(parts) + return s.replace(".[", "[") + + def _getfslineno(self): + return getfslineno(self.obj) + + def reportinfo(self): + # XXX caching? + obj = self.obj + compat_co_firstlineno = getattr(obj, 'compat_co_firstlineno', None) + if isinstance(compat_co_firstlineno, int): + # nose compatibility + fspath = sys.modules[obj.__module__].__file__ + if fspath.endswith(".pyc"): + fspath = fspath[:-1] + lineno = compat_co_firstlineno + else: + fspath, lineno = getfslineno(obj) + modpath = self.getmodpath() + assert isinstance(lineno, int) + return fspath, lineno, modpath + + +class PyCollector(PyobjMixin, main.Collector): + + def funcnamefilter(self, name): + return self._matches_prefix_or_glob_option('python_functions', name) + + def isnosetest(self, obj): + """ Look for the __test__ attribute, which is applied by the + @nose.tools.istest decorator + """ + # We explicitly check for "is True" here to not mistakenly treat + # classes with a custom __getattr__ returning something truthy (like a + # function) as test classes. + return safe_getattr(obj, '__test__', False) is True + + def classnamefilter(self, name): + return self._matches_prefix_or_glob_option('python_classes', name) + + def istestfunction(self, obj, name): + if self.funcnamefilter(name) or self.isnosetest(obj): + if isinstance(obj, staticmethod): + # static methods need to be unwrapped + obj = safe_getattr(obj, '__func__', False) + if obj is False: + # Python 2.6 wraps in a different way that we won't try to handle + msg = "cannot collect static method %r because " \ + "it is not a function (always the case in Python 2.6)" + self.warn( + code="C2", message=msg % name) + return False + return ( + safe_getattr(obj, "__call__", False) and fixtures.getfixturemarker(obj) is None + ) + else: + return False + + def istestclass(self, obj, name): + return self.classnamefilter(name) or self.isnosetest(obj) + + def _matches_prefix_or_glob_option(self, option_name, name): + """ + checks if the given name matches the prefix or glob-pattern defined + in ini configuration. + """ + for option in self.config.getini(option_name): + if name.startswith(option): + return True + # check that name looks like a glob-string before calling fnmatch + # because this is called for every name in each collected module, + # and fnmatch is somewhat expensive to call + elif ('*' in option or '?' in option or '[' in option) and \ + fnmatch.fnmatch(name, option): + return True + return False + + def collect(self): + if not getattr(self.obj, "__test__", True): + return [] + + # NB. we avoid random getattrs and peek in the __dict__ instead + # (XXX originally introduced from a PyPy need, still true?) + dicts = [getattr(self.obj, '__dict__', {})] + for basecls in inspect.getmro(self.obj.__class__): + dicts.append(basecls.__dict__) + seen = {} + values = [] + for dic in dicts: + for name, obj in list(dic.items()): + if name in seen: + continue + seen[name] = True + res = self._makeitem(name, obj) + if res is None: + continue + if not isinstance(res, list): + res = [res] + values.extend(res) + values.sort(key=lambda item: item.reportinfo()[:2]) + return values + + def makeitem(self, name, obj): + warnings.warn(deprecated.COLLECTOR_MAKEITEM, stacklevel=2) + self._makeitem(name, obj) + + def _makeitem(self, name, obj): + # assert self.ihook.fspath == self.fspath, self + return self.ihook.pytest_pycollect_makeitem( + collector=self, name=name, obj=obj) + + def _genfunctions(self, name, funcobj): + module = self.getparent(Module).obj + clscol = self.getparent(Class) + cls = clscol and clscol.obj or None + transfer_markers(funcobj, cls, module) + fm = self.session._fixturemanager + fixtureinfo = fm.getfixtureinfo(self, funcobj, cls) + metafunc = Metafunc(funcobj, fixtureinfo, self.config, + cls=cls, module=module) + methods = [] + if hasattr(module, "pytest_generate_tests"): + methods.append(module.pytest_generate_tests) + if hasattr(cls, "pytest_generate_tests"): + methods.append(cls().pytest_generate_tests) + if methods: + self.ihook.pytest_generate_tests.call_extra(methods, + dict(metafunc=metafunc)) + else: + self.ihook.pytest_generate_tests(metafunc=metafunc) + + Function = self._getcustomclass("Function") + if not metafunc._calls: + yield Function(name, parent=self, fixtureinfo=fixtureinfo) + else: + # add funcargs() as fixturedefs to fixtureinfo.arg2fixturedefs + fixtures.add_funcarg_pseudo_fixture_def(self, metafunc, fm) + + for callspec in metafunc._calls: + subname = "%s[%s]" % (name, callspec.id) + yield Function(name=subname, parent=self, + callspec=callspec, callobj=funcobj, + fixtureinfo=fixtureinfo, + keywords={callspec.id: True}, + originalname=name, + ) + + +class Module(main.File, PyCollector): + """ Collector for test classes and functions. """ + + def _getobj(self): + return self._importtestmodule() + + def collect(self): + self.session._fixturemanager.parsefactories(self) + return super(Module, self).collect() + + def _importtestmodule(self): + # we assume we are only called once per module + importmode = self.config.getoption("--import-mode") + try: + mod = self.fspath.pyimport(ensuresyspath=importmode) + except SyntaxError: + raise self.CollectError( + _pytest._code.ExceptionInfo().getrepr(style="short")) + except self.fspath.ImportMismatchError: + e = sys.exc_info()[1] + raise self.CollectError( + "import file mismatch:\n" + "imported module %r has this __file__ attribute:\n" + " %s\n" + "which is not the same as the test file we want to collect:\n" + " %s\n" + "HINT: remove __pycache__ / .pyc files and/or use a " + "unique basename for your test file modules" + % e.args + ) + except ImportError: + from _pytest._code.code import ExceptionInfo + exc_info = ExceptionInfo() + if self.config.getoption('verbose') < 2: + exc_info.traceback = exc_info.traceback.filter(filter_traceback) + exc_repr = exc_info.getrepr(style='short') if exc_info.traceback else exc_info.exconly() + formatted_tb = safe_str(exc_repr) + raise self.CollectError( + "ImportError while importing test module '{fspath}'.\n" + "Hint: make sure your test modules/packages have valid Python names.\n" + "Traceback:\n" + "{traceback}".format(fspath=self.fspath, traceback=formatted_tb) + ) + except _pytest.runner.Skipped as e: + if e.allow_module_level: + raise + raise self.CollectError( + "Using pytest.skip outside of a test is not allowed. " + "To decorate a test function, use the @pytest.mark.skip " + "or @pytest.mark.skipif decorators instead, and to skip a " + "module use `pytestmark = pytest.mark.{skip,skipif}." + ) + self.config.pluginmanager.consider_module(mod) + return mod + + def setup(self): + setup_module = _get_xunit_setup_teardown(self.obj, "setUpModule") + if setup_module is None: + setup_module = _get_xunit_setup_teardown(self.obj, "setup_module") + if setup_module is not None: + setup_module() + + teardown_module = _get_xunit_setup_teardown(self.obj, 'tearDownModule') + if teardown_module is None: + teardown_module = _get_xunit_setup_teardown(self.obj, 'teardown_module') + if teardown_module is not None: + self.addfinalizer(teardown_module) + + +def _get_xunit_setup_teardown(holder, attr_name, param_obj=None): + """ + Return a callable to perform xunit-style setup or teardown if + the function exists in the ``holder`` object. + The ``param_obj`` parameter is the parameter which will be passed to the function + when the callable is called without arguments, defaults to the ``holder`` object. + Return ``None`` if a suitable callable is not found. + """ + param_obj = param_obj if param_obj is not None else holder + result = _get_xunit_func(holder, attr_name) + if result is not None: + arg_count = result.__code__.co_argcount + if inspect.ismethod(result): + arg_count -= 1 + if arg_count: + return lambda: result(param_obj) + else: + return result + + +def _get_xunit_func(obj, name): + """Return the attribute from the given object to be used as a setup/teardown + xunit-style function, but only if not marked as a fixture to + avoid calling it twice. + """ + meth = getattr(obj, name, None) + if fixtures.getfixturemarker(meth) is None: + return meth + + +class Class(PyCollector): + """ Collector for test methods. """ + + def collect(self): + if not safe_getattr(self.obj, "__test__", True): + return [] + if hasinit(self.obj): + self.warn("C1", "cannot collect test class %r because it has a " + "__init__ constructor" % self.obj.__name__) + return [] + elif hasnew(self.obj): + self.warn("C1", "cannot collect test class %r because it has a " + "__new__ constructor" % self.obj.__name__) + return [] + return [self._getcustomclass("Instance")(name="()", parent=self)] + + def setup(self): + setup_class = _get_xunit_func(self.obj, 'setup_class') + if setup_class is not None: + setup_class = getattr(setup_class, 'im_func', setup_class) + setup_class = getattr(setup_class, '__func__', setup_class) + setup_class(self.obj) + + fin_class = getattr(self.obj, 'teardown_class', None) + if fin_class is not None: + fin_class = getattr(fin_class, 'im_func', fin_class) + fin_class = getattr(fin_class, '__func__', fin_class) + self.addfinalizer(lambda: fin_class(self.obj)) + + +class Instance(PyCollector): + def _getobj(self): + return self.parent.obj() + + def collect(self): + self.session._fixturemanager.parsefactories(self) + return super(Instance, self).collect() + + def newinstance(self): + self.obj = self._getobj() + return self.obj + + +class FunctionMixin(PyobjMixin): + """ mixin for the code common to Function and Generator. + """ + + def setup(self): + """ perform setup for this test function. """ + if hasattr(self, '_preservedparent'): + obj = self._preservedparent + elif isinstance(self.parent, Instance): + obj = self.parent.newinstance() + self.obj = self._getobj() + else: + obj = self.parent.obj + if inspect.ismethod(self.obj): + setup_name = 'setup_method' + teardown_name = 'teardown_method' + else: + setup_name = 'setup_function' + teardown_name = 'teardown_function' + setup_func_or_method = _get_xunit_setup_teardown(obj, setup_name, param_obj=self.obj) + if setup_func_or_method is not None: + setup_func_or_method() + teardown_func_or_method = _get_xunit_setup_teardown(obj, teardown_name, param_obj=self.obj) + if teardown_func_or_method is not None: + self.addfinalizer(teardown_func_or_method) + + def _prunetraceback(self, excinfo): + if hasattr(self, '_obj') and not self.config.option.fulltrace: + code = _pytest._code.Code(get_real_func(self.obj)) + path, firstlineno = code.path, code.firstlineno + traceback = excinfo.traceback + ntraceback = traceback.cut(path=path, firstlineno=firstlineno) + if ntraceback == traceback: + ntraceback = ntraceback.cut(path=path) + if ntraceback == traceback: + # ntraceback = ntraceback.cut(excludepath=cutdir2) + ntraceback = ntraceback.filter(filter_traceback) + if not ntraceback: + ntraceback = traceback + + excinfo.traceback = ntraceback.filter() + # issue364: mark all but first and last frames to + # only show a single-line message for each frame + if self.config.option.tbstyle == "auto": + if len(excinfo.traceback) > 2: + for entry in excinfo.traceback[1:-1]: + entry.set_repr_style('short') + + def _repr_failure_py(self, excinfo, style="long"): + if excinfo.errisinstance(fail.Exception): + if not excinfo.value.pytrace: + return py._builtin._totext(excinfo.value) + return super(FunctionMixin, self)._repr_failure_py(excinfo, + style=style) + + def repr_failure(self, excinfo, outerr=None): + assert outerr is None, "XXX outerr usage is deprecated" + style = self.config.option.tbstyle + if style == "auto": + style = "long" + return self._repr_failure_py(excinfo, style=style) + + +class Generator(FunctionMixin, PyCollector): + def collect(self): + # test generators are seen as collectors but they also + # invoke setup/teardown on popular request + # (induced by the common "test_*" naming shared with normal tests) + from _pytest import deprecated + self.session._setupstate.prepare(self) + # see FunctionMixin.setup and test_setupstate_is_preserved_134 + self._preservedparent = self.parent.obj + values = [] + seen = {} + for i, x in enumerate(self.obj()): + name, call, args = self.getcallargs(x) + if not callable(call): + raise TypeError("%r yielded non callable test %r" % (self.obj, call,)) + if name is None: + name = "[%d]" % i + else: + name = "['%s']" % name + if name in seen: + raise ValueError("%r generated tests with non-unique name %r" % (self, name)) + seen[name] = True + values.append(self.Function(name, self, args=args, callobj=call)) + self.warn('C1', deprecated.YIELD_TESTS) + return values + + def getcallargs(self, obj): + if not isinstance(obj, (tuple, list)): + obj = (obj,) + # explicit naming + if isinstance(obj[0], six.string_types): + name = obj[0] + obj = obj[1:] + else: + name = None + call, args = obj[0], obj[1:] + return name, call, args + + +def hasinit(obj): + init = getattr(obj, '__init__', None) + if init: + return init != object.__init__ + + +def hasnew(obj): + new = getattr(obj, '__new__', None) + if new: + return new != object.__new__ + + +class CallSpec2(object): + def __init__(self, metafunc): + self.metafunc = metafunc + self.funcargs = {} + self._idlist = [] + self.params = {} + self._globalid = NOTSET + self._globalid_args = set() + self._globalparam = NOTSET + self._arg2scopenum = {} # used for sorting parametrized resources + self.marks = [] + self.indices = {} + + def copy(self, metafunc): + cs = CallSpec2(self.metafunc) + cs.funcargs.update(self.funcargs) + cs.params.update(self.params) + cs.marks.extend(self.marks) + cs.indices.update(self.indices) + cs._arg2scopenum.update(self._arg2scopenum) + cs._idlist = list(self._idlist) + cs._globalid = self._globalid + cs._globalid_args = self._globalid_args + cs._globalparam = self._globalparam + return cs + + def _checkargnotcontained(self, arg): + if arg in self.params or arg in self.funcargs: + raise ValueError("duplicate %r" % (arg,)) + + def getparam(self, name): + try: + return self.params[name] + except KeyError: + if self._globalparam is NOTSET: + raise ValueError(name) + return self._globalparam + + @property + def id(self): + return "-".join(map(str, filter(None, self._idlist))) + + def setmulti2(self, valtypes, argnames, valset, id, marks, scopenum, + param_index): + for arg, val in zip(argnames, valset): + self._checkargnotcontained(arg) + valtype_for_arg = valtypes[arg] + getattr(self, valtype_for_arg)[arg] = val + self.indices[arg] = param_index + self._arg2scopenum[arg] = scopenum + self._idlist.append(id) + self.marks.extend(marks) + + def setall(self, funcargs, id, param): + for x in funcargs: + self._checkargnotcontained(x) + self.funcargs.update(funcargs) + if id is not NOTSET: + self._idlist.append(id) + if param is not NOTSET: + assert self._globalparam is NOTSET + self._globalparam = param + for arg in funcargs: + self._arg2scopenum[arg] = fixtures.scopenum_function + + +class Metafunc(fixtures.FuncargnamesCompatAttr): + """ + Metafunc objects are passed to the ``pytest_generate_tests`` hook. + They help to inspect a test function and to generate tests according to + test configuration or values specified in the class or module where a + test function is defined. + """ + + def __init__(self, function, fixtureinfo, config, cls=None, module=None): + #: access to the :class:`_pytest.config.Config` object for the test session + self.config = config + + #: the module object where the test function is defined in. + self.module = module + + #: underlying python test function + self.function = function + + #: set of fixture names required by the test function + self.fixturenames = fixtureinfo.names_closure + + #: class object where the test function is defined in or ``None``. + self.cls = cls + + self._calls = [] + self._ids = set() + self._arg2fixturedefs = fixtureinfo.name2fixturedefs + + def parametrize(self, argnames, argvalues, indirect=False, ids=None, + scope=None): + """ Add new invocations to the underlying test function using the list + of argvalues for the given argnames. Parametrization is performed + during the collection phase. If you need to setup expensive resources + see about setting indirect to do it rather at test setup time. + + :arg argnames: a comma-separated string denoting one or more argument + names, or a list/tuple of argument strings. + + :arg argvalues: The list of argvalues determines how often a + test is invoked with different argument values. If only one + argname was specified argvalues is a list of values. If N + argnames were specified, argvalues must be a list of N-tuples, + where each tuple-element specifies a value for its respective + argname. + + :arg indirect: The list of argnames or boolean. A list of arguments' + names (subset of argnames). If True the list contains all names from + the argnames. Each argvalue corresponding to an argname in this list will + be passed as request.param to its respective argname fixture + function so that it can perform more expensive setups during the + setup phase of a test rather than at collection time. + + :arg ids: list of string ids, or a callable. + If strings, each is corresponding to the argvalues so that they are + part of the test id. If None is given as id of specific test, the + automatically generated id for that argument will be used. + If callable, it should take one argument (a single argvalue) and return + a string or return None. If None, the automatically generated id for that + argument will be used. + If no ids are provided they will be generated automatically from + the argvalues. + + :arg scope: if specified it denotes the scope of the parameters. + The scope is used for grouping tests by parameter instances. + It will also override any fixture-function defined scope, allowing + to set a dynamic scope using test context or configuration. + """ + from _pytest.fixtures import scope2index + from _pytest.mark import ParameterSet + from py.io import saferepr + argnames, parameters = ParameterSet._for_parameterize( + argnames, argvalues, self.function) + del argvalues + + if scope is None: + scope = _find_parametrized_scope(argnames, self._arg2fixturedefs, indirect) + + scopenum = scope2index(scope, descr='call to {0}'.format(self.parametrize)) + valtypes = {} + for arg in argnames: + if arg not in self.fixturenames: + if isinstance(indirect, (tuple, list)): + name = 'fixture' if arg in indirect else 'argument' + else: + name = 'fixture' if indirect else 'argument' + raise ValueError( + "%r uses no %s %r" % ( + self.function, name, arg)) + + if indirect is True: + valtypes = dict.fromkeys(argnames, "params") + elif indirect is False: + valtypes = dict.fromkeys(argnames, "funcargs") + elif isinstance(indirect, (tuple, list)): + valtypes = dict.fromkeys(argnames, "funcargs") + for arg in indirect: + if arg not in argnames: + raise ValueError("indirect given to %r: fixture %r doesn't exist" % ( + self.function, arg)) + valtypes[arg] = "params" + idfn = None + if callable(ids): + idfn = ids + ids = None + if ids: + if len(ids) != len(parameters): + raise ValueError('%d tests specified with %d ids' % ( + len(parameters), len(ids))) + for id_value in ids: + if id_value is not None and not isinstance(id_value, six.string_types): + msg = 'ids must be list of strings, found: %s (type: %s)' + raise ValueError(msg % (saferepr(id_value), type(id_value).__name__)) + ids = idmaker(argnames, parameters, idfn, ids, self.config) + newcalls = [] + for callspec in self._calls or [CallSpec2(self)]: + elements = zip(ids, parameters, count()) + for a_id, param, param_index in elements: + if len(param.values) != len(argnames): + raise ValueError( + 'In "parametrize" the number of values ({0}) must be ' + 'equal to the number of names ({1})'.format( + param.values, argnames)) + newcallspec = callspec.copy(self) + newcallspec.setmulti2(valtypes, argnames, param.values, a_id, + param.marks, scopenum, param_index) + newcalls.append(newcallspec) + self._calls = newcalls + + def addcall(self, funcargs=None, id=NOTSET, param=NOTSET): + """ Add a new call to the underlying test function during the collection phase of a test run. + + .. deprecated:: 3.3 + + Use :meth:`parametrize` instead. + + Note that request.addcall() is called during the test collection phase prior and + independently to actual test execution. You should only use addcall() + if you need to specify multiple arguments of a test function. + + :arg funcargs: argument keyword dictionary used when invoking + the test function. + + :arg id: used for reporting and identification purposes. If you + don't supply an `id` an automatic unique id will be generated. + + :arg param: a parameter which will be exposed to a later fixture function + invocation through the ``request.param`` attribute. + """ + if self.config: + self.config.warn('C1', message=deprecated.METAFUNC_ADD_CALL, fslocation=None) + assert funcargs is None or isinstance(funcargs, dict) + if funcargs is not None: + for name in funcargs: + if name not in self.fixturenames: + fail("funcarg %r not used in this function." % name) + else: + funcargs = {} + if id is None: + raise ValueError("id=None not allowed") + if id is NOTSET: + id = len(self._calls) + id = str(id) + if id in self._ids: + raise ValueError("duplicate id %r" % id) + self._ids.add(id) + + cs = CallSpec2(self) + cs.setall(funcargs, id, param) + self._calls.append(cs) + + +def _find_parametrized_scope(argnames, arg2fixturedefs, indirect): + """Find the most appropriate scope for a parametrized call based on its arguments. + + When there's at least one direct argument, always use "function" scope. + + When a test function is parametrized and all its arguments are indirect + (e.g. fixtures), return the most narrow scope based on the fixtures used. + + Related to issue #1832, based on code posted by @Kingdread. + """ + from _pytest.fixtures import scopes + indirect_as_list = isinstance(indirect, (list, tuple)) + all_arguments_are_fixtures = indirect is True or \ + indirect_as_list and len(indirect) == argnames + if all_arguments_are_fixtures: + fixturedefs = arg2fixturedefs or {} + used_scopes = [fixturedef[0].scope for name, fixturedef in fixturedefs.items()] + if used_scopes: + # Takes the most narrow scope from used fixtures + for scope in reversed(scopes): + if scope in used_scopes: + return scope + + return 'function' + + +def _idval(val, argname, idx, idfn, config=None): + if idfn: + s = None + try: + s = idfn(val) + except Exception: + # See issue https://github.com/pytest-dev/pytest/issues/2169 + import warnings + msg = "Raised while trying to determine id of parameter %s at position %d." % (argname, idx) + msg += '\nUpdate your code as this will raise an error in pytest-4.0.' + warnings.warn(msg, DeprecationWarning) + if s: + return ascii_escaped(s) + + if config: + hook_id = config.hook.pytest_make_parametrize_id( + config=config, val=val, argname=argname) + if hook_id: + return hook_id + + if isinstance(val, STRING_TYPES): + return ascii_escaped(val) + elif isinstance(val, (float, int, bool, NoneType)): + return str(val) + elif isinstance(val, REGEX_TYPE): + return ascii_escaped(val.pattern) + elif enum is not None and isinstance(val, enum.Enum): + return str(val) + elif isclass(val) and hasattr(val, '__name__'): + return val.__name__ + return str(argname) + str(idx) + + +def _idvalset(idx, parameterset, argnames, idfn, ids, config=None): + if parameterset.id is not None: + return parameterset.id + if ids is None or (idx >= len(ids) or ids[idx] is None): + this_id = [_idval(val, argname, idx, idfn, config) + for val, argname in zip(parameterset.values, argnames)] + return "-".join(this_id) + else: + return ascii_escaped(ids[idx]) + + +def idmaker(argnames, parametersets, idfn=None, ids=None, config=None): + ids = [_idvalset(valindex, parameterset, argnames, idfn, ids, config) + for valindex, parameterset in enumerate(parametersets)] + if len(set(ids)) != len(ids): + # The ids are not unique + duplicates = [testid for testid in ids if ids.count(testid) > 1] + counters = collections.defaultdict(lambda: 0) + for index, testid in enumerate(ids): + if testid in duplicates: + ids[index] = testid + str(counters[testid]) + counters[testid] += 1 + return ids + + +def show_fixtures_per_test(config): + from _pytest.main import wrap_session + return wrap_session(config, _show_fixtures_per_test) + + +def _show_fixtures_per_test(config, session): + import _pytest.config + session.perform_collect() + curdir = py.path.local() + tw = _pytest.config.create_terminal_writer(config) + verbose = config.getvalue("verbose") + + def get_best_relpath(func): + loc = getlocation(func, curdir) + return curdir.bestrelpath(loc) + + def write_fixture(fixture_def): + argname = fixture_def.argname + if verbose <= 0 and argname.startswith("_"): + return + if verbose > 0: + bestrel = get_best_relpath(fixture_def.func) + funcargspec = "{0} -- {1}".format(argname, bestrel) + else: + funcargspec = argname + tw.line(funcargspec, green=True) + fixture_doc = fixture_def.func.__doc__ + if fixture_doc: + write_docstring(tw, fixture_doc) + else: + tw.line(' no docstring available', red=True) + + def write_item(item): + try: + info = item._fixtureinfo + except AttributeError: + # doctests items have no _fixtureinfo attribute + return + if not info.name2fixturedefs: + # this test item does not use any fixtures + return + tw.line() + tw.sep('-', 'fixtures used by {0}'.format(item.name)) + tw.sep('-', '({0})'.format(get_best_relpath(item.function))) + # dict key not used in loop but needed for sorting + for _, fixturedefs in sorted(info.name2fixturedefs.items()): + assert fixturedefs is not None + if not fixturedefs: + continue + # last item is expected to be the one used by the test item + write_fixture(fixturedefs[-1]) + + for session_item in session.items: + write_item(session_item) + + +def showfixtures(config): + from _pytest.main import wrap_session + return wrap_session(config, _showfixtures_main) + + +def _showfixtures_main(config, session): + import _pytest.config + session.perform_collect() + curdir = py.path.local() + tw = _pytest.config.create_terminal_writer(config) + verbose = config.getvalue("verbose") + + fm = session._fixturemanager + + available = [] + seen = set() + + for argname, fixturedefs in fm._arg2fixturedefs.items(): + assert fixturedefs is not None + if not fixturedefs: + continue + for fixturedef in fixturedefs: + loc = getlocation(fixturedef.func, curdir) + if (fixturedef.argname, loc) in seen: + continue + seen.add((fixturedef.argname, loc)) + available.append((len(fixturedef.baseid), + fixturedef.func.__module__, + curdir.bestrelpath(loc), + fixturedef.argname, fixturedef)) + + available.sort() + currentmodule = None + for baseid, module, bestrel, argname, fixturedef in available: + if currentmodule != module: + if not module.startswith("_pytest."): + tw.line() + tw.sep("-", "fixtures defined from %s" % (module,)) + currentmodule = module + if verbose <= 0 and argname[0] == "_": + continue + if verbose > 0: + funcargspec = "%s -- %s" % (argname, bestrel,) + else: + funcargspec = argname + tw.line(funcargspec, green=True) + loc = getlocation(fixturedef.func, curdir) + doc = fixturedef.func.__doc__ or "" + if doc: + write_docstring(tw, doc) + else: + tw.line(" %s: no docstring available" % (loc,), + red=True) + + +def write_docstring(tw, doc): + INDENT = " " + doc = doc.rstrip() + if "\n" in doc: + firstline, rest = doc.split("\n", 1) + else: + firstline, rest = doc, "" + + if firstline.strip(): + tw.line(INDENT + firstline.strip()) + + if rest: + for line in dedent(rest).split("\n"): + tw.write(INDENT + line + "\n") + + +class Function(FunctionMixin, main.Item, fixtures.FuncargnamesCompatAttr): + """ a Function Item is responsible for setting up and executing a + Python test function. + """ + _genid = None + + def __init__(self, name, parent, args=None, config=None, + callspec=None, callobj=NOTSET, keywords=None, session=None, + fixtureinfo=None, originalname=None): + super(Function, self).__init__(name, parent, config=config, + session=session) + self._args = args + if callobj is not NOTSET: + self.obj = callobj + + self.keywords.update(self.obj.__dict__) + if callspec: + self.callspec = callspec + # this is total hostile and a mess + # keywords are broken by design by now + # this will be redeemed later + for mark in callspec.marks: + # feel free to cry, this was broken for years before + # and keywords cant fix it per design + self.keywords[mark.name] = mark + if keywords: + self.keywords.update(keywords) + + if fixtureinfo is None: + fixtureinfo = self.session._fixturemanager.getfixtureinfo( + self.parent, self.obj, self.cls, + funcargs=not self._isyieldedfunction()) + self._fixtureinfo = fixtureinfo + self.fixturenames = fixtureinfo.names_closure + self._initrequest() + + #: original function name, without any decorations (for example + #: parametrization adds a ``"[...]"`` suffix to function names). + #: + #: .. versionadded:: 3.0 + self.originalname = originalname + + def _initrequest(self): + self.funcargs = {} + if self._isyieldedfunction(): + assert not hasattr(self, "callspec"), ( + "yielded functions (deprecated) cannot have funcargs") + else: + if hasattr(self, "callspec"): + callspec = self.callspec + assert not callspec.funcargs + self._genid = callspec.id + if hasattr(callspec, "param"): + self.param = callspec.param + self._request = fixtures.FixtureRequest(self) + + @property + def function(self): + "underlying python 'function' object" + return getattr(self.obj, 'im_func', self.obj) + + def _getobj(self): + name = self.name + i = name.find("[") # parametrization + if i != -1: + name = name[:i] + return getattr(self.parent.obj, name) + + @property + def _pyfuncitem(self): + "(compatonly) for code expecting pytest-2.2 style request objects" + return self + + def _isyieldedfunction(self): + return getattr(self, "_args", None) is not None + + def runtest(self): + """ execute the underlying test function. """ + self.ihook.pytest_pyfunc_call(pyfuncitem=self) + + def setup(self): + super(Function, self).setup() + fixtures.fillfixtures(self) diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/python_api.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/python_api.py new file mode 100644 index 00000000000..81960295b38 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/python_api.py @@ -0,0 +1,619 @@ +import math +import sys + +import py +from six.moves import zip + +from _pytest.compat import isclass +from _pytest.outcomes import fail +import _pytest._code + + +def _cmp_raises_type_error(self, other): + """__cmp__ implementation which raises TypeError. Used + by Approx base classes to implement only == and != and raise a + TypeError for other comparisons. + + Needed in Python 2 only, Python 3 all it takes is not implementing the + other operators at all. + """ + __tracebackhide__ = True + raise TypeError('Comparison operators other than == and != not supported by approx objects') + + +# builtin pytest.approx helper + + +class ApproxBase(object): + """ + Provide shared utilities for making approximate comparisons between numbers + or sequences of numbers. + """ + + def __init__(self, expected, rel=None, abs=None, nan_ok=False): + self.expected = expected + self.abs = abs + self.rel = rel + self.nan_ok = nan_ok + + def __repr__(self): + raise NotImplementedError + + def __eq__(self, actual): + return all( + a == self._approx_scalar(x) + for a, x in self._yield_comparisons(actual)) + + __hash__ = None + + def __ne__(self, actual): + return not (actual == self) + + if sys.version_info[0] == 2: + __cmp__ = _cmp_raises_type_error + + def _approx_scalar(self, x): + return ApproxScalar(x, rel=self.rel, abs=self.abs, nan_ok=self.nan_ok) + + def _yield_comparisons(self, actual): + """ + Yield all the pairs of numbers to be compared. This is used to + implement the `__eq__` method. + """ + raise NotImplementedError + + +class ApproxNumpy(ApproxBase): + """ + Perform approximate comparisons for numpy arrays. + """ + + # Tell numpy to use our `__eq__` operator instead of its. + __array_priority__ = 100 + + def __repr__(self): + # It might be nice to rewrite this function to account for the + # shape of the array... + return "approx({0!r})".format(list( + self._approx_scalar(x) for x in self.expected)) + + if sys.version_info[0] == 2: + __cmp__ = _cmp_raises_type_error + + def __eq__(self, actual): + import numpy as np + + try: + actual = np.asarray(actual) + except: # noqa + raise TypeError("cannot compare '{0}' to numpy.ndarray".format(actual)) + + if actual.shape != self.expected.shape: + return False + + return ApproxBase.__eq__(self, actual) + + def _yield_comparisons(self, actual): + import numpy as np + + # We can be sure that `actual` is a numpy array, because it's + # casted in `__eq__` before being passed to `ApproxBase.__eq__`, + # which is the only method that calls this one. + for i in np.ndindex(self.expected.shape): + yield actual[i], self.expected[i] + + +class ApproxMapping(ApproxBase): + """ + Perform approximate comparisons for mappings where the values are numbers + (the keys can be anything). + """ + + def __repr__(self): + return "approx({0!r})".format(dict( + (k, self._approx_scalar(v)) + for k, v in self.expected.items())) + + def __eq__(self, actual): + if set(actual.keys()) != set(self.expected.keys()): + return False + + return ApproxBase.__eq__(self, actual) + + def _yield_comparisons(self, actual): + for k in self.expected.keys(): + yield actual[k], self.expected[k] + + +class ApproxSequence(ApproxBase): + """ + Perform approximate comparisons for sequences of numbers. + """ + + # Tell numpy to use our `__eq__` operator instead of its. + __array_priority__ = 100 + + def __repr__(self): + seq_type = type(self.expected) + if seq_type not in (tuple, list, set): + seq_type = list + return "approx({0!r})".format(seq_type( + self._approx_scalar(x) for x in self.expected)) + + def __eq__(self, actual): + if len(actual) != len(self.expected): + return False + return ApproxBase.__eq__(self, actual) + + def _yield_comparisons(self, actual): + return zip(actual, self.expected) + + +class ApproxScalar(ApproxBase): + """ + Perform approximate comparisons for single numbers only. + """ + + def __repr__(self): + """ + Return a string communicating both the expected value and the tolerance + for the comparison being made, e.g. '1.0 +- 1e-6'. Use the unicode + plus/minus symbol if this is python3 (it's too hard to get right for + python2). + """ + if isinstance(self.expected, complex): + return str(self.expected) + + # Infinities aren't compared using tolerances, so don't show a + # tolerance. + if math.isinf(self.expected): + return str(self.expected) + + # If a sensible tolerance can't be calculated, self.tolerance will + # raise a ValueError. In this case, display '???'. + try: + vetted_tolerance = '{:.1e}'.format(self.tolerance) + except ValueError: + vetted_tolerance = '???' + + if sys.version_info[0] == 2: + return '{0} +- {1}'.format(self.expected, vetted_tolerance) + else: + return u'{0} \u00b1 {1}'.format(self.expected, vetted_tolerance) + + def __eq__(self, actual): + """ + Return true if the given value is equal to the expected value within + the pre-specified tolerance. + """ + + # Short-circuit exact equality. + if actual == self.expected: + return True + + # Allow the user to control whether NaNs are considered equal to each + # other or not. The abs() calls are for compatibility with complex + # numbers. + if math.isnan(abs(self.expected)): + return self.nan_ok and math.isnan(abs(actual)) + + # Infinity shouldn't be approximately equal to anything but itself, but + # if there's a relative tolerance, it will be infinite and infinity + # will seem approximately equal to everything. The equal-to-itself + # case would have been short circuited above, so here we can just + # return false if the expected value is infinite. The abs() call is + # for compatibility with complex numbers. + if math.isinf(abs(self.expected)): + return False + + # Return true if the two numbers are within the tolerance. + return abs(self.expected - actual) <= self.tolerance + + __hash__ = None + + @property + def tolerance(self): + """ + Return the tolerance for the comparison. This could be either an + absolute tolerance or a relative tolerance, depending on what the user + specified or which would be larger. + """ + def set_default(x, default): + return x if x is not None else default + + # Figure out what the absolute tolerance should be. ``self.abs`` is + # either None or a value specified by the user. + absolute_tolerance = set_default(self.abs, 1e-12) + + if absolute_tolerance < 0: + raise ValueError("absolute tolerance can't be negative: {}".format(absolute_tolerance)) + if math.isnan(absolute_tolerance): + raise ValueError("absolute tolerance can't be NaN.") + + # If the user specified an absolute tolerance but not a relative one, + # just return the absolute tolerance. + if self.rel is None: + if self.abs is not None: + return absolute_tolerance + + # Figure out what the relative tolerance should be. ``self.rel`` is + # either None or a value specified by the user. This is done after + # we've made sure the user didn't ask for an absolute tolerance only, + # because we don't want to raise errors about the relative tolerance if + # we aren't even going to use it. + relative_tolerance = set_default(self.rel, 1e-6) * abs(self.expected) + + if relative_tolerance < 0: + raise ValueError("relative tolerance can't be negative: {}".format(absolute_tolerance)) + if math.isnan(relative_tolerance): + raise ValueError("relative tolerance can't be NaN.") + + # Return the larger of the relative and absolute tolerances. + return max(relative_tolerance, absolute_tolerance) + + +def approx(expected, rel=None, abs=None, nan_ok=False): + """ + Assert that two numbers (or two sets of numbers) are equal to each other + within some tolerance. + + Due to the `intricacies of floating-point arithmetic`__, numbers that we + would intuitively expect to be equal are not always so:: + + >>> 0.1 + 0.2 == 0.3 + False + + __ https://docs.python.org/3/tutorial/floatingpoint.html + + This problem is commonly encountered when writing tests, e.g. when making + sure that floating-point values are what you expect them to be. One way to + deal with this problem is to assert that two floating-point numbers are + equal to within some appropriate tolerance:: + + >>> abs((0.1 + 0.2) - 0.3) < 1e-6 + True + + However, comparisons like this are tedious to write and difficult to + understand. Furthermore, absolute comparisons like the one above are + usually discouraged because there's no tolerance that works well for all + situations. ``1e-6`` is good for numbers around ``1``, but too small for + very big numbers and too big for very small ones. It's better to express + the tolerance as a fraction of the expected value, but relative comparisons + like that are even more difficult to write correctly and concisely. + + The ``approx`` class performs floating-point comparisons using a syntax + that's as intuitive as possible:: + + >>> from pytest import approx + >>> 0.1 + 0.2 == approx(0.3) + True + + The same syntax also works for sequences of numbers:: + + >>> (0.1 + 0.2, 0.2 + 0.4) == approx((0.3, 0.6)) + True + + Dictionary *values*:: + + >>> {'a': 0.1 + 0.2, 'b': 0.2 + 0.4} == approx({'a': 0.3, 'b': 0.6}) + True + + And ``numpy`` arrays:: + + >>> import numpy as np # doctest: +SKIP + >>> np.array([0.1, 0.2]) + np.array([0.2, 0.4]) == approx(np.array([0.3, 0.6])) # doctest: +SKIP + True + + By default, ``approx`` considers numbers within a relative tolerance of + ``1e-6`` (i.e. one part in a million) of its expected value to be equal. + This treatment would lead to surprising results if the expected value was + ``0.0``, because nothing but ``0.0`` itself is relatively close to ``0.0``. + To handle this case less surprisingly, ``approx`` also considers numbers + within an absolute tolerance of ``1e-12`` of its expected value to be + equal. Infinity and NaN are special cases. Infinity is only considered + equal to itself, regardless of the relative tolerance. NaN is not + considered equal to anything by default, but you can make it be equal to + itself by setting the ``nan_ok`` argument to True. (This is meant to + facilitate comparing arrays that use NaN to mean "no data".) + + Both the relative and absolute tolerances can be changed by passing + arguments to the ``approx`` constructor:: + + >>> 1.0001 == approx(1) + False + >>> 1.0001 == approx(1, rel=1e-3) + True + >>> 1.0001 == approx(1, abs=1e-3) + True + + If you specify ``abs`` but not ``rel``, the comparison will not consider + the relative tolerance at all. In other words, two numbers that are within + the default relative tolerance of ``1e-6`` will still be considered unequal + if they exceed the specified absolute tolerance. If you specify both + ``abs`` and ``rel``, the numbers will be considered equal if either + tolerance is met:: + + >>> 1 + 1e-8 == approx(1) + True + >>> 1 + 1e-8 == approx(1, abs=1e-12) + False + >>> 1 + 1e-8 == approx(1, rel=1e-6, abs=1e-12) + True + + If you're thinking about using ``approx``, then you might want to know how + it compares to other good ways of comparing floating-point numbers. All of + these algorithms are based on relative and absolute tolerances and should + agree for the most part, but they do have meaningful differences: + + - ``math.isclose(a, b, rel_tol=1e-9, abs_tol=0.0)``: True if the relative + tolerance is met w.r.t. either ``a`` or ``b`` or if the absolute + tolerance is met. Because the relative tolerance is calculated w.r.t. + both ``a`` and ``b``, this test is symmetric (i.e. neither ``a`` nor + ``b`` is a "reference value"). You have to specify an absolute tolerance + if you want to compare to ``0.0`` because there is no tolerance by + default. Only available in python>=3.5. `More information...`__ + + __ https://docs.python.org/3/library/math.html#math.isclose + + - ``numpy.isclose(a, b, rtol=1e-5, atol=1e-8)``: True if the difference + between ``a`` and ``b`` is less that the sum of the relative tolerance + w.r.t. ``b`` and the absolute tolerance. Because the relative tolerance + is only calculated w.r.t. ``b``, this test is asymmetric and you can + think of ``b`` as the reference value. Support for comparing sequences + is provided by ``numpy.allclose``. `More information...`__ + + __ http://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.isclose.html + + - ``unittest.TestCase.assertAlmostEqual(a, b)``: True if ``a`` and ``b`` + are within an absolute tolerance of ``1e-7``. No relative tolerance is + considered and the absolute tolerance cannot be changed, so this function + is not appropriate for very large or very small numbers. Also, it's only + available in subclasses of ``unittest.TestCase`` and it's ugly because it + doesn't follow PEP8. `More information...`__ + + __ https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertAlmostEqual + + - ``a == pytest.approx(b, rel=1e-6, abs=1e-12)``: True if the relative + tolerance is met w.r.t. ``b`` or if the absolute tolerance is met. + Because the relative tolerance is only calculated w.r.t. ``b``, this test + is asymmetric and you can think of ``b`` as the reference value. In the + special case that you explicitly specify an absolute tolerance but not a + relative tolerance, only the absolute tolerance is considered. + + .. warning:: + + .. versionchanged:: 3.2 + + In order to avoid inconsistent behavior, ``TypeError`` is + raised for ``>``, ``>=``, ``<`` and ``<=`` comparisons. + The example below illustrates the problem:: + + assert approx(0.1) > 0.1 + 1e-10 # calls approx(0.1).__gt__(0.1 + 1e-10) + assert 0.1 + 1e-10 > approx(0.1) # calls approx(0.1).__lt__(0.1 + 1e-10) + + In the second example one expects ``approx(0.1).__le__(0.1 + 1e-10)`` + to be called. But instead, ``approx(0.1).__lt__(0.1 + 1e-10)`` is used to + comparison. This is because the call hierarchy of rich comparisons + follows a fixed behavior. `More information...`__ + + __ https://docs.python.org/3/reference/datamodel.html#object.__ge__ + """ + + from collections import Mapping, Sequence + from _pytest.compat import STRING_TYPES as String + + # Delegate the comparison to a class that knows how to deal with the type + # of the expected value (e.g. int, float, list, dict, numpy.array, etc). + # + # This architecture is really driven by the need to support numpy arrays. + # The only way to override `==` for arrays without requiring that approx be + # the left operand is to inherit the approx object from `numpy.ndarray`. + # But that can't be a general solution, because it requires (1) numpy to be + # installed and (2) the expected value to be a numpy array. So the general + # solution is to delegate each type of expected value to a different class. + # + # This has the advantage that it made it easy to support mapping types + # (i.e. dict). The old code accepted mapping types, but would only compare + # their keys, which is probably not what most people would expect. + + if _is_numpy_array(expected): + cls = ApproxNumpy + elif isinstance(expected, Mapping): + cls = ApproxMapping + elif isinstance(expected, Sequence) and not isinstance(expected, String): + cls = ApproxSequence + else: + cls = ApproxScalar + + return cls(expected, rel, abs, nan_ok) + + +def _is_numpy_array(obj): + """ + Return true if the given object is a numpy array. Make a special effort to + avoid importing numpy unless it's really necessary. + """ + import inspect + + for cls in inspect.getmro(type(obj)): + if cls.__module__ == 'numpy': + try: + import numpy as np + return isinstance(obj, np.ndarray) + except ImportError: + pass + + return False + + +# builtin pytest.raises helper + +def raises(expected_exception, *args, **kwargs): + """ + Assert that a code block/function call raises ``expected_exception`` + and raise a failure exception otherwise. + + This helper produces a ``ExceptionInfo()`` object (see below). + + You may use this function as a context manager:: + + >>> with raises(ZeroDivisionError): + ... 1/0 + + .. versionchanged:: 2.10 + + In the context manager form you may use the keyword argument + ``message`` to specify a custom failure message:: + + >>> with raises(ZeroDivisionError, message="Expecting ZeroDivisionError"): + ... pass + Traceback (most recent call last): + ... + Failed: Expecting ZeroDivisionError + + .. note:: + + When using ``pytest.raises`` as a context manager, it's worthwhile to + note that normal context manager rules apply and that the exception + raised *must* be the final line in the scope of the context manager. + Lines of code after that, within the scope of the context manager will + not be executed. For example:: + + >>> value = 15 + >>> with raises(ValueError) as exc_info: + ... if value > 10: + ... raise ValueError("value must be <= 10") + ... assert exc_info.type == ValueError # this will not execute + + Instead, the following approach must be taken (note the difference in + scope):: + + >>> with raises(ValueError) as exc_info: + ... if value > 10: + ... raise ValueError("value must be <= 10") + ... + >>> assert exc_info.type == ValueError + + + Since version ``3.1`` you can use the keyword argument ``match`` to assert that the + exception matches a text or regex:: + + >>> with raises(ValueError, match='must be 0 or None'): + ... raise ValueError("value must be 0 or None") + + >>> with raises(ValueError, match=r'must be \d+$'): + ... raise ValueError("value must be 42") + + **Legacy forms** + + The forms below are fully supported but are discouraged for new code because the + context manager form is regarded as more readable and less error-prone. + + It is possible to specify a callable by passing a to-be-called lambda:: + + >>> raises(ZeroDivisionError, lambda: 1/0) + + + or you can specify an arbitrary callable with arguments:: + + >>> def f(x): return 1/x + ... + >>> raises(ZeroDivisionError, f, 0) + + >>> raises(ZeroDivisionError, f, x=0) + + + It is also possible to pass a string to be evaluated at runtime:: + + >>> raises(ZeroDivisionError, "f(0)") + + + The string will be evaluated using the same ``locals()`` and ``globals()`` + at the moment of the ``raises`` call. + + .. autoclass:: _pytest._code.ExceptionInfo + :members: + + .. note:: + Similar to caught exception objects in Python, explicitly clearing + local references to returned ``ExceptionInfo`` objects can + help the Python interpreter speed up its garbage collection. + + Clearing those references breaks a reference cycle + (``ExceptionInfo`` --> caught exception --> frame stack raising + the exception --> current frame stack --> local variables --> + ``ExceptionInfo``) which makes Python keep all objects referenced + from that cycle (including all local variables in the current + frame) alive until the next cyclic garbage collection run. See the + official Python ``try`` statement documentation for more detailed + information. + + """ + __tracebackhide__ = True + msg = ("exceptions must be old-style classes or" + " derived from BaseException, not %s") + if isinstance(expected_exception, tuple): + for exc in expected_exception: + if not isclass(exc): + raise TypeError(msg % type(exc)) + elif not isclass(expected_exception): + raise TypeError(msg % type(expected_exception)) + + message = "DID NOT RAISE {0}".format(expected_exception) + match_expr = None + + if not args: + if "message" in kwargs: + message = kwargs.pop("message") + if "match" in kwargs: + match_expr = kwargs.pop("match") + message += " matching '{0}'".format(match_expr) + return RaisesContext(expected_exception, message, match_expr) + elif isinstance(args[0], str): + code, = args + assert isinstance(code, str) + frame = sys._getframe(1) + loc = frame.f_locals.copy() + loc.update(kwargs) + # print "raises frame scope: %r" % frame.f_locals + try: + code = _pytest._code.Source(code).compile() + py.builtin.exec_(code, frame.f_globals, loc) + # XXX didn'T mean f_globals == f_locals something special? + # this is destroyed here ... + except expected_exception: + return _pytest._code.ExceptionInfo() + else: + func = args[0] + try: + func(*args[1:], **kwargs) + except expected_exception: + return _pytest._code.ExceptionInfo() + fail(message) + + +raises.Exception = fail.Exception + + +class RaisesContext(object): + def __init__(self, expected_exception, message, match_expr): + self.expected_exception = expected_exception + self.message = message + self.match_expr = match_expr + self.excinfo = None + + def __enter__(self): + self.excinfo = object.__new__(_pytest._code.ExceptionInfo) + return self.excinfo + + def __exit__(self, *tp): + __tracebackhide__ = True + if tp[0] is None: + fail(self.message) + self.excinfo.__init__(tp) + suppress_exception = issubclass(self.excinfo.type, self.expected_exception) + if sys.version_info[0] == 2 and suppress_exception: + sys.exc_clear() + if self.match_expr: + self.excinfo.match(self.match_expr) + return suppress_exception diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/recwarn.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/recwarn.py new file mode 100644 index 00000000000..4fceb10a7f3 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/recwarn.py @@ -0,0 +1,236 @@ +""" recording warnings during test function execution. """ +from __future__ import absolute_import, division, print_function + +import inspect + +import _pytest._code +import py +import sys +import warnings + +import re + +from _pytest.fixtures import yield_fixture +from _pytest.outcomes import fail + + +@yield_fixture +def recwarn(): + """Return a WarningsRecorder instance that provides these methods: + + * ``pop(category=None)``: return last warning matching the category. + * ``clear()``: clear list of warnings + + See http://docs.python.org/library/warnings.html for information + on warning categories. + """ + wrec = WarningsRecorder() + with wrec: + warnings.simplefilter('default') + yield wrec + + +def deprecated_call(func=None, *args, **kwargs): + """context manager that can be used to ensure a block of code triggers a + ``DeprecationWarning`` or ``PendingDeprecationWarning``:: + + >>> import warnings + >>> def api_call_v2(): + ... warnings.warn('use v3 of this api', DeprecationWarning) + ... return 200 + + >>> with deprecated_call(): + ... assert api_call_v2() == 200 + + ``deprecated_call`` can also be used by passing a function and ``*args`` and ``*kwargs``, + in which case it will ensure calling ``func(*args, **kwargs)`` produces one of the warnings + types above. + """ + if not func: + return _DeprecatedCallContext() + else: + __tracebackhide__ = True + with _DeprecatedCallContext(): + return func(*args, **kwargs) + + +class _DeprecatedCallContext(object): + """Implements the logic to capture deprecation warnings as a context manager.""" + + def __enter__(self): + self._captured_categories = [] + self._old_warn = warnings.warn + self._old_warn_explicit = warnings.warn_explicit + warnings.warn_explicit = self._warn_explicit + warnings.warn = self._warn + + def _warn_explicit(self, message, category, *args, **kwargs): + self._captured_categories.append(category) + + def _warn(self, message, category=None, *args, **kwargs): + if isinstance(message, Warning): + self._captured_categories.append(message.__class__) + else: + self._captured_categories.append(category) + + def __exit__(self, exc_type, exc_val, exc_tb): + warnings.warn_explicit = self._old_warn_explicit + warnings.warn = self._old_warn + + if exc_type is None: + deprecation_categories = (DeprecationWarning, PendingDeprecationWarning) + if not any(issubclass(c, deprecation_categories) for c in self._captured_categories): + __tracebackhide__ = True + msg = "Did not produce DeprecationWarning or PendingDeprecationWarning" + raise AssertionError(msg) + + +def warns(expected_warning, *args, **kwargs): + """Assert that code raises a particular class of warning. + + Specifically, the input @expected_warning can be a warning class or + tuple of warning classes, and the code must return that warning + (if a single class) or one of those warnings (if a tuple). + + This helper produces a list of ``warnings.WarningMessage`` objects, + one for each warning raised. + + This function can be used as a context manager, or any of the other ways + ``pytest.raises`` can be used:: + + >>> with warns(RuntimeWarning): + ... warnings.warn("my warning", RuntimeWarning) + + In the context manager form you may use the keyword argument ``match`` to assert + that the exception matches a text or regex:: + + >>> with warns(UserWarning, match='must be 0 or None'): + ... warnings.warn("value must be 0 or None", UserWarning) + + >>> with warns(UserWarning, match=r'must be \d+$'): + ... warnings.warn("value must be 42", UserWarning) + + >>> with warns(UserWarning, match=r'must be \d+$'): + ... warnings.warn("this is not here", UserWarning) + Traceback (most recent call last): + ... + Failed: DID NOT WARN. No warnings of type ...UserWarning... was emitted... + + """ + match_expr = None + if not args: + if "match" in kwargs: + match_expr = kwargs.pop("match") + return WarningsChecker(expected_warning, match_expr=match_expr) + elif isinstance(args[0], str): + code, = args + assert isinstance(code, str) + frame = sys._getframe(1) + loc = frame.f_locals.copy() + loc.update(kwargs) + + with WarningsChecker(expected_warning, match_expr=match_expr): + code = _pytest._code.Source(code).compile() + py.builtin.exec_(code, frame.f_globals, loc) + else: + func = args[0] + with WarningsChecker(expected_warning, match_expr=match_expr): + return func(*args[1:], **kwargs) + + +class WarningsRecorder(warnings.catch_warnings): + """A context manager to record raised warnings. + + Adapted from `warnings.catch_warnings`. + """ + + def __init__(self): + super(WarningsRecorder, self).__init__(record=True) + self._entered = False + self._list = [] + + @property + def list(self): + """The list of recorded warnings.""" + return self._list + + def __getitem__(self, i): + """Get a recorded warning by index.""" + return self._list[i] + + def __iter__(self): + """Iterate through the recorded warnings.""" + return iter(self._list) + + def __len__(self): + """The number of recorded warnings.""" + return len(self._list) + + def pop(self, cls=Warning): + """Pop the first recorded warning, raise exception if not exists.""" + for i, w in enumerate(self._list): + if issubclass(w.category, cls): + return self._list.pop(i) + __tracebackhide__ = True + raise AssertionError("%r not found in warning list" % cls) + + def clear(self): + """Clear the list of recorded warnings.""" + self._list[:] = [] + + def __enter__(self): + if self._entered: + __tracebackhide__ = True + raise RuntimeError("Cannot enter %r twice" % self) + self._list = super(WarningsRecorder, self).__enter__() + warnings.simplefilter('always') + return self + + def __exit__(self, *exc_info): + if not self._entered: + __tracebackhide__ = True + raise RuntimeError("Cannot exit %r without entering first" % self) + super(WarningsRecorder, self).__exit__(*exc_info) + + +class WarningsChecker(WarningsRecorder): + def __init__(self, expected_warning=None, match_expr=None): + super(WarningsChecker, self).__init__() + + msg = ("exceptions must be old-style classes or " + "derived from Warning, not %s") + if isinstance(expected_warning, tuple): + for exc in expected_warning: + if not inspect.isclass(exc): + raise TypeError(msg % type(exc)) + elif inspect.isclass(expected_warning): + expected_warning = (expected_warning,) + elif expected_warning is not None: + raise TypeError(msg % type(expected_warning)) + + self.expected_warning = expected_warning + self.match_expr = match_expr + + def __exit__(self, *exc_info): + super(WarningsChecker, self).__exit__(*exc_info) + + # only check if we're not currently handling an exception + if all(a is None for a in exc_info): + if self.expected_warning is not None: + if not any(issubclass(r.category, self.expected_warning) + for r in self): + __tracebackhide__ = True + fail("DID NOT WARN. No warnings of type {0} was emitted. " + "The list of emitted warnings is: {1}.".format( + self.expected_warning, + [each.message for each in self])) + elif self.match_expr is not None: + for r in self: + if issubclass(r.category, self.expected_warning): + if re.compile(self.match_expr).search(str(r.message)): + break + else: + fail("DID NOT WARN. No warnings of type {0} matching" + " ('{1}') was emitted. The list of emitted warnings" + " is: {2}.".format(self.expected_warning, self.match_expr, + [each.message for each in self])) diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/resultlog.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/resultlog.py similarity index 85% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/resultlog.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/resultlog.py index 3670f0214c9..9f9c2d1f653 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/resultlog.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/resultlog.py @@ -1,15 +1,18 @@ """ log machine-parseable test session result information in a plain text file. """ +from __future__ import absolute_import, division, print_function import py import os + def pytest_addoption(parser): group = parser.getgroup("terminal reporting", "resultlog plugin options") group.addoption('--resultlog', '--result-log', action="store", - metavar="path", default=None, - help="path for machine-readable result log.") + metavar="path", default=None, + help="DEPRECATED path for machine-readable result log.") + def pytest_configure(config): resultlog = config.option.resultlog @@ -18,10 +21,14 @@ def pytest_configure(config): dirname = os.path.dirname(os.path.abspath(resultlog)) if not os.path.isdir(dirname): os.makedirs(dirname) - logfile = open(resultlog, 'w', 1) # line buffered + logfile = open(resultlog, 'w', 1) # line buffered config._resultlog = ResultLog(config, logfile) config.pluginmanager.register(config._resultlog) + from _pytest.deprecated import RESULT_LOG + config.warn('C1', RESULT_LOG) + + def pytest_unconfigure(config): resultlog = getattr(config, '_resultlog', None) if resultlog: @@ -29,6 +36,7 @@ def pytest_unconfigure(config): del config._resultlog config.pluginmanager.unregister(resultlog) + def generic_path(item): chain = item.listchain() gpath = [chain[0].name] @@ -52,15 +60,16 @@ def generic_path(item): fspath = newfspath return ''.join(gpath) + class ResultLog(object): def __init__(self, config, logfile): self.config = config - self.logfile = logfile # preferably line buffered + self.logfile = logfile # preferably line buffered def write_log_entry(self, testpath, lettercode, longrepr): - py.builtin.print_("%s %s" % (lettercode, testpath), file=self.logfile) + print("%s %s" % (lettercode, testpath), file=self.logfile) for line in longrepr.splitlines(): - py.builtin.print_(" %s" % line, file=self.logfile) + print(" %s" % line, file=self.logfile) def log_outcome(self, report, lettercode, longrepr): testpath = getattr(report, 'nodeid', None) diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/runner.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/runner.py similarity index 72% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/runner.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/runner.py index cde94c8c89e..e07ed2a248b 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/runner.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/runner.py @@ -1,29 +1,25 @@ """ basic collect and runtest protocol implementations """ +from __future__ import absolute_import, division, print_function + import bdb +import os import sys from time import time import py -import pytest from _pytest._code.code import TerminalRepr, ExceptionInfo - - -def pytest_namespace(): - return { - 'fail' : fail, - 'skip' : skip, - 'importorskip' : importorskip, - 'exit' : exit, - } +from _pytest.outcomes import skip, Skipped, TEST_OUTCOME # # pytest plugin hooks + def pytest_addoption(parser): group = parser.getgroup("terminal reporting", "reporting", after="general") group.addoption('--durations', - action="store", type=int, default=None, metavar="N", - help="show N slowest setup/test durations (N=0 for all)."), + action="store", type=int, default=None, metavar="N", + help="show N slowest setup/test durations (N=0 for all)."), + def pytest_terminal_summary(terminalreporter): durations = terminalreporter.config.option.durations @@ -48,16 +44,16 @@ def pytest_terminal_summary(terminalreporter): for rep in dlist: nodeid = rep.nodeid.replace("::()::", "::") tr.write_line("%02.2fs %-8s %s" % - (rep.duration, rep.when, nodeid)) + (rep.duration, rep.when, nodeid)) + def pytest_sessionstart(session): session._setupstate = SetupState() + + def pytest_sessionfinish(session): session._setupstate.teardown_all() -class NodeInfo: - def __init__(self, location): - self.location = location def pytest_runtest_protocol(item, nextitem): item.ihook.pytest_runtest_logstart( @@ -66,6 +62,7 @@ def pytest_runtest_protocol(item, nextitem): runtestprotocol(item, nextitem=nextitem) return True + def runtestprotocol(item, log=True, nextitem=None): hasrequest = hasattr(item, "_request") if hasrequest and not item._request: @@ -73,9 +70,12 @@ def runtestprotocol(item, log=True, nextitem=None): rep = call_and_report(item, "setup", log) reports = [rep] if rep.passed: - reports.append(call_and_report(item, "call", log)) + if item.config.option.setupshow: + show_test_item(item) + if not item.config.option.setuponly: + reports.append(call_and_report(item, "call", log)) reports.append(call_and_report(item, "teardown", log, - nextitem=nextitem)) + nextitem=nextitem)) # after all teardown hooks have been called # want funcargs and request info to go away if hasrequest: @@ -83,10 +83,25 @@ def runtestprotocol(item, log=True, nextitem=None): item.funcargs = None return reports + +def show_test_item(item): + """Show test function, parameters and the fixtures of the test item.""" + tw = item.config.get_terminal_writer() + tw.line() + tw.write(' ' * 8) + tw.write(item._nodeid) + used_fixtures = sorted(item._fixtureinfo.name2fixturedefs.keys()) + if used_fixtures: + tw.write(' (fixtures used: {0})'.format(', '.join(used_fixtures))) + + def pytest_runtest_setup(item): + _update_current_test_var(item, 'setup') item.session._setupstate.prepare(item) + def pytest_runtest_call(item): + _update_current_test_var(item, 'call') try: item.runtest() except Exception: @@ -99,8 +114,28 @@ def pytest_runtest_call(item): del tb # Get rid of it in this namespace raise + def pytest_runtest_teardown(item, nextitem): + _update_current_test_var(item, 'teardown') item.session._setupstate.teardown_exact(item, nextitem) + _update_current_test_var(item, None) + + +def _update_current_test_var(item, when): + """ + Update PYTEST_CURRENT_TEST to reflect the current item and stage. + + If ``when`` is None, delete PYTEST_CURRENT_TEST from the environment. + """ + var_name = 'PYTEST_CURRENT_TEST' + if when: + value = '{0} ({1})'.format(item.nodeid, when) + # don't allow null bytes on environment variables (see #2644, #2957) + value = value.replace('\x00', '(null)') + os.environ[var_name] = value + else: + os.environ.pop(var_name) + def pytest_report_teststatus(report): if report.when in ("setup", "teardown"): @@ -126,21 +161,25 @@ def call_and_report(item, when, log=True, **kwds): hook.pytest_exception_interact(node=item, call=call, report=report) return report + def check_interactive_exception(call, report): return call.excinfo and not ( - hasattr(report, "wasxfail") or - call.excinfo.errisinstance(skip.Exception) or - call.excinfo.errisinstance(bdb.BdbQuit)) + hasattr(report, "wasxfail") or + call.excinfo.errisinstance(skip.Exception) or + call.excinfo.errisinstance(bdb.BdbQuit)) + def call_runtest_hook(item, when, **kwds): hookname = "pytest_runtest_" + when ihook = getattr(item.ihook, hookname) return CallInfo(lambda: ihook(item=item, **kwds), when=when) + class CallInfo: """ Result/Exception info a function invocation. """ #: None or ExceptionInfo object. excinfo = None + def __init__(self, func, when): #: context of invocation: one of "setup", "call", #: "teardown", "memocollect" @@ -151,7 +190,7 @@ class CallInfo: except KeyboardInterrupt: self.stop = time() raise - except: + except: # noqa self.excinfo = ExceptionInfo() self.stop = time() @@ -162,6 +201,7 @@ class CallInfo: status = "result: %r" % (self.result,) return "" % (self.when, status) + def getslaveinfoline(node): try: return node._slaveinfocache @@ -172,6 +212,7 @@ def getslaveinfoline(node): d['id'], d['sysplatform'], ver, d['executable']) return s + class BaseReport(object): def __init__(self, **kw): @@ -198,6 +239,36 @@ class BaseReport(object): if name.startswith(prefix): yield prefix, content + @property + def longreprtext(self): + """ + Read-only property that returns the full string representation + of ``longrepr``. + + .. versionadded:: 3.0 + """ + tw = py.io.TerminalWriter(stringio=True) + tw.hasmarkup = False + self.toterminal(tw) + exc = tw.stringio.getvalue() + return exc.strip() + + @property + def capstdout(self): + """Return captured text from stdout, if capturing is enabled + + .. versionadded:: 3.0 + """ + return ''.join(content for (prefix, content) in self.get_sections('Captured stdout')) + + @property + def capstderr(self): + """Return captured text from stderr, if capturing is enabled + + .. versionadded:: 3.0 + """ + return ''.join(content for (prefix, content) in self.get_sections('Captured stderr')) + passed = property(lambda x: x.outcome == "passed") failed = property(lambda x: x.outcome == "failed") skipped = property(lambda x: x.outcome == "skipped") @@ -206,10 +277,11 @@ class BaseReport(object): def fspath(self): return self.nodeid.split("::")[0] + def pytest_runtest_makereport(item, call): when = call.when - duration = call.stop-call.start - keywords = dict([(x,1) for x in item.keywords]) + duration = call.stop - call.start + keywords = dict([(x, 1) for x in item.keywords]) excinfo = call.excinfo sections = [] if not call.excinfo: @@ -219,7 +291,7 @@ def pytest_runtest_makereport(item, call): if not isinstance(excinfo, ExceptionInfo): outcome = "failed" longrepr = excinfo - elif excinfo.errisinstance(pytest.skip.Exception): + elif excinfo.errisinstance(skip.Exception): outcome = "skipped" r = excinfo._getreprcrash() longrepr = (str(r.path), r.lineno, r.message) @@ -227,19 +299,21 @@ def pytest_runtest_makereport(item, call): outcome = "failed" if call.when == "call": longrepr = item.repr_failure(excinfo) - else: # exception in setup or teardown + else: # exception in setup or teardown longrepr = item._repr_failure_py(excinfo, - style=item.config.option.tbstyle) + style=item.config.option.tbstyle) for rwhen, key, content in item._report_sections: - sections.append(("Captured %s %s" %(key, rwhen), content)) + sections.append(("Captured %s %s" % (key, rwhen), content)) return TestReport(item.nodeid, item.location, keywords, outcome, longrepr, when, sections, duration) + class TestReport(BaseReport): """ Basic test report object (also used for setup and teardown calls if they fail). """ + def __init__(self, nodeid, location, keywords, outcome, longrepr, when, sections=(), duration=0, **extra): #: normalized collection node id @@ -263,8 +337,10 @@ class TestReport(BaseReport): #: one of 'setup', 'call', 'teardown' to indicate runtest phase. self.when = when - #: list of (secname, data) extra information which needs to - #: marshallable + #: list of pairs ``(str, str)`` of extra information which needs to + #: marshallable. Used by pytest to add captured text + #: from ``stdout`` and ``stderr``, but may be used by other plugins + #: to add arbitrary information to reports. self.sections = list(sections) #: time it took to run just the test @@ -276,16 +352,21 @@ class TestReport(BaseReport): return "" % ( self.nodeid, self.when, self.outcome) + class TeardownErrorReport(BaseReport): outcome = "failed" when = "teardown" + def __init__(self, longrepr, **extra): self.longrepr = longrepr self.sections = [] self.__dict__.update(extra) + def pytest_make_collect_report(collector): - call = CallInfo(collector._memocollect, "memocollect") + call = CallInfo( + lambda: list(collector.collect()), + 'collect') longrepr = None if not call.excinfo: outcome = "passed" @@ -303,7 +384,7 @@ def pytest_make_collect_report(collector): errorinfo = CollectErrorRepr(errorinfo) longrepr = errorinfo rep = CollectReport(collector.nodeid, outcome, longrepr, - getattr(call, 'result', None)) + getattr(call, 'result', None)) rep.call = call # see collect_one_node return rep @@ -324,16 +405,20 @@ class CollectReport(BaseReport): def __repr__(self): return "" % ( - self.nodeid, len(self.result), self.outcome) + self.nodeid, len(self.result), self.outcome) + class CollectErrorRepr(TerminalRepr): def __init__(self, msg): self.longrepr = msg + def toterminal(self, out): out.line(self.longrepr, red=True) + class SetupState(object): """ shared state for setting up/tearing down test items or collectors. """ + def __init__(self): self.stack = [] self._finalizers = {} @@ -344,8 +429,8 @@ class SetupState(object): is called at the end of teardown_all(). """ assert colitem and not isinstance(colitem, tuple) - assert py.builtin.callable(finalizer) - #assert colitem in self.stack # some unit tests don't setup stack :/ + assert callable(finalizer) + # assert colitem in self.stack # some unit tests don't setup stack :/ self._finalizers.setdefault(colitem, []).append(finalizer) def _pop_and_teardown(self): @@ -359,7 +444,7 @@ class SetupState(object): fin = finalizers.pop() try: fin() - except Exception: + except TEST_OUTCOME: # XXX Only first exception will be seen by user, # ideally all should be reported. if exc is None: @@ -373,7 +458,7 @@ class SetupState(object): colitem.teardown() for colitem in self._finalizers: assert colitem is None or colitem in self.stack \ - or isinstance(colitem, tuple) + or isinstance(colitem, tuple) def teardown_all(self): while self.stack: @@ -406,10 +491,11 @@ class SetupState(object): self.stack.append(col) try: col.setup() - except Exception: + except TEST_OUTCOME: col._prepare_exc = sys.exc_info() raise + def collect_one_node(collector): ihook = collector.ihook ihook.pytest_collectstart(collector=collector) @@ -418,98 +504,3 @@ def collect_one_node(collector): if call and check_interactive_exception(call, rep): ihook.pytest_exception_interact(node=collector, call=call, report=rep) return rep - - -# ============================================================= -# Test OutcomeExceptions and helpers for creating them. - - -class OutcomeException(Exception): - """ OutcomeException and its subclass instances indicate and - contain info about test and collection outcomes. - """ - def __init__(self, msg=None, pytrace=True): - Exception.__init__(self, msg) - self.msg = msg - self.pytrace = pytrace - - def __repr__(self): - if self.msg: - val = self.msg - if isinstance(val, bytes): - val = py._builtin._totext(val, errors='replace') - return val - return "<%s instance>" %(self.__class__.__name__,) - __str__ = __repr__ - -class Skipped(OutcomeException): - # XXX hackish: on 3k we fake to live in the builtins - # in order to have Skipped exception printing shorter/nicer - __module__ = 'builtins' - -class Failed(OutcomeException): - """ raised from an explicit call to pytest.fail() """ - __module__ = 'builtins' - -class Exit(KeyboardInterrupt): - """ raised for immediate program exits (no tracebacks/summaries)""" - def __init__(self, msg="unknown reason"): - self.msg = msg - KeyboardInterrupt.__init__(self, msg) - -# exposed helper methods - -def exit(msg): - """ exit testing process as if KeyboardInterrupt was triggered. """ - __tracebackhide__ = True - raise Exit(msg) - -exit.Exception = Exit - -def skip(msg=""): - """ skip an executing test with the given message. Note: it's usually - better to use the pytest.mark.skipif marker to declare a test to be - skipped under certain conditions like mismatching platforms or - dependencies. See the pytest_skipping plugin for details. - """ - __tracebackhide__ = True - raise Skipped(msg=msg) -skip.Exception = Skipped - -def fail(msg="", pytrace=True): - """ explicitly fail an currently-executing test with the given Message. - - :arg pytrace: if false the msg represents the full failure information - and no python traceback will be reported. - """ - __tracebackhide__ = True - raise Failed(msg=msg, pytrace=pytrace) -fail.Exception = Failed - - -def importorskip(modname, minversion=None): - """ return imported module if it has at least "minversion" as its - __version__ attribute. If no minversion is specified the a skip - is only triggered if the module can not be imported. - """ - __tracebackhide__ = True - compile(modname, '', 'eval') # to catch syntaxerrors - try: - __import__(modname) - except ImportError: - skip("could not import %r" %(modname,)) - mod = sys.modules[modname] - if minversion is None: - return mod - verattr = getattr(mod, '__version__', None) - if minversion is not None: - try: - from pkg_resources import parse_version as pv - except ImportError: - skip("we have a required version for %r but can not import " - "no pkg_resources to parse version strings." %(modname,)) - if verattr is None or pv(verattr) < pv(minversion): - skip("module %r has __version__ %r, required is: %r" %( - modname, verattr, minversion)) - return mod - diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/setuponly.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/setuponly.py new file mode 100644 index 00000000000..a1c7457d7e5 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/setuponly.py @@ -0,0 +1,74 @@ +from __future__ import absolute_import, division, print_function + +import pytest +import sys + + +def pytest_addoption(parser): + group = parser.getgroup("debugconfig") + group.addoption('--setuponly', '--setup-only', action="store_true", + help="only setup fixtures, do not execute tests.") + group.addoption('--setupshow', '--setup-show', action="store_true", + help="show setup of fixtures while executing tests.") + + +@pytest.hookimpl(hookwrapper=True) +def pytest_fixture_setup(fixturedef, request): + yield + config = request.config + if config.option.setupshow: + if hasattr(request, 'param'): + # Save the fixture parameter so ._show_fixture_action() can + # display it now and during the teardown (in .finish()). + if fixturedef.ids: + if callable(fixturedef.ids): + fixturedef.cached_param = fixturedef.ids(request.param) + else: + fixturedef.cached_param = fixturedef.ids[ + request.param_index] + else: + fixturedef.cached_param = request.param + _show_fixture_action(fixturedef, 'SETUP') + + +def pytest_fixture_post_finalizer(fixturedef): + if hasattr(fixturedef, "cached_result"): + config = fixturedef._fixturemanager.config + if config.option.setupshow: + _show_fixture_action(fixturedef, 'TEARDOWN') + if hasattr(fixturedef, "cached_param"): + del fixturedef.cached_param + + +def _show_fixture_action(fixturedef, msg): + config = fixturedef._fixturemanager.config + capman = config.pluginmanager.getplugin('capturemanager') + if capman: + out, err = capman.suspend_global_capture() + + tw = config.get_terminal_writer() + tw.line() + tw.write(' ' * 2 * fixturedef.scopenum) + tw.write('{step} {scope} {fixture}'.format( + step=msg.ljust(8), # align the output to TEARDOWN + scope=fixturedef.scope[0].upper(), + fixture=fixturedef.argname)) + + if msg == 'SETUP': + deps = sorted(arg for arg in fixturedef.argnames if arg != 'request') + if deps: + tw.write(' (fixtures used: {0})'.format(', '.join(deps))) + + if hasattr(fixturedef, 'cached_param'): + tw.write('[{0}]'.format(fixturedef.cached_param)) + + if capman: + capman.resume_global_capture() + sys.stdout.write(out) + sys.stderr.write(err) + + +@pytest.hookimpl(tryfirst=True) +def pytest_cmdline_main(config): + if config.option.setuponly: + config.option.setupshow = True diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/setupplan.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/setupplan.py new file mode 100644 index 00000000000..e11bd40698b --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/setupplan.py @@ -0,0 +1,25 @@ +from __future__ import absolute_import, division, print_function + +import pytest + + +def pytest_addoption(parser): + group = parser.getgroup("debugconfig") + group.addoption('--setupplan', '--setup-plan', action="store_true", + help="show what fixtures and tests would be executed but " + "don't execute anything.") + + +@pytest.hookimpl(tryfirst=True) +def pytest_fixture_setup(fixturedef, request): + # Will return a dummy fixture if the setuponly option is provided. + if request.config.option.setupplan: + fixturedef.cached_result = (None, None, None) + return fixturedef.cached_result + + +@pytest.hookimpl(tryfirst=True) +def pytest_cmdline_main(config): + if config.option.setupplan: + config.option.setuponly = True + config.option.setupshow = True diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/skipping.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/skipping.py similarity index 53% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/skipping.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/skipping.py index 69157f485a0..a1e5b43800b 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/skipping.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/skipping.py @@ -1,18 +1,21 @@ """ support for skip/xfail functions and markers. """ +from __future__ import absolute_import, division, print_function + import os +import six import sys import traceback -import py -import pytest +from _pytest.config import hookimpl from _pytest.mark import MarkInfo, MarkDecorator +from _pytest.outcomes import fail, skip, xfail, TEST_OUTCOME def pytest_addoption(parser): group = parser.getgroup("general") group.addoption('--runxfail', - action="store_true", dest="runxfail", default=False, - help="run tests even if they are marked xfail") + action="store_true", dest="runxfail", default=False, + help="run tests even if they are marked xfail") parser.addini("xfail_strict", "default for the strict parameter of xfail " "markers when not given explicitly (default: " @@ -23,62 +26,65 @@ def pytest_addoption(parser): def pytest_configure(config): if config.option.runxfail: + # yay a hack + import pytest old = pytest.xfail config._cleanup.append(lambda: setattr(pytest, "xfail", old)) + def nop(*args, **kwargs): pass - nop.Exception = XFailed + + nop.Exception = xfail.Exception setattr(pytest, "xfail", nop) config.addinivalue_line("markers", - "skipif(condition): skip the given test function if eval(condition) " - "results in a True value. Evaluation happens within the " - "module global context. Example: skipif('sys.platform == \"win32\"') " - "skips the test if we are on the win32 platform. see " - "http://pytest.org/latest/skipping.html" - ) + "skip(reason=None): skip the given test function with an optional reason. " + "Example: skip(reason=\"no way of currently testing this\") skips the " + "test." + ) config.addinivalue_line("markers", - "xfail(condition, reason=None, run=True, raises=None): mark the the test function " - "as an expected failure if eval(condition) has a True value. " - "Optionally specify a reason for better reporting and run=False if " - "you don't even want to execute the test function. If only specific " - "exception(s) are expected, you can list them in raises, and if the test fails " - "in other ways, it will be reported as a true failure. " - "See http://pytest.org/latest/skipping.html" - ) + "skipif(condition): skip the given test function if eval(condition) " + "results in a True value. Evaluation happens within the " + "module global context. Example: skipif('sys.platform == \"win32\"') " + "skips the test if we are on the win32 platform. see " + "http://pytest.org/latest/skipping.html" + ) + config.addinivalue_line("markers", + "xfail(condition, reason=None, run=True, raises=None, strict=False): " + "mark the test function as an expected failure if eval(condition) " + "has a True value. Optionally specify a reason for better reporting " + "and run=False if you don't even want to execute the test function. " + "If only specific exception(s) are expected, you can list them in " + "raises, and if the test fails in other ways, it will be reported as " + "a true failure. See http://pytest.org/latest/skipping.html" + ) -def pytest_namespace(): - return dict(xfail=xfail) - - -class XFailed(pytest.fail.Exception): - """ raised from an explicit call to pytest.xfail() """ - - -def xfail(reason=""): - """ xfail an executing test or setup functions with the given reason.""" - __tracebackhide__ = True - raise XFailed(reason) -xfail.Exception = XFailed - - -class MarkEvaluator: +class MarkEvaluator(object): def __init__(self, item, name): self.item = item - self.name = name - - @property - def holder(self): - return self.item.keywords.get(self.name) + self._marks = None + self._mark = None + self._mark_name = name def __bool__(self): - return bool(self.holder) + self._marks = self._get_marks() + return bool(self._marks) __nonzero__ = __bool__ def wasvalid(self): return not hasattr(self, 'exc') + def _get_marks(self): + + keyword = self.item.keywords.get(self._mark_name) + if isinstance(keyword, MarkDecorator): + return [keyword.mark] + elif isinstance(keyword, MarkInfo): + return [x.combined for x in keyword] + else: + return [] + def invalidraise(self, exc): raises = self.get('raises') if not raises: @@ -88,65 +94,67 @@ class MarkEvaluator: def istrue(self): try: return self._istrue() - except Exception: + except TEST_OUTCOME: self.exc = sys.exc_info() if isinstance(self.exc[1], SyntaxError): - msg = [" " * (self.exc[1].offset + 4) + "^",] + msg = [" " * (self.exc[1].offset + 4) + "^", ] msg.append("SyntaxError: invalid syntax") else: msg = traceback.format_exception_only(*self.exc[:2]) - pytest.fail("Error evaluating %r expression\n" - " %s\n" - "%s" - %(self.name, self.expr, "\n".join(msg)), - pytrace=False) + fail("Error evaluating %r expression\n" + " %s\n" + "%s" + % (self._mark_name, self.expr, "\n".join(msg)), + pytrace=False) def _getglobals(self): d = {'os': os, 'sys': sys, 'config': self.item.config} - func = self.item.obj - try: - d.update(func.__globals__) - except AttributeError: - d.update(func.func_globals) + if hasattr(self.item, 'obj'): + d.update(self.item.obj.__globals__) return d def _istrue(self): if hasattr(self, 'result'): return self.result - if self.holder: - d = self._getglobals() - if self.holder.args: - self.result = False - # "holder" might be a MarkInfo or a MarkDecorator; only - # MarkInfo keeps track of all parameters it received in an - # _arglist attribute - if hasattr(self.holder, '_arglist'): - arglist = self.holder._arglist + self._marks = self._get_marks() + + if self._marks: + self.result = False + for mark in self._marks: + self._mark = mark + if 'condition' in mark.kwargs: + args = (mark.kwargs['condition'],) else: - arglist = [(self.holder.args, self.holder.kwargs)] - for args, kwargs in arglist: - for expr in args: + args = mark.args + + for expr in args: + self.expr = expr + if isinstance(expr, six.string_types): + d = self._getglobals() + result = cached_eval(self.item.config, expr, d) + else: + if "reason" not in mark.kwargs: + # XXX better be checked at collection time + msg = "you need to specify reason=STRING " \ + "when using booleans as conditions." + fail(msg) + result = bool(expr) + if result: + self.result = True + self.reason = mark.kwargs.get('reason', None) self.expr = expr - if isinstance(expr, py.builtin._basestring): - result = cached_eval(self.item.config, expr, d) - else: - if "reason" not in kwargs: - # XXX better be checked at collection time - msg = "you need to specify reason=STRING " \ - "when using booleans as conditions." - pytest.fail(msg) - result = bool(expr) - if result: - self.result = True - self.reason = kwargs.get('reason', None) - self.expr = expr - return self.result - else: - self.result = True - return getattr(self, 'result', False) + return self.result + + if not args: + self.result = True + self.reason = mark.kwargs.get('reason', None) + return self.result + return False def get(self, attr, default=None): - return self.holder.kwargs.get(attr, default) + if self._mark is None: + return default + return self._mark.kwargs.get(attr, default) def getexplanation(self): expl = getattr(self, 'reason', None) or self.get('reason', None) @@ -158,32 +166,32 @@ class MarkEvaluator: return expl -@pytest.hookimpl(tryfirst=True) +@hookimpl(tryfirst=True) def pytest_runtest_setup(item): # Check if skip or skipif are specified as pytest marks - + item._skipped_by_mark = False skipif_info = item.keywords.get('skipif') if isinstance(skipif_info, (MarkInfo, MarkDecorator)): eval_skipif = MarkEvaluator(item, 'skipif') if eval_skipif.istrue(): - item._evalskip = eval_skipif - pytest.skip(eval_skipif.getexplanation()) + item._skipped_by_mark = True + skip(eval_skipif.getexplanation()) skip_info = item.keywords.get('skip') if isinstance(skip_info, (MarkInfo, MarkDecorator)): - item._evalskip = True + item._skipped_by_mark = True if 'reason' in skip_info.kwargs: - pytest.skip(skip_info.kwargs['reason']) + skip(skip_info.kwargs['reason']) elif skip_info.args: - pytest.skip(skip_info.args[0]) + skip(skip_info.args[0]) else: - pytest.skip("unconditional skip") + skip("unconditional skip") item._evalxfail = MarkEvaluator(item, 'xfail') check_xfail_no_run(item) -@pytest.mark.hookwrapper +@hookimpl(hookwrapper=True) def pytest_pyfunc_call(pyfuncitem): check_xfail_no_run(pyfuncitem) outcome = yield @@ -198,7 +206,7 @@ def check_xfail_no_run(item): evalxfail = item._evalxfail if evalxfail.istrue(): if not evalxfail.get('run', True): - pytest.xfail("[NOTRUN] " + evalxfail.getexplanation()) + xfail("[NOTRUN] " + evalxfail.getexplanation()) def check_strict_xfail(pyfuncitem): @@ -210,27 +218,33 @@ def check_strict_xfail(pyfuncitem): if is_strict_xfail: del pyfuncitem._evalxfail explanation = evalxfail.getexplanation() - pytest.fail('[XPASS(strict)] ' + explanation, pytrace=False) + fail('[XPASS(strict)] ' + explanation, pytrace=False) -@pytest.hookimpl(hookwrapper=True) +@hookimpl(hookwrapper=True) def pytest_runtest_makereport(item, call): outcome = yield rep = outcome.get_result() evalxfail = getattr(item, '_evalxfail', None) - evalskip = getattr(item, '_evalskip', None) # unitttest special case, see setting of _unexpectedsuccess if hasattr(item, '_unexpectedsuccess') and rep.when == "call": - # we need to translate into how pytest encodes xpass - rep.wasxfail = "reason: " + repr(item._unexpectedsuccess) - rep.outcome = "failed" + from _pytest.compat import _is_unittest_unexpected_success_a_failure + if item._unexpectedsuccess: + rep.longrepr = "Unexpected success: {0}".format(item._unexpectedsuccess) + else: + rep.longrepr = "Unexpected success" + if _is_unittest_unexpected_success_a_failure(): + rep.outcome = "failed" + else: + rep.outcome = "passed" + rep.wasxfail = rep.longrepr elif item.config.option.runxfail: pass # don't interefere - elif call.excinfo and call.excinfo.errisinstance(pytest.xfail.Exception): + elif call.excinfo and call.excinfo.errisinstance(xfail.Exception): rep.wasxfail = "reason: " + call.excinfo.value.msg rep.outcome = "skipped" elif evalxfail and not rep.skipped and evalxfail.wasvalid() and \ - evalxfail.istrue(): + evalxfail.istrue(): if call.excinfo: if evalxfail.invalidraise(call.excinfo.value): rep.outcome = "failed" @@ -238,9 +252,16 @@ def pytest_runtest_makereport(item, call): rep.outcome = "skipped" rep.wasxfail = evalxfail.getexplanation() elif call.when == "call": - rep.outcome = "failed" # xpass outcome - rep.wasxfail = evalxfail.getexplanation() - elif evalskip is not None and rep.skipped and type(rep.longrepr) is tuple: + strict_default = item.config.getini('xfail_strict') + is_strict_xfail = evalxfail.get('strict', strict_default) + explanation = evalxfail.getexplanation() + if is_strict_xfail: + rep.outcome = "failed" + rep.longrepr = "[XPASS(strict)] {0}".format(explanation) + else: + rep.outcome = "passed" + rep.wasxfail = explanation + elif item._skipped_by_mark and rep.skipped and type(rep.longrepr) is tuple: # skipped by mark.skipif; change the location of the failure # to point to the item definition, otherwise it will display # the location of where the skip exception was raised within pytest @@ -249,18 +270,22 @@ def pytest_runtest_makereport(item, call): rep.longrepr = filename, line, reason # called by terminalreporter progress reporting + + def pytest_report_teststatus(report): if hasattr(report, "wasxfail"): if report.skipped: return "xfailed", "x", "xfail" - elif report.failed: + elif report.passed: return "xpassed", "X", ("XPASS", {'yellow': True}) # called by the terminalreporter instance/plugin + + def pytest_terminal_summary(terminalreporter): tr = terminalreporter if not tr.reportchars: - #for name in "xfailed skipped failed xpassed": + # for name in "xfailed skipped failed xpassed": # if not tr.stats.get(name, 0): # tr.write_line("HINT: use '-r' option to see extra " # "summary info about tests") @@ -287,12 +312,14 @@ def pytest_terminal_summary(terminalreporter): for line in lines: tr._tw.line(line) + def show_simple(terminalreporter, lines, stat, format): failed = terminalreporter.stats.get(stat) if failed: for rep in failed: pos = terminalreporter.config.cwd_relative_nodeid(rep.nodeid) - lines.append(format %(pos,)) + lines.append(format % (pos,)) + def show_xfailed(terminalreporter, lines): xfailed = terminalreporter.stats.get("xfailed") @@ -304,13 +331,15 @@ def show_xfailed(terminalreporter, lines): if reason: lines.append(" " + str(reason)) + def show_xpassed(terminalreporter, lines): xpassed = terminalreporter.stats.get("xpassed") if xpassed: for rep in xpassed: pos = terminalreporter.config.cwd_relative_nodeid(rep.nodeid) reason = rep.wasxfail - lines.append("XPASS %s %s" %(pos, reason)) + lines.append("XPASS %s %s" % (pos, reason)) + def cached_eval(config, expr, d): if not hasattr(config, '_evalcache'): @@ -329,26 +358,40 @@ def folded_skips(skipped): for event in skipped: key = event.longrepr assert len(key) == 3, (event, key) + keywords = getattr(event, 'keywords', {}) + # folding reports with global pytestmark variable + # this is workaround, because for now we cannot identify the scope of a skip marker + # TODO: revisit after marks scope would be fixed + when = getattr(event, 'when', None) + if when == 'setup' and 'skip' in keywords and 'pytestmark' not in keywords: + key = (key[0], None, key[2], ) d.setdefault(key, []).append(event) - l = [] + values = [] for key, events in d.items(): - l.append((len(events),) + key) - return l + values.append((len(events),) + key) + return values + def show_skipped(terminalreporter, lines): tr = terminalreporter skipped = tr.stats.get('skipped', []) if skipped: - #if not tr.hasopt('skipped'): + # if not tr.hasopt('skipped'): # tr.write_line( # "%d skipped tests, specify -rs for more info" % # len(skipped)) # return fskips = folded_skips(skipped) if fskips: - #tr.write_sep("_", "skipped test summary") + # tr.write_sep("_", "skipped test summary") for num, fspath, lineno, reason in fskips: if reason.startswith("Skipped: "): reason = reason[9:] - lines.append("SKIP [%d] %s:%d: %s" % - (num, fspath, lineno, reason)) + if lineno is not None: + lines.append( + "SKIP [%d] %s:%d: %s" % + (num, fspath, lineno + 1, reason)) + else: + lines.append( + "SKIP [%d] %s: %s" % + (num, fspath, reason)) diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/terminal.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/terminal.py similarity index 65% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/terminal.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/terminal.py index 825f553ef2c..1aba5e845e5 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/terminal.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/terminal.py @@ -2,45 +2,58 @@ This is a good source for looking at the various reporting hooks. """ -from _pytest.main import EXIT_OK, EXIT_TESTSFAILED, EXIT_INTERRUPTED, \ - EXIT_USAGEERROR, EXIT_NOTESTSCOLLECTED -import pytest -import py +from __future__ import absolute_import, division, print_function + +import itertools +import platform import sys import time -import platform -import _pytest._pluggy as pluggy +import pluggy +import py +import six + +import pytest +from _pytest import nodes +from _pytest.main import EXIT_OK, EXIT_TESTSFAILED, EXIT_INTERRUPTED, \ + EXIT_USAGEERROR, EXIT_NOTESTSCOLLECTED def pytest_addoption(parser): group = parser.getgroup("terminal reporting", "reporting", after="general") group._addoption('-v', '--verbose', action="count", - dest="verbose", default=0, help="increase verbosity."), + dest="verbose", default=0, help="increase verbosity."), group._addoption('-q', '--quiet', action="count", - dest="quiet", default=0, help="decrease verbosity."), + dest="quiet", default=0, help="decrease verbosity."), group._addoption('-r', - action="store", dest="reportchars", default=None, metavar="chars", - help="show extra test summary info as specified by chars (f)ailed, " - "(E)error, (s)skipped, (x)failed, (X)passed (w)pytest-warnings " - "(p)passed, (P)passed with output, (a)all except pP.") + action="store", dest="reportchars", default='', metavar="chars", + help="show extra test summary info as specified by chars (f)ailed, " + "(E)error, (s)skipped, (x)failed, (X)passed, " + "(p)passed, (P)passed with output, (a)all except pP. " + "Warnings are displayed at all times except when " + "--disable-warnings is set") + group._addoption('--disable-warnings', '--disable-pytest-warnings', default=False, + dest='disable_warnings', action='store_true', + help='disable warnings summary') group._addoption('-l', '--showlocals', - action="store_true", dest="showlocals", default=False, - help="show locals in tracebacks (disabled by default).") - group._addoption('--report', - action="store", dest="report", default=None, metavar="opts", - help="(deprecated, use -r)") + action="store_true", dest="showlocals", default=False, + help="show locals in tracebacks (disabled by default).") group._addoption('--tb', metavar="style", - action="store", dest="tbstyle", default='auto', - choices=['auto', 'long', 'short', 'no', 'line', 'native'], - help="traceback print mode (auto/long/short/line/native/no).") + action="store", dest="tbstyle", default='auto', + choices=['auto', 'long', 'short', 'no', 'line', 'native'], + help="traceback print mode (auto/long/short/line/native/no).") group._addoption('--fulltrace', '--full-trace', - action="store_true", default=False, - help="don't cut any tracebacks (default is to cut).") + action="store_true", default=False, + help="don't cut any tracebacks (default is to cut).") group._addoption('--color', metavar="color", - action="store", dest="color", default='auto', - choices=['yes', 'no', 'auto'], - help="color terminal output (yes/no/auto).") + action="store", dest="color", default='auto', + choices=['yes', 'no', 'auto'], + help="color terminal output (yes/no/auto).") + + parser.addini("console_output_style", + help="console output: classic or with additional progress information (classic|progress).", + default='progress') + def pytest_configure(config): config.option.verbose -= config.option.quiet @@ -52,20 +65,14 @@ def pytest_configure(config): reporter.write_line("[traceconfig] " + msg) config.trace.root.setprocessor("pytest:config", mywriter) + def getreportopt(config): reportopts = "" - optvalue = config.option.report - if optvalue: - py.builtin.print_("DEPRECATED: use -r instead of --report option.", - file=sys.stderr) - if optvalue: - for setting in optvalue.split(","): - setting = setting.strip() - if setting == "skipped": - reportopts += "s" - elif setting == "xfailed": - reportopts += "x" reportchars = config.option.reportchars + if not config.option.disable_warnings and 'w' not in reportchars: + reportchars += 'w' + elif config.option.disable_warnings and 'w' in reportchars: + reportchars = reportchars.replace('w', '') if reportchars: for char in reportchars: if char not in reportopts and char != 'a': @@ -74,6 +81,7 @@ def getreportopt(config): reportopts = 'fEsxXw' return reportopts + def pytest_report_teststatus(report): if report.passed: letter = "." @@ -85,13 +93,41 @@ def pytest_report_teststatus(report): letter = "f" return report.outcome, letter, report.outcome.upper() + class WarningReport: + """ + Simple structure to hold warnings information captured by ``pytest_logwarning``. + """ + def __init__(self, code, message, nodeid=None, fslocation=None): + """ + :param code: unused + :param str message: user friendly message about the warning + :param str|None nodeid: node id that generated the warning (see ``get_location``). + :param tuple|py.path.local fslocation: + file system location of the source of the warning (see ``get_location``). + """ self.code = code self.message = message self.nodeid = nodeid self.fslocation = fslocation + def get_location(self, config): + """ + Returns the more user-friendly information about the location + of a warning, or None. + """ + if self.nodeid: + return self.nodeid + if self.fslocation: + if isinstance(self.fslocation, tuple) and len(self.fslocation) >= 2: + filename, linenum = self.fslocation[:2] + relpath = py.path.local(filename).relto(config.invocation_dir) + return '%s:%s' % (relpath, linenum) + else: + return str(self.fslocation) + return None + class TerminalReporter: def __init__(self, config, file=None): @@ -102,17 +138,22 @@ class TerminalReporter: self.showfspath = self.verbosity >= 0 self.showlongtestinfo = self.verbosity > 0 self._numcollected = 0 + self._session = None self.stats = {} self.startdir = py.path.local() if file is None: file = sys.stdout - self._tw = self.writer = _pytest.config.create_terminal_writer(config, - file) + self._tw = _pytest.config.create_terminal_writer(config, file) + # self.writer will be deprecated in pytest-3.4 + self.writer = self._tw + self._screen_width = self._tw.fullwidth self.currentfspath = None self.reportchars = getreportopt(config) self.hasmarkup = self._tw.hasmarkup self.isatty = file.isatty() + self._progress_items_reported = 0 + self._show_progress_info = self.config.getini('console_output_style') == 'progress' def hasopt(self, char): char = {'xfailed': 'x', 'skipped': 's'}.get(char, char) @@ -121,6 +162,8 @@ class TerminalReporter: def write_fspath_result(self, nodeid, res): fspath = self.config.rootdir.join(nodeid.split("::")[0]) if fspath != self.currentfspath: + if self.currentfspath is not None: + self._write_progress_information_filling_space() self.currentfspath = fspath fspath = self.startdir.bestrelpath(fspath) self._tw.line() @@ -135,6 +178,7 @@ class TerminalReporter: if extra: self._tw.write(extra, **kwargs) self.currentfspath = -2 + self._write_progress_information_filling_space() def ensure_newline(self): if self.currentfspath: @@ -145,14 +189,28 @@ class TerminalReporter: self._tw.write(content, **markup) def write_line(self, line, **markup): - if not py.builtin._istext(line): - line = py.builtin.text(line, errors="replace") + if not isinstance(line, six.text_type): + line = six.text_type(line, errors="replace") self.ensure_newline() self._tw.line(line, **markup) def rewrite(self, line, **markup): + """ + Rewinds the terminal cursor to the beginning and writes the given line. + + :kwarg erase: if True, will also add spaces until the full terminal width to ensure + previous lines are properly erased. + + The rest of the keyword arguments are markup instructions. + """ + erase = markup.pop('erase', False) + if erase: + fill_count = self._tw.fullwidth - len(line) - 1 + fill = ' ' * fill_count + else: + fill = '' line = str(line) - self._tw.write("\r" + line, **markup) + self._tw.write("\r" + line + fill, **markup) def write_sep(self, sep, title=None, **markup): self.ensure_newline() @@ -165,14 +223,12 @@ class TerminalReporter: self._tw.line(msg, **kw) def pytest_internalerror(self, excrepr): - for line in py.builtin.text(excrepr).split("\n"): + for line in six.text_type(excrepr).split("\n"): self.write_line("INTERNALERROR> " + line) return 1 def pytest_logwarning(self, code, fslocation, message, nodeid): warnings = self.stats.setdefault("warnings", []) - if isinstance(fslocation, tuple): - fslocation = "%s:%d" % fslocation warning = WarningReport(code=code, fslocation=fslocation, message=message, nodeid=nodeid) warnings.append(warning) @@ -202,38 +258,76 @@ class TerminalReporter: rep = report res = self.config.hook.pytest_report_teststatus(report=rep) cat, letter, word = res + if isinstance(word, tuple): + word, markup = word + else: + markup = None self.stats.setdefault(cat, []).append(rep) self._tests_ran = True if not letter and not word: # probably passed setup/teardown return + running_xdist = hasattr(rep, 'node') + self._progress_items_reported += 1 if self.verbosity <= 0: - if not hasattr(rep, 'node') and self.showfspath: + if not running_xdist and self.showfspath: self.write_fspath_result(rep.nodeid, letter) else: self._tw.write(letter) + self._write_progress_if_past_edge() else: - if isinstance(word, tuple): - word, markup = word - else: + if markup is None: if rep.passed: - markup = {'green':True} + markup = {'green': True} elif rep.failed: - markup = {'red':True} + markup = {'red': True} elif rep.skipped: - markup = {'yellow':True} + markup = {'yellow': True} + else: + markup = {} line = self._locationline(rep.nodeid, *rep.location) - if not hasattr(rep, 'node'): + if not running_xdist: self.write_ensure_prefix(line, word, **markup) - #self._tw.write(word, **markup) else: self.ensure_newline() - if hasattr(rep, 'node'): - self._tw.write("[%s] " % rep.node.gateway.id) + self._tw.write("[%s]" % rep.node.gateway.id) + if self._show_progress_info: + self._tw.write(self._get_progress_information_message() + " ", cyan=True) + else: + self._tw.write(' ') self._tw.write(word, **markup) self._tw.write(" " + line) self.currentfspath = -2 + def _write_progress_if_past_edge(self): + if not self._show_progress_info: + return + last_item = self._progress_items_reported == self._session.testscollected + if last_item: + self._write_progress_information_filling_space() + return + + past_edge = self._tw.chars_on_current_line + self._PROGRESS_LENGTH + 1 >= self._screen_width + if past_edge: + msg = self._get_progress_information_message() + self._tw.write(msg + '\n', cyan=True) + + _PROGRESS_LENGTH = len(' [100%]') + + def _get_progress_information_message(self): + collected = self._session.testscollected + if collected: + progress = self._progress_items_reported * 100 // collected + return ' [{:3d}%]'.format(progress) + return ' [100%]' + + def _write_progress_information_filling_space(self): + if not self._show_progress_info: + return + msg = self._get_progress_information_message() + fill = ' ' * (self._tw.fullwidth - self._tw.chars_on_current_line - len(msg) - 1) + self.write(fill + msg, cyan=True) + def pytest_collection(self): if not self.isatty and self.config.option.verbose >= 1: self.write("collecting ... ", bold=True) @@ -246,7 +340,7 @@ class TerminalReporter: items = [x for x in report.result if isinstance(x, pytest.Item)] self._numcollected += len(items) if self.isatty: - #self.write_fspath_result(report.nodeid, 'E') + # self.write_fspath_result(report.nodeid, 'E') self.report_collect() def report_collect(self, final=False): @@ -259,15 +353,15 @@ class TerminalReporter: line = "collected " else: line = "collecting " - line += str(self._numcollected) + " items" + line += str(self._numcollected) + " item" + ('' if self._numcollected == 1 else 's') if errors: line += " / %d errors" % errors if skipped: line += " / %d skipped" % skipped if self.isatty: + self.rewrite(line, bold=True, erase=True) if final: - line += " \n" - self.rewrite(line, bold=True) + self.write('\n') else: self.write_line(line) @@ -276,6 +370,7 @@ class TerminalReporter: @pytest.hookimpl(trylast=True) def pytest_sessionstart(self, session): + self._session = session self._sessionstarttime = time.time() if not self.showheader: return @@ -293,6 +388,9 @@ class TerminalReporter: self.write_line(msg) lines = self.config.hook.pytest_report_header( config=self.config, startdir=self.startdir) + self._write_report_lines_from_hooks(lines) + + def _write_report_lines_from_hooks(self, lines): lines.reverse() for line in flatten(lines): self.write_line(line) @@ -300,8 +398,8 @@ class TerminalReporter: def pytest_report_header(self, config): inifile = "" if config.inifile: - inifile = config.rootdir.bestrelpath(config.inifile) - lines = ["rootdir: %s, inifile: %s" %(config.rootdir, inifile)] + inifile = " " + config.rootdir.bestrelpath(config.inifile) + lines = ["rootdir: %s, inifile:%s" % (config.rootdir, inifile)] plugininfo = config.pluginmanager.list_plugin_distinfo() if plugininfo: @@ -319,10 +417,9 @@ class TerminalReporter: rep.toterminal(self._tw) return 1 return 0 - if not self.showheader: - return - #for i, testarg in enumerate(self.config.args): - # self.write_line("test path %d: %s" %(i+1, testarg)) + lines = self.config.hook.pytest_report_collectionfinish( + config=self.config, startdir=self.startdir, items=session.items) + self._write_report_lines_from_hooks(lines) def _printcollecteditems(self, items): # to print out items and their parent collectors @@ -345,14 +442,14 @@ class TerminalReporter: stack = [] indent = "" for item in items: - needed_collectors = item.listchain()[1:] # strip root node + needed_collectors = item.listchain()[1:] # strip root node while stack: if stack == needed_collectors[:len(stack)]: break stack.pop() for col in needed_collectors[len(stack):]: stack.append(col) - #if col.name == "()": + # if col.name == "()": # continue indent = (len(stack) - 1) * " " self._tw.line("%s%s" % (indent, col)) @@ -366,7 +463,8 @@ class TerminalReporter: EXIT_OK, EXIT_TESTSFAILED, EXIT_INTERRUPTED, EXIT_USAGEERROR, EXIT_NOTESTSCOLLECTED) if exitstatus in summary_exit_codes: - self.config.hook.pytest_terminal_summary(terminalreporter=self) + self.config.hook.pytest_terminal_summary(terminalreporter=self, + exitstatus=exitstatus) self.summary_errors() self.summary_failures() self.summary_warnings() @@ -400,15 +498,15 @@ class TerminalReporter: line = self.config.cwd_relative_nodeid(nodeid) if domain and line.endswith(domain): line = line[:-len(domain)] - l = domain.split("[") - l[0] = l[0].replace('.', '::') # don't replace '.' in params - line += "[".join(l) + values = domain.split("[") + values[0] = values[0].replace('.', '::') # don't replace '.' in params + line += "[".join(values) return line # collect_fspath comes from testid which has a "/"-normalized path if fspath: res = mkrel(nodeid).replace("::()", "") # parens-normalization - if nodeid.split("::")[0] != fspath.replace("\\", "/"): + if nodeid.split("::")[0] != fspath.replace("\\", nodes.SEP): res += " <- " + self.startdir.bestrelpath(fspath) else: res = "[location]" @@ -419,7 +517,7 @@ class TerminalReporter: fspath, lineno, domain = rep.location return domain else: - return "test session" # XXX? + return "test session" # XXX? def _getcrashline(self, rep): try: @@ -434,21 +532,29 @@ class TerminalReporter: # summaries for sessionfinish # def getreports(self, name): - l = [] + values = [] for x in self.stats.get(name, []): if not hasattr(x, '_pdbshown'): - l.append(x) - return l + values.append(x) + return values def summary_warnings(self): if self.hasopt("w"): - warnings = self.stats.get("warnings") - if not warnings: + all_warnings = self.stats.get("warnings") + if not all_warnings: return - self.write_sep("=", "pytest-warning summary") - for w in warnings: - self._tw.line("W%s %s %s" % (w.code, - w.fslocation, w.message)) + + grouped = itertools.groupby(all_warnings, key=lambda wr: wr.get_location(self.config)) + + self.write_sep("=", "warnings summary", yellow=True, bold=False) + for location, warning_records in grouped: + self._tw.line(str(location) or '') + for w in warning_records: + lines = w.message.splitlines() + indented = '\n'.join(' ' + x for x in lines) + self._tw.line(indented) + self._tw.line() + self._tw.line('-- Docs: http://doc.pytest.org/en/latest/warnings.html') def summary_passes(self): if self.config.option.tbstyle != "no": @@ -462,6 +568,14 @@ class TerminalReporter: self.write_sep("_", msg) self._outrep_summary(rep) + def print_teardown_sections(self, rep): + for secname, content in rep.sections: + if 'teardown' in secname: + self._tw.sep('-', secname) + if content[-1:] == "\n": + content = content[:-1] + self._tw.line(content) + def summary_failures(self): if self.config.option.tbstyle != "no": reports = self.getreports('failed') @@ -477,6 +591,9 @@ class TerminalReporter: markup = {'red': True, 'bold': True} self.write_sep("_", msg, **markup) self._outrep_summary(rep) + for report in self.getreports(''): + if report.nodeid == rep.nodeid and report.when == 'teardown': + self.print_teardown_sections(report) def summary_errors(self): if self.config.option.tbstyle != "no": @@ -517,16 +634,9 @@ class TerminalReporter: def summary_deselected(self): if 'deselected' in self.stats: - l = [] - k = self.config.option.keyword - if k: - l.append("-k%s" % k) - m = self.config.option.markexpr - if m: - l.append("-m %r" % m) - if l: - self.write_sep("=", "%d tests deselected by %r" % ( - len(self.stats['deselected']), " ".join(l)), bold=True) + self.write_sep("=", "%d tests deselected" % ( + len(self.stats['deselected'])), bold=True) + def repr_pythonversion(v=None): if v is None: @@ -536,30 +646,30 @@ def repr_pythonversion(v=None): except (TypeError, ValueError): return str(v) -def flatten(l): - for x in l: + +def flatten(values): + for x in values: if isinstance(x, (list, tuple)): for y in flatten(x): yield y else: yield x + def build_summary_stats_line(stats): keys = ("failed passed skipped deselected " - "xfailed xpassed warnings error").split() - key_translation = {'warnings': 'pytest-warnings'} + "xfailed xpassed warnings error").split() unknown_key_seen = False for key in stats.keys(): if key not in keys: - if key: # setup/teardown reports have an empty key, ignore them + if key: # setup/teardown reports have an empty key, ignore them keys.append(key) unknown_key_seen = True parts = [] for key in keys: val = stats.get(key, None) if val: - key_name = key_translation.get(key, key) - parts.append("%d %s" % (len(val), key_name)) + parts.append("%d %s" % (len(val), key)) if parts: line = ", ".join(parts) @@ -579,7 +689,7 @@ def build_summary_stats_line(stats): def _plugin_nameversions(plugininfo): - l = [] + values = [] for plugin, dist in plugininfo: # gets us name and version! name = '{dist.project_name}-{dist.version}'.format(dist=dist) @@ -588,6 +698,6 @@ def _plugin_nameversions(plugininfo): name = name[7:] # we decided to print python package names # they can have more than one plugin - if name not in l: - l.append(name) - return l + if name not in values: + values.append(name) + return values diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/tmpdir.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/tmpdir.py similarity index 91% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/tmpdir.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/tmpdir.py index ebc48dbe5b2..da1b032237a 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/tmpdir.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/tmpdir.py @@ -1,9 +1,11 @@ """ support for providing temporary directories to test functions. """ +from __future__ import absolute_import, division, print_function + import re import pytest import py -from _pytest.monkeypatch import monkeypatch +from _pytest.monkeypatch import MonkeyPatch class TempdirFactory: @@ -23,7 +25,7 @@ class TempdirFactory: provides an empty unique-per-test-invocation directory and is guaranteed to be empty. """ - #py.log._apiwarn(">1.1", "use tmpdir function argument") + # py.log._apiwarn(">1.1", "use tmpdir function argument") return self.getbasetemp().ensure(string, dir=dir) def mktemp(self, basename, numbered=True): @@ -36,7 +38,7 @@ class TempdirFactory: p = basetemp.mkdir(basename) else: p = py.path.local.make_numbered_dir(prefix=basename, - keep=0, rootdir=basetemp, lock_timeout=None) + keep=0, rootdir=basetemp, lock_timeout=None) self.trace("mktemp", p) return p @@ -81,6 +83,7 @@ def get_user(): except (ImportError, KeyError): return None + # backward compatibility TempdirHandler = TempdirFactory @@ -92,7 +95,7 @@ def pytest_configure(config): available at pytest_configure time, but ideally should be moved entirely to the tmpdir_factory session fixture. """ - mp = monkeypatch() + mp = MonkeyPatch() t = TempdirFactory(config) config._cleanup.extend([mp.undo, t.finish]) mp.setattr(config, '_tmpdirhandler', t, raising=False) @@ -108,14 +111,14 @@ def tmpdir_factory(request): @pytest.fixture def tmpdir(request, tmpdir_factory): - """return a temporary directory path object + """Return a temporary directory path object which is unique to each test function invocation, created as a sub directory of the base temporary directory. The returned object is a `py.path.local`_ path object. """ name = request.node.name - name = re.sub("[\W]", "_", name) + name = re.sub(r"[\W]", "_", name) MAXVAL = 30 if len(name) > MAXVAL: name = name[:MAXVAL] diff --git a/tests/wpt/web-platform-tests/tools/pytest/_pytest/unittest.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/unittest.py similarity index 67% rename from tests/wpt/web-platform-tests/tools/pytest/_pytest/unittest.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/unittest.py index 8120e94fbf4..3ddb39495e3 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/_pytest/unittest.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/unittest.py @@ -1,14 +1,14 @@ """ discovery and running of std-library "unittest" style tests. """ -from __future__ import absolute_import +from __future__ import absolute_import, division, print_function import sys import traceback -import pytest -# for transfering markers +# for transferring markers import _pytest._code -from _pytest.python import transfer_markers -from _pytest.skipping import MarkEvaluator +from _pytest.config import hookimpl +from _pytest.outcomes import fail, skip, xfail +from _pytest.python import transfer_markers, Class, Module, Function def pytest_pycollect_makeitem(collector, name, obj): @@ -22,11 +22,11 @@ def pytest_pycollect_makeitem(collector, name, obj): return UnitTestCase(name, parent=collector) -class UnitTestCase(pytest.Class): +class UnitTestCase(Class): # marker for fixturemanger.getfixtureinfo() # to declare that our children do not support funcargs nofuncargs = True - + def setup(self): cls = self.obj if getattr(cls, '__unittest_skip__', False): @@ -46,10 +46,12 @@ class UnitTestCase(pytest.Class): return self.session._fixturemanager.parsefactories(self, unittest=True) loader = TestLoader() - module = self.getparent(pytest.Module).obj + module = self.getparent(Module).obj foundsomething = False for name in loader.getTestCaseNames(self.obj): x = getattr(self.obj, name) + if not getattr(x, '__test__', True): + continue funcobj = getattr(x, 'im_func', x) transfer_markers(funcobj, cls, module) yield TestCaseFunction(name, parent=self) @@ -63,8 +65,7 @@ class UnitTestCase(pytest.Class): yield TestCaseFunction('runTest', parent=self) - -class TestCaseFunction(pytest.Function): +class TestCaseFunction(Function): _excinfo = None def setup(self): @@ -92,6 +93,9 @@ class TestCaseFunction(pytest.Function): def teardown(self): if hasattr(self._testcase, 'teardown_method'): self._testcase.teardown_method(self._obj) + # Allow garbage collection on TestCase instance attributes. + self._testcase = None + self._obj = None def startTest(self, testcase): pass @@ -104,38 +108,38 @@ class TestCaseFunction(pytest.Function): except TypeError: try: try: - l = traceback.format_exception(*rawexcinfo) - l.insert(0, "NOTE: Incompatible Exception Representation, " - "displaying natively:\n\n") - pytest.fail("".join(l), pytrace=False) - except (pytest.fail.Exception, KeyboardInterrupt): + values = traceback.format_exception(*rawexcinfo) + values.insert(0, "NOTE: Incompatible Exception Representation, " + "displaying natively:\n\n") + fail("".join(values), pytrace=False) + except (fail.Exception, KeyboardInterrupt): raise - except: - pytest.fail("ERROR: Unknown Incompatible Exception " - "representation:\n%r" %(rawexcinfo,), pytrace=False) + except: # noqa + fail("ERROR: Unknown Incompatible Exception " + "representation:\n%r" % (rawexcinfo,), pytrace=False) except KeyboardInterrupt: raise - except pytest.fail.Exception: + except fail.Exception: excinfo = _pytest._code.ExceptionInfo() self.__dict__.setdefault('_excinfo', []).append(excinfo) def addError(self, testcase, rawexcinfo): self._addexcinfo(rawexcinfo) + def addFailure(self, testcase, rawexcinfo): self._addexcinfo(rawexcinfo) def addSkip(self, testcase, reason): try: - pytest.skip(reason) - except pytest.skip.Exception: - self._evalskip = MarkEvaluator(self, 'SkipTest') - self._evalskip.result = True + skip(reason) + except skip.Exception: + self._skipped_by_mark = True self._addexcinfo(sys.exc_info()) def addExpectedFailure(self, testcase, rawexcinfo, reason=""): try: - pytest.xfail(str(reason)) - except pytest.xfail.Exception: + xfail(str(reason)) + except xfail.Exception: self._addexcinfo(sys.exc_info()) def addUnexpectedSuccess(self, testcase, reason=""): @@ -147,17 +151,42 @@ class TestCaseFunction(pytest.Function): def stopTest(self, testcase): pass + def _handle_skip(self): + # implements the skipping machinery (see #2137) + # analog to pythons Lib/unittest/case.py:run + testMethod = getattr(self._testcase, self._testcase._testMethodName) + if (getattr(self._testcase.__class__, "__unittest_skip__", False) or + getattr(testMethod, "__unittest_skip__", False)): + # If the class or method was skipped. + skip_why = (getattr(self._testcase.__class__, '__unittest_skip_why__', '') or + getattr(testMethod, '__unittest_skip_why__', '')) + try: # PY3, unittest2 on PY2 + self._testcase._addSkip(self, self._testcase, skip_why) + except TypeError: # PY2 + if sys.version_info[0] != 2: + raise + self._testcase._addSkip(self, skip_why) + return True + return False + def runtest(self): - self._testcase(result=self) + if self.config.pluginmanager.get_plugin("pdbinvoke") is None: + self._testcase(result=self) + else: + # disables tearDown and cleanups for post mortem debugging (see #1890) + if self._handle_skip(): + return + self._testcase.debug() def _prunetraceback(self, excinfo): - pytest.Function._prunetraceback(self, excinfo) + Function._prunetraceback(self, excinfo) traceback = excinfo.traceback.filter( - lambda x:not x.frame.f_globals.get('__unittest')) + lambda x: not x.frame.f_globals.get('__unittest')) if traceback: excinfo.traceback = traceback -@pytest.hookimpl(tryfirst=True) + +@hookimpl(tryfirst=True) def pytest_runtest_makereport(item, call): if isinstance(item, TestCaseFunction): if item._excinfo: @@ -169,15 +198,17 @@ def pytest_runtest_makereport(item, call): # twisted trial support -@pytest.hookimpl(hookwrapper=True) + +@hookimpl(hookwrapper=True) def pytest_runtest_protocol(item): if isinstance(item, TestCaseFunction) and \ 'twisted.trial.unittest' in sys.modules: ut = sys.modules['twisted.python.failure'] Failure__init__ = ut.Failure.__init__ check_testcase_implements_trial_reporter() + def excstore(self, exc_value=None, exc_type=None, exc_tb=None, - captureVars=None): + captureVars=None): if exc_value is None: self._rawexcinfo = sys.exc_info() else: @@ -186,9 +217,10 @@ def pytest_runtest_protocol(item): self._rawexcinfo = (exc_type, exc_value, exc_tb) try: Failure__init__(self, exc_value, exc_type, exc_tb, - captureVars=captureVars) + captureVars=captureVars) except TypeError: Failure__init__(self, exc_value, exc_type, exc_tb) + ut.Failure.__init__ = excstore yield ut.Failure.__init__ = Failure__init__ diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/warnings.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/warnings.py new file mode 100644 index 00000000000..3c2b1914fb6 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/_pytest/warnings.py @@ -0,0 +1,96 @@ +from __future__ import absolute_import, division, print_function + +import warnings +from contextlib import contextmanager + +import pytest + +from _pytest import compat + + +def _setoption(wmod, arg): + """ + Copy of the warning._setoption function but does not escape arguments. + """ + parts = arg.split(':') + if len(parts) > 5: + raise wmod._OptionError("too many fields (max 5): %r" % (arg,)) + while len(parts) < 5: + parts.append('') + action, message, category, module, lineno = [s.strip() + for s in parts] + action = wmod._getaction(action) + category = wmod._getcategory(category) + if lineno: + try: + lineno = int(lineno) + if lineno < 0: + raise ValueError + except (ValueError, OverflowError): + raise wmod._OptionError("invalid lineno %r" % (lineno,)) + else: + lineno = 0 + wmod.filterwarnings(action, message, category, module, lineno) + + +def pytest_addoption(parser): + group = parser.getgroup("pytest-warnings") + group.addoption( + '-W', '--pythonwarnings', action='append', + help="set which warnings to report, see -W option of python itself.") + parser.addini("filterwarnings", type="linelist", + help="Each line specifies a pattern for " + "warnings.filterwarnings. " + "Processed after -W and --pythonwarnings.") + + +@contextmanager +def catch_warnings_for_item(item): + """ + catches the warnings generated during setup/call/teardown execution + of the given item and after it is done posts them as warnings to this + item. + """ + args = item.config.getoption('pythonwarnings') or [] + inifilters = item.config.getini("filterwarnings") + with warnings.catch_warnings(record=True) as log: + for arg in args: + warnings._setoption(arg) + + for arg in inifilters: + _setoption(warnings, arg) + + mark = item.get_marker('filterwarnings') + if mark: + for arg in mark.args: + warnings._setoption(arg) + + yield + + for warning in log: + warn_msg = warning.message + unicode_warning = False + + if compat._PY2 and any(isinstance(m, compat.UNICODE_TYPES) for m in warn_msg.args): + new_args = [] + for m in warn_msg.args: + new_args.append(compat.ascii_escaped(m) if isinstance(m, compat.UNICODE_TYPES) else m) + unicode_warning = list(warn_msg.args) != new_args + warn_msg.args = new_args + + msg = warnings.formatwarning( + warn_msg, warning.category, + warning.filename, warning.lineno, warning.line) + item.warn("unused", msg) + + if unicode_warning: + warnings.warn( + "Warning is using unicode non convertible to ascii, " + "converting to a safe representation:\n %s" % msg, + UnicodeWarning) + + +@pytest.hookimpl(hookwrapper=True) +def pytest_runtest_protocol(item): + with catch_warnings_for_item(item): + yield diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/appveyor.yml b/tests/wpt/web-platform-tests/tools/third_party/pytest/appveyor.yml new file mode 100644 index 00000000000..4f4afe15c38 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/appveyor.yml @@ -0,0 +1,44 @@ +environment: + COVERALLS_REPO_TOKEN: + secure: 2NJ5Ct55cHJ9WEg3xbSqCuv0rdgzzb6pnzOIG5OkMbTndw3wOBrXntWFoQrXiMFi + # this is pytest's token in coveralls.io, encrypted + # using pytestbot account as detailed here: + # https://www.appveyor.com/docs/build-configuration#secure-variables + + matrix: + # coveralls is not in the default env list + - TOXENV: "coveralls" + # note: please use "tox --listenvs" to populate the build matrix below + - TOXENV: "linting" + - TOXENV: "py27" + - TOXENV: "py34" + - TOXENV: "py35" + - TOXENV: "py36" + - TOXENV: "pypy" + - TOXENV: "py27-pexpect" + - TOXENV: "py27-xdist" + - TOXENV: "py27-trial" + - TOXENV: "py27-numpy" + - TOXENV: "py27-pluggymaster" + - TOXENV: "py36-pexpect" + - TOXENV: "py36-xdist" + - TOXENV: "py36-trial" + - TOXENV: "py36-numpy" + - TOXENV: "py36-pluggymaster" + - TOXENV: "py27-nobyte" + - TOXENV: "doctesting" + - TOXENV: "py35-freeze" + - TOXENV: "docs" + +install: + - echo Installed Pythons + - dir c:\Python* + + - if "%TOXENV%" == "pypy" call scripts\install-pypy.bat + + - C:\Python36\python -m pip install --upgrade --pre tox + +build: false # Not a C# project, build stuff at the test step instead. + +test_script: + - call scripts\call-tox.bat diff --git a/tests/wpt/web-platform-tests/tools/pytest/bench/bench.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/bench/bench.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/bench/bench.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/bench/bench.py diff --git a/tests/wpt/web-platform-tests/tools/pytest/bench/bench_argcomplete.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/bench/bench_argcomplete.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/bench/bench_argcomplete.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/bench/bench_argcomplete.py diff --git a/tests/wpt/web-platform-tests/tools/pytest/bench/empty.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/bench/empty.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/bench/empty.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/bench/empty.py diff --git a/tests/wpt/web-platform-tests/tools/pytest/bench/manyparam.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/bench/manyparam.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/bench/manyparam.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/bench/manyparam.py diff --git a/tests/wpt/web-platform-tests/tools/pytest/bench/skip.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/bench/skip.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/bench/skip.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/bench/skip.py diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/changelog/2920.bugfix b/tests/wpt/web-platform-tests/tools/third_party/pytest/changelog/2920.bugfix new file mode 100644 index 00000000000..9c5217278ae --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/changelog/2920.bugfix @@ -0,0 +1 @@ +Fix issue about ``-p no:`` having no effect. diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/changelog/2949.trivial b/tests/wpt/web-platform-tests/tools/third_party/pytest/changelog/2949.trivial new file mode 100644 index 00000000000..39789e72b7a --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/changelog/2949.trivial @@ -0,0 +1 @@ +Update github "bugs" link in CONTRIBUTING.rst diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/changelog/2956.bugfix b/tests/wpt/web-platform-tests/tools/third_party/pytest/changelog/2956.bugfix new file mode 100644 index 00000000000..13717657bf1 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/changelog/2956.bugfix @@ -0,0 +1 @@ +Fix regression with warnings that contained non-strings in their arguments in Python 2. diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/changelog/2957.bugfix b/tests/wpt/web-platform-tests/tools/third_party/pytest/changelog/2957.bugfix new file mode 100644 index 00000000000..589665b692a --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/changelog/2957.bugfix @@ -0,0 +1 @@ +Always escape null bytes when setting ``PYTEST_CURRENT_TEST``. diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/changelog/2963.doc b/tests/wpt/web-platform-tests/tools/third_party/pytest/changelog/2963.doc new file mode 100644 index 00000000000..c9a1d661b64 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/changelog/2963.doc @@ -0,0 +1 @@ +Fix broken link to plugin pytest-localserver. diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/changelog/2971.bugfix b/tests/wpt/web-platform-tests/tools/third_party/pytest/changelog/2971.bugfix new file mode 100644 index 00000000000..36684e8c880 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/changelog/2971.bugfix @@ -0,0 +1 @@ +Fix ``ZeroDivisionError`` when using the ``testmon`` plugin when no tests were actually collected. diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/changelog/2984.bugfix b/tests/wpt/web-platform-tests/tools/third_party/pytest/changelog/2984.bugfix new file mode 100644 index 00000000000..21f5748d523 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/changelog/2984.bugfix @@ -0,0 +1 @@ +Bring back ``TerminalReporter.writer`` as an alias to ``TerminalReporter._tw``. This alias was removed by accident in the ``3.3.0`` release. diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/changelog/_template.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/changelog/_template.rst new file mode 100644 index 00000000000..a898abc15af --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/changelog/_template.rst @@ -0,0 +1,40 @@ +{% for section in sections %} +{% set underline = "-" %} +{% if section %} +{{section}} +{{ underline * section|length }}{% set underline = "~" %} + +{% endif %} +{% if sections[section] %} +{% for category, val in definitions.items() if category in sections[section] %} + +{{ definitions[category]['name'] }} +{{ underline * definitions[category]['name']|length }} + +{% if definitions[category]['showcontent'] %} +{% for text, values in sections[section][category]|dictsort(by='value') %} +{% set issue_joiner = joiner(', ') %} +- {{ text }}{% if category != 'vendor' %} ({% for value in values|sort %}{{ issue_joiner() }}`{{ value }} `_{% endfor %}){% endif %} + + +{% endfor %} +{% else %} +- {{ sections[section][category]['']|sort|join(', ') }} + + +{% endif %} +{% if sections[section][category]|length == 0 %} + +No significant changes. + + +{% else %} +{% endif %} +{% endfor %} +{% else %} + +No significant changes. + + +{% endif %} +{% endfor %} diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/Makefile b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/Makefile similarity index 88% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/Makefile rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/Makefile index 8621f779c70..fa8e8266a29 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/Makefile +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/Makefile @@ -13,16 +13,18 @@ PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . REGENDOC_ARGS := \ - --normalize "/={8,} (.*) ={8,}/======= \1 ========/" \ - --normalize "/_{8,} (.*) _{8,}/_______ \1 ________/" \ --normalize "/in \d+.\d+ seconds/in 0.12 seconds/" \ --normalize "@/tmp/pytest-of-.*/pytest-\d+@PYTEST_TMPDIR@" \ - - + --normalize "@pytest-(\d+)\\.[^ ,]+@pytest-\1.x.y@" \ + --normalize "@(This is pytest version )(\d+)\\.[^ ,]+@\1\2.x.y@" \ + --normalize "@py-(\d+)\\.[^ ,]+@py-\1.x.y@" \ + --normalize "@pluggy-(\d+)\\.[.\d,]+@pluggy-\1.x.y@" \ + --normalize "@hypothesis-(\d+)\\.[.\d,]+@hypothesis-\1.x.y@" \ + --normalize "@Python (\d+)\\.[^ ,]+@Python \1.x.y@" .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest - + help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @@ -36,24 +38,8 @@ help: clean: -rm -rf $(BUILDDIR)/* -SITETARGET=$(shell ./_getdoctarget.py) - -showtarget: - @echo $(SITETARGET) - -install: html - # for access talk to someone with login rights to - # pytest-dev@pytest.org to add your ssh key - rsync -avz _build/html/ pytest-dev@pytest.org:pytest.org/$(SITETARGET) - -installpdf: latexpdf - @scp $(BUILDDIR)/latex/pytest.pdf pytest-dev@pytest.org:pytest.org/$(SITETARGET) - -installall: clean install installpdf - @echo "done" - regen: - PYTHONDONTWRITEBYTECODE=1 COLUMNS=76 regendoc --update *.rst */*.rst ${REGENDOC_ARGS} + PYTHONDONTWRITEBYTECODE=1 PYTEST_ADDOPT=-pno:hypothesis COLUMNS=76 regendoc --update *.rst */*.rst ${REGENDOC_ARGS} html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/_templates/globaltoc.html b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_templates/globaltoc.html similarity index 88% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/_templates/globaltoc.html rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_templates/globaltoc.html index af427198a62..fdd4dd59b32 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/_templates/globaltoc.html +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_templates/globaltoc.html @@ -9,6 +9,7 @@
  • Contact
  • Talks/Posts
  • Changelog
  • +
  • Backwards Compatibility
  • License
  • diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/_templates/layout.html b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_templates/layout.html similarity index 60% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/_templates/layout.html rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_templates/layout.html index 0ce480be300..2fc8e2a7fb4 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/_templates/layout.html +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_templates/layout.html @@ -1,19 +1,5 @@ {% extends "!layout.html" %} {% block header %} -
    -

    - Want to help improve pytest? Please - - contribute to - - or - - join - - our upcoming sprint in June 2016! - -

    -
    {{super()}} {% endblock %} {% block footer %} diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/_templates/links.html b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_templates/links.html similarity index 69% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/_templates/links.html rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_templates/links.html index 200258e165f..d855a013f34 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/_templates/links.html +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_templates/links.html @@ -1,16 +1,11 @@

    Useful Links

    diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/_templates/sidebarintro.html b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_templates/sidebarintro.html similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/_templates/sidebarintro.html rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_templates/sidebarintro.html diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/_themes/.gitignore b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_themes/.gitignore similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/_themes/.gitignore rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_themes/.gitignore diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/_themes/LICENSE b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_themes/LICENSE similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/_themes/LICENSE rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_themes/LICENSE diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/_themes/README b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_themes/README similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/_themes/README rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_themes/README diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/_themes/flask/layout.html b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_themes/flask/layout.html similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/_themes/flask/layout.html rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_themes/flask/layout.html diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/_themes/flask/relations.html b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_themes/flask/relations.html similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/_themes/flask/relations.html rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_themes/flask/relations.html diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/_themes/flask/static/flasky.css_t b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_themes/flask/static/flasky.css_t similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/_themes/flask/static/flasky.css_t rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_themes/flask/static/flasky.css_t diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/_themes/flask/theme.conf b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_themes/flask/theme.conf similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/_themes/flask/theme.conf rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_themes/flask/theme.conf diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/_themes/flask_theme_support.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_themes/flask_theme_support.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/_themes/flask_theme_support.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/_themes/flask_theme_support.py diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/adopt.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/adopt.rst similarity index 97% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/adopt.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/adopt.rst index aead96e7f3d..710f431be30 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/adopt.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/adopt.rst @@ -1,3 +1,7 @@ +:orphan: + +.. warnings about this file not being included in any toctree will be suppressed by :orphan: + April 2015 is "adopt pytest month" ============================================= diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/index.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/index.rst similarity index 67% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/index.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/index.rst index 877afff7777..1a5f3760b68 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/index.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/index.rst @@ -5,8 +5,29 @@ Release announcements .. toctree:: :maxdepth: 2 - + + release-3.3.0 + release-3.2.5 + release-3.2.4 + release-3.2.3 + release-3.2.2 + release-3.2.1 + release-3.2.0 + release-3.1.3 + release-3.1.2 + release-3.1.1 + release-3.1.0 + release-3.0.7 + release-3.0.6 + release-3.0.5 + release-3.0.4 + release-3.0.3 + release-3.0.2 + release-3.0.1 + release-3.0.0 sprint2016 + release-2.9.2 + release-2.9.1 release-2.9.0 release-2.8.7 release-2.8.6 @@ -45,4 +66,3 @@ Release announcements release-2.0.2 release-2.0.1 release-2.0.0 - diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.0.0.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.0.0.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.0.0.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.0.0.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.0.1.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.0.1.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.0.1.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.0.1.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.0.2.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.0.2.rst similarity index 95% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.0.2.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.0.2.rst index 733a9f7bdd8..f1f44f34f4f 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.0.2.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.0.2.rst @@ -63,9 +63,9 @@ Changes between 2.0.1 and 2.0.2 this. - fixed typos in the docs (thanks Victor Garcia, Brianna Laugher) and particular - thanks to Laura Creighton who also revieved parts of the documentation. + thanks to Laura Creighton who also reviewed parts of the documentation. -- fix slighly wrong output of verbose progress reporting for classes +- fix slightly wrong output of verbose progress reporting for classes (thanks Amaury) - more precise (avoiding of) deprecation warnings for node.Class|Function accesses diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.0.3.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.0.3.rst similarity index 90% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.0.3.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.0.3.rst index ed746e8519b..9bbfdaab361 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.0.3.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.0.3.rst @@ -13,7 +13,7 @@ If you want to install or upgrade pytest, just type one of:: easy_install -U pytest There also is a bugfix release 1.6 of pytest-xdist, the plugin -that enables seemless distributed and "looponfail" testing for Python. +that enables seamless distributed and "looponfail" testing for Python. best, holger krekel @@ -33,7 +33,7 @@ Changes between 2.0.2 and 2.0.3 - don't require zlib (and other libs) for genscript plugin without --genscript actually being used. -- speed up skips (by not doing a full traceback represenation +- speed up skips (by not doing a full traceback representation internally) - fix issue37: avoid invalid characters in junitxml's output diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.1.0.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.1.0.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.1.0.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.1.0.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.1.1.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.1.1.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.1.1.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.1.1.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.1.2.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.1.2.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.1.2.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.1.2.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.1.3.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.1.3.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.1.3.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.1.3.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.2.0.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.2.0.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.2.0.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.2.0.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.2.1.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.2.1.rst similarity index 95% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.2.1.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.2.1.rst index f9764634c72..5d28bcb01f4 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.2.1.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.2.1.rst @@ -2,7 +2,7 @@ pytest-2.2.1: bug fixes, perfect teardowns =========================================================================== -pytest-2.2.1 is a minor backward-compatible release of the the py.test +pytest-2.2.1 is a minor backward-compatible release of the py.test testing tool. It contains bug fixes and little improvements, including documentation fixes. If you are using the distributed testing pluginmake sure to upgrade it to pytest-xdist-1.8. diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.2.2.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.2.2.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.2.2.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.2.2.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.2.4.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.2.4.rst similarity index 96% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.2.4.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.2.4.rst index 8720bdb28a7..67f0feb27c7 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.2.4.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.2.4.rst @@ -29,7 +29,7 @@ Changes between 2.2.3 and 2.2.4 - fix issue with unittest: now @unittest.expectedFailure markers should be processed correctly (you can also use @pytest.mark markers) - document integration with the extended distribute/setuptools test commands -- fix issue 140: propperly get the real functions +- fix issue 140: properly get the real functions of bound classmethods for setup/teardown_class - fix issue #141: switch from the deceased paste.pocoo.org to bpaste.net - fix issue #143: call unconfigure/sessionfinish always when diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.3.0.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.3.0.rst similarity index 97% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.3.0.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.3.0.rst index 54fe3961fd8..f863aad0ace 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.3.0.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.3.0.rst @@ -89,7 +89,7 @@ Changes between 2.2.4 and 2.3.0 - fix issue128: show captured output when capsys/capfd are used -- fix issue179: propperly show the dependency chain of factories +- fix issue179: properly show the dependency chain of factories - pluginmanager.register(...) now raises ValueError if the plugin has been already registered or the name is taken @@ -130,5 +130,5 @@ Changes between 2.2.4 and 2.3.0 - don't show deselected reason line if there is none - - py.test -vv will show all of assert comparisations instead of truncating + - py.test -vv will show all of assert comparisons instead of truncating diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.3.1.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.3.1.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.3.1.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.3.1.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.3.2.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.3.2.rst similarity index 97% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.3.2.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.3.2.rst index 948b374d43b..75312b429cd 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.3.2.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.3.2.rst @@ -1,7 +1,7 @@ pytest-2.3.2: some fixes and more traceback-printing speed =========================================================================== -pytest-2.3.2 is a another stabilization release: +pytest-2.3.2 is another stabilization release: - issue 205: fixes a regression with conftest detection - issue 208/29: fixes traceback-printing speed in some bad cases diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.3.3.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.3.3.rst similarity index 90% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.3.3.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.3.3.rst index 1d7c7027bed..3a48b6ac4ba 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.3.3.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.3.3.rst @@ -1,7 +1,7 @@ -pytest-2.3.3: integration fixes, py24 suport, ``*/**`` shown in traceback +pytest-2.3.3: integration fixes, py24 support, ``*/**`` shown in traceback =========================================================================== -pytest-2.3.3 is a another stabilization release of the py.test tool +pytest-2.3.3 is another stabilization release of the py.test tool which offers uebersimple assertions, scalable fixture mechanisms and deep customization for testing with Python. Particularly, this release provides: @@ -46,7 +46,7 @@ Changes between 2.3.2 and 2.3.3 - fix issue209 - reintroduce python2.4 support by depending on newer pylib which re-introduced statement-finding for pre-AST interpreters -- nose support: only call setup if its a callable, thanks Andrew +- nose support: only call setup if it's a callable, thanks Andrew Taumoefolau - fix issue219 - add py2.4-3.3 classifiers to TROVE list diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.3.4.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.3.4.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.3.4.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.3.4.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.3.5.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.3.5.rst similarity index 93% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.3.5.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.3.5.rst index c4e91e0e614..112399ef3ca 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.3.5.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.3.5.rst @@ -44,11 +44,11 @@ Changes between 2.3.4 and 2.3.5 (thanks Adam Goucher) - Issue 265 - integrate nose setup/teardown with setupstate - so it doesnt try to teardown if it did not setup + so it doesn't try to teardown if it did not setup -- issue 271 - dont write junitxml on slave nodes +- issue 271 - don't write junitxml on slave nodes -- Issue 274 - dont try to show full doctest example +- Issue 274 - don't try to show full doctest example when doctest does not know the example location - issue 280 - disable assertion rewriting on buggy CPython 2.6.0 @@ -84,7 +84,7 @@ Changes between 2.3.4 and 2.3.5 - allow to specify prefixes starting with "_" when customizing python_functions test discovery. (thanks Graham Horler) -- improve PYTEST_DEBUG tracing output by puting +- improve PYTEST_DEBUG tracing output by putting extra data on a new lines with additional indent - ensure OutcomeExceptions like skip/fail have initialized exception attributes diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.4.0.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.4.0.rst similarity index 98% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.4.0.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.4.0.rst index 88130c481f1..be3aaedb09f 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.4.0.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.4.0.rst @@ -36,7 +36,7 @@ a full list of details. A few feature highlights: - reporting: color the last line red or green depending if failures/errors occurred or everything passed. -The documentation has been updated to accomodate the changes, +The documentation has been updated to accommodate the changes, see `http://pytest.org `_ To install or upgrade pytest:: @@ -118,7 +118,7 @@ new features: - fix issue322: tearDownClass is not run if setUpClass failed. Thanks Mathieu Agopian for the initial fix. Also make all of pytest/nose - finalizer mimick the same generic behaviour: if a setupX exists and + finalizer mimic the same generic behaviour: if a setupX exists and fails, don't run teardownX. This internally introduces a new method "node.addfinalizer()" helper which can only be called during the setup phase of a node. diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.4.1.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.4.1.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.4.1.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.4.1.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.4.2.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.4.2.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.4.2.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.4.2.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.5.0.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.5.0.rst similarity index 98% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.5.0.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.5.0.rst index b8f28d6fd5e..b04a825cd8e 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.5.0.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.5.0.rst @@ -70,7 +70,7 @@ holger krekel to problems for more than >966 non-function scoped parameters). - fix issue290 - there is preliminary support now for parametrizing - with repeated same values (sometimes useful to to test if calling + with repeated same values (sometimes useful to test if calling a second time works as with the first time). - close issue240 - document precisely how pytest module importing @@ -149,7 +149,7 @@ holger krekel would not work correctly because pytest assumes @pytest.mark.some gets a function to be decorated already. We now at least detect if this - arg is an lambda and thus the example will work. Thanks Alex Gaynor + arg is a lambda and thus the example will work. Thanks Alex Gaynor for bringing it up. - xfail a test on pypy that checks wrong encoding/ascii (pypy does diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.5.1.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.5.1.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.5.1.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.5.1.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.5.2.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.5.2.rst similarity index 96% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.5.2.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.5.2.rst index 9308ffdd626..d5cfca2dbda 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.5.2.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.5.2.rst @@ -60,5 +60,5 @@ holger krekel - fix issue429: comparing byte strings with non-ascii chars in assert expressions now work better. Thanks Floris Bruynooghe. -- make capfd/capsys.capture private, its unused and shouldnt be exposed +- make capfd/capsys.capture private, its unused and shouldn't be exposed diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.6.0.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.6.0.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.6.0.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.6.0.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.6.1.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.6.1.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.6.1.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.6.1.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.6.2.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.6.2.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.6.2.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.6.2.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.6.3.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.6.3.rst similarity index 91% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.6.3.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.6.3.rst index 13fae31b8a1..ee0d2692c47 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.6.3.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.6.3.rst @@ -41,8 +41,8 @@ Changes 2.6.3 dep). Thanks Charles Cloud for analysing the issue. - fix conftest related fixture visibility issue: when running with a - CWD outside a test package pytest would get fixture discovery wrong. - Thanks to Wolfgang Schnerring for figuring out a reproducable example. + CWD outside of a test package pytest would get fixture discovery wrong. + Thanks to Wolfgang Schnerring for figuring out a reproducible example. - Introduce pytest_enter_pdb hook (needed e.g. by pytest_timeout to cancel the timeout when interactively entering pdb). Thanks Wolfgang Schnerring. diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.7.0.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.7.0.rst similarity index 98% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.7.0.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.7.0.rst index 07ae44ca1ac..4e317ff8f34 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.7.0.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.7.0.rst @@ -62,7 +62,7 @@ holger krekel - fix issue655: work around different ways that cause python2/3 to leak sys.exc_info into fixtures/tests causing failures in 3rd party code -- fix issue615: assertion re-writing did not correctly escape % signs +- fix issue615: assertion rewriting did not correctly escape % signs when formatting boolean operations, which tripped over mixing booleans with modulo operators. Thanks to Tom Viner for the report, triaging and fix. diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.7.1.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.7.1.rst similarity index 96% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.7.1.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.7.1.rst index cd37cad0cb8..fdc71eebba9 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.7.1.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.7.1.rst @@ -32,7 +32,7 @@ The py.test Development Team explanations. Thanks Carl Meyer for the report and test case. - fix issue553: properly handling inspect.getsourcelines failures in - FixtureLookupError which would lead to to an internal error, + FixtureLookupError which would lead to an internal error, obfuscating the original problem. Thanks talljosh for initial diagnose/patch and Bruno Oliveira for final patch. diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.7.2.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.7.2.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.7.2.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.7.2.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.8.2.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.8.2.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.8.2.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.8.2.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.8.3.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.8.3.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.8.3.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.8.3.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.8.4.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.8.4.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.8.4.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.8.4.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.8.5.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.8.5.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.8.5.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.8.5.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.8.6.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.8.6.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.8.6.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.8.6.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.8.7.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.8.7.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.8.7.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.8.7.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.9.0.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.9.0.rst similarity index 98% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.9.0.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.9.0.rst index 99c1c631f17..011b1ffb9d2 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.9.0.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.9.0.rst @@ -75,7 +75,7 @@ The py.test Development Team **Changes** -* **Important**: `py.code `_ has been +* **Important**: `py.code `_ has been merged into the ``pytest`` repository as ``pytest._code``. This decision was made because ``py.code`` had very few uses outside ``pytest`` and the fact that it was in a different repository made it difficult to fix bugs on @@ -88,7 +88,7 @@ The py.test Development Team **experimental**, so you definitely should not import it explicitly! Please note that the original ``py.code`` is still available in - `pylib `_. + `pylib `_. * ``pytest_enter_pdb`` now optionally receives the pytest config object. Thanks `@nicoddemus`_ for the PR. diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.9.1.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.9.1.rst similarity index 97% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.9.1.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.9.1.rst index 05a44843042..3277da1e9b0 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/announce/release-2.9.1.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.9.1.rst @@ -63,3 +63,5 @@ The py.test Development Team .. _#649: https://github.com/pytest-dev/pytest/issues/649 .. _@asottile: https://github.com/asottile +.. _@nicoddemus: https://github.com/nicoddemus +.. _@tomviner: https://github.com/tomviner diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.9.2.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.9.2.rst new file mode 100644 index 00000000000..8f274cdf398 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-2.9.2.rst @@ -0,0 +1,78 @@ +pytest-2.9.2 +============ + +pytest is a mature Python testing tool with more than a 1100 tests +against itself, passing on many different interpreters and platforms. + +See below for the changes and see docs at: + + http://pytest.org + +As usual, you can upgrade from pypi via:: + + pip install -U pytest + +Thanks to all who contributed to this release, among them: + + Adam Chainz + Benjamin Dopplinger + Bruno Oliveira + Florian Bruhin + John Towler + Martin Prusse + Meng Jue + MengJueM + Omar Kohl + Quentin Pradet + Ronny Pfannschmidt + Thomas Güttler + TomV + Tyler Goodlet + + +Happy testing, +The py.test Development Team + + +2.9.2 (compared to 2.9.1) +--------------------------- + +**Bug Fixes** + +* fix `#510`_: skip tests where one parameterize dimension was empty + thanks Alex Stapleton for the Report and `@RonnyPfannschmidt`_ for the PR + +* Fix Xfail does not work with condition keyword argument. + Thanks `@astraw38`_ for reporting the issue (`#1496`_) and `@tomviner`_ + for PR the (`#1524`_). + +* Fix win32 path issue when putting custom config file with absolute path + in ``pytest.main("-c your_absolute_path")``. + +* Fix maximum recursion depth detection when raised error class is not aware + of unicode/encoded bytes. + Thanks `@prusse-martin`_ for the PR (`#1506`_). + +* Fix ``pytest.mark.skip`` mark when used in strict mode. + Thanks `@pquentin`_ for the PR and `@RonnyPfannschmidt`_ for + showing how to fix the bug. + +* Minor improvements and fixes to the documentation. + Thanks `@omarkohl`_ for the PR. + +* Fix ``--fixtures`` to show all fixture definitions as opposed to just + one per fixture name. + Thanks to `@hackebrot`_ for the PR. + +.. _#510: https://github.com/pytest-dev/pytest/issues/510 +.. _#1506: https://github.com/pytest-dev/pytest/pull/1506 +.. _#1496: https://github.com/pytest-dev/pytest/issue/1496 +.. _#1524: https://github.com/pytest-dev/pytest/issue/1524 + +.. _@astraw38: https://github.com/astraw38 +.. _@hackebrot: https://github.com/hackebrot +.. _@omarkohl: https://github.com/omarkohl +.. _@pquentin: https://github.com/pquentin +.. _@prusse-martin: https://github.com/prusse-martin +.. _@RonnyPfannschmidt: https://github.com/RonnyPfannschmidt +.. _@tomviner: https://github.com/tomviner diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.0.0.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.0.0.rst new file mode 100644 index 00000000000..4bf1e8534ec --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.0.0.rst @@ -0,0 +1,82 @@ +pytest-3.0.0 +============ + +The pytest team is proud to announce the 3.0.0 release! + +pytest is a mature Python testing tool with more than a 1600 tests +against itself, passing on many different interpreters and platforms. + +This release contains a lot of bugs fixes and improvements, and much of +the work done on it was possible because of the 2016 Sprint[1], which +was funded by an indiegogo campaign which raised over US$12,000 with +nearly 100 backers. + +There's a "What's new in pytest 3.0" [2] blog post highlighting the +major features in this release. + +To see the complete changelog and documentation, please visit: + + http://docs.pytest.org + +As usual, you can upgrade from pypi via: + + pip install -U pytest + +Thanks to all who contributed to this release, among them: + + AbdealiJK + Ana Ribeiro + Antony Lee + Brandon W Maister + Brianna Laugher + Bruno Oliveira + Ceridwen + Christian Boelsen + Daniel Hahler + Danielle Jenkins + Dave Hunt + Diego Russo + Dmitry Dygalo + Edoardo Batini + Eli Boyarski + Florian Bruhin + Floris Bruynooghe + Greg Price + Guyzmo + HEAD KANGAROO + JJ + Javi Romero + Javier Domingo Cansino + Kale Kundert + Kalle Bronsen + Marius Gedminas + Matt Williams + Mike Lundy + Oliver Bestwalter + Omar Kohl + Raphael Pierzina + RedBeardCode + Roberto Polli + Romain Dorgueil + Roman Bolshakov + Ronny Pfannschmidt + Stefan Zimmermann + Steffen Allner + Tareq Alayan + Ted Xiao + Thomas Grainger + Tom Viner + TomV + Vasily Kuznetsov + aostr + marscher + palaviv + satoru + taschini + + +Happy testing, +The Pytest Development Team + +[1] http://blog.pytest.org/2016/pytest-development-sprint/ +[2] http://blog.pytest.org/2016/whats-new-in-pytest-30/ diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.0.1.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.0.1.rst new file mode 100644 index 00000000000..9fb38047b9c --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.0.1.rst @@ -0,0 +1,26 @@ +pytest-3.0.1 +============ + +pytest 3.0.1 has just been released to PyPI. + +This release fixes some regressions reported in version 3.0.0, being a +drop-in replacement. To upgrade: + + pip install --upgrade pytest + +The changelog is available at http://doc.pytest.org/en/latest/changelog.html. + +Thanks to all who contributed to this release, among them: + + Adam Chainz + Andrew Svetlov + Bruno Oliveira + Daniel Hahler + Dmitry Dygalo + Florian Bruhin + Marcin Bachry + Ronny Pfannschmidt + matthiasha + +Happy testing, +The py.test Development Team diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.0.2.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.0.2.rst new file mode 100644 index 00000000000..9d1c05f2d45 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.0.2.rst @@ -0,0 +1,24 @@ +pytest-3.0.2 +============ + +pytest 3.0.2 has just been released to PyPI. + +This release fixes some regressions and bugs reported in version 3.0.1, being a +drop-in replacement. To upgrade:: + + pip install --upgrade pytest + +The changelog is available at http://doc.pytest.org/en/latest/changelog.html. + +Thanks to all who contributed to this release, among them: + +* Ahn Ki-Wook +* Bruno Oliveira +* Florian Bruhin +* Jordan Guymon +* Raphael Pierzina +* Ronny Pfannschmidt +* mbyt + +Happy testing, +The pytest Development Team diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.0.3.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.0.3.rst new file mode 100644 index 00000000000..f00172195db --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.0.3.rst @@ -0,0 +1,27 @@ +pytest-3.0.3 +============ + +pytest 3.0.3 has just been released to PyPI. + +This release fixes some regressions and bugs reported in the last version, +being a drop-in replacement. To upgrade:: + + pip install --upgrade pytest + +The changelog is available at http://doc.pytest.org/en/latest/changelog.html. + +Thanks to all who contributed to this release, among them: + +* Bruno Oliveira +* Florian Bruhin +* Floris Bruynooghe +* Huayi Zhang +* Lev Maximov +* Raquel Alegre +* Ronny Pfannschmidt +* Roy Williams +* Tyler Goodlet +* mbyt + +Happy testing, +The pytest Development Team diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.0.4.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.0.4.rst new file mode 100644 index 00000000000..852057037dd --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.0.4.rst @@ -0,0 +1,29 @@ +pytest-3.0.4 +============ + +pytest 3.0.4 has just been released to PyPI. + +This release fixes some regressions and bugs reported in the last version, +being a drop-in replacement. To upgrade:: + + pip install --upgrade pytest + +The changelog is available at http://doc.pytest.org/en/latest/changelog.html. + +Thanks to all who contributed to this release, among them: + +* Bruno Oliveira +* Dan Wandschneider +* Florian Bruhin +* Georgy Dyuldin +* Grigorii Eremeev +* Jason R. Coombs +* Manuel Jacob +* Mathieu Clabaut +* Michael Seifert +* Nikolaus Rath +* Ronny Pfannschmidt +* Tom V + +Happy testing, +The pytest Development Team diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.0.5.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.0.5.rst new file mode 100644 index 00000000000..3e2419d7e5d --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.0.5.rst @@ -0,0 +1,27 @@ +pytest-3.0.5 +============ + +pytest 3.0.5 has just been released to PyPI. + +This is a bug-fix release, being a drop-in replacement. To upgrade:: + + pip install --upgrade pytest + +The changelog is available at http://doc.pytest.org/en/latest/changelog.html. + +Thanks to all who contributed to this release, among them: + +* Ana Vojnovic +* Bruno Oliveira +* Daniel Hahler +* Duncan Betts +* Igor Starikov +* Ismail +* Luke Murphy +* Ned Batchelder +* Ronny Pfannschmidt +* Sebastian Ramacher +* nmundar + +Happy testing, +The pytest Development Team diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.0.6.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.0.6.rst new file mode 100644 index 00000000000..2988b9cb3b8 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.0.6.rst @@ -0,0 +1,33 @@ +pytest-3.0.6 +============ + +pytest 3.0.6 has just been released to PyPI. + +This is a bug-fix release, being a drop-in replacement. To upgrade:: + + pip install --upgrade pytest + +The full changelog is available at http://doc.pytest.org/en/latest/changelog.html. + + +Thanks to all who contributed to this release, among them: + +* Andreas Pelme +* Bruno Oliveira +* Dmitry Malinovsky +* Eli Boyarski +* Jakub Wilk +* Jeff Widman +* Loïc Estève +* Luke Murphy +* Miro Hrončok +* Oscar Hellström +* Peter Heatwole +* Philippe Ombredanne +* Ronny Pfannschmidt +* Rutger Prins +* Stefan Scherfke + + +Happy testing, +The pytest Development Team diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.0.7.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.0.7.rst new file mode 100644 index 00000000000..591557aa787 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.0.7.rst @@ -0,0 +1,33 @@ +pytest-3.0.7 +============ + +pytest 3.0.7 has just been released to PyPI. + +This is a bug-fix release, being a drop-in replacement. To upgrade:: + + pip install --upgrade pytest + +The full changelog is available at http://doc.pytest.org/en/latest/changelog.html. + +Thanks to all who contributed to this release, among them: + +* Anthony Sottile +* Barney Gale +* Bruno Oliveira +* Florian Bruhin +* Floris Bruynooghe +* Ionel Cristian Mărieș +* Katerina Koukiou +* NODA, Kai +* Omer Hadari +* Patrick Hayes +* Ran Benita +* Ronny Pfannschmidt +* Victor Uriarte +* Vidar Tonaas Fauske +* Ville Skyttä +* fbjorn +* mbyt + +Happy testing, +The pytest Development Team diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.1.0.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.1.0.rst new file mode 100644 index 00000000000..99cc6bdbe20 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.1.0.rst @@ -0,0 +1,61 @@ +pytest-3.1.0 +======================================= + +The pytest team is proud to announce the 3.1.0 release! + +pytest is a mature Python testing tool with more than a 1600 tests +against itself, passing on many different interpreters and platforms. + +This release contains a bugs fixes and improvements, so users are encouraged +to take a look at the CHANGELOG: + +http://doc.pytest.org/en/latest/changelog.html + +For complete documentation, please visit: + + http://docs.pytest.org + +As usual, you can upgrade from pypi via: + + pip install -U pytest + +Thanks to all who contributed to this release, among them: + +* Anthony Sottile +* Ben Lloyd +* Bruno Oliveira +* David Giese +* David Szotten +* Dmitri Pribysh +* Florian Bruhin +* Florian Schulze +* Floris Bruynooghe +* John Towler +* Jonas Obrist +* Katerina Koukiou +* Kodi Arfer +* Krzysztof Szularz +* Lev Maximov +* Loïc Estève +* Luke Murphy +* Manuel Krebber +* Matthew Duck +* Matthias Bussonnier +* Michael Howitz +* Michal Wajszczuk +* Paweł Adamczak +* Rafael Bertoldi +* Ravi Chandra +* Ronny Pfannschmidt +* Skylar Downes +* Thomas Kriechbaumer +* Vitaly Lashmanov +* Vlad Dragos +* Wheerd +* Xander Johnson +* mandeep +* reut + + +Happy testing, +The Pytest Development Team diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.1.1.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.1.1.rst new file mode 100644 index 00000000000..370b8fd7355 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.1.1.rst @@ -0,0 +1,23 @@ +pytest-3.1.1 +======================================= + +pytest 3.1.1 has just been released to PyPI. + +This is a bug-fix release, being a drop-in replacement. To upgrade:: + + pip install --upgrade pytest + +The full changelog is available at http://doc.pytest.org/en/latest/changelog.html. + +Thanks to all who contributed to this release, among them: + +* Bruno Oliveira +* Florian Bruhin +* Floris Bruynooghe +* Jason R. Coombs +* Ronny Pfannschmidt +* wanghui + + +Happy testing, +The pytest Development Team diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.1.2.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.1.2.rst new file mode 100644 index 00000000000..60168a857ba --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.1.2.rst @@ -0,0 +1,23 @@ +pytest-3.1.2 +======================================= + +pytest 3.1.2 has just been released to PyPI. + +This is a bug-fix release, being a drop-in replacement. To upgrade:: + + pip install --upgrade pytest + +The full changelog is available at http://doc.pytest.org/en/latest/changelog.html. + +Thanks to all who contributed to this release, among them: + +* Andreas Pelme +* ApaDoctor +* Bruno Oliveira +* Florian Bruhin +* Ronny Pfannschmidt +* Segev Finer + + +Happy testing, +The pytest Development Team diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.1.3.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.1.3.rst new file mode 100644 index 00000000000..a55280626ba --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.1.3.rst @@ -0,0 +1,23 @@ +pytest-3.1.3 +======================================= + +pytest 3.1.3 has just been released to PyPI. + +This is a bug-fix release, being a drop-in replacement. To upgrade:: + + pip install --upgrade pytest + +The full changelog is available at http://doc.pytest.org/en/latest/changelog.html. + +Thanks to all who contributed to this release, among them: + +* Antoine Legrand +* Bruno Oliveira +* Max Moroz +* Raphael Pierzina +* Ronny Pfannschmidt +* Ryan Fitzpatrick + + +Happy testing, +The pytest Development Team diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.2.0.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.2.0.rst new file mode 100644 index 00000000000..4d2830edd2d --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.2.0.rst @@ -0,0 +1,48 @@ +pytest-3.2.0 +======================================= + +The pytest team is proud to announce the 3.2.0 release! + +pytest is a mature Python testing tool with more than a 1600 tests +against itself, passing on many different interpreters and platforms. + +This release contains a number of bugs fixes and improvements, so users are encouraged +to take a look at the CHANGELOG: + + http://doc.pytest.org/en/latest/changelog.html + +For complete documentation, please visit: + + http://docs.pytest.org + +As usual, you can upgrade from pypi via: + + pip install -U pytest + +Thanks to all who contributed to this release, among them: + +* Alex Hartoto +* Andras Tim +* Bruno Oliveira +* Daniel Hahler +* Florian Bruhin +* Floris Bruynooghe +* John Still +* Jordan Moldow +* Kale Kundert +* Lawrence Mitchell +* Llandy Riveron Del Risco +* Maik Figura +* Martin Altmayer +* Mihai Capotă +* Nathaniel Waisbrot +* Nguyễn Hồng Quân +* Pauli Virtanen +* Raphael Pierzina +* Ronny Pfannschmidt +* Segev Finer +* V.Kuznetsov + + +Happy testing, +The Pytest Development Team diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.2.1.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.2.1.rst new file mode 100644 index 00000000000..899ffcd4b4a --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.2.1.rst @@ -0,0 +1,22 @@ +pytest-3.2.1 +======================================= + +pytest 3.2.1 has just been released to PyPI. + +This is a bug-fix release, being a drop-in replacement. To upgrade:: + + pip install --upgrade pytest + +The full changelog is available at http://doc.pytest.org/en/latest/changelog.html. + +Thanks to all who contributed to this release, among them: + +* Alex Gaynor +* Bruno Oliveira +* Florian Bruhin +* Ronny Pfannschmidt +* Srinivas Reddy Thatiparthy + + +Happy testing, +The pytest Development Team diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.2.2.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.2.2.rst new file mode 100644 index 00000000000..599bf872775 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.2.2.rst @@ -0,0 +1,28 @@ +pytest-3.2.2 +======================================= + +pytest 3.2.2 has just been released to PyPI. + +This is a bug-fix release, being a drop-in replacement. To upgrade:: + + pip install --upgrade pytest + +The full changelog is available at http://doc.pytest.org/en/latest/changelog.html. + +Thanks to all who contributed to this release, among them: + +* Andreas Pelme +* Antonio Hidalgo +* Bruno Oliveira +* Felipe Dau +* Fernando Macedo +* Jesús Espino +* Joan Massich +* Joe Talbott +* Kirill Pinchuk +* Ronny Pfannschmidt +* Xuan Luong + + +Happy testing, +The pytest Development Team diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.2.3.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.2.3.rst new file mode 100644 index 00000000000..589374974d9 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.2.3.rst @@ -0,0 +1,23 @@ +pytest-3.2.3 +======================================= + +pytest 3.2.3 has just been released to PyPI. + +This is a bug-fix release, being a drop-in replacement. To upgrade:: + + pip install --upgrade pytest + +The full changelog is available at http://doc.pytest.org/en/latest/changelog.html. + +Thanks to all who contributed to this release, among them: + +* Bruno Oliveira +* Evan +* Joe Hamman +* Oliver Bestwalter +* Ronny Pfannschmidt +* Xuan Luong + + +Happy testing, +The pytest Development Team diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.2.4.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.2.4.rst new file mode 100644 index 00000000000..44bfcc27e29 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.2.4.rst @@ -0,0 +1,36 @@ +pytest-3.2.4 +======================================= + +pytest 3.2.4 has just been released to PyPI. + +This is a bug-fix release, being a drop-in replacement. To upgrade:: + + pip install --upgrade pytest + +The full changelog is available at http://doc.pytest.org/en/latest/changelog.html. + +Thanks to all who contributed to this release, among them: + +* Bruno Oliveira +* Christian Boelsen +* Christoph Buchner +* Daw-Ran Liou +* Florian Bruhin +* Franck Michea +* Leonard Lausen +* Matty G +* Owen Tuz +* Pavel Karateev +* Pierre GIRAUD +* Ronny Pfannschmidt +* Stephen Finucane +* Sviatoslav Abakumov +* Thomas Hisch +* Tom Dalton +* Xuan Luong +* Yorgos Pagles +* Семён Марьясин + + +Happy testing, +The pytest Development Team diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.2.5.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.2.5.rst new file mode 100644 index 00000000000..a520ce2b333 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.2.5.rst @@ -0,0 +1,18 @@ +pytest-3.2.5 +======================================= + +pytest 3.2.5 has just been released to PyPI. + +This is a bug-fix release, being a drop-in replacement. To upgrade:: + + pip install --upgrade pytest + +The full changelog is available at http://doc.pytest.org/en/latest/changelog.html. + +Thanks to all who contributed to this release, among them: + +* Bruno Oliveira + + +Happy testing, +The pytest Development Team diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.3.0.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.3.0.rst new file mode 100644 index 00000000000..e0740e7d592 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/release-3.3.0.rst @@ -0,0 +1,50 @@ +pytest-3.3.0 +======================================= + +The pytest team is proud to announce the 3.3.0 release! + +pytest is a mature Python testing tool with more than a 1600 tests +against itself, passing on many different interpreters and platforms. + +This release contains a number of bugs fixes and improvements, so users are encouraged +to take a look at the CHANGELOG: + + http://doc.pytest.org/en/latest/changelog.html + +For complete documentation, please visit: + + http://docs.pytest.org + +As usual, you can upgrade from pypi via: + + pip install -U pytest + +Thanks to all who contributed to this release, among them: + +* Anthony Sottile +* Bruno Oliveira +* Ceridwen +* Daniel Hahler +* Dirk Thomas +* Dmitry Malinovsky +* Florian Bruhin +* George Y. Kussumoto +* Hugo +* Jesús Espino +* Joan Massich +* Ofir +* OfirOshir +* Ronny Pfannschmidt +* Samuel Dion-Girardeau +* Srinivas Reddy Thatiparthy +* Sviatoslav Abakumov +* Tarcisio Fischer +* Thomas Hisch +* Tyler Goodlet +* hugovk +* je +* prokaktus + + +Happy testing, +The Pytest Development Team diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/sprint2016.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/sprint2016.rst new file mode 100644 index 00000000000..8e706589876 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/announce/sprint2016.rst @@ -0,0 +1,64 @@ +python testing sprint June 20th-26th 2016 +====================================================== + +.. image:: ../img/freiburg2.jpg + :width: 400 + +The pytest core group held the biggest sprint +in its history in June 2016, taking place in the black forest town Freiburg +in Germany. In February 2016 we started a `funding +campaign on Indiegogo to cover expenses +`_ The page also mentions +some preliminary topics: + +- improving pytest-xdist test scheduling to take into account + fixture setups and explicit user hints. + +- provide info on fixture dependencies during --collect-only + +- tying pytest-xdist to tox so that you can do "py.test -e py34" + to run tests in a particular tox-managed virtualenv. Also + look into making pytest-xdist use tox environments on + remote ssh-sides so that remote dependency management becomes + easier. + +- refactoring the fixture system so more people understand it :) + +- integrating PyUnit setup methods as autouse fixtures. + possibly adding ways to influence ordering of same-scoped + fixtures (so you can make a choice of which fixtures come + before others) + +- fixing bugs and issues from the tracker, really an endless source :) + + +Participants +-------------- + +Over 20 participants took part from 4 continents, including employees +from Splunk, Personalkollen, Cobe.io, FanDuel and Dolby. Some newcomers +mixed with developers who have worked on pytest since its beginning, and +of course everyone in between. + + +Sprint organisation, schedule +------------------------------- + +People arrived in Freiburg on the 19th, with sprint development taking +place on 20th, 21st, 22nd, 24th and 25th. On the 23rd we took a break +day for some hot hiking in the Black Forest. + +Sprint activity was organised heavily around pairing, with plenty of group +discusssions to take advantage of the high bandwidth, and lightning talks +as well. + + +Money / funding +--------------- + + +The Indiegogo campaign aimed for 11000 USD and in the end raised over +12000, to reimburse travel costs, pay for a sprint venue and catering. + +Excess money is reserved for further sprint/travel funding for pytest/tox +contributors. diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/assert.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/assert.rst similarity index 64% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/assert.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/assert.rst index e7f14e8bd1a..4a852978ed2 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/assert.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/assert.rst @@ -24,16 +24,16 @@ following:: to assert that your function returns a certain value. If this assertion fails you will see the return value of the function call:: - $ py.test test_assert1.py - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: - collected 1 items + $ pytest test_assert1.py + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: + collected 1 item - test_assert1.py F + test_assert1.py F [100%] - ======= FAILURES ======== - _______ test_function ________ + ================================= FAILURES ================================= + ______________________________ test_function _______________________________ def test_function(): > assert f() == 4 @@ -41,7 +41,7 @@ you will see the return value of the function call:: E + where 3 = f() test_assert1.py:5: AssertionError - ======= 1 failed in 0.12 seconds ======== + ========================= 1 failed in 0.12 seconds ========================= ``pytest`` has support for showing the values of the most common subexpressions including calls, attributes, comparisons, and binary and unary @@ -85,6 +85,15 @@ and if you need to have access to the actual exception info you may use:: the actual exception raised. The main attributes of interest are ``.type``, ``.value`` and ``.traceback``. +.. versionchanged:: 3.0 + +In the context manager form you may use the keyword argument +``message`` to specify a custom failure message:: + + >>> with raises(ZeroDivisionError, message="Expecting ZeroDivisionError"): + ... pass + ... Failed: Expecting ZeroDivisionError + If you want to write test code that works on Python 2.4 as well, you may also use two other ways to test for an expected exception:: @@ -110,6 +119,23 @@ exceptions your own code is deliberately raising, whereas using like documenting unfixed bugs (where the test describes what "should" happen) or bugs in dependencies. +Also, the context manager form accepts a ``match`` keyword parameter to test +that a regular expression matches on the string representation of an exception +(like the ``TestCase.assertRaisesRegexp`` method from ``unittest``):: + + import pytest + + def myfunc(): + raise ValueError("Exception 123 raised") + + def test_match(): + with pytest.raises(ValueError, match=r'.* 123 .*'): + myfunc() + +The regexp parameter of the ``match`` method is matched with the ``re.search`` +function. So in the above example ``match='123'`` would have worked as +well. + .. _`assertwarns`: @@ -141,22 +167,22 @@ when it encounters comparisons. For example:: if you run this module:: - $ py.test test_assert2.py - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: - collected 1 items + $ pytest test_assert2.py + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: + collected 1 item - test_assert2.py F + test_assert2.py F [100%] - ======= FAILURES ======== - _______ test_set_comparison ________ + ================================= FAILURES ================================= + ___________________________ test_set_comparison ____________________________ def test_set_comparison(): set1 = set("1308") set2 = set("8035") > assert set1 == set2 - E assert set(['0', '1', '3', '8']) == set(['0', '3', '5', '8']) + E AssertionError: assert {'0', '1', '3', '8'} == {'0', '3', '5', '8'} E Extra items in the left set: E '1' E Extra items in the right set: @@ -164,7 +190,7 @@ if you run this module:: E Use -v to get the full diff test_assert2.py:5: AssertionError - ======= 1 failed in 0.12 seconds ======== + ========================= 1 failed in 0.12 seconds ========================= Special comparisons are done for a number of cases: @@ -181,9 +207,10 @@ It is possible to add your own detailed explanations by implementing the ``pytest_assertrepr_compare`` hook. .. autofunction:: _pytest.hookspec.pytest_assertrepr_compare + :noindex: -As an example consider adding the following hook in a conftest.py which -provides an alternative explanation for ``Foo`` objects:: +As an example consider adding the following hook in a :ref:`conftest.py ` +file which provides an alternative explanation for ``Foo`` objects:: # content of conftest.py from test_foocompare import Foo @@ -195,7 +222,7 @@ provides an alternative explanation for ``Foo`` objects:: now, given this test module:: # content of test_foocompare.py - class Foo: + class Foo(object): def __init__(self, val): self.val = val @@ -210,10 +237,10 @@ now, given this test module:: you can run the test module and get the custom output defined in the conftest file:: - $ py.test -q test_foocompare.py - F - ======= FAILURES ======== - _______ test_compare ________ + $ pytest -q test_foocompare.py + F [100%] + ================================= FAILURES ================================= + _______________________________ test_compare _______________________________ def test_compare(): f1 = Foo(1) @@ -234,50 +261,29 @@ Advanced assertion introspection .. versionadded:: 2.1 -Reporting details about a failing assertion is achieved either by rewriting -assert statements before they are run or re-evaluating the assert expression and -recording the intermediate values. Which technique is used depends on the -location of the assert, ``pytest`` configuration, and Python version being used -to run ``pytest``. - -By default, ``pytest`` rewrites assert statements in test modules. -Rewritten assert statements put introspection information into the assertion failure message. -``pytest`` only rewrites test modules directly discovered by its test collection process, so -asserts in supporting modules which are not themselves test modules will not be -rewritten. +Reporting details about a failing assertion is achieved by rewriting assert +statements before they are run. Rewritten assert statements put introspection +information into the assertion failure message. ``pytest`` only rewrites test +modules directly discovered by its test collection process, so asserts in +supporting modules which are not themselves test modules will not be rewritten. .. note:: - ``pytest`` rewrites test modules on import. It does this by using an import - hook to write a new pyc files. Most of the time this works transparently. + ``pytest`` rewrites test modules on import by using an import + hook to write new ``pyc`` files. Most of the time this works transparently. However, if you are messing with import yourself, the import hook may - interfere. If this is the case, simply use ``--assert=reinterp`` or - ``--assert=plain``. Additionally, rewriting will fail silently if it cannot - write new pycs, i.e. in a read-only filesystem or a zipfile. + interfere. -If an assert statement has not been rewritten or the Python version is less than -2.6, ``pytest`` falls back on assert reinterpretation. In assert -reinterpretation, ``pytest`` walks the frame of the function containing the -assert statement to discover sub-expression results of the failing assert -statement. You can force ``pytest`` to always use assertion reinterpretation by -passing the ``--assert=reinterp`` option. + If this is the case you have two options: -Assert reinterpretation has a caveat not present with assert rewriting: If -evaluating the assert expression has side effects you may get a warning that the -intermediate values could not be determined safely. A common example of this -issue is an assertion which reads from a file:: + * Disable rewriting for a specific module by adding the string + ``PYTEST_DONT_REWRITE`` to its docstring. - assert f.read() != '...' + * Disable rewriting for all modules by using ``--assert=plain``. -If this assertion fails then the re-evaluation will probably succeed! -This is because ``f.read()`` will return an empty string when it is -called the second time during the re-evaluation. However, it is -easy to rewrite the assertion and avoid any trouble:: + Additionally, rewriting will fail silently if it cannot write new ``.pyc`` files, + i.e. in a read-only filesystem or a zipfile. - content = f.read() - assert content != '...' - -All assert introspection can be turned off by passing ``--assert=plain``. For further information, Benjamin Peterson wrote up `Behind the scenes of pytest's new assertion rewriting `_. @@ -287,3 +293,7 @@ For further information, Benjamin Peterson wrote up `Behind the scenes of pytest .. versionchanged:: 2.1 Introduce the ``--assert`` option. Deprecate ``--no-assert`` and ``--nomagic``. + +.. versionchanged:: 3.0 + Removes the ``--no-assert`` and ``--nomagic`` options. + Removes the ``--assert=reinterp`` option. diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/backwards-compatibility.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/backwards-compatibility.rst new file mode 100644 index 00000000000..84f2c43edaa --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/backwards-compatibility.rst @@ -0,0 +1,105 @@ +.. _backwards-compatibility: + +Backwards Compatibility Policy +============================== + +Keeping backwards compatibility has a very high priority in the pytest project. Although we have deprecated functionality over the years, most of it is still supported. All deprecations in pytest were done because simpler or more efficient ways of accomplishing the same tasks have emerged, making the old way of doing things unnecessary. + +With the pytest 3.0 release we introduced a clear communication scheme for when we will actually remove the old busted joint and politely ask you to use the new hotness instead, while giving you enough time to adjust your tests or raise concerns if there are valid reasons to keep deprecated functionality around. + +To communicate changes we are already issuing deprecation warnings, but they are not displayed by default. In pytest 3.0 we changed the default setting so that pytest deprecation warnings are displayed if not explicitly silenced (with ``--disable-pytest-warnings``). + +We will only remove deprecated functionality in major releases (e.g. if we deprecate something in 3.0 we will remove it in 4.0), and keep it around for at least two minor releases (e.g. if we deprecate something in 3.9 and 4.0 is the next release, we will not remove it in 4.0 but in 5.0). + + +Deprecation Roadmap +------------------- + +This page lists deprecated features and when we plan to remove them. It is important to list the feature, the version where it got deprecated and the version we plan to remove it. + +Following our deprecation policy, we should aim to keep features for *at least* two minor versions after it was considered deprecated. + + +Future Releases +~~~~~~~~~~~~~~~ + +3.4 +^^^ + +**Old style classes** + +Issue: `#2147 `_. + +Deprecated in ``3.2``. + +4.0 +^^^ + +**Yield tests** + +Deprecated in ``3.0``. + +**pytest-namespace hook** + +deprecated in ``3.2``. + +**Marks in parameter sets** + +Deprecated in ``3.2``. + +**--result-log** + +Deprecated in ``3.0``. + +See `#830 `_ for more information. Suggested alternative: `pytest-tap `_. + +**metafunc.addcall** + +Issue: `#2876 `_. + +Deprecated in ``3.3``. + +**pytest_plugins in non-toplevel conftests** + +There is a deep conceptual confusion as ``conftest.py`` files themselves are activated/deactivated based on path, but the plugins they depend on aren't. + +Issue: `#2639 `_. + +Not yet officially deprecated. + +**passing a single string to pytest.main()** + +Pass a list of strings to ``pytest.main()`` instead. + +Deprecated in ``3.1``. + +**[pytest] section in setup.cfg** + +Use ``[tool:pytest]`` instead for compatibility with other tools. + +Deprecated in ``3.0``. + +Past Releases +~~~~~~~~~~~~~ + +3.0 +^^^ + +* The following deprecated commandline options were removed: + + * ``--genscript``: no longer supported; + * ``--no-assert``: use ``--assert=plain`` instead; + * ``--nomagic``: use ``--assert=plain`` instead; + * ``--report``: use ``-r`` instead; + +* Removed all ``py.test-X*`` entry points. The versioned, suffixed entry points + were never documented and a leftover from a pre-virtualenv era. These entry + points also created broken entry points in wheels, so removing them also + removes a source of confusion for users. + + + +3.3 +^^^ + +* Dropped support for EOL Python 2.6 and 3.3. \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/bash-completion.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/bash-completion.rst similarity index 75% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/bash-completion.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/bash-completion.rst index b2a52fa637b..81fe62183fb 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/bash-completion.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/bash-completion.rst @@ -5,7 +5,7 @@ Setting up bash completion ========================== When using bash as your shell, ``pytest`` can use argcomplete -(https://argcomplete.readthedocs.org/) for auto-completion. +(https://argcomplete.readthedocs.io/) for auto-completion. For this ``argcomplete`` needs to be installed **and** enabled. Install argcomplete using:: @@ -18,11 +18,11 @@ For global activation of all argcomplete enabled python applications run:: For permanent (but not global) ``pytest`` activation, use:: - register-python-argcomplete py.test >> ~/.bashrc + register-python-argcomplete pytest >> ~/.bashrc For one-time activation of argcomplete for ``pytest`` only, use:: - eval "$(register-python-argcomplete py.test)" + eval "$(register-python-argcomplete pytest)" diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/builtin.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/builtin.rst similarity index 55% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/builtin.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/builtin.rst index b18c3f8280a..d11eb5606e0 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/builtin.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/builtin.rst @@ -35,6 +35,11 @@ Examples at :ref:`assertraises`. .. autofunction:: deprecated_call +Comparing floating point numbers +-------------------------------- + +.. autofunction:: approx + Raising a specific test outcome -------------------------------------- @@ -42,24 +47,24 @@ You can use the following functions in your test, fixture or setup functions to force a certain test outcome. Note that most often you can rather use declarative marks, see :ref:`skipping`. -.. autofunction:: _pytest.runner.fail -.. autofunction:: _pytest.runner.skip -.. autofunction:: _pytest.runner.importorskip -.. autofunction:: _pytest.skipping.xfail -.. autofunction:: _pytest.runner.exit +.. autofunction:: _pytest.outcomes.fail +.. autofunction:: _pytest.outcomes.skip +.. autofunction:: _pytest.outcomes.importorskip +.. autofunction:: _pytest.outcomes.xfail +.. autofunction:: _pytest.outcomes.exit -fixtures and requests +Fixtures and requests ----------------------------------------------------- To mark a fixture function: -.. autofunction:: _pytest.python.fixture +.. autofunction:: _pytest.fixtures.fixture Tutorial at :ref:`fixtures`. The ``request`` object that can be used from fixture functions. -.. autoclass:: _pytest.python.FixtureRequest() +.. autoclass:: _pytest.fixtures.FixtureRequest() :members: @@ -72,7 +77,7 @@ Builtin fixtures/function arguments You can ask for available builtin or project-custom :ref:`fixtures ` by typing:: - $ py.test -q --fixtures + $ pytest -q --fixtures cache Return a cache object that can persist state between testing sessions. @@ -84,36 +89,58 @@ You can ask for available builtin or project-custom Values can be any object handled by the json stdlib module. capsys - enables capturing of writes to sys.stdout/sys.stderr and makes + Enable capturing of writes to sys.stdout/sys.stderr and make captured output available via ``capsys.readouterr()`` method calls - which return a ``(out, err)`` tuple. + which return a ``(out, err)`` tuple. ``out`` and ``err`` will be ``text`` + objects. + capsysbinary + Enable capturing of writes to sys.stdout/sys.stderr and make + captured output available via ``capsys.readouterr()`` method calls + which return a ``(out, err)`` tuple. ``out`` and ``err`` will be ``bytes`` + objects. capfd - enables capturing of writes to file descriptors 1 and 2 and makes + Enable capturing of writes to file descriptors 1 and 2 and make captured output available via ``capfd.readouterr()`` method calls - which return a ``(out, err)`` tuple. - record_xml_property - Fixture that adds extra xml properties to the tag for the calling test. - The fixture is callable with (name, value), with value being automatically - xml-encoded. - monkeypatch - The returned ``monkeypatch`` funcarg provides these - helper methods to modify objects, dictionaries or os.environ:: - - monkeypatch.setattr(obj, name, value, raising=True) - monkeypatch.delattr(obj, name, raising=True) - monkeypatch.setitem(mapping, name, value) - monkeypatch.delitem(obj, name, raising=True) - monkeypatch.setenv(name, value, prepend=False) - monkeypatch.delenv(name, value, raising=True) - monkeypatch.syspath_prepend(path) - monkeypatch.chdir(path) - - All modifications will be undone after the requesting - test function has finished. The ``raising`` - parameter determines if a KeyError or AttributeError - will be raised if the set/deletion operation has no target. + which return a ``(out, err)`` tuple. ``out`` and ``err`` will be ``text`` + objects. + capfdbinary + Enable capturing of write to file descriptors 1 and 2 and make + captured output available via ``capfdbinary.readouterr`` method calls + which return a ``(out, err)`` tuple. ``out`` and ``err`` will be + ``bytes`` objects. + doctest_namespace + Inject names into the doctest namespace. pytestconfig the pytest config object with access to command line opts. + record_xml_property + Add extra xml properties to the tag for the calling test. + The fixture is callable with ``(name, value)``, with value being automatically + xml-encoded. + caplog + Access and control log capturing. + + Captured logs are available through the following methods:: + + * caplog.text() -> string containing formatted log output + * caplog.records() -> list of logging.LogRecord instances + * caplog.record_tuples() -> list of (logger_name, level, message) tuples + monkeypatch + The returned ``monkeypatch`` fixture provides these + helper methods to modify objects, dictionaries or os.environ:: + + monkeypatch.setattr(obj, name, value, raising=True) + monkeypatch.delattr(obj, name, raising=True) + monkeypatch.setitem(mapping, name, value) + monkeypatch.delitem(obj, name, raising=True) + monkeypatch.setenv(name, value, prepend=False) + monkeypatch.delenv(name, value, raising=True) + monkeypatch.syspath_prepend(path) + monkeypatch.chdir(path) + + All modifications will be undone after the requesting + test function or fixture has finished. The ``raising`` + parameter determines if a KeyError or AttributeError + will be raised if the set/deletion operation has no target. recwarn Return a WarningsRecorder instance that provides these methods: @@ -125,7 +152,7 @@ You can ask for available builtin or project-custom tmpdir_factory Return a TempdirFactory instance for the test session. tmpdir - return a temporary directory path object + Return a temporary directory path object which is unique to each test function invocation, created as a sub directory of the base temporary directory. The returned object is a `py.path.local`_ diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/cache.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/cache.rst similarity index 63% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/cache.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/cache.rst index 52abb52a0df..c88721b11b0 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/cache.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/cache.rst @@ -1,21 +1,17 @@ +.. _`cache_provider`: +.. _cache: + + Cache: working with cross-testrun state ======================================= .. versionadded:: 2.8 -.. warning:: - - The functionality of this core plugin was previously distributed - as a third party plugin named ``pytest-cache``. The core plugin - is compatible regarding command line options and API usage except that you - can only store/receive data between test runs that is json-serializable. - - Usage --------- The plugin provides two command line options to rerun failures from the -last ``py.test`` invocation: +last ``pytest`` invocation: * ``--lf``, ``--last-failed`` - to only re-run the failures. * ``--ff``, ``--failed-first`` - to run the failures first and then the rest of @@ -25,7 +21,7 @@ For cleanup (usually not needed), a ``--cache-clear`` option allows to remove all cross-session cache contents ahead of a test run. Other plugins may access the `config.cache`_ object to set/get -**json encodable** values between ``py.test`` invocations. +**json encodable** values between ``pytest`` invocations. .. note:: @@ -49,10 +45,10 @@ First, let's create 50 test invocation of which only 2 fail:: If you run this for the first time you will see two failures:: - $ py.test -q - .................F.......F........................ - ======= FAILURES ======== - _______ test_num[17] ________ + $ pytest -q + .................F.......F........................ [100%] + ================================= FAILURES ================================= + _______________________________ test_num[17] _______________________________ i = 17 @@ -63,7 +59,7 @@ If you run this for the first time you will see two failures:: E Failed: bad luck test_50.py:6: Failed - _______ test_num[25] ________ + _______________________________ test_num[25] _______________________________ i = 25 @@ -78,17 +74,17 @@ If you run this for the first time you will see two failures:: If you then run it with ``--lf``:: - $ py.test --lf - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - run-last-failure: rerun last 2 failures - rootdir: $REGENDOC_TMPDIR, inifile: + $ pytest --lf + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: collected 50 items + run-last-failure: rerun previous 2 failures - test_50.py FF + test_50.py FF [100%] - ======= FAILURES ======== - _______ test_num[17] ________ + ================================= FAILURES ================================= + _______________________________ test_num[17] _______________________________ i = 17 @@ -99,7 +95,7 @@ If you then run it with ``--lf``:: E Failed: bad luck test_50.py:6: Failed - _______ test_num[25] ________ + _______________________________ test_num[25] _______________________________ i = 25 @@ -110,7 +106,8 @@ If you then run it with ``--lf``:: E Failed: bad luck test_50.py:6: Failed - ======= 2 failed, 48 deselected in 0.12 seconds ======== + =========================== 48 tests deselected ============================ + ================= 2 failed, 48 deselected in 0.12 seconds ================== You have run only the two failing test from the last run, while 48 tests have not been run ("deselected"). @@ -119,17 +116,17 @@ Now, if you run with the ``--ff`` option, all tests will be run but the first previous failures will be executed first (as can be seen from the series of ``FF`` and dots):: - $ py.test --ff - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - run-last-failure: rerun last 2 failures first - rootdir: $REGENDOC_TMPDIR, inifile: + $ pytest --ff + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: collected 50 items + run-last-failure: rerun previous 2 failures first - test_50.py FF................................................ + test_50.py FF................................................ [100%] - ======= FAILURES ======== - _______ test_num[17] ________ + ================================= FAILURES ================================= + _______________________________ test_num[17] _______________________________ i = 17 @@ -140,7 +137,7 @@ of ``FF`` and dots):: E Failed: bad luck test_50.py:6: Failed - _______ test_num[25] ________ + _______________________________ test_num[25] _______________________________ i = 25 @@ -151,7 +148,7 @@ of ``FF`` and dots):: E Failed: bad luck test_50.py:6: Failed - ======= 2 failed, 48 passed in 0.12 seconds ======== + =================== 2 failed, 48 passed in 0.12 seconds ==================== .. _`config.cache`: @@ -163,7 +160,7 @@ The new config.cache object Plugins or conftest.py support code can get a cached value using the pytest ``config`` object. Here is a basic example plugin which implements a :ref:`fixture` which re-uses previously created state -across py.test invocations:: +across pytest invocations:: # content of test_caching.py import pytest @@ -184,10 +181,10 @@ across py.test invocations:: If you run this command once, it will take a while because of the sleep:: - $ py.test -q - F - ======= FAILURES ======== - _______ test_function ________ + $ pytest -q + F [100%] + ================================= FAILURES ================================= + ______________________________ test_function _______________________________ mydata = 42 @@ -201,10 +198,10 @@ of the sleep:: If you run it a second time the value will be retrieved from the cache and this will be quick:: - $ py.test -q - F - ======= FAILURES ======== - _______ test_function ________ + $ pytest -q + F [100%] + ================================= FAILURES ================================= + ______________________________ test_function _______________________________ mydata = 42 @@ -222,27 +219,20 @@ Inspecting Cache content ------------------------------- You can always peek at the content of the cache using the -``--cache-clear`` command line option:: +``--cache-show`` command line option:: - $ py.test --cache-clear - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: - collected 1 items + $ py.test --cache-show + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: + cachedir: $REGENDOC_TMPDIR/.cache + ------------------------------- cache values ------------------------------- + cache/lastfailed contains: + {'test_caching.py::test_function': True} + example/value contains: + 42 - test_caching.py F - - ======= FAILURES ======== - _______ test_function ________ - - mydata = 42 - - def test_function(mydata): - > assert mydata == 23 - E assert 42 == 23 - - test_caching.py:14: AssertionError - ======= 1 failed in 0.12 seconds ======== + ======================= no tests ran in 0.12 seconds ======================= Clearing Cache content ------------------------------- @@ -250,9 +240,9 @@ Clearing Cache content You can instruct pytest to clear all cache files and values by adding the ``--cache-clear`` option like this:: - py.test --cache-clear + pytest --cache-clear -This is recommended for invocations from Continous Integration +This is recommended for invocations from Continuous Integration servers where isolation and correctness is more important than speed. diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/capture.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/capture.rst similarity index 61% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/capture.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/capture.rst index 8892f5be756..a87b57f8fc0 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/capture.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/capture.rst @@ -36,9 +36,9 @@ There are two ways in which ``pytest`` can perform capturing: You can influence output capturing mechanisms from the command line:: - py.test -s # disable all capturing - py.test --capture=sys # replace sys.stdout/stderr with in-mem files - py.test --capture=fd # also point filedescriptors 1 and 2 to temp file + pytest -s # disable all capturing + pytest --capture=sys # replace sys.stdout/stderr with in-mem files + pytest --capture=fd # also point filedescriptors 1 and 2 to temp file .. _printdebugging: @@ -62,16 +62,16 @@ is that you can use print statements for debugging:: and running this module will show you precisely the output of the failing function and hide the other one:: - $ py.test - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: + $ pytest + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items - test_module.py .F + test_module.py .F [100%] - ======= FAILURES ======== - _______ test_func2 ________ + ================================= FAILURES ================================= + ________________________________ test_func2 ________________________________ def test_func2(): > assert False @@ -80,14 +80,14 @@ of the failing function and hide the other one:: test_module.py:9: AssertionError -------------------------- Captured stdout setup --------------------------- setting up - ======= 1 failed, 1 passed in 0.12 seconds ======== + ==================== 1 failed, 1 passed in 0.12 seconds ==================== Accessing captured output from a test function --------------------------------------------------- -The ``capsys`` and ``capfd`` fixtures allow to access stdout/stderr -output created during test execution. Here is an example test function -that performs some output related checks: +The ``capsys``, ``capsysbinary``, ``capfd``, and ``capfdbinary`` fixtures +allow access to stdout/stderr output created during test execution. Here is +an example test function that performs some output related checks: .. code-block:: python @@ -97,7 +97,7 @@ that performs some output related checks: out, err = capsys.readouterr() assert out == "hello\n" assert err == "world\n" - print "next" + print ("next") out, err = capsys.readouterr() assert out == "next\n" @@ -110,9 +110,39 @@ output streams and also interacts well with pytest's own per-test capturing. If you want to capture on filedescriptor level you can use -the ``capfd`` function argument which offers the exact +the ``capfd`` fixture which offers the exact same interface but allows to also capture output from libraries or subprocesses that directly write to operating system level output streams (FD1 and FD2). +.. versionadded:: 3.3 + +If the code under test writes non-textual data, you can capture this using +the ``capsysbinary`` fixture which instead returns ``bytes`` from +the ``readouterr`` method. The ``capfsysbinary`` fixture is currently only +available in python 3. + + +.. versionadded:: 3.3 + +If the code under test writes non-textual data, you can capture this using +the ``capfdbinary`` fixture which instead returns ``bytes`` from +the ``readouterr`` method. The ``capfdbinary`` fixture operates on the +filedescriptor level. + + +.. versionadded:: 3.0 + +To temporarily disable capture within a test, both ``capsys`` +and ``capfd`` have a ``disabled()`` method that can be used +as a context manager, disabling capture inside the ``with`` block: + +.. code-block:: python + + def test_disabling_capturing(capsys): + print('this output is captured') + with capsys.disabled(): + print('output not captured, going directly to sys.stdout') + print('this output is also captured') + .. include:: links.inc diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/changelog.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/changelog.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/changelog.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/changelog.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/check_sphinx.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/check_sphinx.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/check_sphinx.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/check_sphinx.py diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/conf.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/conf.py similarity index 97% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/conf.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/conf.py index aca0442c5d6..40f1e4165e4 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/conf.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/conf.py @@ -19,11 +19,8 @@ # The short X.Y version. import os, sys -sys.path.insert(0, os.path.dirname(__file__)) -import _getdoctarget - -version = _getdoctarget.get_minor_version_string() -release = _getdoctarget.get_version_string() +from _pytest import __version__ as version +release = ".".join(version.split(".")[:2]) # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -127,7 +124,7 @@ html_theme_options = { # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -html_title = None +html_title = 'pytest documentation' # A shorter title for the navigation bar. Default is the same as html_title. html_short_title = "pytest-%s" % release @@ -144,7 +141,7 @@ html_favicon = "img/pytest1favi.ico" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +# html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. @@ -306,7 +303,7 @@ texinfo_documents = [ ('Holger Krekel@*Benjamin Peterson@*Ronny Pfannschmidt@*' 'Floris Bruynooghe@*others'), 'pytest', - 'simple powerful testing with Pytho', + 'simple powerful testing with Python', 'Programming', 1), ] diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/conftest.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/conftest.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/conftest.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/conftest.py diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/contact.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/contact.rst similarity index 91% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/contact.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/contact.rst index d4a1a03dee3..83d496640d5 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/contact.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/contact.rst @@ -19,9 +19,9 @@ Contact channels - `pytest-commit at python.org (mailing list)`_: for commits and new issues - :doc:`contribution guide ` for help on submitting pull - requests to bitbucket (including using git via gitifyhg). + requests to GitHub. -- #pylib on irc.freenode.net IRC channel for random questions. +- ``#pylib`` on irc.freenode.net IRC channel for random questions. - private mail to Holger.Krekel at gmail com if you want to communicate sensitive issues @@ -46,6 +46,5 @@ Contact channels .. _`py-dev`: .. _`development mailing list`: .. _`pytest-dev at python.org (mailing list)`: http://mail.python.org/mailman/listinfo/pytest-dev -.. _`py-svn`: .. _`pytest-commit at python.org (mailing list)`: http://mail.python.org/mailman/listinfo/pytest-commit diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/contents.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/contents.rst new file mode 100644 index 00000000000..7a6570e0bc5 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/contents.rst @@ -0,0 +1,65 @@ +.. _toc: + +Full pytest documentation +=========================== + +`Download latest version as PDF `_ + +.. `Download latest version as EPUB `_ + +.. toctree:: + :maxdepth: 2 + + getting-started + usage + existingtestsuite + assert + builtin + fixture + monkeypatch + tmpdir + capture + warnings + doctest + mark + skipping + parametrize + cache + unittest + nose + xunit_setup + plugins + writing_plugins + logging + + goodpractices + pythonpath + customize + example/index + bash-completion + + backwards-compatibility + historical-notes + license + contributing + development_guide + talks + projects + faq + contact + +.. only:: html + + .. toctree:: + :maxdepth: 1 + + announce/index + +.. only:: html + + .. toctree:: + :hidden: + :maxdepth: 1 + + changelog + diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/contributing.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/contributing.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/contributing.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/contributing.rst diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/customize.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/customize.rst new file mode 100644 index 00000000000..8133704a52c --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/customize.rst @@ -0,0 +1,333 @@ +Configuration +============= + +Command line options and configuration file settings +----------------------------------------------------------------- + +You can get help on command line options and values in INI-style +configurations files by using the general help option:: + + pytest -h # prints options _and_ config file settings + +This will display command line and configuration file settings +which were registered by installed plugins. + +.. _rootdir: +.. _inifiles: + +Initialization: determining rootdir and inifile +----------------------------------------------- + +.. versionadded:: 2.7 + +pytest determines a ``rootdir`` for each test run which depends on +the command line arguments (specified test files, paths) and on +the existence of *ini-files*. The determined ``rootdir`` and *ini-file* are +printed as part of the pytest header during startup. + +Here's a summary what ``pytest`` uses ``rootdir`` for: + +* Construct *nodeids* during collection; each test is assigned + a unique *nodeid* which is rooted at the ``rootdir`` and takes in account full path, + class name, function name and parametrization (if any). + +* Is used by plugins as a stable location to store project/test run specific information; + for example, the internal :ref:`cache ` plugin creates a ``.cache`` subdirectory + in ``rootdir`` to store its cross-test run state. + +Important to emphasize that ``rootdir`` is **NOT** used to modify ``sys.path``/``PYTHONPATH`` or +influence how modules are imported. See :ref:`pythonpath` for more details. + +Finding the ``rootdir`` +~~~~~~~~~~~~~~~~~~~~~~~ + +Here is the algorithm which finds the rootdir from ``args``: + +- determine the common ancestor directory for the specified ``args`` that are + recognised as paths that exist in the file system. If no such paths are + found, the common ancestor directory is set to the current working directory. + +- look for ``pytest.ini``, ``tox.ini`` and ``setup.cfg`` files in the ancestor + directory and upwards. If one is matched, it becomes the ini-file and its + directory becomes the rootdir. + +- if no ini-file was found, look for ``setup.py`` upwards from the common + ancestor directory to determine the ``rootdir``. + +- if no ``setup.py`` was found, look for ``pytest.ini``, ``tox.ini`` and + ``setup.cfg`` in each of the specified ``args`` and upwards. If one is + matched, it becomes the ini-file and its directory becomes the rootdir. + +- if no ini-file was found, use the already determined common ancestor as root + directory. This allows the use of pytest in structures that are not part of + a package and don't have any particular ini-file configuration. + +If no ``args`` are given, pytest collects test below the current working +directory and also starts determining the rootdir from there. + +:warning: custom pytest plugin commandline arguments may include a path, as in + ``pytest --log-output ../../test.log args``. Then ``args`` is mandatory, + otherwise pytest uses the folder of test.log for rootdir determination + (see also `issue 1435 `_). + A dot ``.`` for referencing to the current working directory is also + possible. + +Note that an existing ``pytest.ini`` file will always be considered a match, +whereas ``tox.ini`` and ``setup.cfg`` will only match if they contain a +``[pytest]`` or ``[tool:pytest]`` section, respectively. Options from multiple ini-files candidates are never +merged - the first one wins (``pytest.ini`` always wins, even if it does not +contain a ``[pytest]`` section). + +The ``config`` object will subsequently carry these attributes: + +- ``config.rootdir``: the determined root directory, guaranteed to exist. + +- ``config.inifile``: the determined ini-file, may be ``None``. + +The rootdir is used a reference directory for constructing test +addresses ("nodeids") and can be used also by plugins for storing +per-testrun information. + +Example:: + + pytest path/to/testdir path/other/ + +will determine the common ancestor as ``path`` and then +check for ini-files as follows:: + + # first look for pytest.ini files + path/pytest.ini + path/setup.cfg # must also contain [tool:pytest] section to match + path/tox.ini # must also contain [pytest] section to match + pytest.ini + ... # all the way down to the root + + # now look for setup.py + path/setup.py + setup.py + ... # all the way down to the root + + +.. _`how to change command line options defaults`: +.. _`adding default options`: + + + +How to change command line options defaults +------------------------------------------------ + +It can be tedious to type the same series of command line options +every time you use ``pytest``. For example, if you always want to see +detailed info on skipped and xfailed tests, as well as have terser "dot" +progress output, you can write it into a configuration file: + +.. code-block:: ini + + # content of pytest.ini + # (or tox.ini or setup.cfg) + [pytest] + addopts = -ra -q + +Alternatively, you can set a ``PYTEST_ADDOPTS`` environment variable to add command +line options while the environment is in use:: + + export PYTEST_ADDOPTS="-v" + +Here's how the command-line is built in the presence of ``addopts`` or the environment variable:: + + $PYTEST_ADDOTPS + +So if the user executes in the command-line:: + + pytest -m slow + +The actual command line executed is:: + + pytest -ra -q -v -m slow + +Note that as usual for other command-line applications, in case of conflicting options the last one wins, so the example +above will show verbose output because ``-v`` overwrites ``-q``. + + +Builtin configuration file options +---------------------------------------------- + +.. confval:: minversion + + Specifies a minimal pytest version required for running tests. + + minversion = 2.1 # will fail if we run with pytest-2.0 + +.. confval:: addopts + + Add the specified ``OPTS`` to the set of command line arguments as if they + had been specified by the user. Example: if you have this ini file content: + + .. code-block:: ini + + [pytest] + addopts = --maxfail=2 -rf # exit after 2 failures, report fail info + + issuing ``pytest test_hello.py`` actually means:: + + pytest --maxfail=2 -rf test_hello.py + + Default is to add no options. + +.. confval:: norecursedirs + + Set the directory basename patterns to avoid when recursing + for test discovery. The individual (fnmatch-style) patterns are + applied to the basename of a directory to decide if to recurse into it. + Pattern matching characters:: + + * matches everything + ? matches any single character + [seq] matches any character in seq + [!seq] matches any char not in seq + + Default patterns are ``'.*', 'build', 'dist', 'CVS', '_darcs', '{arch}', '*.egg', 'venv'``. + Setting a ``norecursedirs`` replaces the default. Here is an example of + how to avoid certain directories: + + .. code-block:: ini + + # content of pytest.ini + [pytest] + norecursedirs = .svn _build tmp* + + This would tell ``pytest`` to not look into typical subversion or + sphinx-build directories or into any ``tmp`` prefixed directory. + + Additionally, ``pytest`` will attempt to intelligently identify and ignore a + virtualenv by the presence of an activation script. Any directory deemed to + be the root of a virtual environment will not be considered during test + collection unless ``‑‑collect‑in‑virtualenv`` is given. Note also that + ``norecursedirs`` takes precedence over ``‑‑collect‑in‑virtualenv``; e.g. if + you intend to run tests in a virtualenv with a base directory that matches + ``'.*'`` you *must* override ``norecursedirs`` in addition to using the + ``‑‑collect‑in‑virtualenv`` flag. + +.. confval:: testpaths + + .. versionadded:: 2.8 + + Sets list of directories that should be searched for tests when + no specific directories, files or test ids are given in the command line when + executing pytest from the :ref:`rootdir ` directory. + Useful when all project tests are in a known location to speed up + test collection and to avoid picking up undesired tests by accident. + + .. code-block:: ini + + # content of pytest.ini + [pytest] + testpaths = testing doc + + This tells pytest to only look for tests in ``testing`` and ``doc`` + directories when executing from the root directory. + +.. confval:: python_files + + One or more Glob-style file patterns determining which python files + are considered as test modules. By default, pytest will consider + any file matching with ``test_*.py`` and ``*_test.py`` globs as a test + module. + +.. confval:: python_classes + + One or more name prefixes or glob-style patterns determining which classes + are considered for test collection. By default, pytest will consider any + class prefixed with ``Test`` as a test collection. Here is an example of how + to collect tests from classes that end in ``Suite``: + + .. code-block:: ini + + # content of pytest.ini + [pytest] + python_classes = *Suite + + Note that ``unittest.TestCase`` derived classes are always collected + regardless of this option, as ``unittest``'s own collection framework is used + to collect those tests. + +.. confval:: python_functions + + One or more name prefixes or glob-patterns determining which test functions + and methods are considered tests. By default, pytest will consider any + function prefixed with ``test`` as a test. Here is an example of how + to collect test functions and methods that end in ``_test``: + + .. code-block:: ini + + # content of pytest.ini + [pytest] + python_functions = *_test + + Note that this has no effect on methods that live on a ``unittest + .TestCase`` derived class, as ``unittest``'s own collection framework is used + to collect those tests. + + See :ref:`change naming conventions` for more detailed examples. + +.. confval:: doctest_optionflags + + One or more doctest flag names from the standard ``doctest`` module. + :doc:`See how pytest handles doctests `. + +.. confval:: confcutdir + + Sets a directory where search upwards for ``conftest.py`` files stops. + By default, pytest will stop searching for ``conftest.py`` files upwards + from ``pytest.ini``/``tox.ini``/``setup.cfg`` of the project if any, + or up to the file-system root. + + +.. confval:: filterwarnings + + .. versionadded:: 3.1 + + Sets a list of filters and actions that should be taken for matched + warnings. By default all warnings emitted during the test session + will be displayed in a summary at the end of the test session. + + .. code-block:: ini + + # content of pytest.ini + [pytest] + filterwarnings = + error + ignore::DeprecationWarning + + This tells pytest to ignore deprecation warnings and turn all other warnings + into errors. For more information please refer to :ref:`warnings`. + +.. confval:: cache_dir + + .. versionadded:: 3.2 + + Sets a directory where stores content of cache plugin. Default directory is + ``.cache`` which is created in :ref:`rootdir `. Directory may be + relative or absolute path. If setting relative path, then directory is created + relative to :ref:`rootdir `. Additionally path may contain environment + variables, that will be expanded. For more information about cache plugin + please refer to :ref:`cache_provider`. + + +.. confval:: console_output_style + + .. versionadded:: 3.3 + + Sets the console output style while running tests: + + * ``classic``: classic pytest output. + * ``progress``: like classic pytest output, but with a progress indicator. + + The default is ``progress``, but you can fallback to ``classic`` if you prefer or + the new mode is causing unexpected problems: + + .. code-block:: ini + + # content of pytest.ini + [pytest] + console_output_style = classic diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/development_guide.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/development_guide.rst new file mode 100644 index 00000000000..465e97de0f9 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/development_guide.rst @@ -0,0 +1,108 @@ +================= +Development Guide +================= + +Some general guidelines regarding development in pytest for core maintainers and general contributors. Nothing here +is set in stone and can't be changed, feel free to suggest improvements or changes in the workflow. + + +Code Style +---------- + +* `PEP-8 `_ +* `flake8 `_ for quality checks +* `invoke `_ to automate development tasks + + +Branches +-------- + +We have two long term branches: + +* ``master``: contains the code for the next bugfix release. +* ``features``: contains the code with new features for the next minor release. + +The official repository usually does not contain topic branches, developers and contributors should create topic +branches in their own forks. + +Exceptions can be made for cases where more than one contributor is working on the same +topic or where it makes sense to use some automatic capability of the main repository, such as automatic docs from +`readthedocs `_ for a branch dealing with documentation refactoring. + +Issues +------ + +Any question, feature, bug or proposal is welcome as an issue. Users are encouraged to use them whenever they need. + +GitHub issues should use labels to categorize them. Labels should be created sporadically, to fill a niche; we should +avoid creating labels just for the sake of creating them. + +Here is a list of labels and a brief description mentioning their intent. + + +**Type** + +* ``type: backward compatibility``: issue that will cause problems with old pytest versions. +* ``type: bug``: problem that needs to be addressed. +* ``type: deprecation``: feature that will be deprecated in the future. +* ``type: docs``: documentation missing or needing clarification. +* ``type: enhancement``: new feature or API change, should be merged into ``features``. +* ``type: feature-branch``: new feature or API change, should be merged into ``features``. +* ``type: infrastructure``: improvement to development/releases/CI structure. +* ``type: performance``: performance or memory problem/improvement. +* ``type: proposal``: proposal for a new feature, often to gather opinions or design the API around the new feature. +* ``type: question``: question regarding usage, installation, internals or how to test something. +* ``type: refactoring``: internal improvements to the code. +* ``type: regression``: indicates a problem that was introduced in a release which was working previously. + +**Status** + +* ``status: critical``: grave problem or usability issue that affects lots of users. +* ``status: easy``: easy issue that is friendly to new contributors. +* ``status: help wanted``: core developers need help from experts on this topic. +* ``status: needs information``: reporter needs to provide more information; can be closed after 2 or more weeks of inactivity. + +**Topic** + +* ``topic: collection`` +* ``topic: fixtures`` +* ``topic: parametrize`` +* ``topic: reporting`` +* ``topic: selection`` +* ``topic: tracebacks`` + +**Plugin (internal or external)** + +* ``plugin: cache`` +* ``plugin: capture`` +* ``plugin: doctests`` +* ``plugin: junitxml`` +* ``plugin: monkeypatch`` +* ``plugin: nose`` +* ``plugin: pastebin`` +* ``plugin: pytester`` +* ``plugin: tmpdir`` +* ``plugin: unittest`` +* ``plugin: warnings`` +* ``plugin: xdist`` + + +**OS** + +Issues specific to a single operating system. Do not use as a means to indicate where an issue originated from, only +for problems that happen **only** in that system. + +* ``os: linux`` +* ``os: mac`` +* ``os: windows`` + +**Temporary** + +Used to classify issues for limited time, to help find issues related in events for example. +They should be removed after they are no longer relevant. + +* ``temporary: EP2017 sprint``: +* ``temporary: sprint-candidate``: + + +.. include:: ../../HOWTORELEASE.rst diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/doctest.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/doctest.rst new file mode 100644 index 00000000000..4c5a878dd61 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/doctest.rst @@ -0,0 +1,165 @@ + +Doctest integration for modules and test files +========================================================= + +By default all files matching the ``test*.txt`` pattern will +be run through the python standard ``doctest`` module. You +can change the pattern by issuing:: + + pytest --doctest-glob='*.rst' + +on the command line. Since version ``2.9``, ``--doctest-glob`` +can be given multiple times in the command-line. + +.. versionadded:: 3.1 + + You can specify the encoding that will be used for those doctest files + using the ``doctest_encoding`` ini option: + + .. code-block:: ini + + # content of pytest.ini + [pytest] + doctest_encoding = latin1 + + The default encoding is UTF-8. + +You can also trigger running of doctests +from docstrings in all python modules (including regular +python test modules):: + + pytest --doctest-modules + +You can make these changes permanent in your project by +putting them into a pytest.ini file like this: + +.. code-block:: ini + + # content of pytest.ini + [pytest] + addopts = --doctest-modules + +If you then have a text file like this:: + + # content of example.rst + + hello this is a doctest + >>> x = 3 + >>> x + 3 + +and another like this:: + + # content of mymodule.py + def something(): + """ a doctest in a docstring + >>> something() + 42 + """ + return 42 + +then you can just invoke ``pytest`` without command line options:: + + $ pytest + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini + collected 1 item + + mymodule.py . [100%] + + ========================= 1 passed in 0.12 seconds ========================= + +It is possible to use fixtures using the ``getfixture`` helper:: + + # content of example.rst + >>> tmp = getfixture('tmpdir') + >>> ... + >>> + +Also, :ref:`usefixtures` and :ref:`autouse` fixtures are supported +when executing text doctest files. + +The standard ``doctest`` module provides some setting flags to configure the +strictness of doctest tests. In pytest You can enable those flags those flags +using the configuration file. To make pytest ignore trailing whitespaces and +ignore lengthy exception stack traces you can just write: + +.. code-block:: ini + + [pytest] + doctest_optionflags= NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL + +pytest also introduces new options to allow doctests to run in Python 2 and +Python 3 unchanged: + +* ``ALLOW_UNICODE``: when enabled, the ``u`` prefix is stripped from unicode + strings in expected doctest output. + +* ``ALLOW_BYTES``: when enabled, the ``b`` prefix is stripped from byte strings + in expected doctest output. + +As with any other option flag, these flags can be enabled in ``pytest.ini`` using +the ``doctest_optionflags`` ini option: + +.. code-block:: ini + + [pytest] + doctest_optionflags = ALLOW_UNICODE ALLOW_BYTES + + +Alternatively, it can be enabled by an inline comment in the doc test +itself:: + + # content of example.rst + >>> get_unicode_greeting() # doctest: +ALLOW_UNICODE + 'Hello' + + +The 'doctest_namespace' fixture +------------------------------- + +.. versionadded:: 3.0 + +The ``doctest_namespace`` fixture can be used to inject items into the +namespace in which your doctests run. It is intended to be used within +your own fixtures to provide the tests that use them with context. + +``doctest_namespace`` is a standard ``dict`` object into which you +place the objects you want to appear in the doctest namespace:: + + # content of conftest.py + import numpy + @pytest.fixture(autouse=True) + def add_np(doctest_namespace): + doctest_namespace['np'] = numpy + +which can then be used in your doctests directly:: + + # content of numpy.py + def arange(): + """ + >>> a = np.arange(10) + >>> len(a) + 10 + """ + pass + + +Output format +------------- + +.. versionadded:: 3.0 + +You can change the diff output format on failure for your doctests +by using one of standard doctest modules format in options +(see :data:`python:doctest.REPORT_UDIFF`, :data:`python:doctest.REPORT_CDIFF`, +:data:`python:doctest.REPORT_NDIFF`, :data:`python:doctest.REPORT_ONLY_FIRST_FAILURE`):: + + pytest --doctest-modules --doctest-report none + pytest --doctest-modules --doctest-report udiff + pytest --doctest-modules --doctest-report cdiff + pytest --doctest-modules --doctest-report ndiff + pytest --doctest-modules --doctest-report only_first_failure + + diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/assertion/failure_demo.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/assertion/failure_demo.py similarity index 96% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/assertion/failure_demo.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/assertion/failure_demo.py index a4ff758b18c..d31fba2adaa 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/assertion/failure_demo.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/assertion/failure_demo.py @@ -128,7 +128,7 @@ def test_attribute_multiple(): def globf(x): return x+1 -class TestRaises: +class TestRaises(object): def test_raises(self): s = 'qwe' raises(TypeError, "int(s)") @@ -167,7 +167,7 @@ def test_dynamic_compile_shows_nicely(): -class TestMoreErrors: +class TestMoreErrors(object): def test_complex_error(self): def f(): return 44 @@ -213,23 +213,23 @@ class TestMoreErrors: x = 0 -class TestCustomAssertMsg: +class TestCustomAssertMsg(object): def test_single_line(self): - class A: + class A(object): a = 1 b = 2 assert A.a == b, "A.a appears not to be b" def test_multiline(self): - class A: + class A(object): a = 1 b = 2 assert A.a == b, "A.a appears not to be b\n" \ "or does not appear to be b\none of those" def test_custom_repr(self): - class JSON: + class JSON(object): a = 1 def __repr__(self): return "This is JSON\n{\n 'foo': 'bar'\n}" diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/assertion/global_testmodule_config/conftest.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/assertion/global_testmodule_config/conftest.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/assertion/global_testmodule_config/conftest.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/assertion/global_testmodule_config/conftest.py diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/assertion/global_testmodule_config/test_hello.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/assertion/global_testmodule_config/test_hello.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/assertion/global_testmodule_config/test_hello.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/assertion/global_testmodule_config/test_hello.py diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/assertion/test_failures.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/assertion/test_failures.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/assertion/test_failures.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/assertion/test_failures.py diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/assertion/test_setup_flow_example.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/assertion/test_setup_flow_example.py similarity index 97% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/assertion/test_setup_flow_example.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/assertion/test_setup_flow_example.py index 512330cb4c7..100effa499f 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/assertion/test_setup_flow_example.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/assertion/test_setup_flow_example.py @@ -1,7 +1,7 @@ def setup_module(module): module.TestStateFullThing.classcount = 0 -class TestStateFullThing: +class TestStateFullThing(object): def setup_class(cls): cls.classcount += 1 diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/attic.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/attic.rst similarity index 95% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/attic.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/attic.rst index 1bc32b2837d..9e124a5d09d 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/attic.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/attic.rst @@ -15,9 +15,9 @@ example: specifying and selecting acceptance tests def pytest_funcarg__accept(request): return AcceptFixture(request) - class AcceptFixture: + class AcceptFixture(object): def __init__(self, request): - if not request.config.option.acceptance: + if not request.config.getoption('acceptance'): pytest.skip("specify -A to run acceptance tests") self.tmpdir = request.config.mktemp(request.function.__name__, numbered=True) @@ -61,7 +61,7 @@ extend the `accept example`_ by putting this in our test module: arg.tmpdir.mkdir("special") return arg - class TestSpecialAcceptance: + class TestSpecialAcceptance(object): def test_sometest(self, accept): assert accept.tmpdir.join("special").check() diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/conftest.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/conftest.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/conftest.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/conftest.py diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/costlysetup/conftest.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/costlysetup/conftest.py similarity index 78% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/costlysetup/conftest.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/costlysetup/conftest.py index d689c11b207..ea3c1cffb72 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/costlysetup/conftest.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/costlysetup/conftest.py @@ -4,10 +4,10 @@ import pytest @pytest.fixture("session") def setup(request): setup = CostlySetup() - request.addfinalizer(setup.finalize) - return setup + yield setup + setup.finalize() -class CostlySetup: +class CostlySetup(object): def __init__(self): import time print ("performing costly setup") diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/costlysetup/sub1/__init__.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/costlysetup/sub1/__init__.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/costlysetup/sub1/__init__.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/costlysetup/sub1/__init__.py diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/costlysetup/sub1/test_quick.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/costlysetup/sub1/test_quick.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/costlysetup/sub1/test_quick.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/costlysetup/sub1/test_quick.py diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/costlysetup/sub2/__init__.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/costlysetup/sub2/__init__.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/costlysetup/sub2/__init__.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/costlysetup/sub2/__init__.py diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/costlysetup/sub2/test_two.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/costlysetup/sub2/test_two.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/costlysetup/sub2/test_two.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/costlysetup/sub2/test_two.py diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/index.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/index.rst similarity index 92% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/index.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/index.rst index 363de5ab714..f63cb822a41 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/index.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/index.rst @@ -1,8 +1,8 @@ .. _examples: -Usages and Examples -=========================================== +Examples and customization tricks +================================= Here is a (growing) list of examples. :ref:`Contact ` us if you need more examples or have questions. Also take a look at the diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/markers.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/markers.rst similarity index 53% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/markers.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/markers.rst index 6bdc603479c..43c20d5b7dc 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/markers.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/markers.rst @@ -21,7 +21,7 @@ You can "mark" a test function with custom metadata like this:: pass def test_another(): pass - class TestClass: + class TestClass(object): def test_method(self): pass @@ -29,33 +29,33 @@ You can "mark" a test function with custom metadata like this:: You can then restrict a test run to only run tests marked with ``webtest``:: - $ py.test -v -m webtest - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.4 + $ pytest -v -m webtest + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache - rootdir: $REGENDOC_TMPDIR, inifile: + rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items - test_server.py::test_send_http PASSED + test_server.py::test_send_http PASSED [100%] - ======= 3 tests deselected by "-m 'webtest'" ======== - ======= 1 passed, 3 deselected in 0.12 seconds ======== + ============================ 3 tests deselected ============================ + ================== 1 passed, 3 deselected in 0.12 seconds ================== Or the inverse, running all tests except the webtest ones:: - $ py.test -v -m "not webtest" - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.4 + $ pytest -v -m "not webtest" + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache - rootdir: $REGENDOC_TMPDIR, inifile: + rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items - test_server.py::test_something_quick PASSED - test_server.py::test_another PASSED - test_server.py::TestClass::test_method PASSED + test_server.py::test_something_quick PASSED [ 33%] + test_server.py::test_another PASSED [ 66%] + test_server.py::TestClass::test_method PASSED [100%] - ======= 1 tests deselected by "-m 'not webtest'" ======== - ======= 3 passed, 1 deselected in 0.12 seconds ======== + ============================ 1 tests deselected ============================ + ================== 3 passed, 1 deselected in 0.12 seconds ================== Selecting tests based on their node ID -------------------------------------- @@ -64,43 +64,43 @@ You can provide one or more :ref:`node IDs ` as positional arguments to select only specified tests. This makes it easy to select tests based on their module, class, method, or function name:: - $ py.test -v test_server.py::TestClass::test_method - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.4 + $ pytest -v test_server.py::TestClass::test_method + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache - rootdir: $REGENDOC_TMPDIR, inifile: - collecting ... collected 5 items + rootdir: $REGENDOC_TMPDIR, inifile: + collecting ... collected 1 item - test_server.py::TestClass::test_method PASSED + test_server.py::TestClass::test_method PASSED [100%] - ======= 1 passed in 0.12 seconds ======== + ========================= 1 passed in 0.12 seconds ========================= You can also select on the class:: - $ py.test -v test_server.py::TestClass - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.4 + $ pytest -v test_server.py::TestClass + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache - rootdir: $REGENDOC_TMPDIR, inifile: - collecting ... collected 4 items + rootdir: $REGENDOC_TMPDIR, inifile: + collecting ... collected 1 item - test_server.py::TestClass::test_method PASSED + test_server.py::TestClass::test_method PASSED [100%] - ======= 1 passed in 0.12 seconds ======== + ========================= 1 passed in 0.12 seconds ========================= Or select multiple nodes:: - $ py.test -v test_server.py::TestClass test_server.py::test_send_http - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.4 + $ pytest -v test_server.py::TestClass test_server.py::test_send_http + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache - rootdir: $REGENDOC_TMPDIR, inifile: - collecting ... collected 8 items + rootdir: $REGENDOC_TMPDIR, inifile: + collecting ... collected 2 items - test_server.py::TestClass::test_method PASSED - test_server.py::test_send_http PASSED + test_server.py::TestClass::test_method PASSED [ 50%] + test_server.py::test_send_http PASSED [100%] - ======= 2 passed in 0.12 seconds ======== + ========================= 2 passed in 0.12 seconds ========================= .. _node-id: @@ -115,8 +115,8 @@ Or select multiple nodes:: ``module.py::function[param]``. Node IDs for failing tests are displayed in the test summary info - when running py.test with the ``-rf`` option. You can also - construct Node IDs from the output of ``py.test --collectonly``. + when running pytest with the ``-rf`` option. You can also + construct Node IDs from the output of ``pytest --collectonly``. Using ``-k expr`` to select tests based on their name ------------------------------------------------------- @@ -128,59 +128,63 @@ which implements a substring match on the test names instead of the exact match on markers that ``-m`` provides. This makes it easy to select tests based on their names:: - $ py.test -v -k http # running with the above defined example module - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.4 + $ pytest -v -k http # running with the above defined example module + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache - rootdir: $REGENDOC_TMPDIR, inifile: + rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items - test_server.py::test_send_http PASSED + test_server.py::test_send_http PASSED [100%] - ======= 3 tests deselected by '-khttp' ======== - ======= 1 passed, 3 deselected in 0.12 seconds ======== + ============================ 3 tests deselected ============================ + ================== 1 passed, 3 deselected in 0.12 seconds ================== And you can also run all tests except the ones that match the keyword:: - $ py.test -k "not send_http" -v - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.4 + $ pytest -k "not send_http" -v + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache - rootdir: $REGENDOC_TMPDIR, inifile: + rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items - test_server.py::test_something_quick PASSED - test_server.py::test_another PASSED - test_server.py::TestClass::test_method PASSED + test_server.py::test_something_quick PASSED [ 33%] + test_server.py::test_another PASSED [ 66%] + test_server.py::TestClass::test_method PASSED [100%] - ======= 1 tests deselected by '-knot send_http' ======== - ======= 3 passed, 1 deselected in 0.12 seconds ======== + ============================ 1 tests deselected ============================ + ================== 3 passed, 1 deselected in 0.12 seconds ================== Or to select "http" and "quick" tests:: - $ py.test -k "http or quick" -v - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.4 + $ pytest -k "http or quick" -v + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache - rootdir: $REGENDOC_TMPDIR, inifile: + rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items - test_server.py::test_send_http PASSED - test_server.py::test_something_quick PASSED + test_server.py::test_send_http PASSED [ 50%] + test_server.py::test_something_quick PASSED [100%] - ======= 2 tests deselected by '-khttp or quick' ======== - ======= 2 passed, 2 deselected in 0.12 seconds ======== + ============================ 2 tests deselected ============================ + ================== 2 passed, 2 deselected in 0.12 seconds ================== .. note:: - If you are using expressions such as "X and Y" then both X and Y - need to be simple non-keyword names. For example, "pass" or "from" - will result in SyntaxErrors because "-k" evaluates the expression. + If you are using expressions such as ``"X and Y"`` then both ``X`` and ``Y`` + need to be simple non-keyword names. For example, ``"pass"`` or ``"from"`` + will result in SyntaxErrors because ``"-k"`` evaluates the expression using + Python's `eval`_ function. - However, if the "-k" argument is a simple string, no such restrictions - apply. Also "-k 'not STRING'" has no restrictions. You can also - specify numbers like "-k 1.3" to match tests which are parametrized - with the float "1.3". +.. _`eval`: https://docs.python.org/3.6/library/functions.html#eval + + + However, if the ``"-k"`` argument is a simple string, no such restrictions + apply. Also ``"-k 'not STRING'"`` has no restrictions. You can also + specify numbers like ``"-k 1.3"`` to match tests which are parametrized + with the float ``"1.3"``. Registering markers ------------------------------------- @@ -198,12 +202,14 @@ Registering markers for your test suite is simple:: You can ask which markers exist for your test suite - the list includes our just defined ``webtest`` markers:: - $ py.test --markers + $ pytest --markers @pytest.mark.webtest: mark a test as a webtest. + @pytest.mark.skip(reason=None): skip the given test function with an optional reason. Example: skip(reason="no way of currently testing this") skips the test. + @pytest.mark.skipif(condition): skip the given test function if eval(condition) results in a True value. Evaluation happens within the module global context. Example: skipif('sys.platform == "win32"') skips the test if we are on the win32 platform. see http://pytest.org/latest/skipping.html - @pytest.mark.xfail(condition, reason=None, run=True, raises=None): mark the the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See http://pytest.org/latest/skipping.html + @pytest.mark.xfail(condition, reason=None, run=True, raises=None, strict=False): mark the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See http://pytest.org/latest/skipping.html @pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in different arguments in turn. argvalues generally needs to be a list of values if argnames specifies only one name or a list of tuples of values if argnames specifies multiple names. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.see http://pytest.org/latest/parametrize.html for more info and examples. @@ -221,13 +227,12 @@ For an example on how to add and work with markers from a plugin, see It is recommended to explicitly register markers so that: - * there is one place in your test suite defining your markers + * There is one place in your test suite defining your markers - * asking for existing markers via ``py.test --markers`` gives good output + * Asking for existing markers via ``pytest --markers`` gives good output - * typos in function markers are treated as an error if you use - the ``--strict`` option. Future versions of ``pytest`` are probably - going to start treating non-registered markers as errors at some point. + * Typos in function markers are treated as an error if you use + the ``--strict`` option. .. _`scoped-marking`: @@ -240,7 +245,7 @@ its test methods:: # content of test_mark_classlevel.py import pytest @pytest.mark.webtest - class TestClass: + class TestClass(object): def test_startup(self): pass def test_startup_and_more(self): @@ -254,14 +259,14 @@ To remain backward-compatible with Python 2.4 you can also set a import pytest - class TestClass: + class TestClass(object): pytestmark = pytest.mark.webtest or if you need to use multiple markers you can use a list:: import pytest - class TestClass: + class TestClass(object): pytestmark = [pytest.mark.webtest, pytest.mark.slowtest] You can also set a module level marker:: @@ -348,36 +353,38 @@ A test file using this local plugin:: and an example invocations specifying a different environment than what the test needs:: - $ py.test -E stage2 - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: - collected 1 items + $ pytest -E stage2 + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: + collected 1 item - test_someenv.py s + test_someenv.py s [100%] - ======= 1 skipped in 0.12 seconds ======== + ======================== 1 skipped in 0.12 seconds ========================= and here is one that specifies exactly the environment needed:: - $ py.test -E stage1 - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: - collected 1 items + $ pytest -E stage1 + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: + collected 1 item - test_someenv.py . + test_someenv.py . [100%] - ======= 1 passed in 0.12 seconds ======== + ========================= 1 passed in 0.12 seconds ========================= The ``--markers`` option always gives you a list of available markers:: - $ py.test --markers + $ pytest --markers @pytest.mark.env(name): mark test to run only on named environment + @pytest.mark.skip(reason=None): skip the given test function with an optional reason. Example: skip(reason="no way of currently testing this") skips the test. + @pytest.mark.skipif(condition): skip the given test function if eval(condition) results in a True value. Evaluation happens within the module global context. Example: skipif('sys.platform == "win32"') skips the test if we are on the win32 platform. see http://pytest.org/latest/skipping.html - @pytest.mark.xfail(condition, reason=None, run=True, raises=None): mark the the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See http://pytest.org/latest/skipping.html + @pytest.mark.xfail(condition, reason=None, run=True, raises=None, strict=False): mark the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See http://pytest.org/latest/skipping.html @pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in different arguments in turn. argvalues generally needs to be a list of values if argnames specifies only one name or a list of tuples of values if argnames specifies multiple names. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.see http://pytest.org/latest/parametrize.html for more info and examples. @@ -388,6 +395,49 @@ The ``--markers`` option always gives you a list of available markers:: @pytest.mark.trylast: mark a hook implementation function such that the plugin machinery will try to call it last/as late as possible. +.. _`passing callables to custom markers`: + +Passing a callable to custom markers +-------------------------------------------- + +.. regendoc:wipe + +Below is the config file that will be used in the next examples:: + + # content of conftest.py + import sys + + def pytest_runtest_setup(item): + marker = item.get_marker('my_marker') + if marker is not None: + for info in marker: + print('Marker info name={} args={} kwars={}'.format(info.name, info.args, info.kwargs)) + sys.stdout.flush() + +A custom marker can have its argument set, i.e. ``args`` and ``kwargs`` properties, defined by either invoking it as a callable or using ``pytest.mark.MARKER_NAME.with_args``. These two methods achieve the same effect most of the time. + +However, if there is a callable as the single positional argument with no keyword arguments, using the ``pytest.mark.MARKER_NAME(c)`` will not pass ``c`` as a positional argument but decorate ``c`` with the custom marker (see :ref:`MarkDecorator `). Fortunately, ``pytest.mark.MARKER_NAME.with_args`` comes to the rescue:: + + # content of test_custom_marker.py + import pytest + + def hello_world(*args, **kwargs): + return 'Hello World' + + @pytest.mark.my_marker.with_args(hello_world) + def test_with_args(): + pass + +The output is as follows:: + + $ pytest -q -s + Marker info name=my_marker args=(,) kwars={} + . [100%] + 1 passed in 0.12 seconds + +We can see that the custom marker has its argument set extended with the function ``hello_world``. This is the key difference between creating a custom marker as a callable, which invokes ``__call__`` behind the scenes, and using ``with_args``. + + Reading markers which were set from multiple places ---------------------------------------------------- @@ -403,7 +453,7 @@ code you can read over all such settings. Example:: pytestmark = pytest.mark.glob("module", x=1) @pytest.mark.glob("class", x=2) - class TestClass: + class TestClass(object): @pytest.mark.glob("function", x=3) def test_something(self): pass @@ -423,11 +473,11 @@ test function. From a conftest file we can read it like this:: Let's run this without capturing output and see what we get:: - $ py.test -q -s + $ pytest -q -s glob args=('function',) kwargs={'x': 3} glob args=('class',) kwargs={'x': 2} glob args=('module',) kwargs={'x': 1} - . + . [100%] 1 passed in 0.12 seconds marking platform specific tests with pytest @@ -446,7 +496,7 @@ for your particular platform, you could use the following plugin:: import sys import pytest - ALL = set("darwin linux2 win32".split()) + ALL = set("darwin linux win32".split()) def pytest_runtest_setup(item): if isinstance(item, item.Function): @@ -466,7 +516,7 @@ Let's do a little test file to show how this looks like:: def test_if_apple_is_evil(): pass - @pytest.mark.linux2 + @pytest.mark.linux def test_if_linux_works(): pass @@ -477,32 +527,32 @@ Let's do a little test file to show how this looks like:: def test_runs_everywhere(): pass -then you will see two test skipped and two executed tests as expected:: +then you will see two tests skipped and two executed tests as expected:: - $ py.test -rs # this option reports skip reasons - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: + $ pytest -rs # this option reports skip reasons + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items - test_plat.py sss. - ======= short test summary info ======== - SKIP [3] $REGENDOC_TMPDIR/conftest.py:12: cannot run on platform linux + test_plat.py s.s. [100%] + ========================= short test summary info ========================== + SKIP [2] $REGENDOC_TMPDIR/conftest.py:13: cannot run on platform linux - ======= 1 passed, 3 skipped in 0.12 seconds ======== + =================== 2 passed, 2 skipped in 0.12 seconds ==================== Note that if you specify a platform via the marker-command line option like this:: - $ py.test -m linux2 - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: + $ pytest -m linux + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items - test_plat.py s + test_plat.py . [100%] - ======= 3 tests deselected by "-m 'linux2'" ======== - ======= 1 skipped, 3 deselected in 0.12 seconds ======== + ============================ 3 tests deselected ============================ + ================== 1 passed, 3 deselected in 0.12 seconds ================== then the unmarked-tests will not be run. It is thus a way to restrict the run to the specific tests. @@ -545,48 +595,48 @@ We want to dynamically define two markers and can do it in a We can now use the ``-m option`` to select one set:: - $ py.test -m interface --tb=short - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: + $ pytest -m interface --tb=short + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items - test_module.py FF + test_module.py FF [100%] - ======= FAILURES ======== - _______ test_interface_simple ________ + ================================= FAILURES ================================= + __________________________ test_interface_simple ___________________________ test_module.py:3: in test_interface_simple assert 0 E assert 0 - _______ test_interface_complex ________ + __________________________ test_interface_complex __________________________ test_module.py:6: in test_interface_complex assert 0 E assert 0 - ======= 2 tests deselected by "-m 'interface'" ======== - ======= 2 failed, 2 deselected in 0.12 seconds ======== + ============================ 2 tests deselected ============================ + ================== 2 failed, 2 deselected in 0.12 seconds ================== or to select both "event" and "interface" tests:: - $ py.test -m "interface or event" --tb=short - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: + $ pytest -m "interface or event" --tb=short + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items - test_module.py FFF + test_module.py FFF [100%] - ======= FAILURES ======== - _______ test_interface_simple ________ + ================================= FAILURES ================================= + __________________________ test_interface_simple ___________________________ test_module.py:3: in test_interface_simple assert 0 E assert 0 - _______ test_interface_complex ________ + __________________________ test_interface_complex __________________________ test_module.py:6: in test_interface_complex assert 0 E assert 0 - _______ test_event_simple ________ + ____________________________ test_event_simple _____________________________ test_module.py:9: in test_event_simple assert 0 E assert 0 - ======= 1 tests deselected by "-m 'interface or event'" ======== - ======= 3 failed, 1 deselected in 0.12 seconds ======== + ============================ 1 tests deselected ============================ + ================== 3 failed, 1 deselected in 0.12 seconds ================== diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/multipython.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/multipython.py similarity index 95% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/multipython.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/multipython.py index 66a368a1267..66079be7e37 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/multipython.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/multipython.py @@ -6,7 +6,7 @@ import py import pytest import _pytest._code -pythonlist = ['python2.6', 'python2.7', 'python3.3'] +pythonlist = ['python2.7', 'python3.4', 'python3.5'] @pytest.fixture(params=pythonlist) def python1(request, tmpdir): picklefile = tmpdir.join("data.pickle") @@ -16,7 +16,7 @@ def python1(request, tmpdir): def python2(request, python1): return Python(request.param, python1.picklefile) -class Python: +class Python(object): def __init__(self, version, picklefile): self.pythonpath = py.path.local.sysfind(version) if not self.pythonpath: diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/nonpython.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/nonpython.rst similarity index 57% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/nonpython.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/nonpython.rst index 6437e398457..cf72c7219e1 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/nonpython.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/nonpython.rst @@ -25,20 +25,20 @@ You can create a simple example file: and if you installed `PyYAML`_ or a compatible YAML-parser you can now execute the test specification:: - nonpython $ py.test test_simple.yml - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR/nonpython, inifile: + nonpython $ pytest test_simple.yml + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR/nonpython, inifile: collected 2 items - test_simple.yml F. + test_simple.yml F. [100%] - ======= FAILURES ======== - _______ usecase: hello ________ + ================================= FAILURES ================================= + ______________________________ usecase: hello ______________________________ usecase execution failed spec failed: 'some': 'other' no further details known at this point. - ======= 1 failed, 1 passed in 0.12 seconds ======== + ==================== 1 failed, 1 passed in 0.12 seconds ==================== .. regendoc:wipe @@ -57,35 +57,35 @@ your own domain specific testing language this way. ``reportinfo()`` is used for representing the test location and is also consulted when reporting in ``verbose`` mode:: - nonpython $ py.test -v - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.4 + nonpython $ pytest -v + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache - rootdir: $REGENDOC_TMPDIR/nonpython, inifile: + rootdir: $REGENDOC_TMPDIR/nonpython, inifile: collecting ... collected 2 items - test_simple.yml::hello FAILED - test_simple.yml::ok PASSED + test_simple.yml::hello FAILED [ 50%] + test_simple.yml::ok PASSED [100%] - ======= FAILURES ======== - _______ usecase: hello ________ + ================================= FAILURES ================================= + ______________________________ usecase: hello ______________________________ usecase execution failed spec failed: 'some': 'other' no further details known at this point. - ======= 1 failed, 1 passed in 0.12 seconds ======== + ==================== 1 failed, 1 passed in 0.12 seconds ==================== .. regendoc:wipe While developing your custom test collection and execution it's also interesting to just look at the collection tree:: - nonpython $ py.test --collect-only - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR/nonpython, inifile: + nonpython $ pytest --collect-only + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR/nonpython, inifile: collected 2 items - ======= no tests ran in 0.12 seconds ======== + ======================= no tests ran in 0.12 seconds ======================= diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/nonpython/__init__.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/nonpython/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/nonpython/conftest.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/nonpython/conftest.py similarity index 92% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/nonpython/conftest.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/nonpython/conftest.py index 2406e8f10bb..baff3001550 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/nonpython/conftest.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/nonpython/conftest.py @@ -10,7 +10,7 @@ class YamlFile(pytest.File): def collect(self): import yaml # we need a yaml parser, e.g. PyYAML raw = yaml.safe_load(self.fspath.open()) - for name, spec in raw.items(): + for name, spec in sorted(raw.items()): yield YamlItem(name, self, spec) class YamlItem(pytest.Item): @@ -19,7 +19,7 @@ class YamlItem(pytest.Item): self.spec = spec def runtest(self): - for name, value in self.spec.items(): + for name, value in sorted(self.spec.items()): # some custom test execution (dumb example follows) if name != value: raise YamlException(self, name, value) diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/nonpython/test_simple.yml b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/nonpython/test_simple.yml similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/nonpython/test_simple.yml rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/nonpython/test_simple.yml diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/parametrize.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/parametrize.rst similarity index 67% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/parametrize.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/parametrize.rst index 5d637ffcbf9..dd01b25277a 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/parametrize.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/parametrize.rst @@ -36,7 +36,7 @@ Now we add a test configuration like this:: def pytest_generate_tests(metafunc): if 'param1' in metafunc.fixturenames: - if metafunc.config.option.all: + if metafunc.config.getoption('all'): end = 5 else: end = 2 @@ -44,17 +44,17 @@ Now we add a test configuration like this:: This means that we only run 2 tests if we do not pass ``--all``:: - $ py.test -q test_compute.py - .. + $ pytest -q test_compute.py + .. [100%] 2 passed in 0.12 seconds We run only two computations, so we see two dots. let's run the full monty:: - $ py.test -q --all - ....F - ======= FAILURES ======== - _______ test_compute[4] ________ + $ pytest -q --all + ....F [100%] + ================================= FAILURES ================================= + _____________________________ test_compute[4] ______________________________ param1 = 4 @@ -116,6 +116,15 @@ the argument name:: diff = a - b assert diff == expected + @pytest.mark.parametrize("a,b,expected", [ + pytest.param(datetime(2001, 12, 12), datetime(2001, 12, 11), + timedelta(1), id='forward'), + pytest.param(datetime(2001, 12, 11), datetime(2001, 12, 12), + timedelta(-1), id='backward'), + ]) + def test_timedistance_v3(a, b, expected): + diff = a - b + assert diff == expected In ``test_timedistance_v0``, we let pytest generate the test IDs. @@ -128,11 +137,11 @@ label generated by ``idfn``, but because we didn't generate a label for ``timede objects, they are still using the default pytest representation:: - $ py.test test_time.py --collect-only - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: - collected 6 items + $ pytest test_time.py --collect-only + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: + collected 8 items @@ -140,8 +149,13 @@ objects, they are still using the default pytest representation:: + + - ======= no tests ran in 0.12 seconds ======== + ======================= no tests ran in 0.12 seconds ======================= + +In ``test_timedistance_v3``, we used ``pytest.param`` to specify the test IDs +together with the actual data, instead of listing them separately. A quick port of "testscenarios" ------------------------------------ @@ -168,7 +182,7 @@ only have to work a bit to construct the correct arguments for pytest's scenario1 = ('basic', {'attribute': 'value'}) scenario2 = ('advanced', {'attribute': 'value2'}) - class TestSampleWithScenarios: + class TestSampleWithScenarios(object): scenarios = [scenario1, scenario2] def test_demo1(self, attribute): @@ -179,23 +193,23 @@ only have to work a bit to construct the correct arguments for pytest's this is a fully self-contained example which you can run with:: - $ py.test test_scenarios.py - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: + $ pytest test_scenarios.py + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items - test_scenarios.py .... + test_scenarios.py .... [100%] - ======= 4 passed in 0.12 seconds ======== + ========================= 4 passed in 0.12 seconds ========================= If you just collect tests you'll also nicely see 'advanced' and 'basic' as variants for the test function:: - $ py.test --collect-only test_scenarios.py - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: + $ pytest --collect-only test_scenarios.py + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -205,7 +219,7 @@ If you just collect tests you'll also nicely see 'advanced' and 'basic' as varia - ======= no tests ran in 0.12 seconds ======== + ======================= no tests ran in 0.12 seconds ======================= Note that we told ``metafunc.parametrize()`` that your scenario values should be considered class-scoped. With pytest-2.3 this leads to a @@ -241,9 +255,9 @@ creates a database object for the actual test invocations:: if 'db' in metafunc.fixturenames: metafunc.parametrize("db", ['d1', 'd2'], indirect=True) - class DB1: + class DB1(object): "one database object" - class DB2: + class DB2(object): "alternative database object" @pytest.fixture @@ -257,23 +271,23 @@ creates a database object for the actual test invocations:: Let's first see how it looks like at collection time:: - $ py.test test_backends.py --collect-only - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: + $ pytest test_backends.py --collect-only + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items - ======= no tests ran in 0.12 seconds ======== + ======================= no tests ran in 0.12 seconds ======================= And then when we run the test:: - $ py.test -q test_backends.py - .F - ======= FAILURES ======== - _______ test_db_initialized[d2] ________ + $ pytest -q test_backends.py + .F [100%] + ================================= FAILURES ================================= + _________________________ test_db_initialized[d2] __________________________ db = @@ -318,15 +332,15 @@ will be passed to respective fixture function:: The result of this test will be successful:: - $ py.test test_indirect_list.py --collect-only - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: - collected 1 items + $ pytest test_indirect_list.py --collect-only + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: + collected 1 item - ======= no tests ran in 0.12 seconds ======== + ======================= no tests ran in 0.12 seconds ======================= .. regendoc:wipe @@ -336,7 +350,7 @@ Parametrizing test methods through per-class configuration .. _`unittest parametrizer`: https://github.com/testing-cabal/unittest-ext/blob/master/params.py -Here is an example ``pytest_generate_function`` function implementing a +Here is an example ``pytest_generate_tests`` function implementing a parametrization scheme similar to Michael Foord's `unittest parametrizer`_ but in a lot less code:: @@ -346,11 +360,11 @@ parametrizer`_ but in a lot less code:: def pytest_generate_tests(metafunc): # called once per each test function funcarglist = metafunc.cls.params[metafunc.function.__name__] - argnames = list(funcarglist[0]) + argnames = sorted(funcarglist[0]) metafunc.parametrize(argnames, [[funcargs[name] for name in argnames] for funcargs in funcarglist]) - class TestClass: + class TestClass(object): # a map specifying multiple argument sets for a test method params = { 'test_equals': [dict(a=1, b=2), dict(a=3, b=3), ], @@ -366,10 +380,10 @@ parametrizer`_ but in a lot less code:: Our test generator looks up a class-level definition which specifies which argument sets to use for each test function. Let's run it:: - $ py.test -q - F.. - ======= FAILURES ======== - _______ TestClass.test_equals[1-2] ________ + $ pytest -q + F.. [100%] + ================================= FAILURES ================================= + ________________________ TestClass.test_equals[1-2] ________________________ self = , a = 1, b = 2 @@ -396,12 +410,9 @@ is to be run with different sets of arguments for its three arguments: Running it results in some skips if we don't have all the python interpreters installed and otherwise runs all combinations (5 interpreters times 5 interpreters times 3 objects to serialize/deserialize):: - . $ py.test -rs -q multipython.py - ssssssssssss...ssssssssssss - ======= short test summary info ======== - SKIP [12] $REGENDOC_TMPDIR/CWD/multipython.py:23: 'python3.3' not found - SKIP [12] $REGENDOC_TMPDIR/CWD/multipython.py:23: 'python2.6' not found - 3 passed, 24 skipped in 0.12 seconds + . $ pytest -rs -q multipython.py + ........................... [100%] + 27 passed in 0.12 seconds Indirect parametrization of optional implementations/imports -------------------------------------------------------------------- @@ -446,17 +457,17 @@ And finally a little test module:: If you run this with reporting for skips enabled:: - $ py.test -rs test_module.py - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: + $ pytest -rs test_module.py + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items - test_module.py .s - ======= short test summary info ======== - SKIP [1] $REGENDOC_TMPDIR/conftest.py:10: could not import 'opt2' + test_module.py .s [100%] + ========================= short test summary info ========================== + SKIP [1] $REGENDOC_TMPDIR/conftest.py:11: could not import 'opt2' - ======= 1 passed, 1 skipped in 0.12 seconds ======== + =================== 1 passed, 1 skipped in 0.12 seconds ==================== You'll see that we don't have a ``opt2`` module and thus the second test run of our ``test_func1`` was skipped. A few notes: @@ -472,4 +483,54 @@ of our ``test_func1`` was skipped. A few notes: values as well. +Set marks or test ID for individual parametrized test +-------------------------------------------------------------------- +Use ``pytest.param`` to apply marks or set test ID to individual parametrized test. +For example:: + + # content of test_pytest_param_example.py + import pytest + @pytest.mark.parametrize('test_input,expected', [ + ('3+5', 8), + pytest.param('1+7', 8, + marks=pytest.mark.basic), + pytest.param('2+4', 6, + marks=pytest.mark.basic, + id='basic_2+4'), + pytest.param('6*9', 42, + marks=[pytest.mark.basic, pytest.mark.xfail], + id='basic_6*9'), + ]) + def test_eval(test_input, expected): + assert eval(test_input) == expected + +In this example, we have 4 parametrized tests. Except for the first test, +we mark the rest three parametrized tests with the custom marker ``basic``, +and for the fourth test we also use the built-in mark ``xfail`` to indicate this +test is expected to fail. For explicitness, we set test ids for some tests. + +Then run ``pytest`` with verbose mode and with only the ``basic`` marker:: + + pytest -v -m basic + ============================================ test session starts ============================================= + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: + collected 4 items + + test_pytest_param_example.py::test_eval[1+7-8] PASSED + test_pytest_param_example.py::test_eval[basic_2+4] PASSED + test_pytest_param_example.py::test_eval[basic_6*9] xfail + ========================================== short test summary info =========================================== + XFAIL test_pytest_param_example.py::test_eval[basic_6*9] + + ============================================= 1 tests deselected ============================================= + +As the result: + +- Four tests were collected +- One test was deselected because it doesn't have the ``basic`` mark. +- Three tests with the ``basic`` mark was selected. +- The test ``test_eval[1+7-8]`` passed, but the name is autogenerated and confusing. +- The test ``test_eval[basic_2+4]`` passed. +- The test ``test_eval[basic_6*9]`` was expected to fail and did fail. diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/py2py3/conftest.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/py2py3/conftest.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/py2py3/conftest.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/py2py3/conftest.py diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/py2py3/test_py2.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/py2py3/test_py2.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/py2py3/test_py2.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/py2py3/test_py2.py diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/py2py3/test_py3.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/py2py3/test_py3.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/py2py3/test_py3.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/py2py3/test_py3.py diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/pythoncollection.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/pythoncollection.py similarity index 58% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/pythoncollection.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/pythoncollection.py index 05858eb854b..9c4bd31cea0 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/pythoncollection.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/pythoncollection.py @@ -1,10 +1,10 @@ -# run this with $ py.test --collect-only test_collectonly.py +# run this with $ pytest --collect-only test_collectonly.py # def test_function(): pass -class TestClass: +class TestClass(object): def test_method(self): pass def test_anothermethod(self): diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/pythoncollection.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/pythoncollection.rst similarity index 56% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/pythoncollection.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/pythoncollection.rst index 5faf4c6c8ad..c9d31d7c420 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/pythoncollection.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/pythoncollection.rst @@ -9,19 +9,19 @@ by passing the ``--ignore=path`` option on the cli. ``pytest`` allows multiple ``--ignore`` options. Example:: tests/ - ├── example - │   ├── test_example_01.py - │   ├── test_example_02.py - │   └── test_example_03.py - ├── foobar - │   ├── test_foobar_01.py - │   ├── test_foobar_02.py - │   └── test_foobar_03.py - └── hello - └── world - ├── test_world_01.py - ├── test_world_02.py - └── test_world_03.py + |-- example + | |-- test_example_01.py + | |-- test_example_02.py + | '-- test_example_03.py + |-- foobar + | |-- test_foobar_01.py + | |-- test_foobar_02.py + | '-- test_foobar_03.py + '-- hello + '-- world + |-- test_world_01.py + |-- test_world_02.py + '-- test_world_03.py Now if you invoke ``pytest`` with ``--ignore=tests/foobar/test_foobar_03.py --ignore=tests/hello/``, you will see that ``pytest`` only collects test-modules, which do not match the patterns specified:: @@ -40,12 +40,46 @@ you will see that ``pytest`` only collects test-modules, which do not match the ======= 5 passed in 0.02 seconds ======= +Keeping duplicate paths specified from command line +---------------------------------------------------- + +Default behavior of ``pytest`` is to ignore duplicate paths specified from the command line. +Example:: + + py.test path_a path_a + + ... + collected 1 item + ... + +Just collect tests once. + +To collect duplicate tests, use the ``--keep-duplicates`` option on the cli. +Example:: + + py.test --keep-duplicates path_a path_a + + ... + collected 2 items + ... + +As the collector just works on directories, if you specify twice a single test file, ``pytest`` will +still collect it twice, no matter if the ``--keep-duplicates`` is not specified. +Example:: + + py.test test_a.py test_a.py + + ... + collected 2 items + ... + + Changing directory recursion ----------------------------------------------------- -You can set the :confval:`norecursedirs` option in an ini-file, for example your ``setup.cfg`` in the project root directory:: +You can set the :confval:`norecursedirs` option in an ini-file, for example your ``pytest.ini`` in the project root directory:: - # content of setup.cfg + # content of pytest.ini [pytest] norecursedirs = .svn _build tmp* @@ -60,8 +94,9 @@ You can configure different naming conventions by setting the :confval:`python_files`, :confval:`python_classes` and :confval:`python_functions` configuration options. Example:: - # content of setup.cfg - # can also be defined in in tox.ini or pytest.ini file + # content of pytest.ini + # can also be defined in tox.ini or setup.cfg file, although the section + # name in setup.cfg files should be "tool:pytest" [pytest] python_files=check_*.py python_classes=Check @@ -72,7 +107,7 @@ This would make ``pytest`` look for tests in files that match the ``check_* that match ``*_check``. For example, if we have:: # content of check_myapp.py - class CheckMyApp: + class CheckMyApp(object): def simple_check(self): pass def complex_check(self): @@ -80,10 +115,10 @@ that match ``*_check``. For example, if we have:: then the test collection looks like this:: - $ py.test --collect-only - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: setup.cfg + $ pytest --collect-only + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini collected 2 items @@ -91,7 +126,7 @@ then the test collection looks like this:: - ======= no tests ran in 0.12 seconds ======== + ======================= no tests ran in 0.12 seconds ======================= .. note:: @@ -107,7 +142,7 @@ interpreting arguments as python package names, deriving their file system path and then running the test. For example if you have unittest2 installed you can type:: - py.test --pyargs unittest2.test.test_skipping -q + pytest --pyargs unittest2.test.test_skipping -q which would run the respective test module. Like with other options, through an ini-file and the :confval:`addopts` option you @@ -117,7 +152,7 @@ can make this change more permanently:: [pytest] addopts = --pyargs -Now a simple invocation of ``py.test NAME`` will check +Now a simple invocation of ``pytest NAME`` will check if NAME exists as an importable package/module and otherwise treat it as a filesystem path. @@ -126,9 +161,9 @@ Finding out what is collected You can always peek at the collection tree without running tests like this:: - . $ py.test --collect-only pythoncollection.py - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 + . $ pytest --collect-only pythoncollection.py + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini collected 3 items @@ -138,23 +173,25 @@ You can always peek at the collection tree without running tests like this:: - ======= no tests ran in 0.12 seconds ======== + ======================= no tests ran in 0.12 seconds ======================= -customizing test collection to find all .py files ---------------------------------------------------------- +.. _customizing-test-collection: + +Customizing test collection +--------------------------- .. regendoc:wipe -You can easily instruct ``pytest`` to discover tests from every python file:: - +You can easily instruct ``pytest`` to discover tests from every Python file:: # content of pytest.ini [pytest] python_files = *.py -However, many projects will have a ``setup.py`` which they don't want to be imported. Moreover, there may files only importable by a specific python version. -For such cases you can dynamically define files to be ignored by listing -them in a ``conftest.py`` file:: +However, many projects will have a ``setup.py`` which they don't want to be +imported. Moreover, there may files only importable by a specific python +version. For such cases you can dynamically define files to be ignored by +listing them in a ``conftest.py`` file:: # content of conftest.py import sys @@ -163,7 +200,7 @@ them in a ``conftest.py`` file:: if sys.version_info[0] > 2: collect_ignore.append("pkg/module_py2.py") -And then if you have a module file like this:: +and then if you have a module file like this:: # content of pkg/module_py2.py def test_only_on_python2(): @@ -172,21 +209,31 @@ And then if you have a module file like this:: except Exception, e: pass -and a setup.py dummy file like this:: +and a ``setup.py`` dummy file like this:: # content of setup.py 0/0 # will raise exception if imported -then a pytest run on python2 will find the one test when run with a python2 -interpreters and will leave out the setup.py file:: +If you run with a Python 2 interpreter then you will find the one test and will +leave out the ``setup.py`` file:: - $ py.test --collect-only - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 + #$ pytest --collect-only + ====== test session starts ====== + platform linux2 -- Python 2.7.10, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 + rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini + collected 1 items + + + + ====== no tests ran in 0.04 seconds ====== + +If you run with a Python 3 interpreter both the one test and the ``setup.py`` +file will be left out:: + + $ pytest --collect-only + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini collected 0 items - ======= no tests ran in 0.12 seconds ======== - -If you run with a Python3 interpreter the moduled added through the conftest.py file will not be considered for test collection. - + ======================= no tests ran in 0.12 seconds ======================= diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/reportingdemo.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/reportingdemo.rst similarity index 70% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/reportingdemo.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/reportingdemo.rst index 28624aa07b8..9edc02b3cd4 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/reportingdemo.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/reportingdemo.rst @@ -7,20 +7,18 @@ Demo of Python failure reports with pytest Here is a nice run of several tens of failures and how ``pytest`` presents things (unfortunately not showing the nice colors here in the HTML that you -get on the terminal - we are working on that): +get on the terminal - we are working on that):: -.. code-block:: python - - assertion $ py.test failure_demo.py - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR/assertion, inifile: + assertion $ pytest failure_demo.py + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR/assertion, inifile: collected 42 items - failure_demo.py FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + failure_demo.py FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF [100%] - ======= FAILURES ======== - _______ test_generative[0] ________ + ================================= FAILURES ================================= + ____________________________ test_generative[0] ____________________________ param1 = 3, param2 = 6 @@ -29,7 +27,7 @@ get on the terminal - we are working on that): E assert (3 * 2) < 6 failure_demo.py:16: AssertionError - _______ TestFailing.test_simple ________ + _________________________ TestFailing.test_simple __________________________ self = @@ -45,7 +43,7 @@ get on the terminal - we are working on that): E + and 43 = .g at 0xdeadbeef>() failure_demo.py:29: AssertionError - _______ TestFailing.test_simple_multiline ________ + ____________________ TestFailing.test_simple_multiline _____________________ self = @@ -65,7 +63,7 @@ get on the terminal - we are working on that): E assert 42 == 54 failure_demo.py:12: AssertionError - _______ TestFailing.test_not ________ + ___________________________ TestFailing.test_not ___________________________ self = @@ -77,44 +75,44 @@ get on the terminal - we are working on that): E + where 42 = .f at 0xdeadbeef>() failure_demo.py:39: AssertionError - _______ TestSpecialisedExplanations.test_eq_text ________ + _________________ TestSpecialisedExplanations.test_eq_text _________________ self = def test_eq_text(self): > assert 'spam' == 'eggs' - E assert 'spam' == 'eggs' + E AssertionError: assert 'spam' == 'eggs' E - spam E + eggs failure_demo.py:43: AssertionError - _______ TestSpecialisedExplanations.test_eq_similar_text ________ + _____________ TestSpecialisedExplanations.test_eq_similar_text _____________ self = def test_eq_similar_text(self): > assert 'foo 1 bar' == 'foo 2 bar' - E assert 'foo 1 bar' == 'foo 2 bar' + E AssertionError: assert 'foo 1 bar' == 'foo 2 bar' E - foo 1 bar E ? ^ E + foo 2 bar E ? ^ failure_demo.py:46: AssertionError - _______ TestSpecialisedExplanations.test_eq_multiline_text ________ + ____________ TestSpecialisedExplanations.test_eq_multiline_text ____________ self = def test_eq_multiline_text(self): > assert 'foo\nspam\nbar' == 'foo\neggs\nbar' - E assert 'foo\nspam\nbar' == 'foo\neggs\nbar' + E AssertionError: assert 'foo\nspam\nbar' == 'foo\neggs\nbar' E foo E - spam E + eggs E bar failure_demo.py:49: AssertionError - _______ TestSpecialisedExplanations.test_eq_long_text ________ + ______________ TestSpecialisedExplanations.test_eq_long_text _______________ self = @@ -122,7 +120,7 @@ get on the terminal - we are working on that): a = '1'*100 + 'a' + '2'*100 b = '1'*100 + 'b' + '2'*100 > assert a == b - E assert '111111111111...2222222222222' == '1111111111111...2222222222222' + E AssertionError: assert '111111111111...2222222222222' == '1111111111111...2222222222222' E Skipping 90 identical leading characters in diff, use -v to show E Skipping 91 identical trailing characters in diff, use -v to show E - 1111111111a222222222 @@ -131,7 +129,7 @@ get on the terminal - we are working on that): E ? ^ failure_demo.py:54: AssertionError - _______ TestSpecialisedExplanations.test_eq_long_text_multiline ________ + _________ TestSpecialisedExplanations.test_eq_long_text_multiline __________ self = @@ -139,23 +137,19 @@ get on the terminal - we are working on that): a = '1\n'*100 + 'a' + '2\n'*100 b = '1\n'*100 + 'b' + '2\n'*100 > assert a == b - E assert '1\n1\n1\n1\n...n2\n2\n2\n2\n' == '1\n1\n1\n1\n1...n2\n2\n2\n2\n' + E AssertionError: assert '1\n1\n1\n1\n...n2\n2\n2\n2\n' == '1\n1\n1\n1\n1...n2\n2\n2\n2\n' E Skipping 190 identical leading characters in diff, use -v to show E Skipping 191 identical trailing characters in diff, use -v to show E 1 E 1 E 1 E 1 - E 1 - E - a2 - E + b2 - E 2 - E 2 - E 2 - E 2 + E 1... + E + E ...Full output truncated (7 lines hidden), use '-vv' to show failure_demo.py:59: AssertionError - _______ TestSpecialisedExplanations.test_eq_list ________ + _________________ TestSpecialisedExplanations.test_eq_list _________________ self = @@ -166,7 +160,7 @@ get on the terminal - we are working on that): E Use -v to get the full diff failure_demo.py:62: AssertionError - _______ TestSpecialisedExplanations.test_eq_list_long ________ + ______________ TestSpecialisedExplanations.test_eq_list_long _______________ self = @@ -179,41 +173,43 @@ get on the terminal - we are working on that): E Use -v to get the full diff failure_demo.py:67: AssertionError - _______ TestSpecialisedExplanations.test_eq_dict ________ + _________________ TestSpecialisedExplanations.test_eq_dict _________________ self = def test_eq_dict(self): > assert {'a': 0, 'b': 1, 'c': 0} == {'a': 0, 'b': 2, 'd': 0} - E assert {'a': 0, 'b': 1, 'c': 0} == {'a': 0, 'b': 2, 'd': 0} - E Omitting 1 identical items, use -v to show + E AssertionError: assert {'a': 0, 'b': 1, 'c': 0} == {'a': 0, 'b': 2, 'd': 0} + E Omitting 1 identical items, use -vv to show E Differing items: E {'b': 1} != {'b': 2} E Left contains more items: E {'c': 0} E Right contains more items: - E {'d': 0} - E Use -v to get the full diff + E {'d': 0}... + E + E ...Full output truncated (2 lines hidden), use '-vv' to show failure_demo.py:70: AssertionError - _______ TestSpecialisedExplanations.test_eq_set ________ + _________________ TestSpecialisedExplanations.test_eq_set __________________ self = def test_eq_set(self): > assert set([0, 10, 11, 12]) == set([0, 20, 21]) - E assert set([0, 10, 11, 12]) == set([0, 20, 21]) + E AssertionError: assert {0, 10, 11, 12} == {0, 20, 21} E Extra items in the left set: E 10 E 11 E 12 E Extra items in the right set: E 20 - E 21 - E Use -v to get the full diff + E 21... + E + E ...Full output truncated (2 lines hidden), use '-vv' to show failure_demo.py:73: AssertionError - _______ TestSpecialisedExplanations.test_eq_longer_list ________ + _____________ TestSpecialisedExplanations.test_eq_longer_list ______________ self = @@ -224,7 +220,7 @@ get on the terminal - we are working on that): E Use -v to get the full diff failure_demo.py:76: AssertionError - _______ TestSpecialisedExplanations.test_in_list ________ + _________________ TestSpecialisedExplanations.test_in_list _________________ self = @@ -233,45 +229,46 @@ get on the terminal - we are working on that): E assert 1 in [0, 2, 3, 4, 5] failure_demo.py:79: AssertionError - _______ TestSpecialisedExplanations.test_not_in_text_multiline ________ + __________ TestSpecialisedExplanations.test_not_in_text_multiline __________ self = def test_not_in_text_multiline(self): text = 'some multiline\ntext\nwhich\nincludes foo\nand a\ntail' > assert 'foo' not in text - E assert 'foo' not in 'some multiline\ntext\nw...ncludes foo\nand a\ntail' + E AssertionError: assert 'foo' not in 'some multiline\ntext\nw...ncludes foo\nand a\ntail' E 'foo' is contained here: E some multiline E text E which E includes foo E ? +++ - E and a - E tail + E and a... + E + E ...Full output truncated (2 lines hidden), use '-vv' to show failure_demo.py:83: AssertionError - _______ TestSpecialisedExplanations.test_not_in_text_single ________ + ___________ TestSpecialisedExplanations.test_not_in_text_single ____________ self = def test_not_in_text_single(self): text = 'single foo line' > assert 'foo' not in text - E assert 'foo' not in 'single foo line' + E AssertionError: assert 'foo' not in 'single foo line' E 'foo' is contained here: E single foo line E ? +++ failure_demo.py:87: AssertionError - _______ TestSpecialisedExplanations.test_not_in_text_single_long ________ + _________ TestSpecialisedExplanations.test_not_in_text_single_long _________ self = def test_not_in_text_single_long(self): text = 'head ' * 50 + 'foo ' + 'tail ' * 20 > assert 'foo' not in text - E assert 'foo' not in 'head head head head hea...ail tail tail tail tail ' + E AssertionError: assert 'foo' not in 'head head head head hea...ail tail tail tail tail ' E 'foo' is contained here: E head head foo tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail E ? +++ @@ -284,13 +281,13 @@ get on the terminal - we are working on that): def test_not_in_text_single_long_term(self): text = 'head ' * 50 + 'f'*70 + 'tail ' * 20 > assert 'f'*70 not in text - E assert 'fffffffffff...ffffffffffff' not in 'head head he...l tail tail ' + E AssertionError: assert 'fffffffffff...ffffffffffff' not in 'head head he...l tail tail ' E 'ffffffffffffffffff...fffffffffffffffffff' is contained here: E head head fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffftail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail E ? ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ failure_demo.py:95: AssertionError - _______ test_attribute ________ + ______________________________ test_attribute ______________________________ def test_attribute(): class Foo(object): @@ -301,18 +298,18 @@ get on the terminal - we are working on that): E + where 1 = .Foo object at 0xdeadbeef>.b failure_demo.py:102: AssertionError - _______ test_attribute_instance ________ + _________________________ test_attribute_instance __________________________ def test_attribute_instance(): class Foo(object): b = 1 > assert Foo().b == 2 - E assert 1 == 2 + E AssertionError: assert 1 == 2 E + where 1 = .Foo object at 0xdeadbeef>.b E + where .Foo object at 0xdeadbeef> = .Foo'>() failure_demo.py:108: AssertionError - _______ test_attribute_failure ________ + __________________________ test_attribute_failure __________________________ def test_attribute_failure(): class Foo(object): @@ -332,7 +329,7 @@ get on the terminal - we are working on that): E Exception: Failed to get attrib failure_demo.py:114: Exception - _______ test_attribute_multiple ________ + _________________________ test_attribute_multiple __________________________ def test_attribute_multiple(): class Foo(object): @@ -340,14 +337,14 @@ get on the terminal - we are working on that): class Bar(object): b = 2 > assert Foo().b == Bar().b - E assert 1 == 2 + E AssertionError: assert 1 == 2 E + where 1 = .Foo object at 0xdeadbeef>.b E + where .Foo object at 0xdeadbeef> = .Foo'>() E + and 2 = .Bar object at 0xdeadbeef>.b E + where .Bar object at 0xdeadbeef> = .Bar'>() failure_demo.py:125: AssertionError - _______ TestRaises.test_raises ________ + __________________________ TestRaises.test_raises __________________________ self = @@ -361,8 +358,8 @@ get on the terminal - we are working on that): > int(s) E ValueError: invalid literal for int() with base 10: 'qwe' - <0-codegen $PYTHON_PREFIX/lib/python3.4/site-packages/_pytest/python.py:1302>:1: ValueError - _______ TestRaises.test_raises_doesnt ________ + <0-codegen $PYTHON_PREFIX/lib/python3.5/site-packages/_pytest/python_api.py:580>:1: ValueError + ______________________ TestRaises.test_raises_doesnt _______________________ self = @@ -371,7 +368,7 @@ get on the terminal - we are working on that): E Failed: DID NOT RAISE failure_demo.py:137: Failed - _______ TestRaises.test_raise ________ + __________________________ TestRaises.test_raise ___________________________ self = @@ -380,13 +377,13 @@ get on the terminal - we are working on that): E ValueError: demo error failure_demo.py:140: ValueError - _______ TestRaises.test_tupleerror ________ + ________________________ TestRaises.test_tupleerror ________________________ self = def test_tupleerror(self): > a,b = [1] - E ValueError: need more than 1 value to unpack + E ValueError: not enough values to unpack (expected 2, got 1) failure_demo.py:143: ValueError ______ TestRaises.test_reinterpret_fails_with_print_for_the_fun_of_it ______ @@ -402,7 +399,7 @@ get on the terminal - we are working on that): failure_demo.py:148: TypeError --------------------------- Captured stdout call --------------------------- l is [1, 2, 3] - _______ TestRaises.test_some_error ________ + ________________________ TestRaises.test_some_error ________________________ self = @@ -411,7 +408,7 @@ get on the terminal - we are working on that): E NameError: name 'namenotexi' is not defined failure_demo.py:151: NameError - _______ test_dynamic_compile_shows_nicely ________ + ____________________ test_dynamic_compile_shows_nicely _____________________ def test_dynamic_compile_shows_nicely(): src = 'def foo():\n assert 1 == 0\n' @@ -427,10 +424,10 @@ get on the terminal - we are working on that): def foo(): > assert 1 == 0 - E assert 1 == 0 + E AssertionError <2-codegen 'abc-123' $REGENDOC_TMPDIR/assertion/failure_demo.py:163>:2: AssertionError - _______ TestMoreErrors.test_complex_error ________ + ____________________ TestMoreErrors.test_complex_error _____________________ self = @@ -454,17 +451,17 @@ get on the terminal - we are working on that): E assert 44 == 43 failure_demo.py:6: AssertionError - _______ TestMoreErrors.test_z1_unpack_error ________ + ___________________ TestMoreErrors.test_z1_unpack_error ____________________ self = def test_z1_unpack_error(self): l = [] > a,b = l - E ValueError: need more than 0 values to unpack + E ValueError: not enough values to unpack (expected 2, got 0) failure_demo.py:180: ValueError - _______ TestMoreErrors.test_z2_type_error ________ + ____________________ TestMoreErrors.test_z2_type_error _____________________ self = @@ -474,7 +471,7 @@ get on the terminal - we are working on that): E TypeError: 'int' object is not iterable failure_demo.py:184: TypeError - _______ TestMoreErrors.test_startswith ________ + ______________________ TestMoreErrors.test_startswith ______________________ self = @@ -482,11 +479,12 @@ get on the terminal - we are working on that): s = "123" g = "456" > assert s.startswith(g) - E assert ('456') - E + where = '123'.startswith + E AssertionError: assert False + E + where False = ('456') + E + where = '123'.startswith failure_demo.py:189: AssertionError - _______ TestMoreErrors.test_startswith_nested ________ + __________________ TestMoreErrors.test_startswith_nested ___________________ self = @@ -496,23 +494,25 @@ get on the terminal - we are working on that): def g(): return "456" > assert f().startswith(g()) - E assert ('456') - E + where = '123'.startswith - E + where '123' = .f at 0xdeadbeef>() - E + and '456' = .g at 0xdeadbeef>() + E AssertionError: assert False + E + where False = ('456') + E + where = '123'.startswith + E + where '123' = .f at 0xdeadbeef>() + E + and '456' = .g at 0xdeadbeef>() failure_demo.py:196: AssertionError - _______ TestMoreErrors.test_global_func ________ + _____________________ TestMoreErrors.test_global_func ______________________ self = def test_global_func(self): > assert isinstance(globf(42), float) - E assert isinstance(43, float) - E + where 43 = globf(42) + E assert False + E + where False = isinstance(43, float) + E + where 43 = globf(42) failure_demo.py:199: AssertionError - _______ TestMoreErrors.test_instance ________ + _______________________ TestMoreErrors.test_instance _______________________ self = @@ -523,7 +523,7 @@ get on the terminal - we are working on that): E + where 42 = .x failure_demo.py:203: AssertionError - _______ TestMoreErrors.test_compare ________ + _______________________ TestMoreErrors.test_compare ________________________ self = @@ -533,7 +533,7 @@ get on the terminal - we are working on that): E + where 11 = globf(10) failure_demo.py:206: AssertionError - _______ TestMoreErrors.test_try_finally ________ + _____________________ TestMoreErrors.test_try_finally ______________________ self = @@ -544,12 +544,12 @@ get on the terminal - we are working on that): E assert 1 == 0 failure_demo.py:211: AssertionError - _______ TestCustomAssertMsg.test_single_line ________ + ___________________ TestCustomAssertMsg.test_single_line ___________________ self = def test_single_line(self): - class A: + class A(object): a = 1 b = 2 > assert A.a == b, "A.a appears not to be b" @@ -558,12 +558,12 @@ get on the terminal - we are working on that): E + where 1 = .A'>.a failure_demo.py:222: AssertionError - _______ TestCustomAssertMsg.test_multiline ________ + ____________________ TestCustomAssertMsg.test_multiline ____________________ self = def test_multiline(self): - class A: + class A(object): a = 1 b = 2 > assert A.a == b, "A.a appears not to be b\n" \ @@ -575,12 +575,12 @@ get on the terminal - we are working on that): E + where 1 = .A'>.a failure_demo.py:228: AssertionError - _______ TestCustomAssertMsg.test_custom_repr ________ + ___________________ TestCustomAssertMsg.test_custom_repr ___________________ self = def test_custom_repr(self): - class JSON: + class JSON(object): a = 1 def __repr__(self): return "This is JSON\n{\n 'foo': 'bar'\n}" @@ -595,4 +595,10 @@ get on the terminal - we are working on that): E + where 1 = This is JSON\n{\n 'foo': 'bar'\n}.a failure_demo.py:238: AssertionError - ======= 42 failed in 0.12 seconds ======== + ============================= warnings summary ============================= + None + Metafunc.addcall is deprecated and scheduled to be removed in pytest 4.0. + Please use Metafunc.parametrize instead. + + -- Docs: http://doc.pytest.org/en/latest/warnings.html + ================== 42 failed, 1 warnings in 0.12 seconds =================== diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/simple.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/simple.rst similarity index 52% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/simple.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/simple.rst index be12d2afe41..678a0db0094 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/simple.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/simple.rst @@ -1,5 +1,4 @@ -.. highlightlang:: python Basic patterns and examples ========================================================== @@ -10,7 +9,9 @@ Pass different values to a test function, depending on command line options .. regendoc:wipe Suppose we want to write a test that depends on a command line option. -Here is a basic pattern to achieve this:: +Here is a basic pattern to achieve this: + +.. code-block:: python # content of test_sample.py def test_answer(cmdopt): @@ -22,7 +23,9 @@ Here is a basic pattern to achieve this:: For this to work we need to add a command line option and -provide the ``cmdopt`` through a :ref:`fixture function `:: +provide the ``cmdopt`` through a :ref:`fixture function `: + +.. code-block:: python # content of conftest.py import pytest @@ -37,10 +40,10 @@ provide the ``cmdopt`` through a :ref:`fixture function `:: Let's run this without supplying our new option:: - $ py.test -q test_sample.py - F - ======= FAILURES ======== - _______ test_answer ________ + $ pytest -q test_sample.py + F [100%] + ================================= FAILURES ================================= + _______________________________ test_answer ________________________________ cmdopt = 'type1' @@ -59,10 +62,10 @@ Let's run this without supplying our new option:: And now with supplying a command line option:: - $ py.test -q --cmdopt=type2 - F - ======= FAILURES ======== - _______ test_answer ________ + $ pytest -q --cmdopt=type2 + F [100%] + ================================= FAILURES ================================= + _______________________________ test_answer ________________________________ cmdopt = 'type2' @@ -91,7 +94,9 @@ Dynamically adding command line options Through :confval:`addopts` you can statically add command line options for your project. You can also dynamically modify -the command line arguments before they get processed:: +the command line arguments before they get processed: + +.. code-block:: python # content of conftest.py import sys @@ -101,18 +106,18 @@ the command line arguments before they get processed:: num = max(multiprocessing.cpu_count() / 2, 1) args[:] = ["-n", str(num)] + args -If you have the :ref:`xdist plugin ` installed +If you have the `xdist plugin `_ installed you will now always perform test runs using a number of subprocesses close to your CPU. Running in an empty directory with the above conftest.py:: - $ py.test - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: + $ pytest + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: collected 0 items - ======= no tests ran in 0.12 seconds ======== + ======================= no tests ran in 0.12 seconds ======================= .. _`excontrolskip`: @@ -122,61 +127,67 @@ Control skipping of tests according to command line option .. regendoc:wipe Here is a ``conftest.py`` file adding a ``--runslow`` command -line option to control skipping of ``slow`` marked tests:: +line option to control skipping of ``pytest.mark.slow`` marked tests: + +.. code-block:: python # content of conftest.py import pytest def pytest_addoption(parser): parser.addoption("--runslow", action="store_true", - help="run slow tests") + default=False, help="run slow tests") -We can now write a test module like this:: + def pytest_collection_modifyitems(config, items): + if config.getoption("--runslow"): + # --runslow given in cli: do not skip slow tests + return + skip_slow = pytest.mark.skip(reason="need --runslow option to run") + for item in items: + if "slow" in item.keywords: + item.add_marker(skip_slow) + +We can now write a test module like this: + +.. code-block:: python # content of test_module.py - import pytest - slow = pytest.mark.skipif( - not pytest.config.getoption("--runslow"), - reason="need --runslow option to run" - ) - - def test_func_fast(): pass - @slow + @pytest.mark.slow def test_func_slow(): pass and when running it will see a skipped "slow" test:: - $ py.test -rs # "-rs" means report details on the little 's' - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: + $ pytest -rs # "-rs" means report details on the little 's' + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items - test_module.py .s - ======= short test summary info ======== - SKIP [1] test_module.py:14: need --runslow option to run + test_module.py .s [100%] + ========================= short test summary info ========================== + SKIP [1] test_module.py:8: need --runslow option to run - ======= 1 passed, 1 skipped in 0.12 seconds ======== + =================== 1 passed, 1 skipped in 0.12 seconds ==================== Or run it including the ``slow`` marked test:: - $ py.test --runslow - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: + $ pytest --runslow + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items - test_module.py .. + test_module.py .. [100%] - ======= 2 passed in 0.12 seconds ======== + ========================= 2 passed in 0.12 seconds ========================= Writing well integrated assertion helpers -------------------------------------------------- @@ -187,7 +198,9 @@ If you have a test helper function called from a test you can use the ``pytest.fail`` marker to fail a test with a certain message. The test support function will not show up in the traceback if you set the ``__tracebackhide__`` option somewhere in the helper function. -Example:: +Example: + +.. code-block:: python # content of test_checkconfig.py import pytest @@ -201,13 +214,13 @@ Example:: The ``__tracebackhide__`` setting influences ``pytest`` showing of tracebacks: the ``checkconfig`` function will not be shown -unless the ``--fulltrace`` command line option is specified. +unless the ``--full-trace`` command line option is specified. Let's run our little function:: - $ py.test -q test_checkconfig.py - F - ======= FAILURES ======== - _______ test_something ________ + $ pytest -q test_checkconfig.py + F [100%] + ================================= FAILURES ================================= + ______________________________ test_something ______________________________ def test_something(): > checkconfig(42) @@ -216,6 +229,30 @@ Let's run our little function:: test_checkconfig.py:8: Failed 1 failed in 0.12 seconds +If you only want to hide certain exceptions, you can set ``__tracebackhide__`` +to a callable which gets the ``ExceptionInfo`` object. You can for example use +this to make sure unexpected exception types aren't hidden: + +.. code-block:: python + + import operator + import pytest + + class ConfigException(Exception): + pass + + def checkconfig(x): + __tracebackhide__ = operator.methodcaller('errisinstance', ConfigException) + if not hasattr(x, "config"): + raise ConfigException("not configured: %s" %(x,)) + + def test_something(): + checkconfig(42) + +This will avoid hiding the exception traceback on unrelated exceptions (i.e. +bugs in assertion helpers). + + Detect if running from within a pytest run -------------------------------------------------------------- @@ -224,7 +261,9 @@ Detect if running from within a pytest run Usually it is a bad idea to make application code behave differently if called from a test. But if you absolutely must find out if your application code is -running from a test you can do something like this:: +running from a test you can do something like this: + +.. code-block:: python # content of conftest.py @@ -233,9 +272,12 @@ running from a test you can do something like this:: sys._called_from_test = True def pytest_unconfigure(config): + import sys del sys._called_from_test -and then check for the ``sys._called_from_test`` flag:: +and then check for the ``sys._called_from_test`` flag: + +.. code-block:: python if hasattr(sys, '_called_from_test'): # called from within a test run @@ -251,7 +293,9 @@ Adding info to test report header .. regendoc:wipe -It's easy to present extra information in a ``pytest`` run:: +It's easy to present extra information in a ``pytest`` run: + +.. code-block:: python # content of conftest.py @@ -260,50 +304,51 @@ It's easy to present extra information in a ``pytest`` run:: which will add the string to the test header accordingly:: - $ py.test - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 + $ pytest + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y project deps: mylib-1.1 - rootdir: $REGENDOC_TMPDIR, inifile: + rootdir: $REGENDOC_TMPDIR, inifile: collected 0 items - ======= no tests ran in 0.12 seconds ======== + ======================= no tests ran in 0.12 seconds ======================= .. regendoc:wipe -You can also return a list of strings which will be considered as several -lines of information. You can of course also make the amount of reporting -information on e.g. the value of ``config.option.verbose`` so that -you present more information appropriately:: +It is also possible to return a list of strings which will be considered as several +lines of information. You may consider ``config.getoption('verbose')`` in order to +display more information if applicable: + +.. code-block:: python # content of conftest.py def pytest_report_header(config): - if config.option.verbose > 0: + if config.getoption('verbose') > 0: return ["info1: did you know that ...", "did you?"] which will add info only when run with "--v":: - $ py.test -v - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.4 + $ pytest -v + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache info1: did you know that ... did you? - rootdir: $REGENDOC_TMPDIR, inifile: + rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 0 items - ======= no tests ran in 0.12 seconds ======== + ======================= no tests ran in 0.12 seconds ======================= and nothing when run plainly:: - $ py.test - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: + $ pytest + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: collected 0 items - ======= no tests ran in 0.12 seconds ======== + ======================= no tests ran in 0.12 seconds ======================= profiling test duration -------------------------- @@ -313,36 +358,37 @@ profiling test duration .. versionadded: 2.2 If you have a slow running large test suite you might want to find -out which tests are the slowest. Let's make an artificial test suite:: +out which tests are the slowest. Let's make an artificial test suite: + +.. code-block:: python # content of test_some_are_slow.py - import time def test_funcfast(): - pass - - def test_funcslow1(): time.sleep(0.1) - def test_funcslow2(): + def test_funcslow1(): time.sleep(0.2) + def test_funcslow2(): + time.sleep(0.3) + Now we can profile which test functions execute the slowest:: - $ py.test --durations=3 - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: + $ pytest --durations=3 + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: collected 3 items - test_some_are_slow.py ... + test_some_are_slow.py ... [100%] - ======= slowest 3 test durations ======== - 0.20s call test_some_are_slow.py::test_funcslow2 - 0.10s call test_some_are_slow.py::test_funcslow1 - 0.00s setup test_some_are_slow.py::test_funcfast - ======= 3 passed in 0.12 seconds ======== + ========================= slowest 3 test durations ========================= + 0.30s call test_some_are_slow.py::test_funcslow2 + 0.20s call test_some_are_slow.py::test_funcslow1 + 0.10s call test_some_are_slow.py::test_funcfast + ========================= 3 passed in 0.12 seconds ========================= incremental testing - test steps --------------------------------------------------- @@ -353,7 +399,9 @@ Sometimes you may have a testing situation which consists of a series of test steps. If one step fails it makes no sense to execute further steps as they are all expected to fail anyway and their tracebacks add no insight. Here is a simple ``conftest.py`` file which introduces -an ``incremental`` marker which is to be used on classes:: +an ``incremental`` marker which is to be used on classes: + +.. code-block:: python # content of conftest.py @@ -372,14 +420,16 @@ an ``incremental`` marker which is to be used on classes:: pytest.xfail("previous test failed (%s)" %previousfailed.name) These two hook implementations work together to abort incremental-marked -tests in a class. Here is a test module example:: +tests in a class. Here is a test module example: + +.. code-block:: python # content of test_step.py import pytest @pytest.mark.incremental - class TestUserHandling: + class TestUserHandling(object): def test_login(self): pass def test_modification(self): @@ -392,19 +442,19 @@ tests in a class. Here is a test module example:: If we run this:: - $ py.test -rx - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: + $ pytest -rx + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items - test_step.py .Fx. - ======= short test summary info ======== + test_step.py .Fx. [100%] + ========================= short test summary info ========================== XFAIL test_step.py::TestUserHandling::()::test_deletion reason: previous test failed (test_modification) - ======= FAILURES ======== - _______ TestUserHandling.test_modification ________ + ================================= FAILURES ================================= + ____________________ TestUserHandling.test_modification ____________________ self = @@ -413,7 +463,7 @@ If we run this:: E assert 0 test_step.py:9: AssertionError - ======= 1 failed, 2 passed, 1 xfailed in 0.12 seconds ======== + ============== 1 failed, 2 passed, 1 xfailed in 0.12 seconds =============== We'll see that ``test_deletion`` was not executed because ``test_modification`` failed. It is reported as an "expected failure". @@ -430,32 +480,40 @@ concept. It's however recommended to have explicit fixture references in your tests or test classes rather than relying on implicitly executing setup/teardown functions, especially if they are far away from the actual tests. -Here is a an example for making a ``db`` fixture available in a directory:: +Here is an example for making a ``db`` fixture available in a directory: + +.. code-block:: python # content of a/conftest.py import pytest - class DB: + class DB(object): pass @pytest.fixture(scope="session") def db(): return DB() -and then a test module in that directory:: +and then a test module in that directory: + +.. code-block:: python # content of a/test_db.py def test_a1(db): assert 0, db # to show value -another test module:: +another test module: + +.. code-block:: python # content of a/test_db2.py def test_a2(db): assert 0, db # to show value and then a module in a sister directory which will not see -the ``db`` fixture:: +the ``db`` fixture: + +.. code-block:: python # content of b/test_error.py def test_root(db): # no db here, will error out @@ -463,28 +521,28 @@ the ``db`` fixture:: We can run this:: - $ py.test - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: + $ pytest + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: collected 7 items - test_step.py .Fx. - a/test_db.py F - a/test_db2.py F - b/test_error.py E + test_step.py .Fx. [ 57%] + a/test_db.py F [ 71%] + a/test_db2.py F [ 85%] + b/test_error.py E [100%] - ======= ERRORS ======== - _______ ERROR at setup of test_root ________ + ================================== ERRORS ================================== + _______________________ ERROR at setup of test_root ________________________ file $REGENDOC_TMPDIR/b/test_error.py, line 1 def test_root(db): # no db here, will error out - fixture 'db' not found - available fixtures: record_xml_property, recwarn, cache, capsys, pytestconfig, tmpdir_factory, capfd, monkeypatch, tmpdir - use 'py.test --fixtures [testpath]' for help on them. + E fixture 'db' not found + > available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_xml_property, recwarn, tmpdir, tmpdir_factory + > use 'pytest --fixtures [testpath]' for help on them. $REGENDOC_TMPDIR/b/test_error.py:1 - ======= FAILURES ======== - _______ TestUserHandling.test_modification ________ + ================================= FAILURES ================================= + ____________________ TestUserHandling.test_modification ____________________ self = @@ -493,7 +551,7 @@ We can run this:: E assert 0 test_step.py:9: AssertionError - _______ test_a1 ________ + _________________________________ test_a1 __________________________________ db = @@ -503,7 +561,7 @@ We can run this:: E assert 0 a/test_db.py:2: AssertionError - _______ test_a2 ________ + _________________________________ test_a2 __________________________________ db = @@ -513,7 +571,7 @@ We can run this:: E assert 0 a/test_db2.py:2: AssertionError - ======= 3 failed, 2 passed, 1 xfailed, 1 error in 0.12 seconds ======== + ========== 3 failed, 2 passed, 1 xfailed, 1 error in 0.12 seconds ========== The two test modules in the ``a`` directory see the same ``db`` fixture instance while the one test in the sister-directory ``b`` doesn't see it. We could of course @@ -531,7 +589,9 @@ environment you can implement a hook that gets called when the test "report" object is about to be created. Here we write out all failing test calls and also access a fixture (if it was used by the test) in case you want to query/look at it during your post processing. In our -case we just write some informations out to a ``failures`` file:: +case we just write some information out to a ``failures`` file: + +.. code-block:: python # content of conftest.py @@ -557,7 +617,9 @@ case we just write some informations out to a ``failures`` file:: f.write(rep.nodeid + extra + "\n") -if you then have failing tests:: +if you then have failing tests: + +.. code-block:: python # content of test_module.py def test_fail1(tmpdir): @@ -567,16 +629,16 @@ if you then have failing tests:: and run them:: - $ py.test test_module.py - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: + $ pytest test_module.py + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items - test_module.py FF + test_module.py FF [100%] - ======= FAILURES ======== - _______ test_fail1 ________ + ================================= FAILURES ================================= + ________________________________ test_fail1 ________________________________ tmpdir = local('PYTEST_TMPDIR/test_fail10') @@ -585,14 +647,14 @@ and run them:: E assert 0 test_module.py:2: AssertionError - _______ test_fail2 ________ + ________________________________ test_fail2 ________________________________ def test_fail2(): > assert 0 E assert 0 test_module.py:4: AssertionError - ======= 2 failed in 0.12 seconds ======== + ========================= 2 failed in 0.12 seconds ========================= you will have a "failures" file which contains the failing test ids:: @@ -606,7 +668,9 @@ Making test result information available in fixtures .. regendoc:wipe If you want to make test result reports available in fixture finalizers -here is a little example implemented via a local plugin:: +here is a little example implemented via a local plugin: + +.. code-block:: python # content of conftest.py @@ -618,7 +682,7 @@ here is a little example implemented via a local plugin:: outcome = yield rep = outcome.get_result() - # set an report attribute for each phase of a call, which can + # set a report attribute for each phase of a call, which can # be "setup", "call", "teardown" setattr(item, "rep_" + rep.when, rep) @@ -626,18 +690,19 @@ here is a little example implemented via a local plugin:: @pytest.fixture def something(request): - def fin(): - # request.node is an "item" because we use the default - # "function" scope - if request.node.rep_setup.failed: - print ("setting up a test failed!", request.node.nodeid) - elif request.node.rep_setup.passed: - if request.node.rep_call.failed: - print ("executing test failed", request.node.nodeid) - request.addfinalizer(fin) + yield + # request.node is an "item" because we use the default + # "function" scope + if request.node.rep_setup.failed: + print ("setting up a test failed!", request.node.nodeid) + elif request.node.rep_setup.passed: + if request.node.rep_call.failed: + print ("executing test failed", request.node.nodeid) -if you then have failing tests:: +if you then have failing tests: + +.. code-block:: python # content of test_module.py @@ -658,18 +723,18 @@ if you then have failing tests:: and run it:: - $ py.test -s test_module.py - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: + $ pytest -s test_module.py + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: collected 3 items test_module.py Esetting up a test failed! test_module.py::test_setup_fails Fexecuting test failed test_module.py::test_call_fails - F + F [100%] - ======= ERRORS ======== - _______ ERROR at setup of test_setup_fails ________ + ================================== ERRORS ================================== + ____________________ ERROR at setup of test_setup_fails ____________________ @pytest.fixture def other(): @@ -677,8 +742,8 @@ and run it:: E assert 0 test_module.py:6: AssertionError - ======= FAILURES ======== - _______ test_call_fails ________ + ================================= FAILURES ================================= + _____________________________ test_call_fails ______________________________ something = None @@ -687,52 +752,82 @@ and run it:: E assert 0 test_module.py:12: AssertionError - _______ test_fail2 ________ + ________________________________ test_fail2 ________________________________ def test_fail2(): > assert 0 E assert 0 test_module.py:15: AssertionError - ======= 2 failed, 1 error in 0.12 seconds ======== + ==================== 2 failed, 1 error in 0.12 seconds ===================== You'll see that the fixture finalizers could use the precise reporting information. -Integrating pytest runner and cx_freeze ------------------------------------------------------------ +``PYTEST_CURRENT_TEST`` environment variable +-------------------------------------------- + +.. versionadded:: 3.2 + +Sometimes a test session might get stuck and there might be no easy way to figure out +which test got stuck, for example if pytest was run in quiet mode (``-q``) or you don't have access to the console +output. This is particularly a problem if the problem helps only sporadically, the famous "flaky" kind of tests. + +``pytest`` sets a ``PYTEST_CURRENT_TEST`` environment variable when running tests, which can be inspected +by process monitoring utilities or libraries like `psutil `_ to discover which +test got stuck if necessary: + +.. code-block:: python + + import psutil + + for pid in psutil.pids(): + environ = psutil.Process(pid).environ() + if 'PYTEST_CURRENT_TEST' in environ: + print(f'pytest process {pid} running: {environ["PYTEST_CURRENT_TEST"]}') + +During the test session pytest will set ``PYTEST_CURRENT_TEST`` to the current test +:ref:`nodeid ` and the current stage, which can be ``setup``, ``call`` +and ``teardown``. + +For example, when running a single test function named ``test_foo`` from ``foo_module.py``, +``PYTEST_CURRENT_TEST`` will be set to: + +#. ``foo_module.py::test_foo (setup)`` +#. ``foo_module.py::test_foo (call)`` +#. ``foo_module.py::test_foo (teardown)`` + +In that order. + +.. note:: + + The contents of ``PYTEST_CURRENT_TEST`` is meant to be human readable and the actual format + can be changed between releases (even bug fixes) so it shouldn't be relied on for scripting + or automation. + +Freezing pytest +--------------- If you freeze your application using a tool like -`cx_freeze `_ in order to distribute it -to your end-users, it is a good idea to also package your test runner and run -your tests using the frozen application. +`PyInstaller `_ +in order to distribute it to your end-users, it is a good idea to also package +your test runner and run your tests using the frozen application. This way packaging +errors such as dependencies not being included into the executable can be detected early +while also allowing you to send test files to users so they can run them in their +machines, which can be useful to obtain more information about a hard to reproduce bug. -This way packaging errors such as dependencies not being -included into the executable can be detected early while also allowing you to -send test files to users so they can run them in their machines, which can be -invaluable to obtain more information about a hard to reproduce bug. +Fortunately recent ``PyInstaller`` releases already have a custom hook +for pytest, but if you are using another tool to freeze executables +such as ``cx_freeze`` or ``py2exe``, you can use ``pytest.freeze_includes()`` +to obtain the full list of internal pytest modules. How to configure the tools +to find the internal modules varies from tool to tool, however. -Unfortunately ``cx_freeze`` can't discover them -automatically because of ``pytest``'s use of dynamic module loading, so you -must declare them explicitly by using ``pytest.freeze_includes()``:: +Instead of freezing the pytest runner as a separate executable, you can make +your frozen program work as the pytest runner by some clever +argument handling during program startup. This allows you to +have a single executable, which is usually more convenient. - # contents of setup.py - from cx_Freeze import setup, Executable - import pytest - - setup( - name="app_main", - executables=[Executable("app_main.py")], - options={"build_exe": - { - 'includes': pytest.freeze_includes()} - }, - # ... other options - ) - -If you don't want to ship a different executable just in order to run your tests, -you can make your program check for a certain flag and pass control -over to ``pytest`` instead. For example:: +.. code-block:: python # contents of app_main.py import sys @@ -745,7 +840,8 @@ over to ``pytest`` instead. For example:: # by your argument-parsing library of choice as usual ... -This makes it convenient to execute your tests from within your frozen -application, using standard ``py.test`` command-line options:: + +This allows you to execute tests using the frozen +application with standard ``pytest`` command-line options:: ./app_main --pytest --verbose --tb=long --junitxml=results.xml test-suite/ diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/special.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/special.rst similarity index 91% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/special.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/special.rst index 58e66d44e34..4437e1cc30e 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/special.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/special.rst @@ -28,7 +28,7 @@ will be called ahead of running any tests:: # content of test_module.py - class TestHello: + class TestHello(object): @classmethod def callme(cls): print ("callme called!") @@ -39,7 +39,7 @@ will be called ahead of running any tests:: def test_method2(self): print ("test_method1 called") - class TestOther: + class TestOther(object): @classmethod def callme(cls): print ("callme other called") @@ -59,7 +59,7 @@ will be called ahead of running any tests:: If you run this without output capturing:: - $ py.test -q -s test_module.py + $ pytest -q -s test_module.py callattr_ahead_of_alltests called callme called! callme other called @@ -68,5 +68,5 @@ If you run this without output capturing:: .test_method1 called .test other .test_unit1 method called - . + . [100%] 4 passed in 0.12 seconds diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/example/xfail_demo.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/xfail_demo.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/example/xfail_demo.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/example/xfail_demo.py diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/existingtestsuite.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/existingtestsuite.rst new file mode 100644 index 00000000000..d304b30c9a6 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/existingtestsuite.rst @@ -0,0 +1,34 @@ +.. _existingtestsuite: + +Using pytest with an existing test suite +=========================================== + +Pytest can be used with most existing test suites, but its +behavior differs from other test runners such as :ref:`nose ` or +Python's default unittest framework. + +Before using this section you will want to :ref:`install pytest `. + +Running an existing test suite with pytest +--------------------------------------------- + +Say you want to contribute to an existing repository somewhere. +After pulling the code into your development space using some +flavor of version control and (optionally) setting up a virtualenv +you will want to run:: + + cd + pip install -e . # Environment dependent alternatives include + # 'python setup.py develop' and 'conda develop' + +in your project root. This will set up a symlink to your code in +site-packages, allowing you to edit your code while your tests +run against it as if it were installed. + +Setting up your project in development mode lets you avoid having to +reinstall every time you want to run your tests, and is less brittle than +mucking about with sys.path to point your tests at local code. + +Also consider using :ref:`tox `. + +.. include:: links.inc diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/faq.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/faq.rst similarity index 84% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/faq.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/faq.rst index fd7ca35e943..27d74e1148c 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/faq.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/faq.rst @@ -66,14 +66,6 @@ This completely avoids previous issues of confusing assertion-reporting. It also means, that you can use Python's ``-O`` optimization without losing assertions in test modules. -``pytest`` contains a second, mostly obsolete, assert debugging technique -invoked via ``--assert=reinterpret``: When an ``assert`` statement fails, ``pytest`` re-interprets -the expression part to show intermediate values. This technique suffers -from a caveat that the rewriting does not: If your expression has side -effects (better to avoid them anyway!) the intermediate values may not -be the same, confusing the reinterpreter and obfuscating the initial -error (this is also explained at the command line if it happens). - You can also turn off all assertion interaction using the ``--assert=plain`` option. @@ -81,18 +73,17 @@ You can also turn off all assertion interaction using the .. _`py/__init__.py`: http://bitbucket.org/hpk42/py-trunk/src/trunk/py/__init__.py -Why a ``py.test`` instead of a ``pytest`` command? -++++++++++++++++++++++++++++++++++++++++++++++++++ +Why can I use both ``pytest`` and ``py.test`` commands? ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -Some of the reasons are historic, others are practical. ``pytest`` -used to be part of the ``py`` package which provided several developer -utilities, all starting with ``py.``, thus providing nice -TAB-completion. If -you install ``pip install pycmd`` you get these tools from a separate -package. These days the command line tool could be called ``pytest`` -but since many people have gotten used to the old name and there -is another tool named "pytest" we just decided to stick with -``py.test`` for now. +pytest used to be part of the py package, which provided several developer +utilities, all starting with ``py.``, thus providing nice TAB-completion. +If you install ``pip install pycmd`` you get these tools from a separate +package. Once ``pytest`` became a separate package, the ``py.test`` name was +retained due to avoid a naming conflict with another tool. This conflict was +eventually resolved, and the ``pytest`` command was therefore introduced. In +future versions of pytest, we may deprecate and later remove the ``py.test`` +command to avoid perpetuating the confusion. pytest fixtures, parametrized tests ------------------------------------------------------- diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/fixture.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/fixture.rst similarity index 68% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/fixture.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/fixture.rst index f48607ae2dd..01a941ddf65 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/fixture.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/fixture.rst @@ -11,7 +11,7 @@ pytest fixtures: explicit, modular, scalable .. _`xUnit`: http://en.wikipedia.org/wiki/XUnit .. _`purpose of test fixtures`: http://en.wikipedia.org/wiki/Test_fixture#Software -.. _`Dependency injection`: http://en.wikipedia.org/wiki/Dependency_injection#Definition +.. _`Dependency injection`: http://en.wikipedia.org/wiki/Dependency_injection The `purpose of test fixtures`_ is to provide a fixed baseline upon which tests can reliably and repeatedly execute. pytest fixtures @@ -27,18 +27,13 @@ functions: * fixture management scales from simple unit to complex functional testing, allowing to parametrize fixtures and tests according to configuration and component options, or to re-use fixtures - across class, module or whole test session scopes. + across function, class, module or whole test session scopes. In addition, pytest continues to support :ref:`xunitsetup`. You can mix both styles, moving incrementally from classic to new style, as you prefer. You can also start out from existing :ref:`unittest.TestCase style ` or :ref:`nose based ` projects. -.. note:: - - pytest-2.4 introduced an additional experimental - :ref:`yield fixture mechanism ` for easier context manager - integration and more linear writing of teardown code. .. _`funcargs`: .. _`funcarg mechanism`: @@ -62,7 +57,7 @@ using it:: @pytest.fixture def smtp(): import smtplib - return smtplib.SMTP("smtp.gmail.com") + return smtplib.SMTP("smtp.gmail.com", 587, timeout=5) def test_ehlo(smtp): response, msg = smtp.ehlo() @@ -73,16 +68,16 @@ Here, the ``test_ehlo`` needs the ``smtp`` fixture value. pytest will discover and call the :py:func:`@pytest.fixture <_pytest.python.fixture>` marked ``smtp`` fixture function. Running the test looks like this:: - $ py.test test_smtpsimple.py - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: - collected 1 items + $ pytest test_smtpsimple.py + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: + collected 1 item - test_smtpsimple.py F + test_smtpsimple.py F [100%] - ======= FAILURES ======== - _______ test_ehlo ________ + ================================= FAILURES ================================= + ________________________________ test_ehlo _________________________________ smtp = @@ -93,7 +88,7 @@ marked ``smtp`` fixture function. Running the test looks like this:: E assert 0 test_smtpsimple.py:11: AssertionError - ======= 1 failed in 0.12 seconds ======== + ========================= 1 failed in 0.12 seconds ========================= In the failure traceback we see that the test function was called with a ``smtp`` argument, the ``smtplib.SMTP()`` instance created by the fixture @@ -114,41 +109,57 @@ Note that if you misspell a function argument or want to use one that isn't available, you'll see an error with a list of available function arguments. -.. Note:: +.. note:: You can always issue:: - py.test --fixtures test_simplefactory.py + pytest --fixtures test_simplefactory.py to see available fixtures. - In versions prior to 2.3 there was no ``@pytest.fixture`` marker - and you had to use a magic ``pytest_funcarg__NAME`` prefix - for the fixture factory. This remains and will remain supported - but is not anymore advertised as the primary means of declaring fixture - functions. - -"Funcargs" a prime example of dependency injection +Fixtures: a prime example of dependency injection --------------------------------------------------- -When injecting fixtures to test functions, pytest-2.0 introduced the -term "funcargs" or "funcarg mechanism" which continues to be present -also in docs today. It now refers to the specific case of injecting -fixture values as arguments to test functions. With pytest-2.3 there are -more possibilities to use fixtures but "funcargs" remain as the main way -as they allow to directly state the dependencies of a test function. - -As the following examples show in more detail, funcargs allow test -functions to easily receive and work against specific pre-initialized -application objects without having to care about import/setup/cleanup -details. It's a prime example of `dependency injection`_ where fixture +Fixtures allow test functions to easily receive and work +against specific pre-initialized application objects without having +to care about import/setup/cleanup details. +It's a prime example of `dependency injection`_ where fixture functions take the role of the *injector* and test functions are the *consumers* of fixture objects. +.. _`conftest.py`: +.. _`conftest`: + +``conftest.py``: sharing fixture functions +------------------------------------------ + +If during implementing your tests you realize that you +want to use a fixture function from multiple test files you can move it +to a ``conftest.py`` file. +You don't need to import the fixture you want to use in a test, it +automatically gets discovered by pytest. The discovery of +fixture functions starts at test classes, then test modules, then +``conftest.py`` files and finally builtin and third party plugins. + +You can also use the ``conftest.py`` file to implement +:ref:`local per-directory plugins `. + +Sharing test data +----------------- + +If you want to make test data from files available to your tests, a good way +to do this is by loading these data in a fixture for use by your tests. +This makes use of the automatic caching mechanisms of pytest. + +Another good approach is by adding the data files in the ``tests`` folder. +There are also community plugins available to help managing this aspect of +testing, e.g. `pytest-datadir `__ +and `pytest-datafiles `__. + .. _smtpshared: -Sharing a fixture across tests in a module (or class/session) ------------------------------------------------------------------ +Scope: sharing a fixture instance across tests in a class, module or session +---------------------------------------------------------------------------- .. regendoc:wipe @@ -157,10 +168,12 @@ usually time-expensive to create. Extending the previous example, we can add a ``scope='module'`` parameter to the :py:func:`@pytest.fixture <_pytest.python.fixture>` invocation to cause the decorated ``smtp`` fixture function to only be invoked once -per test module. Multiple test functions in a test module will thus -each receive the same ``smtp`` fixture instance. The next example puts -the fixture function into a separate ``conftest.py`` file so -that tests from multiple test modules in the directory can +per test *module* (the default is to invoke once per test *function*). +Multiple test functions in a test module will thus +each receive the same ``smtp`` fixture instance, thus saving time. + +The next example puts the fixture function into a separate ``conftest.py`` file +so that tests from multiple test modules in the directory can access the fixture function:: # content of conftest.py @@ -169,7 +182,7 @@ access the fixture function:: @pytest.fixture(scope="module") def smtp(): - return smtplib.SMTP("smtp.gmail.com") + return smtplib.SMTP("smtp.gmail.com", 587, timeout=5) The name of the fixture again is ``smtp`` and you can access its result by listing the name ``smtp`` as an input parameter in any test or fixture @@ -181,7 +194,7 @@ function (in or below the directory where ``conftest.py`` is located):: response, msg = smtp.ehlo() assert response == 250 assert b"smtp.gmail.com" in msg - assert 0 # for demo purposes + assert 0 # for demo purposes def test_noop(smtp): response, msg = smtp.noop() @@ -191,16 +204,16 @@ function (in or below the directory where ``conftest.py`` is located):: We deliberately insert failing ``assert 0`` statements in order to inspect what is going on and can now run the tests:: - $ py.test test_module.py - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: + $ pytest test_module.py + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items - test_module.py FF + test_module.py FF [100%] - ======= FAILURES ======== - _______ test_ehlo ________ + ================================= FAILURES ================================= + ________________________________ test_ehlo _________________________________ smtp = @@ -212,7 +225,7 @@ inspect what is going on and can now run the tests:: E assert 0 test_module.py:6: AssertionError - _______ test_noop ________ + ________________________________ test_noop _________________________________ smtp = @@ -223,7 +236,7 @@ inspect what is going on and can now run the tests:: E assert 0 test_module.py:11: AssertionError - ======= 2 failed in 0.12 seconds ======== + ========================= 2 failed in 0.12 seconds ========================= You see the two ``assert 0`` failing and more importantly you can also see that the same (module-scoped) ``smtp`` object was passed into the two @@ -241,15 +254,18 @@ instance, you can simply declare it: # the returned fixture value will be shared for # all tests needing it +Finally, the ``class`` scope will invoke the fixture once per test *class*. + .. _`finalization`: Fixture finalization / executing teardown code ------------------------------------------------------------- pytest supports execution of fixture specific finalization code -when the fixture goes out of scope. By accepting a ``request`` object -into your fixture function you can call its ``request.addfinalizer`` one -or multiple times:: +when the fixture goes out of scope. By using a ``yield`` statement instead of ``return``, all +the code after the *yield* statement serves as the teardown code: + +.. code-block:: python # content of conftest.py @@ -257,21 +273,20 @@ or multiple times:: import pytest @pytest.fixture(scope="module") - def smtp(request): - smtp = smtplib.SMTP("smtp.gmail.com") - def fin(): - print ("teardown smtp") - smtp.close() - request.addfinalizer(fin) - return smtp # provide the fixture value + def smtp(): + smtp = smtplib.SMTP("smtp.gmail.com", 587, timeout=5) + yield smtp # provide the fixture value + print("teardown smtp") + smtp.close() -The ``fin`` function will execute when the last test using -the fixture in the module has finished execution. +The ``print`` and ``smtp.close()`` statements will execute when the last test in +the module has finished execution, regardless of the exception status of the +tests. Let's execute it:: - $ py.test -s -q --tb=no - FFteardown smtp + $ pytest -s -q --tb=no + FF [100%]teardown smtp 2 failed in 0.12 seconds @@ -282,6 +297,72 @@ occur around each single test. In either case the test module itself does not need to change or know about these details of fixture setup. +Note that we can also seamlessly use the ``yield`` syntax with ``with`` statements: + +.. code-block:: python + + # content of test_yield2.py + + import smtplib + import pytest + + @pytest.fixture(scope="module") + def smtp(): + with smtplib.SMTP("smtp.gmail.com", 587, timeout=5) as smtp: + yield smtp # provide the fixture value + + +The ``smtp`` connection will be closed after the test finished execution +because the ``smtp`` object automatically closes when +the ``with`` statement ends. + +Note that if an exception happens during the *setup* code (before the ``yield`` keyword), the +*teardown* code (after the ``yield``) will not be called. + +An alternative option for executing *teardown* code is to +make use of the ``addfinalizer`` method of the `request-context`_ object to register +finalization functions. + +Here's the ``smtp`` fixture changed to use ``addfinalizer`` for cleanup: + +.. code-block:: python + + # content of conftest.py + import smtplib + import pytest + + @pytest.fixture(scope="module") + def smtp(request): + smtp = smtplib.SMTP("smtp.gmail.com", 587, timeout=5) + def fin(): + print ("teardown smtp") + smtp.close() + request.addfinalizer(fin) + return smtp # provide the fixture value + + +Both ``yield`` and ``addfinalizer`` methods work similarly by calling their code after the test +ends, but ``addfinalizer`` has two key differences over ``yield``: + +1. It is possible to register multiple finalizer functions. + +2. Finalizers will always be called regardless if the fixture *setup* code raises an exception. + This is handy to properly close all resources created by a fixture even if one of them + fails to be created/acquired:: + + @pytest.fixture + def equipments(request): + r = [] + for port in ('C1', 'C3', 'C28'): + equip = connect(port) + request.addfinalizer(equip.disconnect) + r.append(equip) + return r + + In the example above, if ``"C28"`` fails with an exception, ``"C1"`` and ``"C3"`` will still + be properly closed. Of course, if an exception happens before the finalize function is + registered then it will not be executed. + .. _`request-context`: @@ -300,20 +381,17 @@ read an optional server URL from the test module which uses our fixture:: @pytest.fixture(scope="module") def smtp(request): server = getattr(request.module, "smtpserver", "smtp.gmail.com") - smtp = smtplib.SMTP(server) - - def fin(): - print ("finalizing %s (%s)" % (smtp, server)) - smtp.close() - request.addfinalizer(fin) - return smtp + smtp = smtplib.SMTP(server, 587, timeout=5) + yield smtp + print ("finalizing %s (%s)" % (smtp, server)) + smtp.close() We use the ``request.module`` attribute to optionally obtain an ``smtpserver`` attribute from the test module. If we just execute again, nothing much has changed:: - $ py.test -s -q --tb=no - FFfinalizing (smtp.gmail.com) + $ pytest -s -q --tb=no + FF [100%]finalizing (smtp.gmail.com) 2 failed in 0.12 seconds @@ -329,21 +407,23 @@ server URL in its module namespace:: Running it:: - $ py.test -qq --tb=short test_anothersmtp.py - F - ======= FAILURES ======== - _______ test_showhelo ________ + $ pytest -qq --tb=short test_anothersmtp.py + F [100%] + ================================= FAILURES ================================= + ______________________________ test_showhelo _______________________________ test_anothersmtp.py:5: in test_showhelo assert 0, smtp.helo() E AssertionError: (250, b'mail.python.org') E assert 0 + ------------------------- Captured stdout teardown ------------------------- + finalizing (mail.python.org) voila! The ``smtp`` fixture function picked up our mail server name from the module namespace. .. _`fixture-parametrize`: -Parametrizing a fixture +Parametrizing fixtures ----------------------------------------------------------------- Fixture functions can be parametrized in which case they will be called @@ -365,12 +445,10 @@ through the special :py:class:`request ` object:: @pytest.fixture(scope="module", params=["smtp.gmail.com", "mail.python.org"]) def smtp(request): - smtp = smtplib.SMTP(request.param) - def fin(): - print ("finalizing %s" % smtp) - smtp.close() - request.addfinalizer(fin) - return smtp + smtp = smtplib.SMTP(request.param, 587, timeout=5) + yield smtp + print ("finalizing %s" % smtp) + smtp.close() The main change is the declaration of ``params`` with :py:func:`@pytest.fixture <_pytest.python.fixture>`, a list of values @@ -378,10 +456,10 @@ for each of which the fixture function will execute and can access a value via ``request.param``. No test function code needs to change. So let's just do another run:: - $ py.test -q test_module.py - FFFF - ======= FAILURES ======== - _______ test_ehlo[smtp.gmail.com] ________ + $ pytest -q test_module.py + FFFF [100%] + ================================= FAILURES ================================= + ________________________ test_ehlo[smtp.gmail.com] _________________________ smtp = @@ -393,7 +471,7 @@ So let's just do another run:: E assert 0 test_module.py:6: AssertionError - _______ test_noop[smtp.gmail.com] ________ + ________________________ test_noop[smtp.gmail.com] _________________________ smtp = @@ -404,7 +482,7 @@ So let's just do another run:: E assert 0 test_module.py:11: AssertionError - _______ test_ehlo[mail.python.org] ________ + ________________________ test_ehlo[mail.python.org] ________________________ smtp = @@ -412,12 +490,12 @@ So let's just do another run:: response, msg = smtp.ehlo() assert response == 250 > assert b"smtp.gmail.com" in msg - E assert b'smtp.gmail.com' in b'mail.python.org\nSIZE 51200000\nETRN\nSTARTTLS\nENHANCEDSTATUSCODES\n8BITMIME\nDSN\nSMTPUTF8' + E AssertionError: assert b'smtp.gmail.com' in b'mail.python.org\nPIPELINING\nSIZE 51200000\nETRN\nSTARTTLS\nAUTH DIGEST-MD5 NTLM CRAM-MD5\nENHANCEDSTATUSCODES\n8BITMIME\nDSN\nSMTPUTF8' test_module.py:5: AssertionError -------------------------- Captured stdout setup --------------------------- finalizing - _______ test_noop[mail.python.org] ________ + ________________________ test_noop[mail.python.org] ________________________ smtp = @@ -428,6 +506,8 @@ So let's just do another run:: E assert 0 test_module.py:11: AssertionError + ------------------------- Captured stdout teardown ------------------------- + finalizing 4 failed in 0.12 seconds We see that our two test functions each ran twice, against the different @@ -478,10 +558,10 @@ return ``None`` then pytest's auto-generated ID will be used. Running the above tests results in the following test IDs being used:: - $ py.test --collect-only - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: + $ pytest --collect-only + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: collected 10 items @@ -497,7 +577,7 @@ Running the above tests results in the following test IDs being used:: - ======= no tests ran in 0.12 seconds ======== + ======================= no tests ran in 0.12 seconds ======================= .. _`interdependent fixtures`: @@ -515,7 +595,7 @@ and instantiate an object ``app`` where we stick the already defined import pytest - class App: + class App(object): def __init__(self, smtp): self.smtp = smtp @@ -529,17 +609,17 @@ and instantiate an object ``app`` where we stick the already defined Here we declare an ``app`` fixture which receives the previously defined ``smtp`` fixture and instantiates an ``App`` object with it. Let's run it:: - $ py.test -v test_appsetup.py - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.4 + $ pytest -v test_appsetup.py + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache - rootdir: $REGENDOC_TMPDIR, inifile: + rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 2 items - test_appsetup.py::test_smtp_exists[smtp.gmail.com] PASSED - test_appsetup.py::test_smtp_exists[mail.python.org] PASSED + test_appsetup.py::test_smtp_exists[smtp.gmail.com] PASSED [ 50%] + test_appsetup.py::test_smtp_exists[mail.python.org] PASSED [100%] - ======= 2 passed in 0.12 seconds ======== + ========================= 2 passed in 0.12 seconds ========================= Due to the parametrization of ``smtp`` the test will run twice with two different ``App`` instances and respective smtp servers. There is no @@ -567,7 +647,7 @@ first execute with one instance and then finalizers are called before the next fixture instance is created. Among other things, this eases testing of applications which create and use global state. -The following example uses two parametrized funcargs, one of which is +The following example uses two parametrized fixture, one of which is scoped on a per-module basis, and all the functions perform ``print`` calls to show the setup/teardown flow:: @@ -577,55 +657,80 @@ to show the setup/teardown flow:: @pytest.fixture(scope="module", params=["mod1", "mod2"]) def modarg(request): param = request.param - print ("create", param) - def fin(): - print ("fin %s" % param) - return param + print (" SETUP modarg %s" % param) + yield param + print (" TEARDOWN modarg %s" % param) @pytest.fixture(scope="function", params=[1,2]) def otherarg(request): - return request.param + param = request.param + print (" SETUP otherarg %s" % param) + yield param + print (" TEARDOWN otherarg %s" % param) def test_0(otherarg): - print (" test0", otherarg) + print (" RUN test0 with otherarg %s" % otherarg) def test_1(modarg): - print (" test1", modarg) + print (" RUN test1 with modarg %s" % modarg) def test_2(otherarg, modarg): - print (" test2", otherarg, modarg) + print (" RUN test2 with otherarg %s and modarg %s" % (otherarg, modarg)) + Let's run the tests in verbose mode and with looking at the print-output:: - $ py.test -v -s test_module.py - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.4 + $ pytest -v -s test_module.py + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache - rootdir: $REGENDOC_TMPDIR, inifile: + rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 8 items - test_module.py::test_0[1] test0 1 - PASSED - test_module.py::test_0[2] test0 2 - PASSED - test_module.py::test_1[mod1] create mod1 - test1 mod1 - PASSED - test_module.py::test_2[1-mod1] test2 1 mod1 - PASSED - test_module.py::test_2[2-mod1] test2 2 mod1 - PASSED - test_module.py::test_1[mod2] create mod2 - test1 mod2 - PASSED - test_module.py::test_2[1-mod2] test2 1 mod2 - PASSED - test_module.py::test_2[2-mod2] test2 2 mod2 - PASSED + test_module.py::test_0[1] SETUP otherarg 1 + RUN test0 with otherarg 1 + PASSED [ 12%] TEARDOWN otherarg 1 - ======= 8 passed in 0.12 seconds ======== + test_module.py::test_0[2] SETUP otherarg 2 + RUN test0 with otherarg 2 + PASSED [ 25%] TEARDOWN otherarg 2 + + test_module.py::test_1[mod1] SETUP modarg mod1 + RUN test1 with modarg mod1 + PASSED [ 37%] + test_module.py::test_2[1-mod1] SETUP otherarg 1 + RUN test2 with otherarg 1 and modarg mod1 + PASSED [ 50%] TEARDOWN otherarg 1 + + test_module.py::test_2[2-mod1] SETUP otherarg 2 + RUN test2 with otherarg 2 and modarg mod1 + PASSED [ 62%] TEARDOWN otherarg 2 + + test_module.py::test_1[mod2] TEARDOWN modarg mod1 + SETUP modarg mod2 + RUN test1 with modarg mod2 + PASSED [ 75%] + test_module.py::test_2[1-mod2] SETUP otherarg 1 + RUN test2 with otherarg 1 and modarg mod2 + PASSED [ 87%] TEARDOWN otherarg 1 + + test_module.py::test_2[2-mod2] SETUP otherarg 2 + RUN test2 with otherarg 2 and modarg mod2 + PASSED [100%] TEARDOWN otherarg 2 + TEARDOWN modarg mod2 + + + ========================= 8 passed in 0.12 seconds ========================= -You can see that the parametrized module-scoped ``modarg`` resource caused -an ordering of test execution that lead to the fewest possible "active" resources. The finalizer for the ``mod1`` parametrized resource was executed -before the ``mod2`` resource was setup. +You can see that the parametrized module-scoped ``modarg`` resource caused an +ordering of test execution that lead to the fewest possible "active" resources. +The finalizer for the ``mod1`` parametrized resource was executed before the +``mod2`` resource was setup. + +In particular notice that test_0 is completely independent and finishes first. +Then test_1 is executed with ``mod1``, then test_2 with ``mod1``, then test_1 +with ``mod2`` and finally test_2 with ``mod2``. + +The ``otherarg`` parametrized resource (having function scope) was set up before +and teared down after every test that used it. .. _`usefixtures`: @@ -638,7 +743,7 @@ Using fixtures from classes, modules or projects Sometimes test functions do not directly need access to a fixture object. For example, tests may require to operate with an empty directory as the current working directory but otherwise do not care for the concrete -directory. Here is how you can can use the standard `tempfile +directory. Here is how you can use the standard `tempfile `_ and pytest fixtures to achieve it. We separate the creation of the fixture into a conftest.py file:: @@ -661,7 +766,7 @@ and declare its use in a test module via a ``usefixtures`` marker:: import pytest @pytest.mark.usefixtures("cleandir") - class TestDirectoryInit: + class TestDirectoryInit(object): def test_cwd_starts_empty(self): assert os.listdir(os.getcwd()) == [] with open("myfile", "w") as f: @@ -675,8 +780,8 @@ will be required for the execution of each test method, just as if you specified a "cleandir" function argument to each of them. Let's run it to verify our fixture is activated and the tests pass:: - $ py.test -q - .. + $ pytest -q + .. [100%] 2 passed in 0.12 seconds You can specify multiple fixtures like this: @@ -714,8 +819,8 @@ Autouse fixtures (xUnit setup on steroids) .. regendoc:wipe Occasionally, you may want to have fixtures get invoked automatically -without a `usefixtures`_ or `funcargs`_ reference. As a practical -example, suppose we have a database fixture which has a +without declaring a function argument explicitly or a `usefixtures`_ decorator. +As a practical example, suppose we have a database fixture which has a begin/rollback/commit architecture and we want to automatically surround each test method by a transaction and a rollback. Here is a dummy self-contained implementation of this idea:: @@ -724,7 +829,7 @@ self-contained implementation of this idea:: import pytest - class DB: + class DB(object): def __init__(self): self.intransaction = [] def begin(self, name): @@ -736,11 +841,12 @@ self-contained implementation of this idea:: def db(): return DB() - class TestClass: + class TestClass(object): @pytest.fixture(autouse=True) def transact(self, request, db): db.begin(request.function.__name__) - request.addfinalizer(db.rollback) + yield + db.rollback() def test_method1(self, db): assert db.intransaction == ["test_method1"] @@ -755,12 +861,16 @@ class-level ``usefixtures`` decorator. If we run it, we get two passing tests:: - $ py.test -q - .. + $ pytest -q + .. [100%] 2 passed in 0.12 seconds Here is how autouse fixtures work in other scopes: +- autouse fixtures obey the ``scope=`` keyword-argument: if an autouse fixture + has ``scope='session'`` it will only be run once, no matter where it is + defined. ``scope='class'`` means it will be run once per class, etc. + - if an autouse fixture is defined in a test module, all its test functions automatically use it. @@ -780,15 +890,16 @@ active. The canonical way to do that is to put the transact definition into a conftest.py file **without** using ``autouse``:: # content of conftest.py - @pytest.fixture() - def transact(self, request, db): + @pytest.fixture + def transact(request, db): db.begin() - request.addfinalizer(db.rollback) + yield + db.rollback() and then e.g. have a TestClass using it by declaring the need:: @pytest.mark.usefixtures("transact") - class TestClass: + class TestClass(object): def test_method1(self): ... @@ -796,16 +907,6 @@ All test methods in this TestClass will use the transaction fixture while other test classes or functions in the module will not use it unless they also add a ``transact`` reference. -Shifting (visibility of) fixture functions ----------------------------------------------------- - -If during implementing your tests you realize that you -want to use a fixture function from multiple test files you can move it -to a :ref:`conftest.py ` file or even separately installable -:ref:`plugins ` without changing test code. The discovery of -fixtures functions starts at test classes, then test modules, then -``conftest.py`` files and finally builtin and third party plugins. - Overriding fixtures on various levels ------------------------------------- @@ -928,7 +1029,7 @@ Given the tests file structure is: @pytest.mark.parametrize('username', ['directly-overridden-username-other']) def test_username_other(other_username): - assert username == 'other-directly-overridden-username-other' + assert other_username == 'other-directly-overridden-username-other' In the example above, a fixture value is overridden by the test parameter value. Note that the value of the fixture can be overridden this way even if the test doesn't use it directly (doesn't mention it in the function prototype). diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/funcarg_compare.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/funcarg_compare.rst similarity index 95% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/funcarg_compare.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/funcarg_compare.rst index 832922e1839..b857a014d31 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/funcarg_compare.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/funcarg_compare.rst @@ -1,3 +1,4 @@ +:orphan: .. _`funcargcompare`: @@ -23,7 +24,7 @@ resources. Here is a basic example how we could implement a per-session Database object:: # content of conftest.py - class Database: + class Database(object): def __init__(self): print ("database instance created") def destroy(self): @@ -96,7 +97,7 @@ sets. pytest-2.3 introduces a decorator for use on the factory itself:: ... # use request.param Here the factory will be invoked twice (with the respective "mysql" -and "pg" values set as ``request.param`` attributes) and and all of +and "pg" values set as ``request.param`` attributes) and all of the tests requiring "db" will run twice as well. The "mysql" and "pg" values will also be used for reporting the test-invocation variants. @@ -172,17 +173,17 @@ to do this with parametrization as ``pytest_runtest_setup()`` is called during test execution and parametrization happens at collection time. It follows that pytest_configure/session/runtest_setup are often not -appropriate for implementing common fixture needs. Therefore, +appropriate for implementing common fixture needs. Therefore, pytest-2.3 introduces :ref:`autouse fixtures` which fully -integrate with the generic :ref:`fixture mechanism ` +integrate with the generic :ref:`fixture mechanism ` and obsolete many prior uses of pytest hooks. funcargs/fixture discovery now happens at collection time --------------------------------------------------------------------- -pytest-2.3 takes care to discover fixture/funcarg factories -at collection time. This is more efficient especially for large test suites. -Moreover, a call to "py.test --collect-only" should be able to in the future +Since pytest-2.3, discovery of fixture/funcarg factories are taken care of +at collection time. This is more efficient especially for large test suites. +Moreover, a call to "pytest --collect-only" should be able to in the future show a lot of setup-information and thus presents a nice method to get an overview of fixture management in your project. diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/funcargs.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/funcargs.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/funcargs.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/funcargs.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/genapi.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/genapi.py similarity index 93% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/genapi.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/genapi.py index f8cdda6cfbf..0ede44fa2de 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/genapi.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/genapi.py @@ -1,7 +1,7 @@ import textwrap import inspect -class Writer: +class Writer(object): def __init__(self, clsname): self.clsname = clsname @@ -32,7 +32,7 @@ class Writer: def pytest_funcarg__a(request): with Writer("request") as writer: - writer.docmethod(request.getfuncargvalue) + writer.docmethod(request.getfixturevalue) writer.docmethod(request.cached_setup) writer.docmethod(request.addfinalizer) writer.docmethod(request.applymarker) diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/getting-started.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/getting-started.rst similarity index 64% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/getting-started.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/getting-started.rst index 4a5b75aea0c..64b0108262d 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/getting-started.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/getting-started.rst @@ -1,7 +1,7 @@ Installation and Getting Started =================================== -**Pythons**: Python 2.6,2.7,3.3,3.4,3.5, Jython, PyPy-2.3 +**Pythons**: Python 2.7, 3.4, 3.5, 3.6, Jython, PyPy-2.3 **Platforms**: Unix/Posix and Windows @@ -9,9 +9,8 @@ Installation and Getting Started **dependencies**: `py `_, `colorama (Windows) `_, -`argparse (py26) `_. -**documentation as PDF**: `download latest `_ +**documentation as PDF**: `download latest `_ .. _`getstarted`: .. _installation: @@ -19,17 +18,14 @@ Installation and Getting Started Installation ---------------------------------------- -Installation options:: +Installation:: - pip install -U pytest # or - easy_install -U pytest + pip install -U pytest To check your installation has installed the correct version:: - $ py.test --version - This is pytest version 2.9.1, imported from $PYTHON_PREFIX/lib/python3.4/site-packages/pytest.py - -If you get an error checkout :ref:`installation issues`. + $ pytest --version + This is pytest version 3.x.y, imported from $PYTHON_PREFIX/lib/python3.5/site-packages/pytest.py .. _`simpletest`: @@ -47,16 +43,16 @@ Let's create a first test file with a simple test function:: That's it. You can execute the test function now:: - $ py.test - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: - collected 1 items + $ pytest + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: + collected 1 item - test_sample.py F + test_sample.py F [100%] - ======= FAILURES ======== - _______ test_answer ________ + ================================= FAILURES ================================= + _______________________________ test_answer ________________________________ def test_answer(): > assert func(3) == 5 @@ -64,7 +60,7 @@ That's it. You can execute the test function now:: E + where 4 = func(3) test_sample.py:5: AssertionError - ======= 1 failed in 0.12 seconds ======== + ========================= 1 failed in 0.12 seconds ========================= We got a failure report because our little ``func(3)`` call did not return ``5``. @@ -102,8 +98,8 @@ use the ``raises`` helper:: Running it with, this time in "quiet" reporting mode:: - $ py.test -q test_sysexit.py - . + $ pytest -q test_sysexit.py + . [100%] 1 passed in 0.12 seconds Grouping multiple tests in a class @@ -114,7 +110,7 @@ to group tests logically, in classes and modules. Let's write a class containing two tests:: # content of test_class.py - class TestClass: + class TestClass(object): def test_one(self): x = "this" assert 'h' in x @@ -127,17 +123,18 @@ The two tests are found because of the standard :ref:`test discovery`. There is no need to subclass anything. We can simply run the module by passing its filename:: - $ py.test -q test_class.py - .F - ======= FAILURES ======== - _______ TestClass.test_two ________ + $ pytest -q test_class.py + .F [100%] + ================================= FAILURES ================================= + ____________________________ TestClass.test_two ____________________________ self = def test_two(self): x = "hello" > assert hasattr(x, 'check') - E assert hasattr('hello', 'check') + E AssertionError: assert False + E + where False = hasattr('hello', 'check') test_class.py:8: AssertionError 1 failed, 1 passed in 0.12 seconds @@ -163,10 +160,10 @@ We list the name ``tmpdir`` in the test function signature and ``pytest`` will lookup and call a fixture factory to create the resource before performing the test function call. Let's just run it:: - $ py.test -q test_tmpdir.py - F - ======= FAILURES ======== - _______ test_needsfiles ________ + $ pytest -q test_tmpdir.py + F [100%] + ================================= FAILURES ================================= + _____________________________ test_needsfiles ______________________________ tmpdir = local('PYTEST_TMPDIR/test_needsfiles0') @@ -185,7 +182,7 @@ was created. More info at :ref:`tmpdir handling`. You can find out what kind of builtin :ref:`fixtures` exist by typing:: - py.test --fixtures # shows builtin and custom fixtures + pytest --fixtures # shows builtin and custom fixtures Where to go next ------------------------------------- @@ -193,45 +190,9 @@ Where to go next Here are a few suggestions where to go next: * :ref:`cmdline` for command line invocation examples -* :ref:`good practices ` for virtualenv, test layout, genscript support +* :ref:`good practices ` for virtualenv, test layout +* :ref:`existingtestsuite` for working with pre-existing tests * :ref:`fixtures` for providing a functional baseline to your tests -* :ref:`apiref` for documentation and examples on using ``pytest`` * :ref:`plugins` managing and writing plugins -.. _`installation issues`: - -Known Installation issues ------------------------------- - -easy_install or pip not found? -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -.. _`install pip`: http://www.pip-installer.org/en/latest/index.html - -`Install pip`_ for a state of the art python package installer. - -Install `setuptools`_ to get ``easy_install`` which allows to install -``.egg`` binary format packages in addition to source-based ones. - -py.test not found on Windows despite installation? -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -.. _`Python for Windows`: http://www.imladris.com/Scripts/PythonForWindows.html - -- **Windows**: If "easy_install" or "py.test" are not found - you need to add the Python script path to your ``PATH``, see here: - `Python for Windows`_. You may alternatively use an `ActivePython install`_ - which does this for you automatically. - -.. _`ActivePython install`: http://www.activestate.com/activepython/downloads - -.. _`Jython does not create command line launchers`: http://bugs.jython.org/issue1491 - -- **Jython2.5.1 on Windows XP**: `Jython does not create command line launchers`_ - so ``py.test`` will not work correctly. You may install py.test on - CPython and type ``py.test --genscript=mytest`` and then use - ``jython mytest`` to run your tests with Jython using ``pytest``. - - :ref:`examples` for more complex examples - .. include:: links.inc diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/goodpractices.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/goodpractices.rst similarity index 54% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/goodpractices.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/goodpractices.rst index 2d8050bd9ca..16fdd24c392 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/goodpractices.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/goodpractices.rst @@ -16,10 +16,12 @@ Conventions for Python test discovery * If no arguments are specified then collection starts from :confval:`testpaths` (if configured) or the current directory. Alternatively, command line arguments can be used in any combination of directories, file names or node ids. -* recurse into directories, unless they match :confval:`norecursedirs` -* ``test_*.py`` or ``*_test.py`` files, imported by their `test package name`_. -* ``Test`` prefixed test classes (without an ``__init__`` method) -* ``test_`` prefixed test functions or methods are test items +* Recurse into directories, unless they match :confval:`norecursedirs`. +* In those directories, search for ``test_*.py`` or ``*_test.py`` files, imported by their `test package name`_. +* From those files, collect test items: + + * ``test_`` prefixed test functions or methods outside of class + * ``test_`` prefixed test functions or methods inside ``Test`` prefixed test classes (without an ``__init__`` method) For examples of how to customize your test discovery :doc:`example/pythoncollection`. @@ -28,68 +30,106 @@ Within Python modules, ``pytest`` also discovers tests using the standard Choosing a test layout / import rules ------------------------------------------- +------------------------------------- ``pytest`` supports two common test layouts: -* putting tests into an extra directory outside your actual application - code, useful if you have many functional tests or for other reasons - want to keep tests separate from actual application code (often a good - idea):: +Tests outside application code +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - setup.py # your setuptools Python package metadata +Putting tests into an extra directory outside your actual application code +might be useful if you have many functional tests or for other reasons want +to keep tests separate from actual application code (often a good idea):: + + setup.py mypkg/ __init__.py - appmodule.py + app.py + view.py tests/ test_app.py + test_view.py ... +This way your tests can run easily against an installed version +of ``mypkg``. -* inlining test directories into your application package, useful if you - have direct relation between (unit-)test and application modules and - want to distribute your tests along with your application:: +Note that using this scheme your test files must have **unique names**, because +``pytest`` will import them as *top-level* modules since there are no packages +to derive a full package name from. In other words, the test files in the example above will +be imported as ``test_app`` and ``test_view`` top-level modules by adding ``tests/`` to +``sys.path``. - setup.py # your setuptools Python package metadata +If you need to have test modules with the same name, you might add ``__init__.py`` files to your +``tests`` folder and subfolders, changing them to packages:: + + setup.py + mypkg/ + ... + tests/ + __init__.py + foo/ + __init__.py + test_view.py + bar/ + __init__.py + test_view.py + +Now pytest will load the modules as ``tests.foo.test_view`` and ``tests.bar.test_view``, allowing +you to have modules with the same name. But now this introduces a subtle problem: in order to load +the test modules from the ``tests`` directory, pytest prepends the root of the repository to +``sys.path``, which adds the side-effect that now ``mypkg`` is also importable. +This is problematic if you are using a tool like `tox`_ to test your package in a virtual environment, +because you want to test the *installed* version of your package, not the local code from the repository. + +In this situation, it is **strongly** suggested to use a ``src`` layout where application root package resides in a +sub-directory of your root:: + + setup.py + src/ + mypkg/ + __init__.py + app.py + view.py + tests/ + __init__.py + foo/ + __init__.py + test_view.py + bar/ + __init__.py + test_view.py + + +This layout prevents a lot of common pitfalls and has many benefits, which are better explained in this excellent +`blog post by Ionel Cristian Mărieș `_. + +Tests as part of application code +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Inlining test directories into your application package +is useful if you have direct relation between tests and application modules and +want to distribute them along with your application:: + + setup.py mypkg/ __init__.py - appmodule.py - ... + app.py + view.py test/ + __init__.py test_app.py + test_view.py ... -Important notes relating to both schemes: +In this scheme, it is easy to run your tests using the ``--pyargs`` option:: -- **make sure that "mypkg" is importable**, for example by typing once:: + pytest --pyargs mypkg - pip install -e . # install package using setup.py in editable mode +``pytest`` will discover where ``mypkg`` is installed and collect tests from there. -- **avoid "__init__.py" files in your test directories**. - This way your tests can run easily against an installed version - of ``mypkg``, independently from the installed package if it contains - the tests or not. +Note that this layout also works in conjunction with the ``src`` layout mentioned in the previous section. -- With inlined tests you might put ``__init__.py`` into test - directories and make them installable as part of your application. - Using the ``py.test --pyargs mypkg`` invocation pytest will - discover where mypkg is installed and collect tests from there. - With the "external" test you can still distribute tests but they - will not be installed or become importable. - -Typically you can run tests by pointing to test directories or modules:: - - py.test tests/test_app.py # for external test dirs - py.test mypkg/test/test_app.py # for inlined test dirs - py.test mypkg # run tests in all below test directories - py.test # run all tests below current dir - ... - -Because of the above ``editable install`` mode you can change your -source code (both tests and the app) and rerun tests at will. -Once you are done with your work, you can `use tox`_ to make sure -that the package is really correct and tests pass in all -required configurations. .. note:: @@ -125,7 +165,7 @@ required configurations. The reason for this somewhat evolved importing technique is that in larger projects multiple test modules might import from each other and thus deriving a canonical import name helps - to avoid surprises such as a test modules getting imported twice. + to avoid surprises such as a test module getting imported twice. .. _`virtualenv`: http://pypi.python.org/pypi/virtualenv @@ -142,19 +182,24 @@ for installing your application and any dependencies as well as the ``pytest`` package itself. This ensures your code and dependencies are isolated from the system Python installation. -If you frequently release code and want to make sure that your actual +You can then install your package in "editable" mode:: + + pip install -e . + +which lets you change your source code (both tests and application) and rerun tests at will. +This is similar to running `python setup.py develop` or `conda develop` in that it installs +your package using a symlink to your development code. + +Once you are done with your work and want to make sure that your actual package passes all tests you may want to look into `tox`_, the virtualenv test automation tool and its `pytest support -`_. +`_. Tox helps you to setup virtualenv environments with pre-defined dependencies and then executing a pre-configured test command with options. It will run tests against the installed package and not against your source code checkout, helping to detect packaging glitches. -Continuous integration services such as Jenkins_ can make use of the -``--junitxml=PATH`` option to create a JUnitXML file and generate reports. - Integrating with setuptools / ``python setup.py test`` / ``pytest-runner`` -------------------------------------------------------------------------- @@ -191,9 +236,18 @@ If you now type:: this will execute your tests using ``pytest-runner``. As this is a standalone version of ``pytest`` no prior installation whatsoever is required for calling the test command. You can also pass additional -arguments to py.test such as your test directory or other +arguments to pytest such as your test directory or other options using ``--addopts``. +You can also specify other pytest-ini options in your ``setup.cfg`` file +by putting them into a ``[tool:pytest]`` section: + +.. code-block:: ini + + [tool:pytest] + addopts = --verbose + python_files = testing/*/*.py + Manual Integration ^^^^^^^^^^^^^^^^^^ @@ -209,16 +263,17 @@ your own setuptools Test command for invoking pytest. class PyTest(TestCommand): - user_options = [('pytest-args=', 'a', "Arguments to pass to py.test")] + user_options = [('pytest-args=', 'a', "Arguments to pass to pytest")] def initialize_options(self): TestCommand.initialize_options(self) - self.pytest_args = [] + self.pytest_args = '' def run_tests(self): + import shlex #import here, cause outside the eggs aren't loaded import pytest - errno = pytest.main(self.pytest_args) + errno = pytest.main(shlex.split(self.pytest_args)) sys.exit(errno) @@ -238,41 +293,7 @@ using the ``--pytest-args`` or ``-a`` command-line option. For example:: python setup.py test -a "--durations=5" -is equivalent to running ``py.test --durations=5``. - - -.. _standalone: -.. _`genscript method`: - -(deprecated) Create a pytest standalone script ------------------------------------------------ - -.. deprecated:: 2.8 - -.. note:: - - ``genscript`` has been deprecated because: - - * It cannot support plugins, rendering its usefulness extremely limited; - * Tooling has become much better since ``genscript`` was introduced; - * It is possible to build a zipped ``pytest`` application without the - shortcomings above. - - There's no planned version in which this command will be removed - at the moment of this writing, but its use is discouraged for new - applications. - -If you are a maintainer or application developer and want people -who don't deal with python much to easily run tests you may generate -a standalone ``pytest`` script:: - - py.test --genscript=runtests.py - -This generates a ``runtests.py`` script which is a fully functional basic -``pytest`` script, running unchanged under Python2 and Python3. -You can tell people to download the script and then e.g. run it like this:: - - python runtests.py +is equivalent to running ``pytest --durations=5``. .. include:: links.inc diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/historical-notes.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/historical-notes.rst new file mode 100644 index 00000000000..028ceff9b17 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/historical-notes.rst @@ -0,0 +1,177 @@ +Historical Notes +================ + +This page lists features or behavior from previous versions of pytest which have changed over the years. They are +kept here as a historical note so users looking at old code can find documentation related to them. + +cache plugin integrated into the core +------------------------------------- + +.. versionadded:: 2.8 + +The functionality of the :ref:`core cache ` plugin was previously distributed +as a third party plugin named ``pytest-cache``. The core plugin +is compatible regarding command line options and API usage except that you +can only store/receive data between test runs that is json-serializable. + + +funcargs and ``pytest_funcarg__`` +--------------------------------- + +.. versionchanged:: 2.3 + +In versions prior to 2.3 there was no ``@pytest.fixture`` marker +and you had to use a magic ``pytest_funcarg__NAME`` prefix +for the fixture factory. This remains and will remain supported +but is not anymore advertised as the primary means of declaring fixture +functions. + + +``@pytest.yield_fixture`` decorator +----------------------------------- + +.. versionchanged:: 2.10 + +Prior to version 2.10, in order to use a ``yield`` statement to execute teardown code one +had to mark a fixture using the ``yield_fixture`` marker. From 2.10 onward, normal +fixtures can use ``yield`` directly so the ``yield_fixture`` decorator is no longer needed +and considered deprecated. + + +``[pytest]`` header in ``setup.cfg`` +------------------------------------ + +.. versionchanged:: 3.0 + +Prior to 3.0, the supported section name was ``[pytest]``. Due to how +this may collide with some distutils commands, the recommended +section name for ``setup.cfg`` files is now ``[tool:pytest]``. + +Note that for ``pytest.ini`` and ``tox.ini`` files the section +name is ``[pytest]``. + + +Applying marks to ``@pytest.mark.parametrize`` parameters +--------------------------------------------------------- + +.. versionchanged:: 3.1 + +Prior to version 3.1 the supported mechanism for marking values +used the syntax:: + + import pytest + @pytest.mark.parametrize("test_input,expected", [ + ("3+5", 8), + ("2+4", 6), + pytest.mark.xfail(("6*9", 42),), + ]) + def test_eval(test_input, expected): + assert eval(test_input) == expected + + +This was an initial hack to support the feature but soon was demonstrated to be incomplete, +broken for passing functions or applying multiple marks with the same name but different parameters. + +The old syntax is planned to be removed in pytest-4.0. + + +``@pytest.mark.parametrize`` argument names as a tuple +------------------------------------------------------ + +.. versionchanged:: 2.4 + +In versions prior to 2.4 one needed to specify the argument +names as a tuple. This remains valid but the simpler ``"name1,name2,..."`` +comma-separated-string syntax is now advertised first because +it's easier to write and produces less line noise. + + +setup: is now an "autouse fixture" +---------------------------------- + +.. versionchanged:: 2.3 + +During development prior to the pytest-2.3 release the name +``pytest.setup`` was used but before the release it was renamed +and moved to become part of the general fixture mechanism, +namely :ref:`autouse fixtures` + + +.. _string conditions: + +Conditions as strings instead of booleans +----------------------------------------- + +.. versionchanged:: 2.4 + +Prior to pytest-2.4 the only way to specify skipif/xfail conditions was +to use strings:: + + import sys + @pytest.mark.skipif("sys.version_info >= (3,3)") + def test_function(): + ... + +During test function setup the skipif condition is evaluated by calling +``eval('sys.version_info >= (3,0)', namespace)``. The namespace contains +all the module globals, and ``os`` and ``sys`` as a minimum. + +Since pytest-2.4 :ref:`boolean conditions ` are considered preferable +because markers can then be freely imported between test modules. +With strings you need to import not only the marker but all variables +used by the marker, which violates encapsulation. + +The reason for specifying the condition as a string was that ``pytest`` can +report a summary of skip conditions based purely on the condition string. +With conditions as booleans you are required to specify a ``reason`` string. + +Note that string conditions will remain fully supported and you are free +to use them if you have no need for cross-importing markers. + +The evaluation of a condition string in ``pytest.mark.skipif(conditionstring)`` +or ``pytest.mark.xfail(conditionstring)`` takes place in a namespace +dictionary which is constructed as follows: + +* the namespace is initialized by putting the ``sys`` and ``os`` modules + and the pytest ``config`` object into it. + +* updated with the module globals of the test function for which the + expression is applied. + +The pytest ``config`` object allows you to skip based on a test +configuration value which you might have added:: + + @pytest.mark.skipif("not config.getvalue('db')") + def test_function(...): + ... + +The equivalent with "boolean conditions" is:: + + @pytest.mark.skipif(not pytest.config.getvalue("db"), + reason="--db was not specified") + def test_function(...): + pass + +.. note:: + + You cannot use ``pytest.config.getvalue()`` in code + imported before pytest's argument parsing takes place. For example, + ``conftest.py`` files are imported before command line parsing and thus + ``config.getvalue()`` will not execute correctly. + +``pytest.set_trace()`` +---------------------- + +.. versionchanged:: 2.4 + +Previous to version 2.4 to set a break point in code one needed to use ``pytest.set_trace()``:: + + import pytest + def test_function(): + ... + pytest.set_trace() # invoke PDB debugger and tracing + + +This is no longer needed and one can use the native ``import pdb;pdb.set_trace()`` call directly. + +For more details see :ref:`breakpoints`. diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/img/cramer2.png b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/img/cramer2.png similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/img/cramer2.png rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/img/cramer2.png diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/img/freiburg2.jpg b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/img/freiburg2.jpg similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/img/freiburg2.jpg rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/img/freiburg2.jpg diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/img/gaynor3.png b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/img/gaynor3.png similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/img/gaynor3.png rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/img/gaynor3.png diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/img/keleshev.png b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/img/keleshev.png similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/img/keleshev.png rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/img/keleshev.png diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/img/pullrequest.png b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/img/pullrequest.png similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/img/pullrequest.png rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/img/pullrequest.png diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/img/pylib.png b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/img/pylib.png similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/img/pylib.png rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/img/pylib.png diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/img/pytest1.png b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/img/pytest1.png similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/img/pytest1.png rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/img/pytest1.png diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/img/pytest1favi.ico b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/img/pytest1favi.ico similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/img/pytest1favi.ico rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/img/pytest1favi.ico diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/img/theuni.png b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/img/theuni.png similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/img/theuni.png rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/img/theuni.png diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/index.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/index.rst new file mode 100644 index 00000000000..66c59f08d34 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/index.rst @@ -0,0 +1,90 @@ +:orphan: + +.. _features: + +pytest: helps you write better programs +======================================= + + +The ``pytest`` framework makes it easy to write small tests, yet +scales to support complex functional testing for applications and libraries. + +An example of a simple test: + +.. code-block:: python + + # content of test_sample.py + def inc(x): + return x + 1 + + def test_answer(): + assert inc(3) == 5 + + +To execute it:: + + $ pytest + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: + collected 1 item + + test_sample.py F [100%] + + ================================= FAILURES ================================= + _______________________________ test_answer ________________________________ + + def test_answer(): + > assert inc(3) == 5 + E assert 4 == 5 + E + where 4 = inc(3) + + test_sample.py:5: AssertionError + ========================= 1 failed in 0.12 seconds ========================= + +Due to ``pytest``'s detailed assertion introspection, only plain ``assert`` statements are used. +See :ref:`Getting Started ` for more examples. + + +Features +-------- + +- Detailed info on failing :ref:`assert statements ` (no need to remember ``self.assert*`` names); + +- :ref:`Auto-discovery ` of test modules and functions; + +- :ref:`Modular fixtures ` for managing small or parametrized long-lived test resources; + +- Can run :ref:`unittest ` (including trial) and :ref:`nose ` test suites out of the box; + +- Python 2.7, Python 3.4+, PyPy 2.3, Jython 2.5 (untested); + +- Rich plugin architecture, with over 315+ `external plugins `_ and thriving community; + + +Documentation +------------- + +Please see :ref:`Contents ` for full documentation, including installation, tutorials and PDF documents. + + +Bugs/Requests +------------- + +Please use the `GitHub issue tracker `_ to submit bugs or request features. + + +Changelog +--------- + +Consult the :ref:`Changelog ` page for fixes and enhancements of each version. + + +License +------- + +Copyright Holger Krekel and others, 2004-2017. + +Distributed under the terms of the `MIT`_ license, pytest is free and open source software. + +.. _`MIT`: https://github.com/pytest-dev/pytest/blob/master/LICENSE diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/license.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/license.rst similarity index 96% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/license.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/license.rst index 3fc1dad52fd..b8c0dce1bea 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/license.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/license.rst @@ -9,7 +9,7 @@ Distributed under the terms of the `MIT`_ license, pytest is free and open sourc The MIT License (MIT) - Copyright (c) 2004-2016 Holger Krekel and others + Copyright (c) 2004-2017 Holger Krekel and others Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/links.inc b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/links.inc similarity index 89% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/links.inc rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/links.inc index 3d7863751e2..b69390baa84 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/links.inc +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/links.inc @@ -6,7 +6,7 @@ .. _`pytest_nose`: plugin/nose.html .. _`reStructured Text`: http://docutils.sourceforge.net .. _`Python debugger`: http://docs.python.org/lib/module-pdb.html -.. _nose: https://nose.readthedocs.org/en/latest/ +.. _nose: https://nose.readthedocs.io/en/latest/ .. _pytest: http://pypi.python.org/pypi/pytest .. _mercurial: http://mercurial.selenic.com/wiki/ .. _`setuptools`: http://pypi.python.org/pypi/setuptools @@ -18,4 +18,4 @@ .. _hudson: http://hudson-ci.org/ .. _jenkins: http://jenkins-ci.org/ .. _tox: http://testrun.org/tox -.. _pylib: http://py.readthedocs.org/en/latest/ +.. _pylib: https://py.readthedocs.io/en/latest/ diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/logging.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/logging.rst new file mode 100644 index 00000000000..e3bf5603887 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/logging.rst @@ -0,0 +1,192 @@ +.. _logging: + +Logging +------- + +.. versionadded 3.3.0 + +.. note:: + + This feature is a drop-in replacement for the `pytest-catchlog + `_ plugin and they will conflict + with each other. The backward compatibility API with ``pytest-capturelog`` + has been dropped when this feature was introduced, so if for that reason you + still need ``pytest-catchlog`` you can disable the internal feature by + adding to your ``pytest.ini``: + + .. code-block:: ini + + [pytest] + addopts=-p no:logging + +Log messages are captured by default and for each failed test will be shown in +the same manner as captured stdout and stderr. + +Running without options:: + + pytest + +Shows failed tests like so:: + + ----------------------- Captured stdlog call ---------------------- + test_reporting.py 26 INFO text going to logger + ----------------------- Captured stdout call ---------------------- + text going to stdout + ----------------------- Captured stderr call ---------------------- + text going to stderr + ==================== 2 failed in 0.02 seconds ===================== + +By default each captured log message shows the module, line number, log level +and message. Showing the exact module and line number is useful for testing and +debugging. If desired the log format and date format can be specified to +anything that the logging module supports. + +Running pytest specifying formatting options:: + + pytest --log-format="%(asctime)s %(levelname)s %(message)s" \ + --log-date-format="%Y-%m-%d %H:%M:%S" + +Shows failed tests like so:: + + ----------------------- Captured stdlog call ---------------------- + 2010-04-10 14:48:44 INFO text going to logger + ----------------------- Captured stdout call ---------------------- + text going to stdout + ----------------------- Captured stderr call ---------------------- + text going to stderr + ==================== 2 failed in 0.02 seconds ===================== + +These options can also be customized through a configuration file: + +.. code-block:: ini + + [pytest] + log_format = %(asctime)s %(levelname)s %(message)s + log_date_format = %Y-%m-%d %H:%M:%S + +Further it is possible to disable reporting logs on failed tests completely +with:: + + pytest --no-print-logs + +Or in you ``pytest.ini``: + +.. code-block:: ini + + [pytest] + log_print = False + + +Shows failed tests in the normal manner as no logs were captured:: + + ----------------------- Captured stdout call ---------------------- + text going to stdout + ----------------------- Captured stderr call ---------------------- + text going to stderr + ==================== 2 failed in 0.02 seconds ===================== + +Inside tests it is possible to change the log level for the captured log +messages. This is supported by the ``caplog`` fixture:: + + def test_foo(caplog): + caplog.set_level(logging.INFO) + pass + +By default the level is set on the handler used to catch the log messages, +however as a convenience it is also possible to set the log level of any +logger:: + + def test_foo(caplog): + caplog.set_level(logging.CRITICAL, logger='root.baz') + pass + +It is also possible to use a context manager to temporarily change the log +level:: + + def test_bar(caplog): + with caplog.at_level(logging.INFO): + pass + +Again, by default the level of the handler is affected but the level of any +logger can be changed instead with:: + + def test_bar(caplog): + with caplog.at_level(logging.CRITICAL, logger='root.baz'): + pass + +Lastly all the logs sent to the logger during the test run are made available on +the fixture in the form of both the LogRecord instances and the final log text. +This is useful for when you want to assert on the contents of a message:: + + def test_baz(caplog): + func_under_test() + for record in caplog.records: + assert record.levelname != 'CRITICAL' + assert 'wally' not in caplog.text + +For all the available attributes of the log records see the +``logging.LogRecord`` class. + +You can also resort to ``record_tuples`` if all you want to do is to ensure, +that certain messages have been logged under a given logger name with a given +severity and message:: + + def test_foo(caplog): + logging.getLogger().info('boo %s', 'arg') + + assert caplog.record_tuples == [ + ('root', logging.INFO, 'boo arg'), + ] + +You can call ``caplog.clear()`` to reset the captured log records in a test:: + + def test_something_with_clearing_records(caplog): + some_method_that_creates_log_records() + caplog.clear() + your_test_method() + assert ['Foo'] == [rec.message for rec in caplog.records] + +Live Logs +^^^^^^^^^ + +By default, pytest will output any logging records with a level higher or +equal to WARNING. In order to actually see these logs in the console you have to +disable pytest output capture by passing ``-s``. + +You can specify the logging level for which log records with equal or higher +level are printed to the console by passing ``--log-cli-level``. This setting +accepts the logging level names as seen in python's documentation or an integer +as the logging level num. + +Additionally, you can also specify ``--log-cli-format`` and +``--log-cli-date-format`` which mirror and default to ``--log-format`` and +``--log-date-format`` if not provided, but are applied only to the console +logging handler. + +All of the CLI log options can also be set in the configuration INI file. The +option names are: + +* ``log_cli_level`` +* ``log_cli_format`` +* ``log_cli_date_format`` + +If you need to record the whole test suite logging calls to a file, you can pass +``--log-file=/path/to/log/file``. This log file is opened in write mode which +means that it will be overwritten at each run tests session. + +You can also specify the logging level for the log file by passing +``--log-file-level``. This setting accepts the logging level names as seen in +python's documentation(ie, uppercased level names) or an integer as the logging +level num. + +Additionally, you can also specify ``--log-file-format`` and +``--log-file-date-format`` which are equal to ``--log-format`` and +``--log-date-format`` but are applied to the log file logging handler. + +All of the log file options can also be set in the configuration INI file. The +option names are: + +* ``log_file`` +* ``log_file_level`` +* ``log_file_format`` +* ``log_file_date_format`` diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/mark.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/mark.rst similarity index 95% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/mark.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/mark.rst index ab9546d317c..0b0e072a09b 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/mark.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/mark.rst @@ -10,6 +10,7 @@ By using the ``pytest.mark`` helper you can easily set metadata on your test functions. There are some builtin markers, for example: +* :ref:`skip ` - always skip a test function * :ref:`skipif ` - skip a test function if a certain condition is met * :ref:`xfail ` - produce an "expected failure" outcome if a certain condition is met diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/monkeypatch.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/monkeypatch.rst similarity index 73% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/monkeypatch.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/monkeypatch.rst index 4155a3a345b..0c07b2f44fc 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/monkeypatch.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/monkeypatch.rst @@ -6,7 +6,7 @@ Monkeypatching/mocking modules and environments Sometimes tests need to invoke functionality which depends on global settings or which invokes code which cannot be easily -tested such as network access. The ``monkeypatch`` function argument +tested such as network access. The ``monkeypatch`` fixture helps you to safely set/delete an attribute, dictionary item or environment variable or to modify ``sys.path`` for importing. See the `monkeypatch blog post`_ for some introduction material @@ -14,6 +14,7 @@ and a discussion of its motivation. .. _`monkeypatch blog post`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/ + Simple example: monkeypatching functions --------------------------------------------------- @@ -34,7 +35,7 @@ patch this function before calling into a function which uses it:: assert x == '/abc/.ssh' Here our test function monkeypatches ``os.path.expanduser`` and -then calls into an function that calls it. After the test function +then calls into a function that calls it. After the test function finishes the ``os.path.expanduser`` modification will be undone. example: preventing "requests" from remote operations @@ -53,28 +54,20 @@ This autouse fixture will be executed for each test function and it will delete the method ``request.session.Session.request`` so that any attempts within tests to create http requests will fail. -example: setting an attribute on some class ------------------------------------------------------- -If you need to patch out ``os.getcwd()`` to return an artificial -value:: - - def test_some_interaction(monkeypatch): - monkeypatch.setattr("os.getcwd", lambda: "/") - -which is equivalent to the long form:: - - def test_some_interaction(monkeypatch): - import os - monkeypatch.setattr(os, "getcwd", lambda: "/") +.. note:: + + Be advised that it is not recommended to patch builtin functions such as ``open``, + ``compile``, etc., because it might break pytest's internals. If that's + unavoidable, passing ``--tb=native``, ``--assert=plain`` and ``--capture=no`` might + help although there's no guarantee. +Method reference of the monkeypatch fixture +------------------------------------------- -Method reference of the monkeypatch function argument ------------------------------------------------------ - -.. autoclass:: monkeypatch - :members: setattr, replace, delattr, setitem, delitem, setenv, delenv, syspath_prepend, chdir, undo +.. autoclass:: MonkeyPatch + :members: ``monkeypatch.setattr/delattr/delitem/delenv()`` all by default raise an Exception if the target does not exist. diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/naming20.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/naming20.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/naming20.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/naming20.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/nose.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/nose.rst similarity index 58% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/nose.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/nose.rst index 3b92e04cffd..10a10633ab0 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/nose.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/nose.rst @@ -1,3 +1,5 @@ +.. _`noseintegration`: + Running tests written for nose ======================================= @@ -13,7 +15,7 @@ Usage After :ref:`installation` type:: python setup.py develop # make sure tests can import our package - py.test # instead of 'nosetests' + pytest # instead of 'nosetests' and you should be able to run your nose style tests and make use of pytest's capabilities. @@ -24,7 +26,7 @@ Supported nose Idioms * setup and teardown at module/class/method level * SkipTest exceptions and markers * setup/teardown decorators -* yield-based tests and their setup +* ``yield``-based tests and their setup (considered deprecated as of pytest 3.0) * ``__test__`` attribute on modules/classes/functions * general usage of nose utilities @@ -45,11 +47,29 @@ Unsupported idioms / known issues ``tests.test_mod``) but different file system paths (e.g. ``tests/test_mode.py`` and ``other/tests/test_mode.py``) by extending sys.path/import semantics. pytest does not do that - but there is discussion in `issue268 `_ for adding some support. Note that - `nose2 choose to avoid this sys.path/import hackery `_. + but there is discussion in `#268 `_ for adding some support. Note that + `nose2 choose to avoid this sys.path/import hackery `_. + + If you place a conftest.py file in the root directory of your project + (as determined by pytest) pytest will run tests "nose style" against + the code below that directory by adding it to your ``sys.path`` instead of + running against your installed code. + + You may find yourself wanting to do this if you ran ``python setup.py install`` + to set up your project, as opposed to ``python setup.py develop`` or any of + the package manager equivalents. Installing with develop in a + virtual environment like Tox is recommended over this pattern. - nose-style doctests are not collected and executed correctly, also doctest fixtures don't work. -- no nose-configuration is recognized +- no nose-configuration is recognized. + +- ``yield``-based methods don't support ``setup`` properly because + the ``setup`` method is always called in the same class instance. + There are no plans to fix this currently because ``yield``-tests + are deprecated in pytest 3.0, with ``pytest.mark.parametrize`` + being the recommended alternative. + + diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/parametrize.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/parametrize.rst similarity index 63% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/parametrize.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/parametrize.rst index 919ac93d25a..7a4ac2e1877 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/parametrize.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/parametrize.rst @@ -9,17 +9,16 @@ Parametrizing fixtures and test functions ========================================================================== -pytest supports test parametrization in several well-integrated ways: +pytest enables test parametrization at several levels: -- :py:func:`pytest.fixture` allows to define :ref:`parametrization - at the level of fixture functions `. +- :py:func:`pytest.fixture` allows one to :ref:`parametrize fixture + functions `. -* `@pytest.mark.parametrize`_ allows to define parametrization at the - function or class level, provides multiple argument/fixture sets - for a particular test function or class. +* `@pytest.mark.parametrize`_ allows one to define multiple sets of + arguments and fixtures at the test function or class. -* `pytest_generate_tests`_ enables implementing your own custom - dynamic parametrization scheme or extensions. +* `pytest_generate_tests`_ allows one to define custom parametrization + schemes or extensions. .. _parametrizemark: .. _`@pytest.mark.parametrize`: @@ -53,16 +52,16 @@ Here, the ``@parametrize`` decorator defines three different ``(test_input,expec tuples so that the ``test_eval`` function will run three times using them in turn:: - $ py.test - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: + $ pytest + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: collected 3 items - test_expectation.py ..F + test_expectation.py ..F [100%] - ======= FAILURES ======== - _______ test_eval[6*9-42] ________ + ================================= FAILURES ================================= + ____________________________ test_eval[6*9-42] _____________________________ test_input = '6*9', expected = 42 @@ -73,11 +72,11 @@ them in turn:: ]) def test_eval(test_input, expected): > assert eval(test_input) == expected - E assert 54 == 42 + E AssertionError: assert 54 == 42 E + where 54 = eval('6*9') test_expectation.py:8: AssertionError - ======= 1 failed, 2 passed in 0.12 seconds ======== + ==================== 1 failed, 2 passed in 0.12 seconds ==================== As designed in this example, only one pair of input/output values fails the simple test function. And as usual with test function arguments, @@ -94,22 +93,23 @@ for example with the builtin ``mark.xfail``:: @pytest.mark.parametrize("test_input,expected", [ ("3+5", 8), ("2+4", 6), - pytest.mark.xfail(("6*9", 42)), + pytest.param("6*9", 42, + marks=pytest.mark.xfail), ]) def test_eval(test_input, expected): assert eval(test_input) == expected Let's run this:: - $ py.test - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: + $ pytest + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: collected 3 items - test_expectation.py ..x + test_expectation.py ..x [100%] - ======= 2 passed, 1 xfailed in 0.12 seconds ======== + =================== 2 passed, 1 xfailed in 0.12 seconds ==================== The one parameter set which caused a failure previously now shows up as an "xfailed (expected to fail)" test. @@ -123,15 +123,8 @@ To get all combinations of multiple parametrized arguments you can stack def test_foo(x, y): pass -This will run the test with the arguments set to x=0/y=2, x=0/y=3, x=1/y=2 and -x=1/y=3. - -.. note:: - - In versions prior to 2.4 one needed to specify the argument - names as a tuple. This remains valid but the simpler ``"name1,name2,..."`` - comma-separated-string syntax is now advertised first because - it's easier to write and produces less line noise. +This will run the test with the arguments set to ``x=0/y=2``, ``x=0/y=3``, ``x=1/y=2`` and +``x=1/y=3``. .. _`pytest_generate_tests`: @@ -167,27 +160,28 @@ command line option and the parametrization of our test function:: def pytest_generate_tests(metafunc): if 'stringinput' in metafunc.fixturenames: metafunc.parametrize("stringinput", - metafunc.config.option.stringinput) + metafunc.config.getoption('stringinput')) If we now pass two stringinput values, our test will run twice:: - $ py.test -q --stringinput="hello" --stringinput="world" test_strings.py - .. + $ pytest -q --stringinput="hello" --stringinput="world" test_strings.py + .. [100%] 2 passed in 0.12 seconds Let's also run with a stringinput that will lead to a failing test:: - $ py.test -q --stringinput="!" test_strings.py - F - ======= FAILURES ======== - _______ test_valid_string[!] ________ + $ pytest -q --stringinput="!" test_strings.py + F [100%] + ================================= FAILURES ================================= + ___________________________ test_valid_string[!] ___________________________ stringinput = '!' def test_valid_string(stringinput): > assert stringinput.isalpha() - E assert () - E + where = '!'.isalpha + E AssertionError: assert False + E + where False = () + E + where = '!'.isalpha test_strings.py:3: AssertionError 1 failed in 0.12 seconds @@ -198,12 +192,18 @@ If you don't specify a stringinput it will be skipped because ``metafunc.parametrize()`` will be called with an empty parameter list:: - $ py.test -q -rs test_strings.py - s - ======= short test summary info ======== - SKIP [1] $PYTHON_PREFIX/lib/python3.4/site-packages/_pytest/python.py:1419: got empty parameter set, function test_valid_string at $REGENDOC_TMPDIR/test_strings.py:1 + $ pytest -q -rs test_strings.py + s [100%] + ========================= short test summary info ========================== + SKIP [1] test_strings.py: got empty parameter set ['stringinput'], function test_valid_string at $REGENDOC_TMPDIR/test_strings.py:1 1 skipped in 0.12 seconds +Note that when calling ``metafunc.parametrize`` multiple times with different parameter sets, all parameter names across +those sets cannot be duplicated, otherwise an error will be raised. + +More examples +------------- + For further examples, you might want to look at :ref:`more parametrization examples `. @@ -214,6 +214,4 @@ The **metafunc** object .. currentmodule:: _pytest.python .. autoclass:: Metafunc - - .. automethod:: Metafunc.parametrize - .. automethod:: Metafunc.addcall(funcargs=None,id=_notexists,param=_notexists) + :members: diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/plugins.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/plugins.rst similarity index 92% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/plugins.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/plugins.rst index e9b3f460cc4..400418aee25 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/plugins.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/plugins.rst @@ -27,9 +27,6 @@ Here is a little annotated list for some popular plugins: for `twisted `_ apps, starting a reactor and processing deferreds from test functions. -* `pytest-catchlog `_: - to capture and assert about messages from the logging module - * `pytest-cov `_: coverage reporting, compatible with distributed testing @@ -37,7 +34,7 @@ Here is a little annotated list for some popular plugins: to distribute tests to CPUs and remote hosts, to run in boxed mode which allows to survive segmentation faults, to run in looponfailing mode, automatically re-running failing tests - on file changes, see also :ref:`xdist` + on file changes. * `pytest-instafail `_: to report failures while the test run is happening. @@ -59,7 +56,7 @@ Here is a little annotated list for some popular plugins: a plugin to run javascript unittests in live browsers. To see a complete list of all plugins with their latest testing -status against different py.test and Python versions, please visit +status against different pytest and Python versions, please visit `plugincompat `_. You may also discover more plugins through a `pytest- pypi.python.org search`_. @@ -90,11 +87,11 @@ Finding out which plugins are active If you want to find out which plugins are active in your environment you can type:: - py.test --traceconfig + pytest --trace-config and will get an extended test header which shows activated plugins and their names. It will also print local plugins aka -:ref:`conftest.py ` files when they are loaded. +:ref:`conftest.py ` files when they are loaded. .. _`cmdunregister`: @@ -103,7 +100,7 @@ Deactivating / unregistering a plugin by name You can prevent plugins from loading or unregister them:: - py.test -p no:NAME + pytest -p no:NAME This means that any subsequent try to activate/load the named plugin will not work. @@ -138,14 +135,13 @@ in the `pytest repository `_. _pytest.capture _pytest.config _pytest.doctest - _pytest.genscript _pytest.helpconfig _pytest.junitxml _pytest.mark _pytest.monkeypatch _pytest.nose _pytest.pastebin - _pytest.pdb + _pytest.debugging _pytest.pytester _pytest.python _pytest.recwarn @@ -156,4 +152,3 @@ in the `pytest repository `_. _pytest.terminal _pytest.tmpdir _pytest.unittest - diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/projects.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/projects.rst similarity index 95% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/projects.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/projects.rst index 76d004916ce..86df99ab2c5 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/projects.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/projects.rst @@ -57,8 +57,8 @@ Here are some examples of projects using ``pytest`` (please send notes via :ref: * `bu `_ a microscopic build system * `katcp `_ Telescope communication protocol over Twisted * `kss plugin timer `_ -* `pyudev `_ a pure Python binding to the Linux library libudev -* `pytest-localserver `_ a plugin for pytest that provides a httpserver and smtpserver +* `pyudev `_ a pure Python binding to the Linux library libudev +* `pytest-localserver `_ a plugin for pytest that provides an httpserver and smtpserver * `pytest-monkeyplus `_ a plugin that extends monkeypatch These projects help integrate ``pytest`` into other Python frameworks: diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/proposals/parametrize_with_fixtures.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/proposals/parametrize_with_fixtures.rst new file mode 100644 index 00000000000..146032aa471 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/proposals/parametrize_with_fixtures.rst @@ -0,0 +1,160 @@ +:orphan: + +=================================== +PROPOSAL: Parametrize with fixtures +=================================== + +.. warning:: + + This document outlines a proposal around using fixtures as input + of parametrized tests or fixtures. + +Problem +------- + +As a user I have functional tests that I would like to run against various +scenarios. + +In this particular example we want to generate a new project based on a +cookiecutter template. We want to test default values but also data that +emulates user input. + +- use default values + +- emulate user input + + - specify 'author' + + - specify 'project_slug' + + - specify 'author' and 'project_slug' + +This is how a functional test could look like: + +.. code-block:: python + + import pytest + + @pytest.fixture + def default_context(): + return {'extra_context': {}} + + + @pytest.fixture(params=[ + {'author': 'alice'}, + {'project_slug': 'helloworld'}, + {'author': 'bob', 'project_slug': 'foobar'}, + ]) + def extra_context(request): + return {'extra_context': request.param} + + + @pytest.fixture(params=['default', 'extra']) + def context(request): + if request.param == 'default': + return request.getfuncargvalue('default_context') + else: + return request.getfuncargvalue('extra_context') + + + def test_generate_project(cookies, context): + """Call the cookiecutter API to generate a new project from a + template. + """ + result = cookies.bake(extra_context=context) + + assert result.exit_code == 0 + assert result.exception is None + assert result.project.isdir() + + +Issues +------ + +* By using ``request.getfuncargvalue()`` we rely on actual fixture function + execution to know what fixtures are involved, due to it's dynamic nature +* More importantly, ``request.getfuncargvalue()`` cannot be combined with + parametrized fixtures, such as ``extra_context`` +* This is very inconvenient if you wish to extend an existing test suite by + certain parameters for fixtures that are already used by tests + +pytest version 3.0 reports an error if you try to run above code:: + + Failed: The requested fixture has no parameter defined for the current + test. + + Requested fixture 'extra_context' + + +Proposed solution +----------------- + +A new function that can be used in modules can be used to dynamically define +fixtures from existing ones. + +.. code-block:: python + + pytest.define_combined_fixture( + name='context', + fixtures=['default_context', 'extra_context'], + ) + +The new fixture ``context`` inherits the scope from the used fixtures and yield +the following values. + +- ``{}`` + +- ``{'author': 'alice'}`` + +- ``{'project_slug': 'helloworld'}`` + +- ``{'author': 'bob', 'project_slug': 'foobar'}`` + +Alternative approach +-------------------- + +A new helper function named ``fixture_request`` would tell pytest to yield +all parameters marked as a fixture. + +.. note:: + + The `pytest-lazy-fixture `_ plugin implements a very + similar solution to the proposal below, make sure to check it out. + +.. code-block:: python + + @pytest.fixture(params=[ + pytest.fixture_request('default_context'), + pytest.fixture_request('extra_context'), + ]) + def context(request): + """Returns all values for ``default_context``, one-by-one before it + does the same for ``extra_context``. + + request.param: + - {} + - {'author': 'alice'} + - {'project_slug': 'helloworld'} + - {'author': 'bob', 'project_slug': 'foobar'} + """ + return request.param + +The same helper can be used in combination with ``pytest.mark.parametrize``. + +.. code-block:: python + + + @pytest.mark.parametrize( + 'context, expected_response_code', + [ + (pytest.fixture_request('default_context'), 0), + (pytest.fixture_request('extra_context'), 0), + ], + ) + def test_generate_project(cookies, context, exit_code): + """Call the cookiecutter API to generate a new project from a + template. + """ + result = cookies.bake(extra_context=context) + + assert result.exit_code == exit_code diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/pytest.ini b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/pytest.ini similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/pytest.ini rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/pytest.ini diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/pythonpath.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/pythonpath.rst new file mode 100644 index 00000000000..b6474276887 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/pythonpath.rst @@ -0,0 +1,76 @@ +.. _pythonpath: + +pytest import mechanisms and ``sys.path``/``PYTHONPATH`` +======================================================== + +Here's a list of scenarios where pytest may need to change ``sys.path`` in order +to import test modules or ``conftest.py`` files. + +Test modules / ``conftest.py`` files inside packages +---------------------------------------------------- + +Consider this file and directory layout:: + + root/ + |- foo/ + |- __init__.py + |- conftest.py + |- bar/ + |- __init__.py + |- tests/ + |- __init__.py + |- test_foo.py + + +When executing:: + + pytest root/ + + + +pytest will find ``foo/bar/tests/test_foo.py`` and realize it is part of a package given that +there's an ``__init__.py`` file in the same folder. It will then search upwards until it can find the +last folder which still contains an ``__init__.py`` file in order to find the package *root* (in +this case ``foo/``). To load the module, it will insert ``root/`` to the front of +``sys.path`` (if not there already) in order to load +``test_foo.py`` as the *module* ``foo.bar.tests.test_foo``. + +The same logic applies to the ``conftest.py`` file: it will be imported as ``foo.conftest`` module. + +Preserving the full package name is important when tests live in a package to avoid problems +and allow test modules to have duplicated names. This is also discussed in details in +:ref:`test discovery`. + +Standalone test modules / ``conftest.py`` files +----------------------------------------------- + +Consider this file and directory layout:: + + root/ + |- foo/ + |- conftest.py + |- bar/ + |- tests/ + |- test_foo.py + + +When executing:: + + pytest root/ + +pytest will find ``foo/bar/tests/test_foo.py`` and realize it is NOT part of a package given that +there's no ``__init__.py`` file in the same folder. It will then add ``root/foo/bar/tests`` to +``sys.path`` in order to import ``test_foo.py`` as the *module* ``test_foo``. The same is done +with the ``conftest.py`` file by adding ``root/foo`` to ``sys.path`` to import it as ``conftest``. + +For this reason this layout cannot have test modules with the same name, as they all will be +imported in the global import namespace. + +This is also discussed in details in :ref:`test discovery`. + +Invoking ``pytest`` versus ``python -m pytest`` +----------------------------------------------- + +Running pytest with ``python -m pytest [...]`` instead of ``pytest [...]`` yields nearly +equivalent behaviour, except that the former call will add the current directory to ``sys.path``. +See also :ref:`cmdline`. diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/recwarn.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/recwarn.rst new file mode 100644 index 00000000000..513af0d450e --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/recwarn.rst @@ -0,0 +1,3 @@ +:orphan: + +This page has been moved, please see :ref:`assertwarnings`. diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/requirements.txt b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/requirements.txt new file mode 100644 index 00000000000..72bb60a811f --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/requirements.txt @@ -0,0 +1,3 @@ +# pinning sphinx to 1.4.* due to search issues with rtd: +# https://github.com/rtfd/readthedocs-sphinx-ext/issues/25 +sphinx ==1.4.* diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/skipping.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/skipping.rst new file mode 100644 index 00000000000..7e001929b23 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/skipping.rst @@ -0,0 +1,378 @@ +.. _`skip and xfail`: + +.. _skipping: + +Skip and xfail: dealing with tests that cannot succeed +====================================================== + +You can mark test functions that cannot be run on certain platforms +or that you expect to fail so pytest can deal with them accordingly and +present a summary of the test session, while keeping the test suite *green*. + +A **skip** means that you expect your test to pass only if some conditions are met, +otherwise pytest should skip running the test altogether. Common examples are skipping +windows-only tests on non-windows platforms, or skipping tests that depend on an external +resource which is not available at the moment (for example a database). + +A **xfail** means that you expect a test to fail for some reason. +A common example is a test for a feature not yet implemented, or a bug not yet fixed. +When a test passes despite being expected to fail (marked with ``pytest.mark.xfail``), +it's an **xpass** and will be reported in the test summary. + +``pytest`` counts and lists *skip* and *xfail* tests separately. Detailed +information about skipped/xfailed tests is not shown by default to avoid +cluttering the output. You can use the ``-r`` option to see details +corresponding to the "short" letters shown in the test progress:: + + pytest -rxXs # show extra info on xfailed, xpassed, and skipped tests + +More details on the ``-r`` option can be found by running ``pytest -h``. + +(See :ref:`how to change command line options defaults`) + +.. _skipif: +.. _skip: +.. _`condition booleans`: + +Skipping test functions +----------------------- + +.. versionadded:: 2.9 + +The simplest way to skip a test function is to mark it with the ``skip`` decorator +which may be passed an optional ``reason``: + +.. code-block:: python + + @pytest.mark.skip(reason="no way of currently testing this") + def test_the_unknown(): + ... + + +Alternatively, it is also possible to skip imperatively during test execution or setup +by calling the ``pytest.skip(reason)`` function: + +.. code-block:: python + + def test_function(): + if not valid_config(): + pytest.skip("unsupported configuration") + +It is also possible to skip the whole module using +``pytest.skip(reason, allow_module_level=True)`` at the module level: + +.. code-block:: python + + import pytest + + if not pytest.config.getoption("--custom-flag"): + pytest.skip("--custom-flag is missing, skipping tests", allow_module_level=True) + +The imperative method is useful when it is not possible to evaluate the skip condition +during import time. + +``skipif`` +~~~~~~~~~~ + +.. versionadded:: 2.0 + +If you wish to skip something conditionally then you can use ``skipif`` instead. +Here is an example of marking a test function to be skipped +when run on a Python3.6 interpreter:: + + import sys + @pytest.mark.skipif(sys.version_info < (3,6), + reason="requires python3.6") + def test_function(): + ... + +If the condition evaluates to ``True`` during collection, the test function will be skipped, +with the specified reason appearing in the summary when using ``-rs``. + +You can share ``skipif`` markers between modules. Consider this test module:: + + # content of test_mymodule.py + import mymodule + minversion = pytest.mark.skipif(mymodule.__versioninfo__ < (1,1), + reason="at least mymodule-1.1 required") + @minversion + def test_function(): + ... + +You can import the marker and reuse it in another test module:: + + # test_myothermodule.py + from test_mymodule import minversion + + @minversion + def test_anotherfunction(): + ... + +For larger test suites it's usually a good idea to have one file +where you define the markers which you then consistently apply +throughout your test suite. + +Alternatively, you can use :ref:`condition strings +` instead of booleans, but they can't be shared between modules easily +so they are supported mainly for backward compatibility reasons. + + +Skip all test functions of a class or module +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can use the ``skipif`` marker (as any other marker) on classes:: + + @pytest.mark.skipif(sys.platform == 'win32', + reason="does not run on windows") + class TestPosixCalls(object): + + def test_function(self): + "will not be setup or run under 'win32' platform" + +If the condition is ``True``, this marker will produce a skip result for +each of the test methods of that class. + +.. warning:: + + The use of ``skipif`` on classes that use inheritance is strongly + discouraged. `A Known bug `_ + in pytest's markers may cause unexpected behavior in super classes. + +If you want to skip all test functions of a module, you may use +the ``pytestmark`` name on the global level: + +.. code-block:: python + + # test_module.py + pytestmark = pytest.mark.skipif(...) + +If multiple ``skipif`` decorators are applied to a test function, it +will be skipped if any of the skip conditions is true. + +.. _`whole class- or module level`: mark.html#scoped-marking + + +Skipping files or directories +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Sometimes you may need to skip an entire file or directory, for example if the +tests rely on Python version-specific features or contain code that you do not +wish pytest to run. In this case, you must exclude the files and directories +from collection. Refer to :ref:`customizing-test-collection` for more +information. + + +Skipping on a missing import dependency +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can use the following helper at module level +or within a test or test setup function:: + + docutils = pytest.importorskip("docutils") + +If ``docutils`` cannot be imported here, this will lead to a +skip outcome of the test. You can also skip based on the +version number of a library:: + + docutils = pytest.importorskip("docutils", minversion="0.3") + +The version will be read from the specified +module's ``__version__`` attribute. + +Summary +~~~~~~~ + +Here's a quick guide on how to skip tests in a module in different situations: + +1. Skip all tests in a module unconditionally: + + .. code-block:: python + + pytestmark = pytest.mark.skip('all tests still WIP') + +2. Skip all tests in a module based on some condition: + + .. code-block:: python + + pytestmark = pytest.mark.skipif(sys.platform == 'win32', 'tests for linux only') + +3. Skip all tests in a module if some import is missing: + + .. code-block:: python + + pexpect = pytest.importorskip('pexpect') + + +.. _xfail: + +XFail: mark test functions as expected to fail +---------------------------------------------- + +You can use the ``xfail`` marker to indicate that you +expect a test to fail:: + + @pytest.mark.xfail + def test_function(): + ... + +This test will be run but no traceback will be reported +when it fails. Instead terminal reporting will list it in the +"expected to fail" (``XFAIL``) or "unexpectedly passing" (``XPASS``) sections. + +Alternatively, you can also mark a test as ``XFAIL`` from within a test or setup function +imperatively: + +.. code-block:: python + + def test_function(): + if not valid_config(): + pytest.xfail("failing configuration (but should work)") + +This will unconditionally make ``test_function`` ``XFAIL``. Note that no other code is executed +after ``pytest.xfail`` call, differently from the marker. That's because it is implemented +internally by raising a known exception. + +Here's the signature of the ``xfail`` **marker** (not the function), using Python 3 keyword-only +arguments syntax: + +.. code-block:: python + + def xfail(condition=None, *, reason=None, raises=None, run=True, strict=False): + + + + +``strict`` parameter +~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 2.9 + +Both ``XFAIL`` and ``XPASS`` don't fail the test suite, unless the ``strict`` keyword-only +parameter is passed as ``True``: + +.. code-block:: python + + @pytest.mark.xfail(strict=True) + def test_function(): + ... + + +This will make ``XPASS`` ("unexpectedly passing") results from this test to fail the test suite. + +You can change the default value of the ``strict`` parameter using the +``xfail_strict`` ini option: + +.. code-block:: ini + + [pytest] + xfail_strict=true + + +``reason`` parameter +~~~~~~~~~~~~~~~~~~~~ + +As with skipif_ you can also mark your expectation of a failure +on a particular platform:: + + @pytest.mark.xfail(sys.version_info >= (3,6), + reason="python3.6 api changes") + def test_function(): + ... + + +``raises`` parameter +~~~~~~~~~~~~~~~~~~~~ + +If you want to be more specific as to why the test is failing, you can specify +a single exception, or a list of exceptions, in the ``raises`` argument. + +.. code-block:: python + + @pytest.mark.xfail(raises=RuntimeError) + def test_function(): + ... + +Then the test will be reported as a regular failure if it fails with an +exception not mentioned in ``raises``. + +``run`` parameter +~~~~~~~~~~~~~~~~~ + +If a test should be marked as xfail and reported as such but should not be +even executed, use the ``run`` parameter as ``False``: + +.. code-block:: python + + @pytest.mark.xfail(run=False) + def test_function(): + ... + +This is specially useful for xfailing tests that are crashing the interpreter and should be +investigated later. + + +Ignoring xfail +~~~~~~~~~~~~~~ + +By specifying on the commandline:: + + pytest --runxfail + +you can force the running and reporting of an ``xfail`` marked test +as if it weren't marked at all. This also causes ``pytest.xfail`` to produce no effect. + +Examples +~~~~~~~~ + +Here is a simple test file with the several usages: + +.. literalinclude:: example/xfail_demo.py + +Running it with the report-on-xfail option gives this output:: + + example $ pytest -rx xfail_demo.py + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR/example, inifile: + collected 7 items + + xfail_demo.py xxxxxxx [100%] + ========================= short test summary info ========================== + XFAIL xfail_demo.py::test_hello + XFAIL xfail_demo.py::test_hello2 + reason: [NOTRUN] + XFAIL xfail_demo.py::test_hello3 + condition: hasattr(os, 'sep') + XFAIL xfail_demo.py::test_hello4 + bug 110 + XFAIL xfail_demo.py::test_hello5 + condition: pytest.__version__[0] != "17" + XFAIL xfail_demo.py::test_hello6 + reason: reason + XFAIL xfail_demo.py::test_hello7 + + ======================== 7 xfailed in 0.12 seconds ========================= + +.. _`skip/xfail with parametrize`: + +Skip/xfail with parametrize +--------------------------- + +It is possible to apply markers like skip and xfail to individual +test instances when using parametrize: + +.. code-block:: python + + import pytest + + @pytest.mark.parametrize(("n", "expected"), [ + (1, 2), + pytest.param(1, 0, marks=pytest.mark.xfail), + pytest.param(1, 3, marks=pytest.mark.xfail(reason="some bug")), + (2, 3), + (3, 4), + (4, 5), + pytest.param(10, 11, marks=pytest.mark.skipif(sys.version_info >= (3, 0), reason="py2k")), + ]) + def test_increment(n, expected): + assert n + 1 == expected diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/talks.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/talks.rst similarity index 59% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/talks.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/talks.rst index 7a5221845ce..bf593db4b4b 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/talks.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/talks.rst @@ -2,17 +2,26 @@ Talks and Tutorials ========================== -.. sidebar:: Next Open Trainings +.. + .. sidebar:: Next Open Trainings - `professional testing with pytest and tox `_, 27-29th June 2016, Freiburg, Germany + `Professional Testing with Python + `_, + 26-28 April 2017, Leipzig, Germany. .. _`funcargs`: funcargs.html +Books +--------------------------------------------- + +- `Python Testing with pytest, by Brian Okken (2017) + `_. + Talks and blog postings --------------------------------------------- -.. _`tutorial1 repository`: http://bitbucket.org/pytest-dev/pytest-tutorial1/ -.. _`pycon 2010 tutorial PDF`: http://bitbucket.org/pytest-dev/pytest-tutorial1/raw/tip/pytest-basic.pdf +- `Pythonic testing, Igor Starikov (Russian, PyNsk, November 2016) + `_. - `pytest - Rapid Simple Testing, Florian Bruhin, Swiss Python Summit 2016 `_. @@ -52,12 +61,14 @@ Talks and blog postings - `pytest introduction from Brian Okken (January 2013) `_ -- `monkey patching done right`_ (blog post, consult `monkeypatch - plugin`_ for up-to-date API) +- pycon australia 2012 pytest talk from Brianna Laugher (`video `_, `slides `_, `code `_) +- `pycon 2012 US talk video from Holger Krekel `_ + +- `monkey patching done right`_ (blog post, consult `monkeypatch plugin`_ for up-to-date API) Test parametrization: -- `generating parametrized tests with funcargs`_ (uses deprecated ``addcall()`` API. +- `generating parametrized tests with fixtures`_. - `test generators and cached setup`_ - `parametrizing tests, generalized`_ (blog post) - `putting test-hooks into local or global plugins`_ (blog post) @@ -78,39 +89,17 @@ Plugin specific examples: - `many examples in the docs for plugins`_ .. _`skipping slow tests by default in pytest`: http://bruynooghe.blogspot.com/2009/12/skipping-slow-test-by-default-in-pytest.html -.. _`many examples in the docs for plugins`: plugin/index.html -.. _`monkeypatch plugin`: plugin/monkeypatch.html -.. _`application setup in test functions with funcargs`: funcargs.html#appsetup +.. _`many examples in the docs for plugins`: plugins.html +.. _`monkeypatch plugin`: monkeypatch.html +.. _`application setup in test functions with fixtures`: fixture.html#interdependent-fixtures .. _`simultaneously test your code on all platforms`: http://tetamap.wordpress.com/2009/03/23/new-simultanously-test-your-code-on-all-platforms/ .. _`monkey patching done right`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/ .. _`putting test-hooks into local or global plugins`: http://tetamap.wordpress.com/2009/05/14/putting-test-hooks-into-local-and-global-plugins/ .. _`parametrizing tests, generalized`: http://tetamap.wordpress.com/2009/05/13/parametrizing-python-tests-generalized/ -.. _`generating parametrized tests with funcargs`: funcargs.html#test-generators +.. _`generating parametrized tests with fixtures`: parametrize.html#test-generators .. _`test generators and cached setup`: http://bruynooghe.blogspot.com/2010/06/pytest-test-generators-and-cached-setup.html -Older conference talks and tutorials ----------------------------------------- -- `pycon australia 2012 pytest talk from Brianna Laugher - `_ (`video `_, `slides `_, `code `_) -- `pycon 2012 US talk video from Holger Krekel `_ -- `pycon 2010 tutorial PDF`_ and `tutorial1 repository`_ -- `ep2009-rapidtesting.pdf`_ tutorial slides (July 2009): - - testing terminology - - basic pytest usage, file system layout - - test function arguments (funcargs_) and test fixtures - - existing plugins - - distributed testing -- `ep2009-pytest.pdf`_ 60 minute pytest talk, highlighting unique features and a roadmap (July 2009) - -- `pycon2009-pytest-introduction.zip`_ slides and files, extended version of pytest basic introduction, discusses more options, also introduces old-style xUnit setup, looponfailing and other features. - -- `pycon2009-pytest-advanced.pdf`_ contain a slightly older version of funcargs and distributed testing, compared to the EuroPython 2009 slides. - -.. _`ep2009-rapidtesting.pdf`: http://codespeak.net/download/py/ep2009-rapidtesting.pdf -.. _`ep2009-pytest.pdf`: http://codespeak.net/download/py/ep2009-pytest.pdf -.. _`pycon2009-pytest-introduction.zip`: http://codespeak.net/download/py/pycon2009-pytest-introduction.zip -.. _`pycon2009-pytest-advanced.pdf`: http://codespeak.net/download/py/pycon2009-pytest-advanced.pdf diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/attic.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/attic.rst similarity index 98% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/test/attic.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/attic.rst index 6408c722584..06944661cb5 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/attic.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/attic.rst @@ -21,7 +21,7 @@ but note that project specific settings will be considered first. There is a flag that helps you debugging your conftest.py configurations:: - py.test --traceconfig + pytest --trace-config customizing the collecting and running process @@ -110,7 +110,7 @@ If you want to disable a complete test class you can set the class-level attribute ``disabled``. For example, in order to avoid running some tests on Win32:: - class TestPosixOnly: + class TestPosixOnly(object): disabled = sys.platform == 'win32' def test_xxx(self): diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/config.html b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/config.html similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/test/config.html rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/config.html diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/dist.html b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/dist.html similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/test/dist.html rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/dist.html diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/extend.html b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/extend.html similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/test/extend.html rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/extend.html diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/index.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/index.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/test/index.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/index.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/mission.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/mission.rst similarity index 89% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/test/mission.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/mission.rst index cda8d9a7208..51c252dc0d8 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/mission.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/mission.rst @@ -5,7 +5,7 @@ Mission ``pytest`` strives to make testing a fun and no-boilerplate effort. The tool is distributed as a `pytest` package. Its project independent -``py.test`` command line tool helps you to: +``pytest`` command line tool helps you to: * rapidly collect and run tests * run unit- or doctests, functional or integration tests diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/cov.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/cov.rst similarity index 95% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/cov.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/cov.rst index 355093f2586..541c7ef9479 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/cov.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/cov.rst @@ -53,7 +53,7 @@ subprocesses. Running centralised testing:: - py.test --cov myproj tests/ + pytest --cov myproj tests/ Shows a terminal report:: @@ -76,7 +76,7 @@ file system. Each slave will have it's subprocesses measured. Running distributed testing with dist mode set to load:: - py.test --cov myproj -n 2 tests/ + pytest --cov myproj -n 2 tests/ Shows a terminal report:: @@ -92,7 +92,7 @@ Shows a terminal report:: Again but spread over different hosts and different directories:: - py.test --cov myproj --dist load + pytest --cov myproj --dist load --tx ssh=memedough@host1//chdir=testenv1 --tx ssh=memedough@host2//chdir=/tmp/testenv2//python=/tmp/env1/bin/python --rsyncdir myproj --rsyncdir tests --rsync examples @@ -119,7 +119,7 @@ environments. Running distributed testing with dist mode set to each:: - py.test --cov myproj --dist each + pytest --cov myproj --dist each --tx popen//chdir=/tmp/testenv3//python=/usr/local/python27/bin/python --tx ssh=memedough@host2//chdir=/tmp/testenv4//python=/tmp/env2/bin/python --rsyncdir myproj --rsyncdir tests --rsync examples @@ -149,7 +149,7 @@ annotated source code. The terminal report without line numbers (default):: - py.test --cov-report term --cov myproj tests/ + pytest --cov-report term --cov myproj tests/ -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- Name Stmts Miss Cover @@ -163,7 +163,7 @@ The terminal report without line numbers (default):: The terminal report with line numbers:: - py.test --cov-report term-missing --cov myproj tests/ + pytest --cov-report term-missing --cov myproj tests/ -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- Name Stmts Miss Cover Missing @@ -178,7 +178,7 @@ The terminal report with line numbers:: The remaining three reports output to files without showing anything on the terminal (useful for when the output is going to a continuous integration server):: - py.test --cov-report html --cov-report xml --cov-report annotate --cov myproj tests/ + pytest --cov-report html --cov-report xml --cov-report annotate --cov myproj tests/ Coverage Data File diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/coverage.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/coverage.rst similarity index 97% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/coverage.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/coverage.rst index 965b4a4ee07..71139d008ba 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/coverage.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/coverage.rst @@ -26,7 +26,7 @@ Usage To get full test coverage reports for a particular package type:: - py.test --cover-report=report + pytest --cover-report=report command line options -------------------- diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/django.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/django.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/django.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/django.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/figleaf.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/figleaf.rst similarity index 97% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/figleaf.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/figleaf.rst index 86e0da65b6b..0c1603ade9f 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/figleaf.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/figleaf.rst @@ -24,7 +24,7 @@ Usage After installation you can simply type:: - py.test --figleaf [...] + pytest --figleaf [...] to enable figleaf coverage in your test run. A default ".figleaf" data file and "html" directory will be created. You can use command line options diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/helpconfig.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/helpconfig.rst similarity index 90% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/helpconfig.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/helpconfig.rst index 9b5b8cddd9d..326b75c4552 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/helpconfig.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/helpconfig.rst @@ -16,10 +16,8 @@ command line options display py lib version and import information. ``-p name`` early-load given plugin (multi-allowed). -``--traceconfig`` +``--trace-config`` trace considerations of conftest.py files. -``--nomagic`` - don't reinterpret asserts, no traceback cutting. ``--debug`` generate and show internal debugging information. ``--help-config`` diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/index.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/index.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/index.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/index.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/links.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/links.rst similarity index 94% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/links.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/links.rst index aa965e73049..6dec2b4848a 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/links.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/links.rst @@ -2,10 +2,8 @@ .. _`pytest_recwarn.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.3.4/py/_plugin/pytest_recwarn.py .. _`unittest`: unittest.html .. _`pytest_monkeypatch.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.3.4/py/_plugin/pytest_monkeypatch.py -.. _`pytest_genscript.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.3.4/py/_plugin/pytest_genscript.py .. _`pastebin`: pastebin.html .. _`skipping`: skipping.html -.. _`genscript`: genscript.html .. _`plugins`: index.html .. _`mark`: mark.html .. _`tmpdir`: tmpdir.html diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/nose.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/nose.rst similarity index 95% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/nose.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/nose.rst index f3aa7d705f5..9eeae5ff697 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/nose.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/nose.rst @@ -14,7 +14,7 @@ Usage type:: - py.test # instead of 'nosetests' + pytest # instead of 'nosetests' and you should be able to run nose style tests and at the same time can make full use of pytest's capabilities. @@ -38,7 +38,7 @@ Unsupported idioms / issues If you find other issues or have suggestions please run:: - py.test --pastebin=all + pytest --pastebin=all and send the resulting URL to a ``pytest`` contact channel, at best to the mailing list. diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/oejskit.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/oejskit.rst similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/oejskit.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/oejskit.rst diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/terminal.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/terminal.rst similarity index 94% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/terminal.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/terminal.rst index 214c24dfccd..e07d4f72183 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/terminal.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/terminal.rst @@ -18,11 +18,9 @@ command line options show extra test summary info as specified by chars (f)ailed, (s)skipped, (x)failed, (X)passed. ``-l, --showlocals`` show locals in tracebacks (disabled by default). -``--report=opts`` - (deprecated, use -r) ``--tb=style`` traceback print mode (long/short/line/no). -``--fulltrace`` +``--full-trace`` don't cut any tracebacks (default is to cut). ``--fixtures`` show available function arguments, sorted by plugin diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/xdist.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/xdist.rst similarity index 94% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/xdist.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/xdist.rst index 7ab6cdc8b83..506d240aee1 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/plugin/xdist.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/plugin/xdist.rst @@ -36,7 +36,7 @@ Speed up test runs by sending tests to multiple CPUs To send tests to multiple CPUs, type:: - py.test -n NUM + pytest -n NUM Especially for longer running tests or tests requiring a lot of IO this can lead to considerable speed ups. @@ -47,7 +47,7 @@ Running tests in a Python subprocess To instantiate a python2.4 sub process and send tests to it, you may type:: - py.test -d --tx popen//python=python2.4 + pytest -d --tx popen//python=python2.4 This will start a subprocess which is run with the "python2.4" Python interpreter, found in your system binary lookup path. @@ -68,10 +68,10 @@ tests that you can successfully run locally. And you have a ssh-reachable machine ``myhost``. Then you can ad-hoc distribute your tests by typing:: - py.test -d --tx ssh=myhostpopen --rsyncdir mypkg mypkg + pytest -d --tx ssh=myhostpopen --rsyncdir mypkg mypkg This will synchronize your ``mypkg`` package directory -to an remote ssh account and then locally collect tests +to a remote ssh account and then locally collect tests and send them to remote places for execution. You can specify multiple ``--rsyncdir`` directories @@ -97,7 +97,7 @@ It will tell you that it starts listening on the default port. You can now on your home machine specify this new socket host with something like this:: - py.test -d --tx socket=192.168.1.102:8888 --rsyncdir mypkg mypkg + pytest -d --tx socket=192.168.1.102:8888 --rsyncdir mypkg mypkg .. _`atonce`: @@ -107,7 +107,7 @@ Running tests on many platforms at once The basic command to run tests on multiple platforms is:: - py.test --dist=each --tx=spec1 --tx=spec2 + pytest --dist=each --tx=spec1 --tx=spec2 If you specify a windows host, an OSX host and a Linux environment this command will send each tests to all diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/test/test.html b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/test.html similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/test/test.html rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/test/test.html diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/tmpdir.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/tmpdir.rst similarity index 83% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/tmpdir.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/tmpdir.rst index f8935b8cef8..b8174484e1d 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/tmpdir.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/tmpdir.rst @@ -27,16 +27,16 @@ and more. Here is an example test usage:: Running this would result in a passed test except for the last ``assert 0`` line which we use to look at values:: - $ py.test test_tmpdir.py - ======= test session starts ======== - platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 - rootdir: $REGENDOC_TMPDIR, inifile: - collected 1 items + $ pytest test_tmpdir.py + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: + collected 1 item - test_tmpdir.py F + test_tmpdir.py F [100%] - ======= FAILURES ======== - _______ test_create_file ________ + ================================= FAILURES ================================= + _____________________________ test_create_file _____________________________ tmpdir = local('PYTEST_TMPDIR/test_create_file0') @@ -49,7 +49,7 @@ Running this would result in a passed test except for the last E assert 0 test_tmpdir.py:7: AssertionError - ======= 1 failed in 0.12 seconds ======== + ========================= 1 failed in 0.12 seconds ========================= The 'tmpdir_factory' fixture ---------------------------- @@ -100,7 +100,7 @@ than 3 temporary directories will be removed. You can override the default temporary directory setting like this:: - py.test --basetemp=mydir + pytest --basetemp=mydir When distributing tests on the local machine, ``pytest`` takes care to configure a basetemp directory for the sub processes such that all temporary diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/unittest.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/unittest.rst new file mode 100644 index 00000000000..b44bda44fa8 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/unittest.rst @@ -0,0 +1,245 @@ + +.. _`unittest.TestCase`: +.. _`unittest`: + +unittest.TestCase Support +========================= + +``pytest`` supports running Python ``unittest``-based tests out of the box. +It's meant for leveraging existing ``unittest``-based test suites +to use pytest as a test runner and also allow to incrementally adapt +the test suite to take full advantage of pytest's features. + +To run an existing ``unittest``-style test suite using ``pytest``, type:: + + pytest tests + + +pytest will automatically collect ``unittest.TestCase`` subclasses and +their ``test`` methods in ``test_*.py`` or ``*_test.py`` files. + +Almost all ``unittest`` features are supported: + +* ``@unittest.skip`` style decorators; +* ``setUp/tearDown``; +* ``setUpClass/tearDownClass()``; + +.. _`load_tests protocol`: https://docs.python.org/3/library/unittest.html#load-tests-protocol +.. _`setUpModule/tearDownModule`: https://docs.python.org/3/library/unittest.html#setupmodule-and-teardownmodule +.. _`subtests`: https://docs.python.org/3/library/unittest.html#distinguishing-test-iterations-using-subtests + +Up to this point pytest does not have support for the following features: + +* `load_tests protocol`_; +* `setUpModule/tearDownModule`_; +* `subtests`_; + +Benefits out of the box +----------------------- + +By running your test suite with pytest you can make use of several features, +in most cases without having to modify existing code: + +* Obtain :ref:`more informative tracebacks `; +* :ref:`stdout and stderr ` capturing; +* :ref:`Test selection options ` using ``-k`` and ``-m`` flags; +* :ref:`maxfail`; +* :ref:`--pdb ` command-line option for debugging on test failures + (see :ref:`note ` below); +* Distribute tests to multiple CPUs using the `pytest-xdist `_ plugin; +* Use :ref:`plain assert-statements ` instead of ``self.assert*`` functions (`unittest2pytest + `__ is immensely helpful in this); + + +pytest features in ``unittest.TestCase`` subclasses +--------------------------------------------------- + +The following pytest features work in ``unittest.TestCase`` subclasses: + +* :ref:`Marks `: :ref:`skip `, :ref:`skipif `, :ref:`xfail `; +* :ref:`Auto-use fixtures `; + +The following pytest features **do not** work, and probably +never will due to different design philosophies: + +* :ref:`Fixtures ` (except for ``autouse`` fixtures, see :ref:`below `); +* :ref:`Parametrization `; +* :ref:`Custom hooks `; + + +Third party plugins may or may not work well, depending on the plugin and the test suite. + +.. _mixing-fixtures: + +Mixing pytest fixtures into ``unittest.TestCase`` subclasses using marks +------------------------------------------------------------------------ + +Running your unittest with ``pytest`` allows you to use its +:ref:`fixture mechanism ` with ``unittest.TestCase`` style +tests. Assuming you have at least skimmed the pytest fixture features, +let's jump-start into an example that integrates a pytest ``db_class`` +fixture, setting up a class-cached database object, and then reference +it from a unittest-style test:: + + # content of conftest.py + + # we define a fixture function below and it will be "used" by + # referencing its name from tests + + import pytest + + @pytest.fixture(scope="class") + def db_class(request): + class DummyDB(object): + pass + # set a class attribute on the invoking test context + request.cls.db = DummyDB() + +This defines a fixture function ``db_class`` which - if used - is +called once for each test class and which sets the class-level +``db`` attribute to a ``DummyDB`` instance. The fixture function +achieves this by receiving a special ``request`` object which gives +access to :ref:`the requesting test context ` such +as the ``cls`` attribute, denoting the class from which the fixture +is used. This architecture de-couples fixture writing from actual test +code and allows re-use of the fixture by a minimal reference, the fixture +name. So let's write an actual ``unittest.TestCase`` class using our +fixture definition:: + + # content of test_unittest_db.py + + import unittest + import pytest + + @pytest.mark.usefixtures("db_class") + class MyTest(unittest.TestCase): + def test_method1(self): + assert hasattr(self, "db") + assert 0, self.db # fail for demo purposes + + def test_method2(self): + assert 0, self.db # fail for demo purposes + +The ``@pytest.mark.usefixtures("db_class")`` class-decorator makes sure that +the pytest fixture function ``db_class`` is called once per class. +Due to the deliberately failing assert statements, we can take a look at +the ``self.db`` values in the traceback:: + + $ pytest test_unittest_db.py + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: + collected 2 items + + test_unittest_db.py FF [100%] + + ================================= FAILURES ================================= + ___________________________ MyTest.test_method1 ____________________________ + + self = + + def test_method1(self): + assert hasattr(self, "db") + > assert 0, self.db # fail for demo purposes + E AssertionError: .DummyDB object at 0xdeadbeef> + E assert 0 + + test_unittest_db.py:9: AssertionError + ___________________________ MyTest.test_method2 ____________________________ + + self = + + def test_method2(self): + > assert 0, self.db # fail for demo purposes + E AssertionError: .DummyDB object at 0xdeadbeef> + E assert 0 + + test_unittest_db.py:12: AssertionError + ========================= 2 failed in 0.12 seconds ========================= + +This default pytest traceback shows that the two test methods +share the same ``self.db`` instance which was our intention +when writing the class-scoped fixture function above. + + +Using autouse fixtures and accessing other fixtures +--------------------------------------------------- + +Although it's usually better to explicitly declare use of fixtures you need +for a given test, you may sometimes want to have fixtures that are +automatically used in a given context. After all, the traditional +style of unittest-setup mandates the use of this implicit fixture writing +and chances are, you are used to it or like it. + +You can flag fixture functions with ``@pytest.fixture(autouse=True)`` +and define the fixture function in the context where you want it used. +Let's look at an ``initdir`` fixture which makes all test methods of a +``TestCase`` class execute in a temporary directory with a +pre-initialized ``samplefile.ini``. Our ``initdir`` fixture itself uses +the pytest builtin :ref:`tmpdir ` fixture to delegate the +creation of a per-test temporary directory:: + + # content of test_unittest_cleandir.py + import pytest + import unittest + + class MyTest(unittest.TestCase): + + @pytest.fixture(autouse=True) + def initdir(self, tmpdir): + tmpdir.chdir() # change to pytest-provided temporary directory + tmpdir.join("samplefile.ini").write("# testdata") + + def test_method(self): + with open("samplefile.ini") as f: + s = f.read() + assert "testdata" in s + +Due to the ``autouse`` flag the ``initdir`` fixture function will be +used for all methods of the class where it is defined. This is a +shortcut for using a ``@pytest.mark.usefixtures("initdir")`` marker +on the class like in the previous example. + +Running this test module ...:: + + $ pytest -q test_unittest_cleandir.py + . [100%] + 1 passed in 0.12 seconds + +... gives us one passed test because the ``initdir`` fixture function +was executed ahead of the ``test_method``. + +.. note:: + + ``unittest.TestCase`` methods cannot directly receive fixture + arguments as implementing that is likely to inflict + on the ability to run general unittest.TestCase test suites. + + The above ``usefixtures`` and ``autouse`` examples should help to mix in + pytest fixtures into unittest suites. + + You can also gradually move away from subclassing from ``unittest.TestCase`` to *plain asserts* + and then start to benefit from the full pytest feature set step by step. + +.. _pdb-unittest-note: + +.. note:: + + Running tests from ``unittest.TestCase`` subclasses with ``--pdb`` will + disable tearDown and cleanup methods for the case that an Exception + occurs. This allows proper post mortem debugging for all applications + which have significant logic in their tearDown machinery. However, + supporting this feature has the following side effect: If people + overwrite ``unittest.TestCase`` ``__call__`` or ``run``, they need to + to overwrite ``debug`` in the same way (this is also true for standard + unittest). + +.. note:: + + Due to architectural differences between the two frameworks, setup and + teardown for ``unittest``-based tests is performed during the ``call`` phase + of testing instead of in ``pytest``'s standard ``setup`` and ``teardown`` + stages. This can be important to understand in some situations, particularly + when reasoning about errors. For example, if a ``unittest``-based suite + exhibits errors during setup, ``pytest`` will report no errors during its + ``setup`` phase and will instead raise the error during ``call``. diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/usage.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/usage.rst new file mode 100644 index 00000000000..6091db8be38 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/usage.rst @@ -0,0 +1,392 @@ + +.. _usage: + +Usage and Invocations +========================================== + + +.. _cmdline: + +Calling pytest through ``python -m pytest`` +----------------------------------------------------- + +.. versionadded:: 2.0 + +You can invoke testing through the Python interpreter from the command line:: + + python -m pytest [...] + +This is almost equivalent to invoking the command line script ``pytest [...]`` +directly, except that calling via ``python`` will also add the current directory to ``sys.path``. + +Possible exit codes +-------------------------------------------------------------- + +Running ``pytest`` can result in six different exit codes: + +:Exit code 0: All tests were collected and passed successfully +:Exit code 1: Tests were collected and run but some of the tests failed +:Exit code 2: Test execution was interrupted by the user +:Exit code 3: Internal error happened while executing tests +:Exit code 4: pytest command line usage error +:Exit code 5: No tests were collected + +Getting help on version, option names, environment variables +-------------------------------------------------------------- + +:: + + pytest --version # shows where pytest was imported from + pytest --fixtures # show available builtin function arguments + pytest -h | --help # show help on command line and config file options + + +.. _maxfail: + +Stopping after the first (or N) failures +--------------------------------------------------- + +To stop the testing process after the first (N) failures:: + + pytest -x # stop after first failure + pytest --maxfail=2 # stop after two failures + +.. _select-tests: + +Specifying tests / selecting tests +--------------------------------------------------- + +Pytest supports several ways to run and select tests from the command-line. + +**Run tests in a module** + +:: + + pytest test_mod.py + +**Run tests in a directory** + +:: + + pytest testing/ + +**Run tests by keyword expressions** + +:: + + pytest -k "MyClass and not method" + +This will run tests which contain names that match the given *string expression*, which can +include Python operators that use filenames, class names and function names as variables. +The example above will run ``TestMyClass.test_something`` but not ``TestMyClass.test_method_simple``. + +.. _nodeids: + +**Run tests by node ids** + +Each collected test is assigned a unique ``nodeid`` which consist of the module filename followed +by specifiers like class names, function names and parameters from parametrization, separated by ``::`` characters. + +To run a specific test within a module:: + + pytest test_mod.py::test_func + + +Another example specifying a test method in the command line:: + + pytest test_mod.py::TestClass::test_method + +**Run tests by marker expressions** + +:: + + pytest -m slow + +Will run all tests which are decorated with the ``@pytest.mark.slow`` decorator. + +For more information see :ref:`marks `. + +**Run tests from packages** + +:: + + pytest --pyargs pkg.testing + +This will import ``pkg.testing`` and use its filesystem location to find and run tests from. + + +Modifying Python traceback printing +---------------------------------------------- + +Examples for modifying traceback printing:: + + pytest --showlocals # show local variables in tracebacks + pytest -l # show local variables (shortcut) + + pytest --tb=auto # (default) 'long' tracebacks for the first and last + # entry, but 'short' style for the other entries + pytest --tb=long # exhaustive, informative traceback formatting + pytest --tb=short # shorter traceback format + pytest --tb=line # only one line per failure + pytest --tb=native # Python standard library formatting + pytest --tb=no # no traceback at all + +The ``--full-trace`` causes very long traces to be printed on error (longer +than ``--tb=long``). It also ensures that a stack trace is printed on +**KeyboardInterrupt** (Ctrl+C). +This is very useful if the tests are taking too long and you interrupt them +with Ctrl+C to find out where the tests are *hanging*. By default no output +will be shown (because KeyboardInterrupt is caught by pytest). By using this +option you make sure a trace is shown. + + +.. _pdb-option: + +Dropping to PDB_ (Python Debugger) on failures +----------------------------------------------- + +.. _PDB: http://docs.python.org/library/pdb.html + +Python comes with a builtin Python debugger called PDB_. ``pytest`` +allows one to drop into the PDB_ prompt via a command line option:: + + pytest --pdb + +This will invoke the Python debugger on every failure. Often you might +only want to do this for the first failing test to understand a certain +failure situation:: + + pytest -x --pdb # drop to PDB on first failure, then end test session + pytest --pdb --maxfail=3 # drop to PDB for first three failures + +Note that on any failure the exception information is stored on +``sys.last_value``, ``sys.last_type`` and ``sys.last_traceback``. In +interactive use, this allows one to drop into postmortem debugging with +any debug tool. One can also manually access the exception information, +for example:: + + >>> import sys + >>> sys.last_traceback.tb_lineno + 42 + >>> sys.last_value + AssertionError('assert result == "ok"',) + +.. _breakpoints: + +Setting breakpoints +------------------- + +.. versionadded: 2.4.0 + +To set a breakpoint in your code use the native Python ``import pdb;pdb.set_trace()`` call +in your code and pytest automatically disables its output capture for that test: + +* Output capture in other tests is not affected. +* Any prior test output that has already been captured and will be processed as + such. +* Any later output produced within the same test will not be captured and will + instead get sent directly to ``sys.stdout``. Note that this holds true even + for test output occurring after you exit the interactive PDB_ tracing session + and continue with the regular test run. + +.. _durations: + +Profiling test execution duration +------------------------------------- + +.. versionadded: 2.2 + +To get a list of the slowest 10 test durations:: + + pytest --durations=10 + + +Creating JUnitXML format files +---------------------------------------------------- + +To create result files which can be read by Jenkins_ or other Continuous +integration servers, use this invocation:: + + pytest --junitxml=path + +to create an XML file at ``path``. + +.. versionadded:: 3.1 + +To set the name of the root test suite xml item, you can configure the ``junit_suite_name`` option in your config file: + +.. code-block:: ini + + [pytest] + junit_suite_name = my_suite + +record_xml_property +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. versionadded:: 2.8 + +If you want to log additional information for a test, you can use the +``record_xml_property`` fixture: + +.. code-block:: python + + def test_function(record_xml_property): + record_xml_property("example_key", 1) + assert 0 + +This will add an extra property ``example_key="1"`` to the generated +``testcase`` tag: + +.. code-block:: xml + + + + + + + +.. warning:: + + ``record_xml_property`` is an experimental feature, and its interface might be replaced + by something more powerful and general in future versions. The + functionality per-se will be kept, however. + + Currently it does not work when used with the ``pytest-xdist`` plugin. + + Also please note that using this feature will break any schema verification. + This might be a problem when used with some CI servers. + +LogXML: add_global_property +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. versionadded:: 3.0 + +If you want to add a properties node in the testsuite level, which may contains properties that are relevant +to all testcases you can use ``LogXML.add_global_properties`` + +.. code-block:: python + + import pytest + + @pytest.fixture(scope="session") + def log_global_env_facts(f): + + if pytest.config.pluginmanager.hasplugin('junitxml'): + my_junit = getattr(pytest.config, '_xml', None) + + my_junit.add_global_property('ARCH', 'PPC') + my_junit.add_global_property('STORAGE_TYPE', 'CEPH') + + @pytest.mark.usefixtures(log_global_env_facts) + def start_and_prepare_env(): + pass + + class TestMe(object): + def test_foo(self): + assert True + +This will add a property node below the testsuite node to the generated xml: + +.. code-block:: xml + + + + + + + + + +.. warning:: + + This is an experimental feature, and its interface might be replaced + by something more powerful and general in future versions. The + functionality per-se will be kept. + +Creating resultlog format files +---------------------------------------------------- + +.. deprecated:: 3.0 + + This option is rarely used and is scheduled for removal in 4.0. + + An alternative for users which still need similar functionality is to use the + `pytest-tap `_ plugin which provides + a stream of test data. + + If you have any concerns, please don't hesitate to + `open an issue `_. + +To create plain-text machine-readable result files you can issue:: + + pytest --resultlog=path + +and look at the content at the ``path`` location. Such files are used e.g. +by the `PyPy-test`_ web page to show test results over several revisions. + +.. _`PyPy-test`: http://buildbot.pypy.org/summary + + +Sending test report to online pastebin service +----------------------------------------------------- + +**Creating a URL for each test failure**:: + + pytest --pastebin=failed + +This will submit test run information to a remote Paste service and +provide a URL for each failure. You may select tests as usual or add +for example ``-x`` if you only want to send one particular failure. + +**Creating a URL for a whole test session log**:: + + pytest --pastebin=all + +Currently only pasting to the http://bpaste.net service is implemented. + +Disabling plugins +----------------- + +To disable loading specific plugins at invocation time, use the ``-p`` option +together with the prefix ``no:``. + +Example: to disable loading the plugin ``doctest``, which is responsible for +executing doctest tests from text files, invoke pytest like this:: + + pytest -p no:doctest + +.. _`pytest.main-usage`: + +Calling pytest from Python code +---------------------------------------------------- + +.. versionadded:: 2.0 + +You can invoke ``pytest`` from Python code directly:: + + pytest.main() + +this acts as if you would call "pytest" from the command line. +It will not raise ``SystemExit`` but return the exitcode instead. +You can pass in options and arguments:: + + pytest.main(['-x', 'mytestdir']) + +You can specify additional plugins to ``pytest.main``:: + + # content of myinvoke.py + import pytest + class MyPlugin(object): + def pytest_sessionfinish(self): + print("*** test run reporting finishing") + + pytest.main(["-qq"], plugins=[MyPlugin()]) + +Running it will show that ``MyPlugin`` was added and its +hook was invoked:: + + $ python myinvoke.py + *** test run reporting finishing + + +.. include:: links.inc diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/warnings.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/warnings.rst new file mode 100644 index 00000000000..f249d7e3b2f --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/warnings.rst @@ -0,0 +1,299 @@ +.. _`warnings`: + +Warnings Capture +================ + +.. versionadded:: 3.1 + +Starting from version ``3.1``, pytest now automatically catches warnings during test execution +and displays them at the end of the session:: + + # content of test_show_warnings.py + import warnings + + def api_v1(): + warnings.warn(UserWarning("api v1, should use functions from v2")) + return 1 + + def test_one(): + assert api_v1() == 1 + +Running pytest now produces this output:: + + $ pytest test_show_warnings.py + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: + collected 1 item + + test_show_warnings.py . [100%] + + ============================= warnings summary ============================= + test_show_warnings.py::test_one + $REGENDOC_TMPDIR/test_show_warnings.py:4: UserWarning: api v1, should use functions from v2 + warnings.warn(UserWarning("api v1, should use functions from v2")) + + -- Docs: http://doc.pytest.org/en/latest/warnings.html + =================== 1 passed, 1 warnings in 0.12 seconds =================== + +Pytest by default catches all warnings except for ``DeprecationWarning`` and ``PendingDeprecationWarning``. + +The ``-W`` flag can be passed to control which warnings will be displayed or even turn +them into errors:: + + $ pytest -q test_show_warnings.py -W error::UserWarning + F [100%] + ================================= FAILURES ================================= + _________________________________ test_one _________________________________ + + def test_one(): + > assert api_v1() == 1 + + test_show_warnings.py:8: + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + + def api_v1(): + > warnings.warn(UserWarning("api v1, should use functions from v2")) + E UserWarning: api v1, should use functions from v2 + + test_show_warnings.py:4: UserWarning + 1 failed in 0.12 seconds + +The same option can be set in the ``pytest.ini`` file using the ``filterwarnings`` ini option. +For example, the configuration below will ignore all user warnings, but will transform +all other warnings into errors. + +.. code-block:: ini + + [pytest] + filterwarnings = + error + ignore::UserWarning + + +When a warning matches more than one option in the list, the action for the last matching option +is performed. + +Both ``-W`` command-line option and ``filterwarnings`` ini option are based on Python's own +`-W option`_ and `warnings.simplefilter`_, so please refer to those sections in the Python +documentation for other examples and advanced usage. + +``@pytest.mark.filterwarnings`` +------------------------------- + +.. versionadded:: 3.2 + +You can use the ``@pytest.mark.filterwarnings`` to add warning filters to specific test items, +allowing you to have finer control of which warnings should be captured at test, class or +even module level: + +.. code-block:: python + + import warnings + + def api_v1(): + warnings.warn(UserWarning("api v1, should use functions from v2")) + return 1 + + @pytest.mark.filterwarnings('ignore:api v1') + def test_one(): + assert api_v1() == 1 + + +Filters applied using a mark take precedence over filters passed on the command line or configured +by the ``filterwarnings`` ini option. + +You may apply a filter to all tests of a class by using the ``filterwarnings`` mark as a class +decorator or to all tests in a module by setting the ``pytestmark`` variable: + +.. code-block:: python + + # turns all warnings into errors for this module + pytestmark = pytest.mark.filterwarnings('error') + + +.. note:: + + ``DeprecationWarning`` and ``PendingDeprecationWarning`` are hidden by the standard library + by default so you have to explicitly configure them to be displayed in your ``pytest.ini``: + + .. code-block:: ini + + [pytest] + filterwarnings = + once::DeprecationWarning + once::PendingDeprecationWarning + + +*Credits go to Florian Schulze for the reference implementation in the* `pytest-warnings`_ +*plugin.* + +.. _`-W option`: https://docs.python.org/3/using/cmdline.html?highlight=#cmdoption-W +.. _warnings.simplefilter: https://docs.python.org/3/library/warnings.html#warnings.simplefilter +.. _`pytest-warnings`: https://github.com/fschulze/pytest-warnings + + +Disabling warning capture +------------------------- + +This feature is enabled by default but can be disabled entirely in your ``pytest.ini`` file with: + + .. code-block:: ini + + [pytest] + addopts = -p no:warnings + +Or passing ``-p no:warnings`` in the command-line. + +.. _`asserting warnings`: + +.. _assertwarnings: + +.. _`asserting warnings with the warns function`: + +.. _warns: + +Asserting warnings with the warns function +----------------------------------------------- + +.. versionadded:: 2.8 + +You can check that code raises a particular warning using ``pytest.warns``, +which works in a similar manner to :ref:`raises `:: + + import warnings + import pytest + + def test_warning(): + with pytest.warns(UserWarning): + warnings.warn("my warning", UserWarning) + +The test will fail if the warning in question is not raised. The keyword +argument ``match`` to assert that the exception matches a text or regex:: + + >>> with warns(UserWarning, match='must be 0 or None'): + ... warnings.warn("value must be 0 or None", UserWarning) + + >>> with warns(UserWarning, match=r'must be \d+$'): + ... warnings.warn("value must be 42", UserWarning) + + >>> with warns(UserWarning, match=r'must be \d+$'): + ... warnings.warn("this is not here", UserWarning) + Traceback (most recent call last): + ... + Failed: DID NOT WARN. No warnings of type ...UserWarning... was emitted... + +You can also call ``pytest.warns`` on a function or code string:: + + pytest.warns(expected_warning, func, *args, **kwargs) + pytest.warns(expected_warning, "func(*args, **kwargs)") + +The function also returns a list of all raised warnings (as +``warnings.WarningMessage`` objects), which you can query for +additional information:: + + with pytest.warns(RuntimeWarning) as record: + warnings.warn("another warning", RuntimeWarning) + + # check that only one warning was raised + assert len(record) == 1 + # check that the message matches + assert record[0].message.args[0] == "another warning" + +Alternatively, you can examine raised warnings in detail using the +:ref:`recwarn ` fixture (see below). + +.. note:: + ``DeprecationWarning`` and ``PendingDeprecationWarning`` are treated + differently; see :ref:`ensuring_function_triggers`. + +.. _`recording warnings`: + +.. _recwarn: + +Recording warnings +------------------------ + +You can record raised warnings either using ``pytest.warns`` or with +the ``recwarn`` fixture. + +To record with ``pytest.warns`` without asserting anything about the warnings, +pass ``None`` as the expected warning type:: + + with pytest.warns(None) as record: + warnings.warn("user", UserWarning) + warnings.warn("runtime", RuntimeWarning) + + assert len(record) == 2 + assert str(record[0].message) == "user" + assert str(record[1].message) == "runtime" + +The ``recwarn`` fixture will record warnings for the whole function:: + + import warnings + + def test_hello(recwarn): + warnings.warn("hello", UserWarning) + assert len(recwarn) == 1 + w = recwarn.pop(UserWarning) + assert issubclass(w.category, UserWarning) + assert str(w.message) == "hello" + assert w.filename + assert w.lineno + +Both ``recwarn`` and ``pytest.warns`` return the same interface for recorded +warnings: a WarningsRecorder instance. To view the recorded warnings, you can +iterate over this instance, call ``len`` on it to get the number of recorded +warnings, or index into it to get a particular recorded warning. It also +provides these methods: + +.. autoclass:: _pytest.recwarn.WarningsRecorder() + :members: + +Each recorded warning has the attributes ``message``, ``category``, +``filename``, ``lineno``, ``file``, and ``line``. The ``category`` is the +class of the warning. The ``message`` is the warning itself; calling +``str(message)`` will return the actual message of the warning. + +.. note:: + :class:`RecordedWarning` was changed from a plain class to a namedtuple in pytest 3.1 + +.. note:: + ``DeprecationWarning`` and ``PendingDeprecationWarning`` are treated + differently; see :ref:`ensuring_function_triggers`. + +.. _`ensuring a function triggers a deprecation warning`: + +.. _ensuring_function_triggers: + +Ensuring a function triggers a deprecation warning +------------------------------------------------------- + +You can also call a global helper for checking +that a certain function call triggers a ``DeprecationWarning`` or +``PendingDeprecationWarning``:: + + import pytest + + def test_global(): + pytest.deprecated_call(myfunction, 17) + +By default, ``DeprecationWarning`` and ``PendingDeprecationWarning`` will not be +caught when using ``pytest.warns`` or ``recwarn`` because default Python warnings filters hide +them. If you wish to record them in your own code, use the +command ``warnings.simplefilter('always')``:: + + import warnings + import pytest + + def test_deprecation(recwarn): + warnings.simplefilter('always') + warnings.warn("deprecated", DeprecationWarning) + assert len(recwarn) == 1 + assert recwarn.pop(DeprecationWarning) + +You can also use it as a contextmanager:: + + def test_global(): + with pytest.deprecated_call(): + myobject.deprecated_method() diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/writing_plugins.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/writing_plugins.rst similarity index 68% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/writing_plugins.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/writing_plugins.rst index cc346aaa85c..eb525583000 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/writing_plugins.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/writing_plugins.rst @@ -23,7 +23,7 @@ reporting by calling `well specified hooks`_ of the following plugins: In principle, each hook call is a ``1:N`` Python function call where ``N`` is the number of registered implementation functions for a given specification. -All specifications and implementations following the ``pytest_`` prefix +All specifications and implementations follow the ``pytest_`` prefix naming convention, making them easy to distinguish and find. .. _`pluginorder`: @@ -49,7 +49,7 @@ Plugin discovery order at tool startup Note that pytest does not find ``conftest.py`` files in deeper nested sub directories at tool startup. It is usually a good idea to keep - your conftest.py file in the top level test or project root directory. + your ``conftest.py`` file in the top level test or project root directory. * by recursively loading all plugins specified by the ``pytest_plugins`` variable in ``conftest.py`` files @@ -57,9 +57,7 @@ Plugin discovery order at tool startup .. _`pytest/plugin`: http://bitbucket.org/pytest-dev/pytest/src/tip/pytest/plugin/ .. _`conftest.py plugins`: -.. _`conftest.py`: .. _`localplugin`: -.. _`conftest`: .. _`local conftest plugins`: conftest.py: local per-directory plugins @@ -87,17 +85,19 @@ sub directory but not for other directories:: Here is how you might run it:: - py.test test_flat.py # will not show "setting up" - py.test a/test_sub.py # will show "setting up" + pytest test_flat.py # will not show "setting up" + pytest a/test_sub.py # will show "setting up" -.. Note:: +.. note:: If you have ``conftest.py`` files which do not reside in a python package directory (i.e. one containing an ``__init__.py``) then "import conftest" can be ambiguous because there might be other - ``conftest.py`` files as well on your PYTHONPATH or ``sys.path``. + ``conftest.py`` files as well on your ``PYTHONPATH`` or ``sys.path``. It is thus good practice for projects to either put ``conftest.py`` under a package scope or to never import anything from a - conftest.py file. + ``conftest.py`` file. + + See also: :ref:`pythonpath`. Writing your own plugin @@ -122,8 +122,8 @@ to extend and add functionality. for authoring plugins. The template provides an excellent starting point with a working plugin, - tests running with tox, comprehensive README and - entry-pointy already pre-configured. + tests running with tox, a comprehensive README file as well as a + pre-configured entry-point. Also consider :ref:`contributing your plugin to pytest-dev` once it has some happy users other than yourself. @@ -158,28 +158,115 @@ it in your setuptools-invocation: 'name_of_plugin = myproject.pluginmodule', ] }, + + # custom PyPI classifier for pytest plugins + classifiers=[ + "Framework :: Pytest", + ], ) If a package is installed this way, ``pytest`` will load ``myproject.pluginmodule`` as a plugin which can define `well specified hooks`_. +.. note:: + + Make sure to include ``Framework :: Pytest`` in your list of + `PyPI classifiers `_ + to make it easy for users to find your plugin. + + +Assertion Rewriting +------------------- + +One of the main features of ``pytest`` is the use of plain assert +statements and the detailed introspection of expressions upon +assertion failures. This is provided by "assertion rewriting" which +modifies the parsed AST before it gets compiled to bytecode. This is +done via a :pep:`302` import hook which gets installed early on when +``pytest`` starts up and will perform this rewriting when modules get +imported. However since we do not want to test different bytecode +then you will run in production this hook only rewrites test modules +themselves as well as any modules which are part of plugins. Any +other imported module will not be rewritten and normal assertion +behaviour will happen. + +If you have assertion helpers in other modules where you would need +assertion rewriting to be enabled you need to ask ``pytest`` +explicitly to rewrite this module before it gets imported. + +.. autofunction:: pytest.register_assert_rewrite + +This is especially important when you write a pytest plugin which is +created using a package. The import hook only treats ``conftest.py`` +files and any modules which are listed in the ``pytest11`` entrypoint +as plugins. As an example consider the following package:: + + pytest_foo/__init__.py + pytest_foo/plugin.py + pytest_foo/helper.py + +With the following typical ``setup.py`` extract: + +.. code-block:: python + + setup( + ... + entry_points={'pytest11': ['foo = pytest_foo.plugin']}, + ... + ) + +In this case only ``pytest_foo/plugin.py`` will be rewritten. If the +helper module also contains assert statements which need to be +rewritten it needs to be marked as such, before it gets imported. +This is easiest by marking it for rewriting inside the +``__init__.py`` module, which will always be imported first when a +module inside a package is imported. This way ``plugin.py`` can still +import ``helper.py`` normally. The contents of +``pytest_foo/__init__.py`` will then need to look like this: + +.. code-block:: python + + import pytest + + pytest.register_assert_rewrite('pytest_foo.helper') Requiring/Loading plugins in a test module or conftest file ----------------------------------------------------------- -You can require plugins in a test module or a conftest file like this:: +You can require plugins in a test module or a ``conftest.py`` file like this: - pytest_plugins = "name1", "name2", +.. code-block:: python + + pytest_plugins = ["name1", "name2"] When the test module or conftest plugin is loaded the specified plugins -will be loaded as well. You can also use dotted path like this:: +will be loaded as well. Any module can be blessed as a plugin, including internal +application modules: + +.. code-block:: python pytest_plugins = "myapp.testsupport.myplugin" -which will import the specified module as a ``pytest`` plugin. +``pytest_plugins`` variables are processed recursively, so note that in the example above +if ``myapp.testsupport.myplugin`` also declares ``pytest_plugins``, the contents +of the variable will also be loaded as plugins, and so on. + +This mechanism makes it easy to share fixtures within applications or even +external applications without the need to create external plugins using +the ``setuptools``'s entry point technique. + +Plugins imported by ``pytest_plugins`` will also automatically be marked +for assertion rewriting (see :func:`pytest.register_assert_rewrite`). +However for this to have any effect the module must not be +imported already; if it was already imported at the time the +``pytest_plugins`` statement is processed, a warning will result and +assertions inside the plugin will not be rewritten. To fix this you +can either call :func:`pytest.register_assert_rewrite` yourself before +the module is imported, or you can arrange the code to delay the +importing until after the plugin is registered. Accessing another plugin by name @@ -194,39 +281,106 @@ the plugin manager like this: plugin = config.pluginmanager.getplugin("name_of_plugin") If you want to look at the names of existing plugins, use -the ``--traceconfig`` option. +the ``--trace-config`` option. Testing plugins --------------- -pytest comes with some facilities that you can enable for testing your -plugin. Given that you have an installed plugin you can enable the -:py:class:`testdir <_pytest.pytester.Testdir>` fixture via specifying a -command line option to include the pytester plugin (``-p pytester``) or -by putting ``pytest_plugins = "pytester"`` into your test or -``conftest.py`` file. You then will have a ``testdir`` fixture which you -can use like this:: +pytest comes with a plugin named ``pytester`` that helps you write tests for +your plugin code. The plugin is disabled by default, so you will have to enable +it before you can use it. - # content of test_myplugin.py +You can do so by adding the following line to a ``conftest.py`` file in your +testing directory: - pytest_plugins = "pytester" # to get testdir fixture +.. code-block:: python - def test_myplugin(testdir): + # content of conftest.py + + pytest_plugins = ["pytester"] + +Alternatively you can invoke pytest with the ``-p pytester`` command line +option. + +This will allow you to use the :py:class:`testdir <_pytest.pytester.Testdir>` +fixture for testing your plugin code. + +Let's demonstrate what you can do with the plugin with an example. Imagine we +developed a plugin that provides a fixture ``hello`` which yields a function +and we can invoke this function with one optional parameter. It will return a +string value of ``Hello World!`` if we do not supply a value or ``Hello +{value}!`` if we do supply a string value. + +.. code-block:: python + + # -*- coding: utf-8 -*- + + import pytest + + def pytest_addoption(parser): + group = parser.getgroup('helloworld') + group.addoption( + '--name', + action='store', + dest='name', + default='World', + help='Default "name" for hello().' + ) + + @pytest.fixture + def hello(request): + name = request.config.getoption('name') + + def _hello(name=None): + if not name: + name = request.config.getoption('name') + return "Hello {name}!".format(name=name) + + return _hello + + +Now the ``testdir`` fixture provides a convenient API for creating temporary +``conftest.py`` files and test files. It also allows us to run the tests and +return a result object, with which we can assert the tests' outcomes. + +.. code-block:: python + + def test_hello(testdir): + """Make sure that our plugin works.""" + + # create a temporary conftest.py file + testdir.makeconftest(""" + import pytest + + @pytest.fixture(params=[ + "Brianna", + "Andreas", + "Floris", + ]) + def name(request): + return request.param + """) + + # create a temporary pytest test file testdir.makepyfile(""" - def test_example(): - pass - """) - result = testdir.runpytest("--verbose") - result.fnmatch_lines(""" - test_example* + def test_hello_default(hello): + assert hello() == "Hello World!" + + def test_hello_name(hello, name): + assert hello(name) == "Hello {0}!".format(name) """) -Note that by default ``testdir.runpytest()`` will perform a pytest -in-process. You can pass the command line option ``--runpytest=subprocess`` -to have it happen in a subprocess. + # run all tests with pytest + result = testdir.runpytest() + + # check that all 4 tests passed + result.assert_outcomes(passed=4) + + +For more information about the result object that ``runpytest()`` returns, and +the methods that it provides please check out the :py:class:`RunResult +<_pytest.pytester.RunResult>` documentation. -Also see the :py:class:`RunResult <_pytest.pytester.RunResult>` for more -methods of the result object that you get from a call to ``runpytest``. .. _`writinghooks`: @@ -270,6 +424,8 @@ allowed to raise exceptions. Doing so will break the pytest run. +.. _firstresult: + firstresult: stop at first non-None result ------------------------------------------- @@ -287,7 +443,7 @@ hookwrapper: executing around other hooks .. currentmodule:: _pytest.core -.. versionadded:: 2.7 (experimental) +.. versionadded:: 2.7 pytest plugins can implement hook wrappers which wrap the execution of other hook implementations. A hook wrapper is a generator function @@ -296,7 +452,7 @@ hook wrappers and passes the same arguments as to the regular hooks. At the yield point of the hook wrapper pytest will execute the next hook implementations and return their result to the yield point in the form of -a :py:class:`CallOutcome` instance which encapsulates a result or +a :py:class:`Result ` instance which encapsulates a result or exception info. The yield point itself will thus typically not raise exceptions (unless there are bugs). @@ -361,7 +517,7 @@ Here is the order of execution: Plugin1). 4. Plugin3's pytest_collection_modifyitems then executing the code after the yield - point. The yield receives a :py:class:`CallOutcome` instance which encapsulates + point. The yield receives a :py:class:`Result ` instance which encapsulates the result from calling the non-wrappers. Wrappers shall not modify the result. It's possible to use ``tryfirst`` and ``trylast`` also in conjunction with @@ -384,7 +540,7 @@ Hooks are usually declared as do-nothing functions that contain only documentation describing when the hook will be called and what return values are expected. -For an example, see `newhooks.py`_ from :ref:`xdist`. +For an example, see `newhooks.py`_ from `xdist `_. .. _`newhooks.py`: https://github.com/pytest-dev/pytest-xdist/blob/974bd566c599dc6a9ea291838c6f226197208b46/xdist/newhooks.py @@ -430,7 +586,6 @@ Initialization, command line and configuration hooks .. autofunction:: pytest_load_initial_conftests .. autofunction:: pytest_cmdline_preparse .. autofunction:: pytest_cmdline_parse -.. autofunction:: pytest_namespace .. autofunction:: pytest_addoption .. autofunction:: pytest_cmdline_main .. autofunction:: pytest_configure @@ -439,7 +594,7 @@ Initialization, command line and configuration hooks Generic "runtest" hooks ----------------------- -All runtest related hooks receive a :py:class:`pytest.Item` object. +All runtest related hooks receive a :py:class:`pytest.Item <_pytest.main.Item>` object. .. autofunction:: pytest_runtest_protocol .. autofunction:: pytest_runtest_setup @@ -470,6 +625,7 @@ you can use the following hook: .. autofunction:: pytest_pycollect_makeitem .. autofunction:: pytest_generate_tests +.. autofunction:: pytest_make_parametrize_id After collection is complete, you can modify the order of items, delete or otherwise amend the test items: @@ -486,8 +642,11 @@ Session related reporting hooks: .. autofunction:: pytest_collectreport .. autofunction:: pytest_deselected .. autofunction:: pytest_report_header +.. autofunction:: pytest_report_collectionfinish .. autofunction:: pytest_report_teststatus .. autofunction:: pytest_terminal_summary +.. autofunction:: pytest_fixture_setup +.. autofunction:: pytest_fixture_post_finalizer And here is the central hook for reporting about test execution: @@ -544,13 +703,18 @@ Reference of objects involved in hooks :members: :show-inheritance: +.. autoclass:: _pytest.fixtures.FixtureDef() + :members: + :show-inheritance: + .. autoclass:: _pytest.runner.CallInfo() :members: .. autoclass:: _pytest.runner.TestReport() :members: + :inherited-members: -.. autoclass:: _pytest.vendored_packages.pluggy._CallOutcome() +.. autoclass:: pluggy._Result :members: .. autofunction:: _pytest.config.get_plugin_manager() diff --git a/tests/wpt/web-platform-tests/tools/pytest/doc/en/xunit_setup.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/xunit_setup.rst similarity index 70% rename from tests/wpt/web-platform-tests/tools/pytest/doc/en/xunit_setup.rst rename to tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/xunit_setup.rst index 7a80f129966..148fb1209ea 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/doc/en/xunit_setup.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/xunit_setup.rst @@ -7,21 +7,20 @@ classic xunit-style setup This section describes a classic and popular way how you can implement fixtures (setup and teardown test state) on a per-module/class/function basis. -pytest started supporting these methods around 2005 and subsequently -nose and the standard library introduced them (under slightly different -names). While these setup/teardown methods are and will remain fully -supported you may also use pytest's more powerful :ref:`fixture mechanism -` which leverages the concept of dependency injection, allowing -for a more modular and more scalable approach for managing test state, -especially for larger projects and for functional testing. You can -mix both fixture mechanisms in the same file but unittest-based -test methods cannot receive fixture arguments. + .. note:: - As of pytest-2.4, teardownX functions are not called if - setupX existed and failed/was skipped. This harmonizes - behaviour across all major python testing tools. + While these setup/teardown methods are simple and familiar to those + coming from a ``unittest`` or nose ``background``, you may also consider + using pytest's more powerful :ref:`fixture mechanism + ` which leverages the concept of dependency injection, allowing + for a more modular and more scalable approach for managing test state, + especially for larger projects and for functional testing. You can + mix both fixture mechanisms in the same file but + test methods of ``unittest.TestCase`` subclasses + cannot receive fixture arguments. + Module level setup/teardown -------------------------------------- @@ -38,6 +37,8 @@ which will usually be called once for all the functions:: method. """ +As of pytest-3.0, the ``module`` parameter is optional. + Class level setup/teardown ---------------------------------- @@ -71,6 +72,8 @@ Similarly, the following methods are called around each method invocation:: call. """ +As of pytest-3.0, the ``method`` parameter is optional. + If you would rather define test functions directly at module level you can also use the following functions to implement fixtures:: @@ -84,7 +87,13 @@ you can also use the following functions to implement fixtures:: call. """ -Note that it is possible for setup/teardown pairs to be invoked multiple times -per testing process. +As of pytest-3.0, the ``function`` parameter is optional. + +Remarks: + +* It is possible for setup/teardown pairs to be invoked multiple times + per testing process. +* teardown functions are not called if the corresponding setup function existed + and failed/was skipped. .. _`unittest.py module`: http://docs.python.org/library/unittest.html diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/yieldfixture.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/yieldfixture.rst new file mode 100644 index 00000000000..6fd1edac2f5 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/doc/en/yieldfixture.rst @@ -0,0 +1,18 @@ +:orphan: + +.. _yieldfixture: + +"yield_fixture" functions +--------------------------------------------------------------- + +.. deprecated:: 3.0 + +.. versionadded:: 2.4 + +.. important:: + Since pytest-3.0, fixtures using the normal ``fixture`` decorator can use a ``yield`` + statement to provide fixture values and execute teardown code, exactly like ``yield_fixture`` + in previous versions. + + Marking functions as ``yield_fixture`` is still supported, but deprecated and should not + be used in new code. diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/extra/get_issues.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/extra/get_issues.py new file mode 100644 index 00000000000..2a8f8c31606 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/extra/get_issues.py @@ -0,0 +1,84 @@ +import json +import py +import textwrap + +issues_url = "https://api.github.com/repos/pytest-dev/pytest/issues" + +import requests + + +def get_issues(): + issues = [] + url = issues_url + while 1: + get_data = {"state": "all"} + r = requests.get(url, params=get_data) + data = r.json() + if r.status_code == 403: + # API request limit exceeded + print(data['message']) + exit(1) + issues.extend(data) + + # Look for next page + links = requests.utils.parse_header_links(r.headers['Link']) + another_page = False + for link in links: + if link['rel'] == 'next': + url = link['url'] + another_page = True + if not another_page: + return issues + + +def main(args): + cachefile = py.path.local(args.cache) + if not cachefile.exists() or args.refresh: + issues = get_issues() + cachefile.write(json.dumps(issues)) + else: + issues = json.loads(cachefile.read()) + + open_issues = [x for x in issues if x["state"] == "open"] + + open_issues.sort(key=lambda x: x["number"]) + report(open_issues) + + +def _get_kind(issue): + labels = [l['name'] for l in issue['labels']] + for key in ('bug', 'enhancement', 'proposal'): + if key in labels: + return key + return 'issue' + + +def report(issues): + for issue in issues: + title = issue["title"] + body = issue["body"] + kind = _get_kind(issue) + status = issue["state"] + number = issue["number"] + link = "https://github.com/pytest-dev/pytest/issues/%s/" % number + print("----") + print(status, kind, link) + print(title) + #print() + #lines = body.split("\n") + #print ("\n".join(lines[:3])) + #if len(lines) > 3 or len(body) > 240: + # print ("...") + print("\n\nFound %s open issues" % len(issues)) + + +if __name__ == "__main__": + import argparse + parser = argparse.ArgumentParser("process bitbucket issues") + parser.add_argument("--refresh", action="store_true", + help="invalidate cache, refresh issues") + parser.add_argument("--cache", action="store", default="issues.json", + help="cache file") + args = parser.parse_args() + main(args) + diff --git a/tests/wpt/web-platform-tests/tools/pytest/extra/setup-py.test/setup.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/extra/setup-py.test/setup.py similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/extra/setup-py.test/setup.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/extra/setup-py.test/setup.py diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/pyproject.toml b/tests/wpt/web-platform-tests/tools/third_party/pytest/pyproject.toml new file mode 100644 index 00000000000..88571e208b9 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/pyproject.toml @@ -0,0 +1,35 @@ +[tool.towncrier] +package = "pytest" +filename = "CHANGELOG.rst" +directory = "changelog/" +template = "changelog/_template.rst" + + [[tool.towncrier.type]] + directory = "removal" + name = "Deprecations and Removals" + showcontent = true + + [[tool.towncrier.type]] + directory = "feature" + name = "Features" + showcontent = true + + [[tool.towncrier.type]] + directory = "bugfix" + name = "Bug Fixes" + showcontent = true + + [[tool.towncrier.type]] + directory = "vendor" + name = "Vendored Libraries" + showcontent = true + + [[tool.towncrier.type]] + directory = "doc" + name = "Improved Documentation" + showcontent = true + + [[tool.towncrier.type]] + directory = "trivial" + name = "Trivial/Internal Changes" + showcontent = true diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/pytest.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/pytest.py new file mode 100644 index 00000000000..2b681b64b4c --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/pytest.py @@ -0,0 +1,77 @@ +# PYTHON_ARGCOMPLETE_OK +""" +pytest: unit and functional testing with Python. +""" + + +# else we are imported + +from _pytest.config import ( + main, UsageError, cmdline, + hookspec, hookimpl +) +from _pytest.fixtures import fixture, yield_fixture +from _pytest.assertion import register_assert_rewrite +from _pytest.freeze_support import freeze_includes +from _pytest import __version__ +from _pytest.debugging import pytestPDB as __pytestPDB +from _pytest.recwarn import warns, deprecated_call +from _pytest.outcomes import fail, skip, importorskip, exit, xfail +from _pytest.mark import MARK_GEN as mark, param +from _pytest.main import Item, Collector, File, Session +from _pytest.fixtures import fillfixtures as _fillfuncargs +from _pytest.python import ( + Module, Class, Instance, Function, Generator, +) + +from _pytest.python_api import approx, raises + +set_trace = __pytestPDB.set_trace + +__all__ = [ + 'main', + 'UsageError', + 'cmdline', + 'hookspec', + 'hookimpl', + '__version__', + 'register_assert_rewrite', + 'freeze_includes', + 'set_trace', + 'warns', + 'deprecated_call', + 'fixture', + 'yield_fixture', + 'fail', + 'skip', + 'xfail', + 'importorskip', + 'exit', + 'mark', + 'param', + 'approx', + '_fillfuncargs', + + 'Item', + 'File', + 'Collector', + 'Session', + 'Module', + 'Class', + 'Instance', + 'Function', + 'Generator', + 'raises', + + +] + +if __name__ == '__main__': + # if run as a script or by 'python -m pytest' + # we trigger the below "else" condition by the following import + import pytest + raise SystemExit(pytest.main()) +else: + + from _pytest.compat import _setup_collect_fakemodule + _setup_collect_fakemodule() diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/scripts/call-tox.bat b/tests/wpt/web-platform-tests/tools/third_party/pytest/scripts/call-tox.bat new file mode 100644 index 00000000000..86fb25c1df1 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/scripts/call-tox.bat @@ -0,0 +1,8 @@ +REM skip "coveralls" run in PRs or forks +if "%TOXENV%" == "coveralls" ( + if not defined COVERALLS_REPO_TOKEN ( + echo skipping coveralls run because COVERALLS_REPO_TOKEN is not defined + exit /b 0 + ) +) +C:\Python36\python -m tox diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/scripts/check-rst.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/scripts/check-rst.py new file mode 100644 index 00000000000..57f717501af --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/scripts/check-rst.py @@ -0,0 +1,11 @@ + +from __future__ import print_function + +import subprocess +import glob +import sys + +sys.exit(subprocess.call([ + 'rst-lint', '--encoding', 'utf-8', + 'CHANGELOG.rst', 'HOWTORELEASE.rst', 'README.rst', +] + glob.glob('changelog/[0-9]*.*'))) diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/scripts/install-pypy.bat b/tests/wpt/web-platform-tests/tools/third_party/pytest/scripts/install-pypy.bat new file mode 100644 index 00000000000..8012ea46aca --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/scripts/install-pypy.bat @@ -0,0 +1,6 @@ +REM install pypy using choco +REM redirect to a file because choco install python.pypy is too noisy. If the command fails, write output to console +choco install python.pypy > pypy-inst.log 2>&1 || (type pypy-inst.log & exit /b 1) +set PATH=C:\tools\pypy\pypy;%PATH% # so tox can find pypy +echo PyPy installed +pypy --version diff --git a/tests/wpt/web-platform-tests/tools/pytest/setup.cfg b/tests/wpt/web-platform-tests/tools/third_party/pytest/setup.cfg similarity index 70% rename from tests/wpt/web-platform-tests/tools/pytest/setup.cfg rename to tests/wpt/web-platform-tests/tools/third_party/pytest/setup.cfg index 1ab4fd059b2..816539e2ec6 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/setup.cfg +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/setup.cfg @@ -9,5 +9,12 @@ upload-dir = doc/en/build/html [bdist_wheel] universal = 1 +[check-manifest] +ignore = + _pytest/_version.py + +[metadata] +license_file = LICENSE + [devpi:upload] formats = sdist.tgz,bdist_wheel diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/setup.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/setup.py new file mode 100644 index 00000000000..3eb38efe655 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/setup.py @@ -0,0 +1,114 @@ +import os +import sys +import setuptools +import pkg_resources +from setuptools import setup, Command + +classifiers = [ + 'Development Status :: 6 - Mature', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Operating System :: POSIX', + 'Operating System :: Microsoft :: Windows', + 'Operating System :: MacOS :: MacOS X', + 'Topic :: Software Development :: Testing', + 'Topic :: Software Development :: Libraries', + 'Topic :: Utilities', +] + [ + ('Programming Language :: Python :: %s' % x) + for x in '2 2.7 3 3.4 3.5 3.6'.split() +] + +with open('README.rst') as fd: + long_description = fd.read() + + +def has_environment_marker_support(): + """ + Tests that setuptools has support for PEP-426 environment marker support. + + The first known release to support it is 0.7 (and the earliest on PyPI seems to be 0.7.2 + so we're using that), see: http://pythonhosted.org/setuptools/history.html#id142 + + References: + + * https://wheel.readthedocs.io/en/latest/index.html#defining-conditional-dependencies + * https://www.python.org/dev/peps/pep-0426/#environment-markers + """ + try: + return pkg_resources.parse_version(setuptools.__version__) >= pkg_resources.parse_version('0.7.2') + except Exception as exc: + sys.stderr.write("Could not test setuptool's version: %s\n" % exc) + return False + + +def main(): + extras_require = {} + install_requires = [ + 'py>=1.5.0', + 'six>=1.10.0', + 'setuptools', + 'attrs>=17.2.0', + ] + # if _PYTEST_SETUP_SKIP_PLUGGY_DEP is set, skip installing pluggy; + # used by tox.ini to test with pluggy master + if '_PYTEST_SETUP_SKIP_PLUGGY_DEP' not in os.environ: + install_requires.append('pluggy>=0.5,<0.7') + if has_environment_marker_support(): + extras_require[':python_version<"3.0"'] = ['funcsigs'] + extras_require[':sys_platform=="win32"'] = ['colorama'] + else: + if sys.platform == 'win32': + install_requires.append('colorama') + if sys.version_info < (3, 0): + install_requires.append('funcsigs') + + setup( + name='pytest', + description='pytest: simple powerful testing with Python', + long_description=long_description, + use_scm_version={ + 'write_to': '_pytest/_version.py', + }, + url='http://pytest.org', + license='MIT license', + platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], + author=( + 'Holger Krekel, Bruno Oliveira, Ronny Pfannschmidt, ' + 'Floris Bruynooghe, Brianna Laugher, Florian Bruhin and others'), + entry_points={'console_scripts': [ + 'pytest=pytest:main', 'py.test=pytest:main']}, + classifiers=classifiers, + keywords="test unittest", + cmdclass={'test': PyTest}, + # the following should be enabled for release + setup_requires=['setuptools-scm'], + python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', + install_requires=install_requires, + extras_require=extras_require, + packages=['_pytest', '_pytest.assertion', '_pytest._code'], + py_modules=['pytest'], + zip_safe=False, + ) + + +class PyTest(Command): + user_options = [] + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + import subprocess + PPATH = [x for x in os.environ.get('PYTHONPATH', '').split(':') if x] + PPATH.insert(0, os.getcwd()) + os.environ['PYTHONPATH'] = ':'.join(PPATH) + errno = subprocess.call([sys.executable, 'pytest.py', '--ignore=doc']) + raise SystemExit(errno) + + +if __name__ == '__main__': + main() diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/tasks/__init__.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/tasks/__init__.py new file mode 100644 index 00000000000..8ea038f0af0 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/tasks/__init__.py @@ -0,0 +1,12 @@ +""" +Invoke tasks to help with pytest development and release process. +""" + +import invoke + +from . import generate + + +ns = invoke.Collection( + generate, +) diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/tasks/generate.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/tasks/generate.py new file mode 100644 index 00000000000..fa8ee6557df --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/tasks/generate.py @@ -0,0 +1,162 @@ +import os +from pathlib import Path +from subprocess import check_output, check_call + +import invoke + + +@invoke.task(help={ + 'version': 'version being released', +}) +def announce(ctx, version): + """Generates a new release announcement entry in the docs.""" + # Get our list of authors + stdout = check_output(["git", "describe", "--abbrev=0", '--tags']) + stdout = stdout.decode('utf-8') + last_version = stdout.strip() + + stdout = check_output(["git", "log", "{}..HEAD".format(last_version), "--format=%aN"]) + stdout = stdout.decode('utf-8') + + contributors = set(stdout.splitlines()) + + template_name = 'release.minor.rst' if version.endswith('.0') else 'release.patch.rst' + template_text = Path(__file__).parent.joinpath(template_name).read_text(encoding='UTF-8') + + contributors_text = '\n'.join('* {}'.format(name) for name in sorted(contributors)) + '\n' + text = template_text.format(version=version, contributors=contributors_text) + + target = Path(__file__).parent.joinpath('../doc/en/announce/release-{}.rst'.format(version)) + target.write_text(text, encoding='UTF-8') + print("[generate.announce] Generated {}".format(target.name)) + + # Update index with the new release entry + index_path = Path(__file__).parent.joinpath('../doc/en/announce/index.rst') + lines = index_path.read_text(encoding='UTF-8').splitlines() + indent = ' ' + for index, line in enumerate(lines): + if line.startswith('{}release-'.format(indent)): + new_line = indent + target.stem + if line != new_line: + lines.insert(index, new_line) + index_path.write_text('\n'.join(lines) + '\n', encoding='UTF-8') + print("[generate.announce] Updated {}".format(index_path.name)) + else: + print("[generate.announce] Skip {} (already contains release)".format(index_path.name)) + break + + check_call(['git', 'add', str(target)]) + + +@invoke.task() +def regen(ctx): + """Call regendoc tool to update examples and pytest output in the docs.""" + print("[generate.regen] Updating docs") + check_call(['tox', '-e', 'regen']) + + +@invoke.task() +def make_tag(ctx, version): + """Create a new (local) tag for the release, only if the repository is clean.""" + from git import Repo + + repo = Repo('.') + if repo.is_dirty(): + print('Current repository is dirty. Please commit any changes and try again.') + raise invoke.Exit(code=2) + + tag_names = [x.name for x in repo.tags] + if version in tag_names: + print("[generate.make_tag] Delete existing tag {}".format(version)) + repo.delete_tag(version) + + print("[generate.make_tag] Create tag {}".format(version)) + repo.create_tag(version) + + +@invoke.task() +def devpi_upload(ctx, version, user, password=None): + """Creates and uploads a package to devpi for testing.""" + if password: + print("[generate.devpi_upload] devpi login {}".format(user)) + check_call(['devpi', 'login', user, '--password', password]) + + check_call(['devpi', 'use', 'https://devpi.net/{}/dev'.format(user)]) + + env = os.environ.copy() + env['SETUPTOOLS_SCM_PRETEND_VERSION'] = version + check_call(['devpi', 'upload', '--formats', 'sdist,bdist_wheel'], env=env) + print("[generate.devpi_upload] package uploaded") + + +@invoke.task(help={ + 'version': 'version being released', + 'user': 'name of the user on devpi to stage the generated package', + 'password': 'user password on devpi to stage the generated package ' + '(if not given assumed logged in)', +}) +def pre_release(ctx, version, user, password=None): + """Generates new docs, release announcements and uploads a new release to devpi for testing.""" + announce(ctx, version) + regen(ctx) + changelog(ctx, version, write_out=True) + + msg = 'Preparing release version {}'.format(version) + check_call(['git', 'commit', '-a', '-m', msg]) + + make_tag(ctx, version) + + devpi_upload(ctx, version=version, user=user, password=password) + + print() + print('[generate.pre_release] Please push your branch and open a PR.') + + +@invoke.task(help={ + 'version': 'version being released', + 'user': 'name of the user on devpi to stage the generated package', + 'pypi_name': 'name of the pypi configuration section in your ~/.pypirc', +}) +def publish_release(ctx, version, user, pypi_name): + """Publishes a package previously created by the 'pre_release' command.""" + from git import Repo + repo = Repo('.') + tag_names = [x.name for x in repo.tags] + if version not in tag_names: + print('Could not find tag for version {}, exiting...'.format(version)) + raise invoke.Exit(code=2) + + check_call(['devpi', 'use', 'https://devpi.net/{}/dev'.format(user)]) + check_call(['devpi', 'push', 'pytest=={}'.format(version), 'pypi:{}'.format(pypi_name)]) + check_call(['git', 'push', 'git@github.com:pytest-dev/pytest.git', version]) + + emails = [ + 'pytest-dev@python.org', + 'python-announce-list@python.org' + ] + if version.endswith('.0'): + emails.append('testing-in-python@lists.idyll.org') + print('Version {} has been published to PyPI!'.format(version)) + print() + print('Please send an email announcement with the contents from:') + print() + print(' doc/en/announce/release-{}.rst'.format(version)) + print() + print('To the following mail lists:') + print() + print(' ', ','.join(emails)) + print() + print('And announce it on twitter adding the #pytest hash tag.') + + +@invoke.task(help={ + 'version': 'version being released', + 'write_out': 'write changes to the actial changelog' +}) +def changelog(ctx, version, write_out=False): + if write_out: + addopts = [] + else: + addopts = ['--draft'] + check_call(['towncrier', '--version', version] + addopts) + diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/tasks/release.minor.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/tasks/release.minor.rst new file mode 100644 index 00000000000..3c0b7d718a1 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/tasks/release.minor.rst @@ -0,0 +1,27 @@ +pytest-{version} +======================================= + +The pytest team is proud to announce the {version} release! + +pytest is a mature Python testing tool with more than a 1600 tests +against itself, passing on many different interpreters and platforms. + +This release contains a number of bugs fixes and improvements, so users are encouraged +to take a look at the CHANGELOG: + + http://doc.pytest.org/en/latest/changelog.html + +For complete documentation, please visit: + + http://docs.pytest.org + +As usual, you can upgrade from pypi via: + + pip install -U pytest + +Thanks to all who contributed to this release, among them: + +{contributors} + +Happy testing, +The Pytest Development Team diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/tasks/release.patch.rst b/tests/wpt/web-platform-tests/tools/third_party/pytest/tasks/release.patch.rst new file mode 100644 index 00000000000..56764b91307 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/tasks/release.patch.rst @@ -0,0 +1,17 @@ +pytest-{version} +======================================= + +pytest {version} has just been released to PyPI. + +This is a bug-fix release, being a drop-in replacement. To upgrade:: + + pip install --upgrade pytest + +The full changelog is available at http://doc.pytest.org/en/latest/changelog.html. + +Thanks to all who contributed to this release, among them: + +{contributors} + +Happy testing, +The pytest Development Team diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/tasks/requirements.txt b/tests/wpt/web-platform-tests/tools/third_party/pytest/tasks/requirements.txt new file mode 100644 index 00000000000..6392de0cc0a --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/tasks/requirements.txt @@ -0,0 +1,5 @@ +invoke +tox +gitpython +towncrier +wheel diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/acceptance_test.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/acceptance_test.py similarity index 75% rename from tests/wpt/web-platform-tests/tools/pytest/testing/acceptance_test.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/acceptance_test.py index 9bc3a191a53..a7838545b07 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/acceptance_test.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/acceptance_test.py @@ -1,3 +1,6 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import, division, print_function +import os import sys import _pytest._code @@ -6,7 +9,7 @@ import pytest from _pytest.main import EXIT_NOTESTSCOLLECTED, EXIT_USAGEERROR -class TestGeneralUsage: +class TestGeneralUsage(object): def test_config_error(self, testdir): testdir.makeconftest(""" def pytest_configure(config): @@ -71,14 +74,13 @@ class TestGeneralUsage: print("---unconfigure") """) result = testdir.runpytest("-s", "asd") - assert result.ret == 4 # EXIT_USAGEERROR + assert result.ret == 4 # EXIT_USAGEERROR result.stderr.fnmatch_lines(["ERROR: file not found*asd"]) result.stdout.fnmatch_lines([ "*---configure", "*---unconfigure", ]) - def test_config_preparse_plugin_option(self, testdir): testdir.makepyfile(pytest_xyz=""" def pytest_addoption(parser): @@ -116,10 +118,11 @@ class TestGeneralUsage: testdir.makepyfile(import_fails="import does_not_work") result = testdir.runpytest(p) result.stdout.fnmatch_lines([ - #XXX on jython this fails: "> import import_fails", - "E ImportError: No module named *does_not_work*", + # XXX on jython this fails: "> import import_fails", + "ImportError while importing test module*", + "*No module named *does_not_work*", ]) - assert result.ret == 1 + assert result.ret == 2 def test_not_collectable_arguments(self, testdir): p1 = testdir.makepyfile("") @@ -127,7 +130,7 @@ class TestGeneralUsage: result = testdir.runpytest(p1, p2) assert result.ret result.stderr.fnmatch_lines([ - "*ERROR: not found:*%s" %(p2.basename,) + "*ERROR: not found:*%s" % (p2.basename,) ]) def test_issue486_better_reporting_on_conftest_load_failure(self, testdir): @@ -143,7 +146,6 @@ class TestGeneralUsage: *ERROR*could not load*conftest.py* """) - def test_early_skip(self, testdir): testdir.mkdir("xyz") testdir.makeconftest(""" @@ -251,7 +253,7 @@ class TestGeneralUsage: if path.basename.startswith("conftest"): return MyCollector(path, parent) """) - result = testdir.runpytest(c.basename+"::"+"xyz") + result = testdir.runpytest(c.basename + "::" + "xyz") assert result.ret == 0 result.stdout.fnmatch_lines([ "*1 pass*", @@ -306,15 +308,15 @@ class TestGeneralUsage: x """) result = testdir.runpytest() - assert result.ret == 3 # internal error + assert result.ret == 3 # internal error result.stderr.fnmatch_lines([ "INTERNAL*pytest_configure*", "INTERNAL*x*", ]) assert 'sessionstarttime' not in result.stderr.str() - @pytest.mark.parametrize('lookfor', ['test_fun.py', 'test_fun.py::test_a']) - def test_issue134_report_syntaxerror_when_collecting_member(self, testdir, lookfor): + @pytest.mark.parametrize('lookfor', ['test_fun.py::test_a']) + def test_issue134_report_error_when_collecting_member(self, testdir, lookfor): testdir.makepyfile(test_fun=""" def test_a(): pass @@ -335,10 +337,16 @@ class TestGeneralUsage: "*ERROR*test_b.py::b*", ]) + @pytest.mark.usefixtures('recwarn') def test_namespace_import_doesnt_confuse_import_hook(self, testdir): - # Ref #383. Python 3.3's namespace package messed with our import hooks - # Importing a module that didn't exist, even if the ImportError was - # gracefully handled, would make our test crash. + """ + Ref #383. Python 3.3's namespace package messed with our import hooks + Importing a module that didn't exist, even if the ImportError was + gracefully handled, would make our test crash. + + Use recwarn here to silence this warning in Python 2.7: + ImportWarning: Not importing directory '...\not_a_package': missing __init__.py + """ testdir.mkdir('not_a_package') p = testdir.makepyfile(""" try: @@ -374,7 +382,7 @@ class TestGeneralUsage: res = testdir.runpytest(p) res.stdout.fnmatch_lines([ "*source code not available*", - "*fixture 'invalid_fixture' not found", + "E*fixture 'invalid_fixture' not found", ]) def test_plugins_given_as_strings(self, tmpdir, monkeypatch): @@ -392,7 +400,7 @@ class TestGeneralUsage: monkeypatch.setitem(sys.modules, 'myplugin', mod) assert pytest.main(args=[str(tmpdir)], plugins=['myplugin']) == 0 - def test_parameterized_with_bytes_regex(self, testdir): + def test_parametrized_with_bytes_regex(self, testdir): p = testdir.makepyfile(""" import re import pytest @@ -400,14 +408,27 @@ class TestGeneralUsage: def test_stuff(r): pass """ - ) + ) res = testdir.runpytest(p) res.stdout.fnmatch_lines([ '*1 passed*' ]) + def test_parametrized_with_null_bytes(self, testdir): + """Test parametrization with values that contain null bytes and unicode characters (#2644, #2957)""" + p = testdir.makepyfile(u""" + # encoding: UTF-8 + import pytest -class TestInvocationVariants: + @pytest.mark.parametrize("data", [b"\\x00", "\\x00", u'ação']) + def test_foo(data): + assert data + """) + res = testdir.runpytest(p) + res.assert_outcomes(passed=3) + + +class TestInvocationVariants(object): def test_earlyinit(self, testdir): p = testdir.makepyfile(""" import pytest @@ -430,8 +451,8 @@ class TestInvocationVariants: #collect #cmdline #Item - #assert collect.Item is Item - #assert collect.Collector is Collector + # assert collect.Item is Item + # assert collect.Collector is Collector main skip xfail @@ -499,7 +520,7 @@ class TestInvocationVariants: out, err = capsys.readouterr() def test_invoke_plugin_api(self, testdir, capsys): - class MyPlugin: + class MyPlugin(object): def pytest_addoption(self, parser): parser.addoption("--myopt") @@ -512,15 +533,15 @@ class TestInvocationVariants: path = testdir.mkpydir("tpkg") path.join("test_hello.py").write('raise ImportError') - result = testdir.runpytest("--pyargs", "tpkg.test_hello") + result = testdir.runpytest_subprocess("--pyargs", "tpkg.test_hello") assert result.ret != 0 - # FIXME: It would be more natural to match NOT - # "ERROR*file*or*package*not*found*". + result.stdout.fnmatch_lines([ - "*collected 0 items*" + "collected*0*items*/*1*errors" ]) def test_cmdline_python_package(self, testdir, monkeypatch): + import warnings monkeypatch.delenv('PYTHONDONTWRITEBYTECODE', False) path = testdir.mkpydir("tpkg") path.join("test_hello.py").write("def test_hello(): pass") @@ -539,22 +560,89 @@ class TestInvocationVariants: def join_pythonpath(what): cur = py.std.os.environ.get('PYTHONPATH') if cur: - return str(what) + ':' + cur + return str(what) + os.pathsep + cur return what empty_package = testdir.mkpydir("empty_package") monkeypatch.setenv('PYTHONPATH', join_pythonpath(empty_package)) - result = testdir.runpytest("--pyargs", ".") + # the path which is not a package raises a warning on pypy; + # no idea why only pypy and not normal python warn about it here + with warnings.catch_warnings(): + warnings.simplefilter('ignore', ImportWarning) + result = testdir.runpytest("--pyargs", ".") assert result.ret == 0 result.stdout.fnmatch_lines([ "*2 passed*" ]) monkeypatch.setenv('PYTHONPATH', join_pythonpath(testdir)) - path.join('test_hello.py').remove() - result = testdir.runpytest("--pyargs", "tpkg.test_hello") + result = testdir.runpytest("--pyargs", "tpkg.test_missing") assert result.ret != 0 result.stderr.fnmatch_lines([ - "*not*found*test_hello*", + "*not*found*test_missing*", + ]) + + def test_cmdline_python_namespace_package(self, testdir, monkeypatch): + """ + test --pyargs option with namespace packages (#1567) + """ + monkeypatch.delenv('PYTHONDONTWRITEBYTECODE', raising=False) + + search_path = [] + for dirname in "hello", "world": + d = testdir.mkdir(dirname) + search_path.append(d) + ns = d.mkdir("ns_pkg") + ns.join("__init__.py").write( + "__import__('pkg_resources').declare_namespace(__name__)") + lib = ns.mkdir(dirname) + lib.ensure("__init__.py") + lib.join("test_{0}.py".format(dirname)). \ + write("def test_{0}(): pass\n" + "def test_other():pass".format(dirname)) + + # The structure of the test directory is now: + # . + # ├── hello + # │   └── ns_pkg + # │   ├── __init__.py + # │   └── hello + # │   ├── __init__.py + # │   └── test_hello.py + # └── world + # └── ns_pkg + # ├── __init__.py + # └── world + # ├── __init__.py + # └── test_world.py + + def join_pythonpath(*dirs): + cur = py.std.os.environ.get('PYTHONPATH') + if cur: + dirs += (cur,) + return os.pathsep.join(str(p) for p in dirs) + monkeypatch.setenv('PYTHONPATH', join_pythonpath(*search_path)) + for p in search_path: + monkeypatch.syspath_prepend(p) + + os.chdir('world') + # mixed module and filenames: + result = testdir.runpytest("--pyargs", "-v", "ns_pkg.hello", "ns_pkg/world") + testdir.chdir() + assert result.ret == 0 + result.stdout.fnmatch_lines([ + "*test_hello.py::test_hello*PASSED*", + "*test_hello.py::test_other*PASSED*", + "*test_world.py::test_world*PASSED*", + "*test_world.py::test_other*PASSED*", + "*4 passed*" + ]) + + # specify tests within a module + result = testdir.runpytest("--pyargs", "-v", "ns_pkg.world.test_world::test_other") + assert result.ret == 0 + result.stdout.fnmatch_lines([ + "*test_world.py::test_other*PASSED*", + "*1 passed*" ]) def test_cmdline_python_package_not_exists(self, testdir): @@ -601,13 +689,12 @@ class TestInvocationVariants: import _pytest.config assert type(_pytest.config.get_plugin_manager()) is _pytest.config.PytestPluginManager - def test_has_plugin(self, request): """Test hasplugin function of the plugin manager (#932).""" assert request.config.pluginmanager.hasplugin('python') -class TestDurations: +class TestDurations(object): source = """ import time frag = 0.002 @@ -644,12 +731,12 @@ class TestDurations: result = testdir.runpytest("--durations=0") assert result.ret == 0 for x in "123": - for y in 'call',: #'setup', 'call', 'teardown': + for y in 'call', : # 'setup', 'call', 'teardown': for line in result.stdout.lines: if ("test_%s" % x) in line and y in line: break else: - raise AssertionError("not found %s %s" % (x,y)) + raise AssertionError("not found %s %s" % (x, y)) def test_with_deselected(self, testdir): testdir.makepyfile(self.source) @@ -664,14 +751,21 @@ class TestDurations: testdir.makepyfile(self.source) testdir.makepyfile(test_collecterror="""xyz""") result = testdir.runpytest("--durations=2", "-k test_1") - assert result.ret != 0 + assert result.ret == 2 result.stdout.fnmatch_lines([ - "*durations*", - "*call*test_1*", + "*Interrupted: 1 errors during collection*", ]) + # Collection errors abort test execution, therefore no duration is + # output + assert "duration" not in result.stdout.str() + + def test_with_not(self, testdir): + testdir.makepyfile(self.source) + result = testdir.runpytest("-k not 1") + assert result.ret == 0 -class TestDurationWithFixture: +class TestDurationWithFixture(object): source = """ import time frag = 0.001 @@ -682,6 +776,7 @@ class TestDurationWithFixture: def test_2(): time.sleep(frag) """ + def test_setup_function(self, testdir): testdir.makepyfile(self.source) result = testdir.runpytest("--durations=10") @@ -693,3 +788,63 @@ class TestDurationWithFixture: * call *test_1* """) + +def test_zipimport_hook(testdir, tmpdir): + """Test package loader is being used correctly (see #1837).""" + zipapp = pytest.importorskip('zipapp') + testdir.tmpdir.join('app').ensure(dir=1) + testdir.makepyfile(**{ + 'app/foo.py': """ + import pytest + def main(): + pytest.main(['--pyarg', 'foo']) + """, + }) + target = tmpdir.join('foo.zip') + zipapp.create_archive(str(testdir.tmpdir.join('app')), str(target), main='foo:main') + result = testdir.runpython(target) + assert result.ret == 0 + result.stderr.fnmatch_lines(['*not found*foo*']) + assert 'INTERNALERROR>' not in result.stdout.str() + + +def test_import_plugin_unicode_name(testdir): + testdir.makepyfile( + myplugin='', + ) + testdir.makepyfile(""" + def test(): pass + """) + testdir.makeconftest(""" + pytest_plugins = [u'myplugin'] + """) + r = testdir.runpytest() + assert r.ret == 0 + + +def test_deferred_hook_checking(testdir): + """ + Check hooks as late as possible (#1821). + """ + testdir.syspathinsert() + testdir.makepyfile(**{ + 'plugin.py': """ + class Hooks: + def pytest_my_hook(self, config): + pass + + def pytest_configure(config): + config.pluginmanager.add_hookspecs(Hooks) + """, + 'conftest.py': """ + pytest_plugins = ['plugin'] + def pytest_my_hook(config): + return 40 + """, + 'test_foo.py': """ + def test(request): + assert request.config.hook.pytest_my_hook(config=request.config) == [40] + """ + }) + result = testdir.runpytest() + result.stdout.fnmatch_lines(['* 1 passed *']) diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/code/test_code.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/code/test_code.py similarity index 78% rename from tests/wpt/web-platform-tests/tools/pytest/testing/code/test_code.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/code/test_code.py index 0db4ad2ab4c..209a8ef19a0 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/code/test_code.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/code/test_code.py @@ -1,8 +1,11 @@ +# coding: utf-8 +from __future__ import absolute_import, division, print_function import sys import _pytest._code import py import pytest +from test_excinfo import TWMock def test_ne(): @@ -11,6 +14,7 @@ def test_ne(): code2 = _pytest._code.Code(compile('foo = "baz"', '', 'exec')) assert code2 != code1 + def test_code_gives_back_name_for_not_existing_file(): name = 'abc-123' co_code = compile("pass\n", name, 'exec') @@ -19,20 +23,24 @@ def test_code_gives_back_name_for_not_existing_file(): assert str(code.path) == name assert code.fullsource is None + def test_code_with_class(): - class A: + class A(object): pass pytest.raises(TypeError, "_pytest._code.Code(A)") + if True: def x(): pass + def test_code_fullsource(): code = _pytest._code.Code(x) full = code.fullsource assert 'test_code_fullsource()' in str(full) + def test_code_source(): code = _pytest._code.Code(x) src = code.source() @@ -40,6 +48,7 @@ def test_code_source(): pass""" assert str(src) == expected + def test_frame_getsourcelineno_myself(): def func(): return sys._getframe(0) @@ -48,6 +57,7 @@ def test_frame_getsourcelineno_myself(): source, lineno = f.code.fullsource, f.lineno assert source[lineno].startswith(" return sys._getframe(0)") + def test_getstatement_empty_fullsource(): def func(): return sys._getframe(0) @@ -60,34 +70,19 @@ def test_getstatement_empty_fullsource(): finally: f.code.__class__.fullsource = prop + def test_code_from_func(): co = _pytest._code.Code(test_frame_getsourcelineno_myself) assert co.firstlineno assert co.path - -def test_builtin_patch_unpatch(monkeypatch): - cpy_builtin = py.builtin.builtins - comp = cpy_builtin.compile - def mycompile(*args, **kwargs): - return comp(*args, **kwargs) - class Sub(AssertionError): - pass - monkeypatch.setattr(cpy_builtin, 'AssertionError', Sub) - monkeypatch.setattr(cpy_builtin, 'compile', mycompile) - _pytest._code.patch_builtins() - assert cpy_builtin.AssertionError != Sub - assert cpy_builtin.compile != mycompile - _pytest._code.unpatch_builtins() - assert cpy_builtin.AssertionError is Sub - assert cpy_builtin.compile == mycompile - - def test_unicode_handling(): value = py.builtin._totext('\xc4\x85\xc4\x87\n', 'utf-8').encode('utf8') + def f(): raise Exception(value) + excinfo = pytest.raises(Exception, f) str(excinfo) if sys.version_info[0] < 3: @@ -97,13 +92,16 @@ def test_unicode_handling(): @pytest.mark.skipif(sys.version_info[0] >= 3, reason='python 2 only issue') def test_unicode_handling_syntax_error(): value = py.builtin._totext('\xc4\x85\xc4\x87\n', 'utf-8').encode('utf8') + def f(): raise SyntaxError('invalid syntax', (None, 1, 3, value)) + excinfo = pytest.raises(Exception, f) str(excinfo) if sys.version_info[0] < 3: unicode(excinfo) + def test_code_getargs(): def f1(x): pass @@ -149,26 +147,50 @@ def test_frame_getargs(): ('z', {'c': 'd'})] -class TestExceptionInfo: +class TestExceptionInfo(object): def test_bad_getsource(self): try: - if False: pass - else: assert False + if False: + pass + else: + assert False except AssertionError: exci = _pytest._code.ExceptionInfo() assert exci.getrepr() -class TestTracebackEntry: +class TestTracebackEntry(object): def test_getsource(self): try: - if False: pass - else: assert False + if False: + pass + else: + assert False except AssertionError: exci = _pytest._code.ExceptionInfo() entry = exci.traceback[0] source = entry.getsource() - assert len(source) == 4 - assert 'else: assert False' in source[3] + assert len(source) == 6 + assert 'assert False' in source[5] + + +class TestReprFuncArgs(object): + + def test_not_raise_exception_with_mixed_encoding(self): + from _pytest._code.code import ReprFuncArgs + + tw = TWMock() + + args = [ + ('unicode_string', u"São Paulo"), + ('utf8_string', 'S\xc3\xa3o Paulo'), + ] + + r = ReprFuncArgs(args) + r.toterminal(tw) + if sys.version_info[0] >= 3: + assert tw.lines[0] == 'unicode_string = São Paulo, utf8_string = São Paulo' + else: + assert tw.lines[0] == 'unicode_string = São Paulo, utf8_string = São Paulo' diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/code/test_excinfo.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/code/test_excinfo.py similarity index 62% rename from tests/wpt/web-platform-tests/tools/pytest/testing/code/test_excinfo.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/code/test_excinfo.py index 2defa31035b..34db8ffa189 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/code/test_excinfo.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/code/test_excinfo.py @@ -1,13 +1,16 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import, division, print_function +import operator import _pytest import py import pytest -from _pytest._code.code import FormattedExcinfo, ReprExceptionInfo +from _pytest._code.code import ( + ExceptionInfo, + FormattedExcinfo, + ReprExceptionInfo, + ExceptionChainRepr) -queue = py.builtin._tryimport('queue', 'Queue') - -failsonjython = pytest.mark.xfail("sys.platform.startswith('java')") from test_source import astonly try: @@ -17,21 +20,40 @@ except ImportError: else: invalidate_import_caches = getattr(importlib, "invalidate_caches", None) -import pytest +queue = py.builtin._tryimport('queue', 'Queue') + +failsonjython = pytest.mark.xfail("sys.platform.startswith('java')") + pytest_version_info = tuple(map(int, pytest.__version__.split(".")[:3])) -class TWMock: + +class TWMock(object): + WRITE = object() + def __init__(self): self.lines = [] + self.is_writing = False + def sep(self, sep, line=None): self.lines.append((sep, line)) + + def write(self, msg, **kw): + self.lines.append((TWMock.WRITE, msg)) + def line(self, line, **kw): self.lines.append(line) + def markup(self, text, **kw): return text + def get_write_msg(self, idx): + flag, msg = self.lines[idx] + assert flag == TWMock.WRITE + return msg + fullwidth = 80 + def test_excinfo_simple(): try: raise ValueError @@ -39,41 +61,51 @@ def test_excinfo_simple(): info = _pytest._code.ExceptionInfo() assert info.type == ValueError + def test_excinfo_getstatement(): def g(): raise ValueError + def f(): g() + try: f() except ValueError: excinfo = _pytest._code.ExceptionInfo() - linenumbers = [_pytest._code.getrawcode(f).co_firstlineno - 1 + 3, + linenumbers = [_pytest._code.getrawcode(f).co_firstlineno - 1 + 4, _pytest._code.getrawcode(f).co_firstlineno - 1 + 1, _pytest._code.getrawcode(g).co_firstlineno - 1 + 1, ] - l = list(excinfo.traceback) - foundlinenumbers = [x.lineno for x in l] + values = list(excinfo.traceback) + foundlinenumbers = [x.lineno for x in values] assert foundlinenumbers == linenumbers - #for x in info: + # for x in info: # print "%s:%d %s" %(x.path.relto(root), x.lineno, x.statement) - #xxx + # xxx # testchain for getentries test below + + def f(): # raise ValueError # + + def g(): # __tracebackhide__ = True f() # + + def h(): # g() # -class TestTraceback_f_g_h: + +class TestTraceback_f_g_h(object): def setup_method(self, method): try: h() @@ -83,8 +115,8 @@ class TestTraceback_f_g_h: def test_traceback_entries(self): tb = self.excinfo.traceback entries = list(tb) - assert len(tb) == 4 # maybe fragile test - assert len(entries) == 4 # maybe fragile test + assert len(tb) == 4 # maybe fragile test + assert len(entries) == 4 # maybe fragile test names = ['f', 'g', 'h'] for entry in entries: try: @@ -95,7 +127,7 @@ class TestTraceback_f_g_h: def test_traceback_entry_getsource(self): tb = self.excinfo.traceback - s = str(tb[-1].getsource() ) + s = str(tb[-1].getsource()) assert s.startswith("def f():") assert s.endswith("raise ValueError") @@ -111,10 +143,10 @@ class TestTraceback_f_g_h: xyz() """) try: - exec (source.compile()) + exec(source.compile()) except NameError: tb = _pytest._code.ExceptionInfo().traceback - print (tb[-1].getsource()) + print(tb[-1].getsource()) s = str(tb[-1].getsource()) assert s.startswith("def xyz():\n try:") assert s.strip().endswith("except somenoname:") @@ -125,7 +157,7 @@ class TestTraceback_f_g_h: traceback = self.excinfo.traceback newtraceback = traceback.cut(path=path, firstlineno=firstlineno) assert len(newtraceback) == 1 - newtraceback = traceback.cut(path=path, lineno=firstlineno+2) + newtraceback = traceback.cut(path=path, lineno=firstlineno + 2) assert len(newtraceback) == 1 def test_traceback_cut_excludepath(self, testdir): @@ -143,6 +175,41 @@ class TestTraceback_f_g_h: ntraceback = traceback.filter() assert len(ntraceback) == len(traceback) - 1 + @pytest.mark.parametrize('tracebackhide, matching', [ + (lambda info: True, True), + (lambda info: False, False), + (operator.methodcaller('errisinstance', ValueError), True), + (operator.methodcaller('errisinstance', IndexError), False), + ]) + def test_traceback_filter_selective(self, tracebackhide, matching): + def f(): + # + raise ValueError + # + + def g(): + # + __tracebackhide__ = tracebackhide + f() + # + + def h(): + # + g() + # + + excinfo = pytest.raises(ValueError, h) + traceback = excinfo.traceback + ntraceback = traceback.filter() + print('old: {0!r}'.format(traceback)) + print('new: {0!r}'.format(ntraceback)) + + if matching: + assert len(ntraceback) == len(traceback) - 2 + else: + # -1 because of the __tracebackhide__ in pytest.raises + assert len(ntraceback) == len(traceback) - 1 + def test_traceback_recursion_index(self): def f(n): if n < 10: @@ -157,7 +224,7 @@ class TestTraceback_f_g_h: def f(n): if n == 0: raise RuntimeError("hello") - f(n-1) + f(n - 1) excinfo = pytest.raises(RuntimeError, f, 100) monkeypatch.delattr(excinfo.traceback.__class__, "recursionindex") @@ -167,22 +234,25 @@ class TestTraceback_f_g_h: def test_traceback_no_recursion_index(self): def do_stuff(): raise RuntimeError + def reraise_me(): import sys exc, val, tb = sys.exc_info() py.builtin._reraise(exc, val, tb) + def f(n): try: do_stuff() - except: + except: # noqa reraise_me() + excinfo = pytest.raises(RuntimeError, f, 8) traceback = excinfo.traceback recindex = traceback.recursionindex() assert recindex is None def test_traceback_messy_recursion(self): - #XXX: simplified locally testable version + # XXX: simplified locally testable version decorator = pytest.importorskip('decorator').decorator def log(f, *k, **kw): @@ -198,17 +268,18 @@ class TestTraceback_f_g_h: excinfo = pytest.raises(ValueError, fail) assert excinfo.traceback.recursionindex() is None - - def test_traceback_getcrashentry(self): def i(): __tracebackhide__ = True raise ValueError + def h(): i() + def g(): __tracebackhide__ = True h() + def f(): g() @@ -224,6 +295,7 @@ class TestTraceback_f_g_h: def g(): __tracebackhide__ = True raise ValueError + def f(): __tracebackhide__ = True g() @@ -236,56 +308,47 @@ class TestTraceback_f_g_h: assert entry.lineno == co.firstlineno + 2 assert entry.frame.code.name == 'g' -def hello(x): - x + 5 - -def test_tbentry_reinterpret(): - try: - hello("hello") - except TypeError: - excinfo = _pytest._code.ExceptionInfo() - tbentry = excinfo.traceback[-1] - msg = tbentry.reinterpret() - assert msg.startswith("TypeError: ('hello' + 5)") def test_excinfo_exconly(): excinfo = pytest.raises(ValueError, h) assert excinfo.exconly().startswith('ValueError') excinfo = pytest.raises(ValueError, - "raise ValueError('hello\\nworld')") + "raise ValueError('hello\\nworld')") msg = excinfo.exconly(tryshort=True) assert msg.startswith('ValueError') assert msg.endswith("world") + def test_excinfo_repr(): excinfo = pytest.raises(ValueError, h) s = repr(excinfo) assert s == "" + def test_excinfo_str(): excinfo = pytest.raises(ValueError, h) s = str(excinfo) - assert s.startswith(__file__[:-9]) # pyc file and $py.class + assert s.startswith(__file__[:-9]) # pyc file and $py.class assert s.endswith("ValueError") - assert len(s.split(":")) >= 3 # on windows it's 4 + assert len(s.split(":")) >= 3 # on windows it's 4 + def test_excinfo_errisinstance(): excinfo = pytest.raises(ValueError, h) assert excinfo.errisinstance(ValueError) + def test_excinfo_no_sourcecode(): try: - exec ("raise ValueError()") + exec("raise ValueError()") except ValueError: excinfo = _pytest._code.ExceptionInfo() s = str(excinfo.traceback[-1]) - if py.std.sys.version_info < (2,5): - assert s == " File '':1 in ?\n ???\n" - else: - assert s == " File '':1 in \n ???\n" + assert s == " File '':1 in \n ???\n" + def test_excinfo_no_python_sourcecode(tmpdir): - #XXX: simplified locally testable version + # XXX: simplified locally testable version tmpdir.join('test.txt').write("{{ h()}}:") jinja2 = pytest.importorskip('jinja2') @@ -293,10 +356,10 @@ def test_excinfo_no_python_sourcecode(tmpdir): env = jinja2.Environment(loader=loader) template = env.get_template('test.txt') excinfo = pytest.raises(ValueError, - template.render, h=h) + template.render, h=h) for item in excinfo.traceback: - print(item) #XXX: for some reason jinja.Template.render is printed in full - item.source # shouldnt fail + print(item) # XXX: for some reason jinja.Template.render is printed in full + item.source # shouldnt fail if item.path.basename == 'test.txt': assert str(item.source) == '{{ h()}}:' @@ -312,6 +375,7 @@ def test_entrysource_Queue_example(): s = str(source).strip() assert s.startswith("def get") + def test_codepath_Queue_example(): try: queue.Queue().get(timeout=0.001) @@ -323,11 +387,35 @@ def test_codepath_Queue_example(): assert path.basename.lower() == "queue.py" assert path.check() -class TestFormattedExcinfo: - def pytest_funcarg__importasmod(self, request): + +def test_match_succeeds(): + with pytest.raises(ZeroDivisionError) as excinfo: + 0 // 0 + excinfo.match(r'.*zero.*') + + +def test_match_raises_error(testdir): + testdir.makepyfile(""" + import pytest + def test_division_zero(): + with pytest.raises(ZeroDivisionError) as excinfo: + 0 / 0 + excinfo.match(r'[123]+') + """) + result = testdir.runpytest() + assert result.ret != 0 + result.stdout.fnmatch_lines([ + "*AssertionError*Pattern*[123]*not found*", + ]) + + +class TestFormattedExcinfo(object): + + @pytest.fixture + def importasmod(self, request): def importasmod(source): source = _pytest._code.Source(source) - tmpdir = request.getfuncargvalue("tmpdir") + tmpdir = request.getfixturevalue("tmpdir") modpath = tmpdir.join("mod.py") tmpdir.ensure("__init__.py") modpath.write(source) @@ -339,10 +427,10 @@ class TestFormattedExcinfo: def excinfo_from_exec(self, source): source = _pytest._code.Source(source).strip() try: - exec (source.compile()) + exec(source.compile()) except KeyboardInterrupt: raise - except: + except: # noqa return _pytest._code.ExceptionInfo() assert 0, "did not raise" @@ -372,19 +460,20 @@ class TestFormattedExcinfo: assert lines == [ ' def f():', '> assert 0', - 'E assert 0' + 'E AssertionError' ] - def test_repr_source_not_existing(self): pr = FormattedExcinfo() co = compile("raise ValueError()", "", "exec") try: - exec (co) + exec(co) except ValueError: excinfo = _pytest._code.ExceptionInfo() repr = pr.repr_excinfo(excinfo) assert repr.reprtraceback.reprentries[1].lines[0] == "> ???" + if py.std.sys.version_info[0] >= 3: + assert repr.chain[0][0].reprentries[1].lines[0] == "> ???" def test_repr_many_line_source_not_existing(self): pr = FormattedExcinfo() @@ -393,23 +482,27 @@ a = 1 raise ValueError() """, "", "exec") try: - exec (co) + exec(co) except ValueError: excinfo = _pytest._code.ExceptionInfo() repr = pr.repr_excinfo(excinfo) assert repr.reprtraceback.reprentries[1].lines[0] == "> ???" + if py.std.sys.version_info[0] >= 3: + assert repr.chain[0][0].reprentries[1].lines[0] == "> ???" def test_repr_source_failing_fullsource(self): pr = FormattedExcinfo() class FakeCode(object): - class raw: + class raw(object): co_filename = '?' + path = '?' firstlineno = 5 def fullsource(self): return None + fullsource = property(fullsource) class FakeFrame(object): @@ -418,8 +511,8 @@ raise ValueError() f_globals = {} class FakeTracebackEntry(_pytest._code.Traceback.Entry): - def __init__(self, tb): - self.lineno = 5+3 + def __init__(self, tb, excinfo=None): + self.lineno = 5 + 3 @property def frame(self): @@ -430,28 +523,36 @@ raise ValueError() class FakeExcinfo(_pytest._code.ExceptionInfo): typename = "Foo" + value = Exception() + def __init__(self): pass def exconly(self, tryshort): return "EXC" + def errisinstance(self, cls): return False excinfo = FakeExcinfo() + class FakeRawTB(object): tb_next = None + tb = FakeRawTB() excinfo.traceback = Traceback(tb) fail = IOError() # noqa repr = pr.repr_excinfo(excinfo) assert repr.reprtraceback.reprentries[0].lines[0] == "> ???" + if py.std.sys.version_info[0] >= 3: + assert repr.chain[0][0].reprentries[0].lines[0] == "> ???" fail = py.error.ENOENT # noqa repr = pr.repr_excinfo(excinfo) assert repr.reprtraceback.reprentries[0].lines[0] == "> ???" - + if py.std.sys.version_info[0] >= 3: + assert repr.chain[0][0].reprentries[0].lines[0] == "> ???" def test_repr_local(self): p = FormattedExcinfo(showlocals=True) @@ -492,19 +593,19 @@ raise ValueError() loc = repr_entry.reprfileloc assert loc.path == mod.__file__ assert loc.lineno == 3 - #assert loc.message == "ValueError: hello" + # assert loc.message == "ValueError: hello" def test_repr_tracebackentry_lines2(self, importasmod): mod = importasmod(""" def func1(m, x, y, z): raise ValueError("hello\\nworld") """) - excinfo = pytest.raises(ValueError, mod.func1, "m"*90, 5, 13, "z"*120) + excinfo = pytest.raises(ValueError, mod.func1, "m" * 90, 5, 13, "z" * 120) excinfo.traceback = excinfo.traceback.filter() entry = excinfo.traceback[-1] p = FormattedExcinfo(funcargs=True) reprfuncargs = p.repr_args(entry) - assert reprfuncargs.args[0] == ('m', repr("m"*90)) + assert reprfuncargs.args[0] == ('m', repr("m" * 90)) assert reprfuncargs.args[1] == ('x', '5') assert reprfuncargs.args[2] == ('y', '13') assert reprfuncargs.args[3] == ('z', repr("z" * 120)) @@ -637,6 +738,9 @@ raise ValueError() repr = p.repr_excinfo(excinfo) assert repr.reprtraceback assert len(repr.reprtraceback.reprentries) == len(reprtb.reprentries) + if py.std.sys.version_info[0] >= 3: + assert repr.chain[0][0] + assert len(repr.chain[0][0].reprentries) == len(reprtb.reprentries) assert repr.reprcrash.path.endswith("mod.py") assert repr.reprcrash.message == "ValueError: 0" @@ -650,8 +754,10 @@ raise ValueError() excinfo = pytest.raises(ValueError, mod.entry) p = FormattedExcinfo() + def raiseos(): raise OSError(2) + monkeypatch.setattr(py.std.os, 'getcwd', raiseos) assert p._makepath(__file__) == __file__ p.repr_traceback(excinfo) @@ -698,23 +804,6 @@ raise ValueError() assert reprtb.extraline == "!!! Recursion detected (same locals & position)" assert str(reprtb) - def test_tb_entry_AssertionError(self, importasmod): - # probably this test is a bit redundant - # as py/magic/testing/test_assertion.py - # already tests correctness of - # assertion-reinterpretation logic - mod = importasmod(""" - def somefunc(): - x = 1 - assert x == 2 - """) - excinfo = pytest.raises(AssertionError, mod.somefunc) - - p = FormattedExcinfo() - reprentry = p.repr_traceback_entry(excinfo.traceback[-1], excinfo) - lines = reprentry.lines - assert lines[-1] == "E assert 1 == 2" - def test_reprexcinfo_getrepr(self, importasmod): mod = importasmod(""" def f(x): @@ -727,14 +816,21 @@ raise ValueError() for style in ("short", "long", "no"): for showlocals in (True, False): repr = excinfo.getrepr(style=style, showlocals=showlocals) - assert isinstance(repr, ReprExceptionInfo) + if py.std.sys.version_info[0] < 3: + assert isinstance(repr, ReprExceptionInfo) assert repr.reprtraceback.style == style + if py.std.sys.version_info[0] >= 3: + assert isinstance(repr, ExceptionChainRepr) + for repr in repr.chain: + assert repr[0].style == style def test_reprexcinfo_unicode(self): from _pytest._code.code import TerminalRepr + class MyRepr(TerminalRepr): def toterminal(self, tw): tw.line(py.builtin._totext("я", "utf-8")) + x = py.builtin._totext(MyRepr()) assert x == py.builtin._totext("я", "utf-8") @@ -755,14 +851,18 @@ raise ValueError() assert tw.lines[0] == " def f():" assert tw.lines[1] == "> g(3)" assert tw.lines[2] == "" - assert tw.lines[3].endswith("mod.py:5: ") - assert tw.lines[4] == ("_ ", None) - assert tw.lines[5] == "" - assert tw.lines[6] == " def g(x):" - assert tw.lines[7] == "> raise ValueError(x)" - assert tw.lines[8] == "E ValueError: 3" - assert tw.lines[9] == "" - assert tw.lines[10].endswith("mod.py:3: ValueError") + line = tw.get_write_msg(3) + assert line.endswith("mod.py") + assert tw.lines[4] == (":5: ") + assert tw.lines[5] == ("_ ", None) + assert tw.lines[6] == "" + assert tw.lines[7] == " def g(x):" + assert tw.lines[8] == "> raise ValueError(x)" + assert tw.lines[9] == "E ValueError: 3" + assert tw.lines[10] == "" + line = tw.get_write_msg(11) + assert line.endswith("mod.py") + assert tw.lines[12] == ":3: ValueError" def test_toterminal_long_missing_source(self, importasmod, tmpdir): mod = importasmod(""" @@ -781,13 +881,17 @@ raise ValueError() tw.lines.pop(0) assert tw.lines[0] == "> ???" assert tw.lines[1] == "" - assert tw.lines[2].endswith("mod.py:5: ") - assert tw.lines[3] == ("_ ", None) - assert tw.lines[4] == "" - assert tw.lines[5] == "> ???" - assert tw.lines[6] == "E ValueError: 3" - assert tw.lines[7] == "" - assert tw.lines[8].endswith("mod.py:3: ValueError") + line = tw.get_write_msg(2) + assert line.endswith("mod.py") + assert tw.lines[3] == ":5: " + assert tw.lines[4] == ("_ ", None) + assert tw.lines[5] == "" + assert tw.lines[6] == "> ???" + assert tw.lines[7] == "E ValueError: 3" + assert tw.lines[8] == "" + line = tw.get_write_msg(9) + assert line.endswith("mod.py") + assert tw.lines[10] == ":3: ValueError" def test_toterminal_long_incomplete_source(self, importasmod, tmpdir): mod = importasmod(""" @@ -806,13 +910,17 @@ raise ValueError() tw.lines.pop(0) assert tw.lines[0] == "> ???" assert tw.lines[1] == "" - assert tw.lines[2].endswith("mod.py:5: ") - assert tw.lines[3] == ("_ ", None) - assert tw.lines[4] == "" - assert tw.lines[5] == "> ???" - assert tw.lines[6] == "E ValueError: 3" - assert tw.lines[7] == "" - assert tw.lines[8].endswith("mod.py:3: ValueError") + line = tw.get_write_msg(2) + assert line.endswith("mod.py") + assert tw.lines[3] == ":5: " + assert tw.lines[4] == ("_ ", None) + assert tw.lines[5] == "" + assert tw.lines[6] == "> ???" + assert tw.lines[7] == "E ValueError: 3" + assert tw.lines[8] == "" + line = tw.get_write_msg(9) + assert line.endswith("mod.py") + assert tw.lines[10] == ":3: ValueError" def test_toterminal_long_filenames(self, importasmod): mod = importasmod(""" @@ -826,25 +934,28 @@ raise ValueError() try: repr = excinfo.getrepr(abspath=False) repr.toterminal(tw) - line = tw.lines[-1] x = py.path.local().bestrelpath(path) if len(x) < len(str(path)): - assert line == "mod.py:3: ValueError" + msg = tw.get_write_msg(-2) + assert msg == "mod.py" + assert tw.lines[-1] == ":3: ValueError" repr = excinfo.getrepr(abspath=True) repr.toterminal(tw) + msg = tw.get_write_msg(-2) + assert msg == path line = tw.lines[-1] - assert line == "%s:3: ValueError" %(path,) + assert line == ":3: ValueError" finally: old.chdir() @pytest.mark.parametrize('reproptions', [ {'style': style, 'showlocals': showlocals, 'funcargs': funcargs, 'tbfilter': tbfilter - } for style in ("long", "short", "no") - for showlocals in (True, False) - for tbfilter in (True, False) - for funcargs in (True, False)]) + } for style in ("long", "short", "no") + for showlocals in (True, False) + for tbfilter in (True, False) + for funcargs in (True, False)]) def test_format_excinfo(self, importasmod, reproptions): mod = importasmod(""" def g(x): @@ -858,21 +969,6 @@ raise ValueError() repr.toterminal(tw) assert tw.stringio.getvalue() - - def test_native_style(self): - excinfo = self.excinfo_from_exec(""" - assert 0 - """) - repr = excinfo.getrepr(style='native') - assert "assert 0" in str(repr.reprcrash) - s = str(repr) - assert s.startswith('Traceback (most recent call last):\n File') - assert s.endswith('\nAssertionError: assert 0') - assert 'exec (source.compile())' in s - # python 2.4 fails to get the source line for the assert - if py.std.sys.version_info >= (2, 5): - assert s.count('assert 0') == 2 - def test_traceback_repr_style(self, importasmod): mod = importasmod(""" def f(): @@ -891,21 +987,259 @@ raise ValueError() r = excinfo.getrepr(style="long") tw = TWMock() r.toterminal(tw) - for line in tw.lines: print (line) + for line in tw.lines: + print(line) assert tw.lines[0] == "" assert tw.lines[1] == " def f():" assert tw.lines[2] == "> g()" assert tw.lines[3] == "" - assert tw.lines[4].endswith("mod.py:3: ") - assert tw.lines[5] == ("_ ", None) - assert tw.lines[6].endswith("in g") - assert tw.lines[7] == " h()" - assert tw.lines[8].endswith("in h") - assert tw.lines[9] == " i()" - assert tw.lines[10] == ("_ ", None) - assert tw.lines[11] == "" - assert tw.lines[12] == " def i():" - assert tw.lines[13] == "> raise ValueError()" - assert tw.lines[14] == "E ValueError" + msg = tw.get_write_msg(4) + assert msg.endswith("mod.py") + assert tw.lines[5] == ":3: " + assert tw.lines[6] == ("_ ", None) + tw.get_write_msg(7) + assert tw.lines[8].endswith("in g") + assert tw.lines[9] == " h()" + tw.get_write_msg(10) + assert tw.lines[11].endswith("in h") + assert tw.lines[12] == " i()" + assert tw.lines[13] == ("_ ", None) + assert tw.lines[14] == "" + assert tw.lines[15] == " def i():" + assert tw.lines[16] == "> raise ValueError()" + assert tw.lines[17] == "E ValueError" + assert tw.lines[18] == "" + msg = tw.get_write_msg(19) + msg.endswith("mod.py") + assert tw.lines[20] == ":9: ValueError" + + @pytest.mark.skipif("sys.version_info[0] < 3") + def test_exc_chain_repr(self, importasmod): + mod = importasmod(""" + class Err(Exception): + pass + def f(): + try: + g() + except Exception as e: + raise Err() from e + finally: + h() + def g(): + raise ValueError() + + def h(): + raise AttributeError() + """) + excinfo = pytest.raises(AttributeError, mod.f) + r = excinfo.getrepr(style="long") + tw = TWMock() + r.toterminal(tw) + for line in tw.lines: + print(line) + assert tw.lines[0] == "" + assert tw.lines[1] == " def f():" + assert tw.lines[2] == " try:" + assert tw.lines[3] == "> g()" + assert tw.lines[4] == "" + line = tw.get_write_msg(5) + assert line.endswith('mod.py') + assert tw.lines[6] == ':6: ' + assert tw.lines[7] == ("_ ", None) + assert tw.lines[8] == "" + assert tw.lines[9] == " def g():" + assert tw.lines[10] == "> raise ValueError()" + assert tw.lines[11] == "E ValueError" + assert tw.lines[12] == "" + line = tw.get_write_msg(13) + assert line.endswith('mod.py') + assert tw.lines[14] == ':12: ValueError' assert tw.lines[15] == "" - assert tw.lines[16].endswith("mod.py:9: ValueError") + assert tw.lines[16] == "The above exception was the direct cause of the following exception:" + assert tw.lines[17] == "" + assert tw.lines[18] == " def f():" + assert tw.lines[19] == " try:" + assert tw.lines[20] == " g()" + assert tw.lines[21] == " except Exception as e:" + assert tw.lines[22] == "> raise Err() from e" + assert tw.lines[23] == "E test_exc_chain_repr0.mod.Err" + assert tw.lines[24] == "" + line = tw.get_write_msg(25) + assert line.endswith('mod.py') + assert tw.lines[26] == ":8: Err" + assert tw.lines[27] == "" + assert tw.lines[28] == "During handling of the above exception, another exception occurred:" + assert tw.lines[29] == "" + assert tw.lines[30] == " def f():" + assert tw.lines[31] == " try:" + assert tw.lines[32] == " g()" + assert tw.lines[33] == " except Exception as e:" + assert tw.lines[34] == " raise Err() from e" + assert tw.lines[35] == " finally:" + assert tw.lines[36] == "> h()" + assert tw.lines[37] == "" + line = tw.get_write_msg(38) + assert line.endswith('mod.py') + assert tw.lines[39] == ":10: " + assert tw.lines[40] == ('_ ', None) + assert tw.lines[41] == "" + assert tw.lines[42] == " def h():" + assert tw.lines[43] == "> raise AttributeError()" + assert tw.lines[44] == "E AttributeError" + assert tw.lines[45] == "" + line = tw.get_write_msg(46) + assert line.endswith('mod.py') + assert tw.lines[47] == ":15: AttributeError" + + @pytest.mark.skipif("sys.version_info[0] < 3") + def test_exc_repr_with_raise_from_none_chain_suppression(self, importasmod): + mod = importasmod(""" + def f(): + try: + g() + except Exception: + raise AttributeError() from None + def g(): + raise ValueError() + """) + excinfo = pytest.raises(AttributeError, mod.f) + r = excinfo.getrepr(style="long") + tw = TWMock() + r.toterminal(tw) + for line in tw.lines: + print(line) + assert tw.lines[0] == "" + assert tw.lines[1] == " def f():" + assert tw.lines[2] == " try:" + assert tw.lines[3] == " g()" + assert tw.lines[4] == " except Exception:" + assert tw.lines[5] == "> raise AttributeError() from None" + assert tw.lines[6] == "E AttributeError" + assert tw.lines[7] == "" + line = tw.get_write_msg(8) + assert line.endswith('mod.py') + assert tw.lines[9] == ":6: AttributeError" + assert len(tw.lines) == 10 + + @pytest.mark.skipif("sys.version_info[0] < 3") + @pytest.mark.parametrize('reason, description', [ + ('cause', 'The above exception was the direct cause of the following exception:'), + ('context', 'During handling of the above exception, another exception occurred:'), + ]) + def test_exc_chain_repr_without_traceback(self, importasmod, reason, description): + """ + Handle representation of exception chains where one of the exceptions doesn't have a + real traceback, such as those raised in a subprocess submitted by the multiprocessing + module (#1984). + """ + from _pytest.pytester import LineMatcher + exc_handling_code = ' from e' if reason == 'cause' else '' + mod = importasmod(""" + def f(): + try: + g() + except Exception as e: + raise RuntimeError('runtime problem'){exc_handling_code} + def g(): + raise ValueError('invalid value') + """.format(exc_handling_code=exc_handling_code)) + + with pytest.raises(RuntimeError) as excinfo: + mod.f() + + # emulate the issue described in #1984 + attr = '__%s__' % reason + getattr(excinfo.value, attr).__traceback__ = None + + r = excinfo.getrepr() + tw = py.io.TerminalWriter(stringio=True) + tw.hasmarkup = False + r.toterminal(tw) + + matcher = LineMatcher(tw.stringio.getvalue().splitlines()) + matcher.fnmatch_lines([ + "ValueError: invalid value", + description, + "* except Exception as e:", + "> * raise RuntimeError('runtime problem')" + exc_handling_code, + "E *RuntimeError: runtime problem", + ]) + + +@pytest.mark.parametrize("style", ["short", "long"]) +@pytest.mark.parametrize("encoding", [None, "utf8", "utf16"]) +def test_repr_traceback_with_unicode(style, encoding): + msg = u'☹' + if encoding is not None: + msg = msg.encode(encoding) + try: + raise RuntimeError(msg) + except RuntimeError: + e_info = ExceptionInfo() + formatter = FormattedExcinfo(style=style) + repr_traceback = formatter.repr_traceback(e_info) + assert repr_traceback is not None + + +def test_cwd_deleted(testdir): + testdir.makepyfile(""" + def test(tmpdir): + tmpdir.chdir() + tmpdir.remove() + assert False + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines(['* 1 failed in *']) + assert 'INTERNALERROR' not in result.stdout.str() + result.stderr.str() + + +def test_exception_repr_extraction_error_on_recursion(): + """ + Ensure we can properly detect a recursion error even + if some locals raise error on comparision (#2459). + """ + class numpy_like(object): + + def __eq__(self, other): + if type(other) is numpy_like: + raise ValueError('The truth value of an array ' + 'with more than one element is ambiguous.') + + def a(x): + return b(numpy_like()) + + def b(x): + return a(numpy_like()) + + try: + a(numpy_like()) + except: # noqa + from _pytest._code.code import ExceptionInfo + from _pytest.pytester import LineMatcher + exc_info = ExceptionInfo() + + matcher = LineMatcher(str(exc_info.getrepr()).splitlines()) + matcher.fnmatch_lines([ + '!!! Recursion error detected, but an error occurred locating the origin of recursion.', + '*The following exception happened*', + '*ValueError: The truth value of an array*', + ]) + + +def test_no_recursion_index_on_recursion_error(): + """ + Ensure that we don't break in case we can't find the recursion index + during a recursion error (#2486). + """ + try: + class RecursionDepthError(object): + def __getattr__(self, attr): + return getattr(self, '_' + attr) + + RecursionDepthError().trigger + except: # noqa + from _pytest._code.code import ExceptionInfo + exc_info = ExceptionInfo() + assert 'maximum recursion' in str(exc_info.getrepr()) + else: + assert 0 diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/code/test_source.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/code/test_source.py similarity index 90% rename from tests/wpt/web-platform-tests/tools/pytest/testing/code/test_source.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/code/test_source.py index 007ad1433aa..8eda68a6e2f 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/code/test_source.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/code/test_source.py @@ -1,6 +1,7 @@ # flake8: noqa # disable flake check on this file because some constructs are strange # or redundant on purpose and can't be disable on a line-by-line basis +from __future__ import absolute_import, division, print_function import sys import _pytest._code @@ -16,6 +17,7 @@ else: failsonjython = pytest.mark.xfail("sys.platform.startswith('java')") + def test_source_str_function(): x = Source("3") assert str(x) == "3" @@ -33,6 +35,7 @@ def test_source_str_function(): """, rstrip=True) assert str(x) == "\n3" + def test_unicode(): try: unicode @@ -44,23 +47,27 @@ def test_unicode(): val = eval(co) assert isinstance(val, unicode) + def test_source_from_function(): source = _pytest._code.Source(test_source_str_function) assert str(source).startswith('def test_source_str_function():') + def test_source_from_method(): - class TestClass: + class TestClass(object): def test_method(self): pass source = _pytest._code.Source(TestClass().test_method) assert source.lines == ["def test_method(self):", " pass"] + def test_source_from_lines(): lines = ["a \n", "b\n", "c"] source = _pytest._code.Source(lines) assert source.lines == ['a ', 'b', 'c'] + def test_source_from_inner_function(): def f(): pass @@ -69,6 +76,7 @@ def test_source_from_inner_function(): source = _pytest._code.Source(f) assert str(source).startswith('def f():') + def test_source_putaround_simple(): source = Source("raise ValueError") source = source.putaround( @@ -77,7 +85,7 @@ def test_source_putaround_simple(): x = 42 else: x = 23""") - assert str(source)=="""\ + assert str(source) == """\ try: raise ValueError except ValueError: @@ -85,6 +93,7 @@ except ValueError: else: x = 23""" + def test_source_putaround(): source = Source() source = source.putaround(""" @@ -93,24 +102,28 @@ def test_source_putaround(): """) assert str(source).strip() == "if 1:\n x=1" + def test_source_strips(): source = Source("") assert source == Source() assert str(source) == '' assert source.strip() == source + def test_source_strip_multiline(): source = Source() source.lines = ["", " hello", " "] source2 = source.strip() assert source2.lines == [" hello"] + def test_syntaxerror_rerepresentation(): ex = pytest.raises(SyntaxError, _pytest._code.compile, 'xyz xyz') assert ex.value.lineno == 1 - assert ex.value.offset in (4,7) # XXX pypy/jython versus cpython? + assert ex.value.offset in (4, 7) # XXX pypy/jython versus cpython? assert ex.value.text.strip(), 'x x' + def test_isparseable(): assert Source("hello").isparseable() assert Source("if 1:\n pass").isparseable() @@ -119,13 +132,15 @@ def test_isparseable(): assert not Source(" \nif 1:\npass").isparseable() assert not Source(chr(0)).isparseable() -class TestAccesses: + +class TestAccesses(object): source = Source("""\ def f(x): pass def g(x): pass """) + def test_getrange(self): x = self.source[0:2] assert x.isparseable() @@ -140,10 +155,11 @@ class TestAccesses: assert len(self.source) == 4 def test_iter(self): - l = [x for x in self.source] - assert len(l) == 4 + values = [x for x in self.source] + assert len(values) == 4 -class TestSourceParsingAndCompiling: + +class TestSourceParsingAndCompiling(object): source = Source("""\ def f(x): assert (x == @@ -154,12 +170,12 @@ class TestSourceParsingAndCompiling: def test_compile(self): co = _pytest._code.compile("x=3") d = {} - exec (co, d) + exec(co, d) assert d['x'] == 3 def test_compile_and_getsource_simple(self): co = _pytest._code.compile("x=3") - exec (co) + exec(co) source = _pytest._code.Source(co) assert str(source) == "x=3" @@ -180,16 +196,16 @@ class TestSourceParsingAndCompiling: assert 'ValueError' in source2 def test_getstatement(self): - #print str(self.source) + # print str(self.source) ass = str(self.source[1:]) for i in range(1, 4): - #print "trying start in line %r" % self.source[i] + # print "trying start in line %r" % self.source[i] s = self.source.getstatement(i) #x = s.deindent() assert str(s) == ass def test_getstatementrange_triple_quoted(self): - #print str(self.source) + # print str(self.source) source = Source("""hello(''' ''')""") s = source.getstatement(0) @@ -210,12 +226,12 @@ class TestSourceParsingAndCompiling: """) assert len(source) == 7 # check all lineno's that could occur in a traceback - #assert source.getstatementrange(0) == (0, 7) - #assert source.getstatementrange(1) == (1, 5) + # assert source.getstatementrange(0) == (0, 7) + # assert source.getstatementrange(1) == (1, 5) assert source.getstatementrange(2) == (2, 3) assert source.getstatementrange(3) == (3, 4) assert source.getstatementrange(4) == (4, 5) - #assert source.getstatementrange(5) == (0, 7) + # assert source.getstatementrange(5) == (0, 7) assert source.getstatementrange(6) == (6, 7) def test_getstatementrange_bug(self): @@ -257,17 +273,15 @@ class TestSourceParsingAndCompiling: assert getstatement(2, source).lines == source.lines[2:3] assert getstatement(3, source).lines == source.lines[3:4] - @pytest.mark.skipif("sys.version_info < (2,6)") def test_getstatementrange_out_of_bounds_py3(self): source = Source("if xxx:\n from .collections import something") r = source.getstatementrange(1) - assert r == (1,2) + assert r == (1, 2) def test_getstatementrange_with_syntaxerror_issue7(self): source = Source(":") pytest.raises(SyntaxError, lambda: source.getstatementrange(0)) - @pytest.mark.skipif("sys.version_info < (2,6)") def test_compile_to_ast(self): import ast source = Source("x = 4") @@ -282,16 +296,17 @@ class TestSourceParsingAndCompiling: excinfo = pytest.raises(AssertionError, "f(6)") frame = excinfo.traceback[-1].frame stmt = frame.code.fullsource.getstatement(frame.lineno) - #print "block", str(block) + # print "block", str(block) assert str(stmt).strip().startswith('assert') - def test_compilefuncs_and_path_sanity(self): + @pytest.mark.parametrize('name', ['', None, 'my']) + def test_compilefuncs_and_path_sanity(self, name): def check(comp, name): co = comp(self.source, name) if not name: - expected = "codegen %s:%d>" %(mypath, mylineno+2+1) + expected = "codegen %s:%d>" % (mypath, mylineno + 2 + 2) else: - expected = "codegen %r %s:%d>" % (name, mypath, mylineno+2+1) + expected = "codegen %r %s:%d>" % (name, mypath, mylineno + 2 + 2) fn = co.co_filename assert fn.endswith(expected) @@ -300,36 +315,23 @@ class TestSourceParsingAndCompiling: mypath = mycode.path for comp in _pytest._code.compile, _pytest._code.Source.compile: - for name in '', None, 'my': - yield check, comp, name + check(comp, name) def test_offsetless_synerr(self): pytest.raises(SyntaxError, _pytest._code.compile, "lambda a,a: 0", mode='eval') + def test_getstartingblock_singleline(): - class A: + class A(object): def __init__(self, *args): frame = sys._getframe(1) self.source = _pytest._code.Frame(frame).statement x = A('x', 'y') - l = [i for i in x.source.lines if i.strip()] - assert len(l) == 1 + values = [i for i in x.source.lines if i.strip()] + assert len(values) == 1 -def test_getstartingblock_multiline(): - class A: - def __init__(self, *args): - frame = sys._getframe(1) - self.source = _pytest._code.Frame(frame).statement - - x = A('x', - 'y' \ - , - 'z') - - l = [i for i in x.source.lines if i.strip()] - assert len(l) == 4 def test_getline_finally(): def c(): pass @@ -344,6 +346,7 @@ def test_getline_finally(): source = excinfo.traceback[-1].statement assert str(source).strip() == 'c(1)' + def test_getfuncsource_dynamic(): source = """ def f(): @@ -385,8 +388,7 @@ def test_deindent(): lines = deindent(source.splitlines()) assert lines == ['', 'def f():', ' def g():', ' pass', ' '] -@pytest.mark.xfail("sys.version_info[:3] < (2,7,0) or " - "((3,0) <= sys.version_info[:2] < (3,2))") + def test_source_of_class_at_eof_without_newline(tmpdir): # this test fails because the implicit inspect.getsource(A) below # does not return the "x = 1" last line. @@ -400,10 +402,12 @@ def test_source_of_class_at_eof_without_newline(tmpdir): s2 = _pytest._code.Source(tmpdir.join("a.py").pyimport().A) assert str(source).strip() == str(s2).strip() + if True: def x(): pass + def test_getsource_fallback(): from _pytest._code.source import getsource expected = """def x(): @@ -411,6 +415,7 @@ def test_getsource_fallback(): src = getsource(x) assert src == expected + def test_idem_compile_and_getsource(): from _pytest._code.source import getsource expected = "def x(): pass" @@ -418,12 +423,14 @@ def test_idem_compile_and_getsource(): src = getsource(co) assert src == expected + def test_findsource_fallback(): from _pytest._code.source import findsource src, lineno = findsource(x) assert 'test_findsource_simple' in str(src) assert src[lineno] == ' def x():' + def test_findsource(): from _pytest._code.source import findsource co = _pytest._code.compile("""if 1: @@ -450,7 +457,7 @@ def test_getfslineno(): fspath, lineno = getfslineno(f) assert fspath.basename == "test_source.py" - assert lineno == _pytest._code.getrawcode(f).co_firstlineno - 1 # see findsource + assert lineno == _pytest._code.getrawcode(f).co_firstlineno - 1 # see findsource class A(object): pass @@ -462,16 +469,19 @@ def test_getfslineno(): assert lineno == A_lineno assert getfslineno(3) == ("", -1) - class B: + + class B(object): pass B.__name__ = "B2" assert getfslineno(B)[1] == -1 + def test_code_of_object_instance_with_call(): - class A: + class A(object): pass pytest.raises(TypeError, lambda: _pytest._code.Source(A())) - class WithCall: + + class WithCall(object): def __call__(self): pass @@ -490,10 +500,12 @@ def getstatement(lineno, source): ast, start, end = getstatementrange_ast(lineno, source) return source[start:end] + def test_oneline(): source = getstatement(0, "raise ValueError") assert str(source) == "raise ValueError" + def test_comment_and_no_newline_at_end(): from _pytest._code.source import getstatementrange_ast source = Source(['def test_basic_complex():', @@ -502,10 +514,12 @@ def test_comment_and_no_newline_at_end(): ast, start, end = getstatementrange_ast(1, source) assert end == 2 + def test_oneline_and_comment(): source = getstatement(0, "raise ValueError\n#hello") assert str(source) == "raise ValueError" + @pytest.mark.xfail(hasattr(sys, "pypy_version_info"), reason='does not work on pypy') def test_comments(): @@ -521,29 +535,33 @@ def test_comments(): comment 4 """ ''' - for line in range(2,6): + for line in range(2, 6): assert str(getstatement(line, source)) == ' x = 1' - for line in range(6,10): + for line in range(6, 10): assert str(getstatement(line, source)) == ' assert False' assert str(getstatement(10, source)) == '"""' + def test_comment_in_statement(): source = '''test(foo=1, # comment 1 bar=2) ''' - for line in range(1,3): + for line in range(1, 3): assert str(getstatement(line, source)) == \ - 'test(foo=1,\n # comment 1\n bar=2)' + 'test(foo=1,\n # comment 1\n bar=2)' + def test_single_line_else(): source = getstatement(1, "if False: 2\nelse: 3") assert str(source) == "else: 3" + def test_single_line_finally(): source = getstatement(1, "try: 1\nfinally: 3") assert str(source) == "finally: 3" + def test_issue55(): source = ('def round_trip(dinp):\n assert 1 == dinp\n' 'def test_rt():\n round_trip("""\n""")\n') @@ -560,7 +578,8 @@ x = 3 """) assert str(source) == "raise ValueError(\n 23\n)" -class TestTry: + +class TestTry(object): pytestmark = astonly source = """\ try: @@ -587,7 +606,8 @@ else: source = getstatement(5, self.source) assert str(source) == " raise KeyError()" -class TestTryFinally: + +class TestTryFinally(object): source = """\ try: raise ValueError @@ -604,8 +624,7 @@ finally: assert str(source) == " raise IndexError(1)" - -class TestIf: +class TestIf(object): pytestmark = astonly source = """\ if 1: @@ -632,6 +651,7 @@ else: source = getstatement(5, self.source) assert str(source) == " y = 7" + def test_semicolon(): s = """\ hello ; pytest.skip() @@ -639,6 +659,7 @@ hello ; pytest.skip() source = getstatement(0, s) assert str(source) == s.strip() + def test_def_online(): s = """\ def func(): raise ValueError(42) @@ -649,6 +670,7 @@ def something(): source = getstatement(0, s) assert str(source) == "def func(): raise ValueError(42)" + def XXX_test_expression_multiline(): source = """\ something @@ -656,4 +678,3 @@ something '''""" result = getstatement(1, source) assert str(result) == "'''\n'''" - diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/code/test_source_multiline_block.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/code/test_source_multiline_block.py new file mode 100644 index 00000000000..b356d191f0b --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/code/test_source_multiline_block.py @@ -0,0 +1,26 @@ +# flake8: noqa +import sys + +import _pytest._code + + +def test_getstartingblock_multiline(): + """ + This test was originally found in test_source.py, but it depends on the weird + formatting of the ``x = A`` construct seen here and our autopep8 tool can only exclude entire + files (it does not support excluding lines/blocks using the traditional #noqa comment yet, + see hhatto/autopep8#307). It was considered better to just move this single test to its own + file and exclude it from autopep8 than try to complicate things. + """ + class A(object): + def __init__(self, *args): + frame = sys._getframe(1) + self.source = _pytest._code.Frame(frame).statement + + x = A('x', + 'y' + , + 'z') + + values = [i for i in x.source.lines if i.strip()] + assert len(values) == 4 diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/deprecated_test.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/deprecated_test.py new file mode 100644 index 00000000000..11c4ad43cbc --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/deprecated_test.py @@ -0,0 +1,127 @@ +from __future__ import absolute_import, division, print_function +import pytest + + +def test_yield_tests_deprecation(testdir): + testdir.makepyfile(""" + def func1(arg, arg2): + assert arg == arg2 + def test_gen(): + yield "m1", func1, 15, 3*5 + yield "m2", func1, 42, 6*7 + def test_gen2(): + for k in range(10): + yield func1, 1, 1 + """) + result = testdir.runpytest('-ra') + result.stdout.fnmatch_lines([ + '*yield tests are deprecated, and scheduled to be removed in pytest 4.0*', + '*2 passed*', + ]) + assert result.stdout.str().count('yield tests are deprecated') == 2 + + +def test_funcarg_prefix_deprecation(testdir): + testdir.makepyfile(""" + def pytest_funcarg__value(): + return 10 + + def test_funcarg_prefix(value): + assert value == 10 + """) + result = testdir.runpytest('-ra') + result.stdout.fnmatch_lines([ + ('*pytest_funcarg__value: ' + 'declaring fixtures using "pytest_funcarg__" prefix is deprecated ' + 'and scheduled to be removed in pytest 4.0. ' + 'Please remove the prefix and use the @pytest.fixture decorator instead.'), + '*1 passed*', + ]) + + +def test_pytest_setup_cfg_deprecated(testdir): + testdir.makefile('.cfg', setup=''' + [pytest] + addopts = --verbose + ''') + result = testdir.runpytest() + result.stdout.fnmatch_lines(['*pytest*section in setup.cfg files is deprecated*use*tool:pytest*instead*']) + + +def test_str_args_deprecated(tmpdir, testdir): + """Deprecate passing strings to pytest.main(). Scheduled for removal in pytest-4.0.""" + from _pytest.main import EXIT_NOTESTSCOLLECTED + warnings = [] + + class Collect(object): + def pytest_logwarning(self, message): + warnings.append(message) + + ret = pytest.main("%s -x" % tmpdir, plugins=[Collect()]) + testdir.delete_loaded_modules() + msg = ('passing a string to pytest.main() is deprecated, ' + 'pass a list of arguments instead.') + assert msg in warnings + assert ret == EXIT_NOTESTSCOLLECTED + + +def test_getfuncargvalue_is_deprecated(request): + pytest.deprecated_call(request.getfuncargvalue, 'tmpdir') + + +def test_resultlog_is_deprecated(testdir): + result = testdir.runpytest('--help') + result.stdout.fnmatch_lines(['*DEPRECATED path for machine-readable result log*']) + + testdir.makepyfile(''' + def test(): + pass + ''') + result = testdir.runpytest('--result-log=%s' % testdir.tmpdir.join('result.log')) + result.stdout.fnmatch_lines([ + '*--result-log is deprecated and scheduled for removal in pytest 4.0*', + '*See https://docs.pytest.org/*/usage.html#creating-resultlog-format-files for more information*', + ]) + + +@pytest.mark.filterwarnings('always:Metafunc.addcall is deprecated') +def test_metafunc_addcall_deprecated(testdir): + testdir.makepyfile(""" + def pytest_generate_tests(metafunc): + metafunc.addcall({'i': 1}) + metafunc.addcall({'i': 2}) + def test_func(i): + pass + """) + res = testdir.runpytest('-s') + assert res.ret == 0 + res.stdout.fnmatch_lines([ + "*Metafunc.addcall is deprecated*", + "*2 passed, 2 warnings*", + ]) + + +def test_terminal_reporter_writer_attr(pytestconfig): + """Check that TerminalReporter._tw is also available as 'writer' (#2984) + This attribute is planned to be deprecated in 3.4. + """ + try: + import xdist # noqa + pytest.skip('xdist workers disable the terminal reporter plugin') + except ImportError: + pass + terminal_reporter = pytestconfig.pluginmanager.get_plugin('terminalreporter') + assert terminal_reporter.writer is terminal_reporter._tw + + +def test_pytest_catchlog_deprecated(testdir): + testdir.makepyfile(""" + def test_func(pytestconfig): + pytestconfig.pluginmanager.register(None, 'pytest_catchlog') + """) + res = testdir.runpytest() + assert res.ret == 0 + res.stdout.fnmatch_lines([ + "*pytest-catchlog plugin has been merged into the core*", + "*1 passed, 1 warnings*", + ]) diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/freeze/.gitignore b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/freeze/.gitignore new file mode 100644 index 00000000000..490310b6c11 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/freeze/.gitignore @@ -0,0 +1,3 @@ +build/ +dist/ +*.spec \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/freeze/create_executable.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/freeze/create_executable.py new file mode 100644 index 00000000000..f4f6088ef7d --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/freeze/create_executable.py @@ -0,0 +1,12 @@ +""" +Generates an executable with pytest runner embedded using PyInstaller. +""" +if __name__ == '__main__': + import pytest + import subprocess + + hidden = [] + for x in pytest.freeze_includes(): + hidden.extend(['--hidden-import', x]) + args = ['pyinstaller', '--noconfirm'] + hidden + ['runtests_script.py'] + subprocess.check_call(' '.join(args), shell=True) diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/cx_freeze/runtests_script.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/freeze/runtests_script.py similarity index 82% rename from tests/wpt/web-platform-tests/tools/pytest/testing/cx_freeze/runtests_script.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/freeze/runtests_script.py index f2b032d7655..d281601c068 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/cx_freeze/runtests_script.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/freeze/runtests_script.py @@ -1,9 +1,9 @@ -""" -This is the script that is actually frozen into an executable: simply executes -py.test main(). -""" - -if __name__ == '__main__': - import sys - import pytest - sys.exit(pytest.main()) \ No newline at end of file +""" +This is the script that is actually frozen into an executable: simply executes +py.test main(). +""" + +if __name__ == '__main__': + import sys + import pytest + sys.exit(pytest.main()) diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/cx_freeze/tests/test_doctest.txt b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/freeze/tests/test_doctest.txt similarity index 100% rename from tests/wpt/web-platform-tests/tools/pytest/testing/cx_freeze/tests/test_doctest.txt rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/freeze/tests/test_doctest.txt diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/cx_freeze/tests/test_trivial.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/freeze/tests/test_trivial.py similarity index 65% rename from tests/wpt/web-platform-tests/tools/pytest/testing/cx_freeze/tests/test_trivial.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/freeze/tests/test_trivial.py index d8a572baaed..45622b850bb 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/cx_freeze/tests/test_trivial.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/freeze/tests/test_trivial.py @@ -1,6 +1,7 @@ - -def test_upper(): - assert 'foo'.upper() == 'FOO' - -def test_lower(): - assert 'FOO'.lower() == 'foo' \ No newline at end of file + +def test_upper(): + assert 'foo'.upper() == 'FOO' + + +def test_lower(): + assert 'FOO'.lower() == 'foo' diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/freeze/tox_run.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/freeze/tox_run.py new file mode 100644 index 00000000000..3fc38804095 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/freeze/tox_run.py @@ -0,0 +1,12 @@ +""" +Called by tox.ini: uses the generated executable to run the tests in ./tests/ +directory. +""" +if __name__ == '__main__': + import os + import sys + + executable = os.path.join(os.getcwd(), 'dist', 'runtests_script', 'runtests_script') + if sys.platform.startswith('win'): + executable += '.exe' + sys.exit(os.system('%s tests' % executable)) diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/logging/test_fixture.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/logging/test_fixture.py new file mode 100644 index 00000000000..c27b31137ff --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/logging/test_fixture.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +import logging + + +logger = logging.getLogger(__name__) +sublogger = logging.getLogger(__name__ + '.baz') + + +def test_fixture_help(testdir): + result = testdir.runpytest('--fixtures') + result.stdout.fnmatch_lines(['*caplog*']) + + +def test_change_level(caplog): + caplog.set_level(logging.INFO) + logger.debug('handler DEBUG level') + logger.info('handler INFO level') + + caplog.set_level(logging.CRITICAL, logger=sublogger.name) + sublogger.warning('logger WARNING level') + sublogger.critical('logger CRITICAL level') + + assert 'DEBUG' not in caplog.text + assert 'INFO' in caplog.text + assert 'WARNING' not in caplog.text + assert 'CRITICAL' in caplog.text + + +def test_with_statement(caplog): + with caplog.at_level(logging.INFO): + logger.debug('handler DEBUG level') + logger.info('handler INFO level') + + with caplog.at_level(logging.CRITICAL, logger=sublogger.name): + sublogger.warning('logger WARNING level') + sublogger.critical('logger CRITICAL level') + + assert 'DEBUG' not in caplog.text + assert 'INFO' in caplog.text + assert 'WARNING' not in caplog.text + assert 'CRITICAL' in caplog.text + + +def test_log_access(caplog): + logger.info('boo %s', 'arg') + assert caplog.records[0].levelname == 'INFO' + assert caplog.records[0].msg == 'boo %s' + assert 'boo arg' in caplog.text + + +def test_record_tuples(caplog): + logger.info('boo %s', 'arg') + + assert caplog.record_tuples == [ + (__name__, logging.INFO, 'boo arg'), + ] + + +def test_unicode(caplog): + logger.info(u'bū') + assert caplog.records[0].levelname == 'INFO' + assert caplog.records[0].msg == u'bū' + assert u'bū' in caplog.text + + +def test_clear(caplog): + logger.info(u'bū') + assert len(caplog.records) + caplog.clear() + assert not len(caplog.records) diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/logging/test_reporting.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/logging/test_reporting.py new file mode 100644 index 00000000000..c02ee217227 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/logging/test_reporting.py @@ -0,0 +1,398 @@ +# -*- coding: utf-8 -*- +import os +import pytest + + +def test_nothing_logged(testdir): + testdir.makepyfile(''' + import sys + + def test_foo(): + sys.stdout.write('text going to stdout') + sys.stderr.write('text going to stderr') + assert False + ''') + result = testdir.runpytest() + assert result.ret == 1 + result.stdout.fnmatch_lines(['*- Captured stdout call -*', + 'text going to stdout']) + result.stdout.fnmatch_lines(['*- Captured stderr call -*', + 'text going to stderr']) + with pytest.raises(pytest.fail.Exception): + result.stdout.fnmatch_lines(['*- Captured *log call -*']) + + +def test_messages_logged(testdir): + testdir.makepyfile(''' + import sys + import logging + + logger = logging.getLogger(__name__) + + def test_foo(): + sys.stdout.write('text going to stdout') + sys.stderr.write('text going to stderr') + logger.info('text going to logger') + assert False + ''') + result = testdir.runpytest() + assert result.ret == 1 + result.stdout.fnmatch_lines(['*- Captured *log call -*', + '*text going to logger*']) + result.stdout.fnmatch_lines(['*- Captured stdout call -*', + 'text going to stdout']) + result.stdout.fnmatch_lines(['*- Captured stderr call -*', + 'text going to stderr']) + + +def test_setup_logging(testdir): + testdir.makepyfile(''' + import logging + + logger = logging.getLogger(__name__) + + def setup_function(function): + logger.info('text going to logger from setup') + + def test_foo(): + logger.info('text going to logger from call') + assert False + ''') + result = testdir.runpytest() + assert result.ret == 1 + result.stdout.fnmatch_lines(['*- Captured *log setup -*', + '*text going to logger from setup*', + '*- Captured *log call -*', + '*text going to logger from call*']) + + +def test_teardown_logging(testdir): + testdir.makepyfile(''' + import logging + + logger = logging.getLogger(__name__) + + def test_foo(): + logger.info('text going to logger from call') + + def teardown_function(function): + logger.info('text going to logger from teardown') + assert False + ''') + result = testdir.runpytest() + assert result.ret == 1 + result.stdout.fnmatch_lines(['*- Captured *log call -*', + '*text going to logger from call*', + '*- Captured *log teardown -*', + '*text going to logger from teardown*']) + + +def test_disable_log_capturing(testdir): + testdir.makepyfile(''' + import sys + import logging + + logger = logging.getLogger(__name__) + + def test_foo(): + sys.stdout.write('text going to stdout') + logger.warning('catch me if you can!') + sys.stderr.write('text going to stderr') + assert False + ''') + result = testdir.runpytest('--no-print-logs') + print(result.stdout) + assert result.ret == 1 + result.stdout.fnmatch_lines(['*- Captured stdout call -*', + 'text going to stdout']) + result.stdout.fnmatch_lines(['*- Captured stderr call -*', + 'text going to stderr']) + with pytest.raises(pytest.fail.Exception): + result.stdout.fnmatch_lines(['*- Captured *log call -*']) + + +def test_disable_log_capturing_ini(testdir): + testdir.makeini( + ''' + [pytest] + log_print=False + ''' + ) + testdir.makepyfile(''' + import sys + import logging + + logger = logging.getLogger(__name__) + + def test_foo(): + sys.stdout.write('text going to stdout') + logger.warning('catch me if you can!') + sys.stderr.write('text going to stderr') + assert False + ''') + result = testdir.runpytest() + print(result.stdout) + assert result.ret == 1 + result.stdout.fnmatch_lines(['*- Captured stdout call -*', + 'text going to stdout']) + result.stdout.fnmatch_lines(['*- Captured stderr call -*', + 'text going to stderr']) + with pytest.raises(pytest.fail.Exception): + result.stdout.fnmatch_lines(['*- Captured *log call -*']) + + +def test_log_cli_default_level(testdir): + # Default log file level + testdir.makepyfile(''' + import pytest + import logging + def test_log_cli(request): + plugin = request.config.pluginmanager.getplugin('logging-plugin') + assert plugin.log_cli_handler.level == logging.WARNING + logging.getLogger('catchlog').info("This log message won't be shown") + logging.getLogger('catchlog').warning("This log message will be shown") + print('PASSED') + ''') + + result = testdir.runpytest('-s') + + # fnmatch_lines does an assertion internally + result.stdout.fnmatch_lines([ + 'test_log_cli_default_level.py PASSED', + ]) + result.stderr.fnmatch_lines([ + "* This log message will be shown" + ]) + for line in result.errlines: + try: + assert "This log message won't be shown" in line + pytest.fail("A log message was shown and it shouldn't have been") + except AssertionError: + continue + + # make sure that that we get a '0' exit code for the testsuite + assert result.ret == 0 + + +def test_log_cli_level(testdir): + # Default log file level + testdir.makepyfile(''' + import pytest + import logging + def test_log_cli(request): + plugin = request.config.pluginmanager.getplugin('logging-plugin') + assert plugin.log_cli_handler.level == logging.INFO + logging.getLogger('catchlog').debug("This log message won't be shown") + logging.getLogger('catchlog').info("This log message will be shown") + print('PASSED') + ''') + + result = testdir.runpytest('-s', '--log-cli-level=INFO') + + # fnmatch_lines does an assertion internally + result.stdout.fnmatch_lines([ + 'test_log_cli_level.py PASSED', + ]) + result.stderr.fnmatch_lines([ + "* This log message will be shown" + ]) + for line in result.errlines: + try: + assert "This log message won't be shown" in line + pytest.fail("A log message was shown and it shouldn't have been") + except AssertionError: + continue + + # make sure that that we get a '0' exit code for the testsuite + assert result.ret == 0 + + result = testdir.runpytest('-s', '--log-level=INFO') + + # fnmatch_lines does an assertion internally + result.stdout.fnmatch_lines([ + 'test_log_cli_level.py PASSED', + ]) + result.stderr.fnmatch_lines([ + "* This log message will be shown" + ]) + for line in result.errlines: + try: + assert "This log message won't be shown" in line + pytest.fail("A log message was shown and it shouldn't have been") + except AssertionError: + continue + + # make sure that that we get a '0' exit code for the testsuite + assert result.ret == 0 + + +def test_log_cli_ini_level(testdir): + testdir.makeini( + """ + [pytest] + log_cli_level = INFO + """) + testdir.makepyfile(''' + import pytest + import logging + def test_log_cli(request): + plugin = request.config.pluginmanager.getplugin('logging-plugin') + assert plugin.log_cli_handler.level == logging.INFO + logging.getLogger('catchlog').debug("This log message won't be shown") + logging.getLogger('catchlog').info("This log message will be shown") + print('PASSED') + ''') + + result = testdir.runpytest('-s') + + # fnmatch_lines does an assertion internally + result.stdout.fnmatch_lines([ + 'test_log_cli_ini_level.py PASSED', + ]) + result.stderr.fnmatch_lines([ + "* This log message will be shown" + ]) + for line in result.errlines: + try: + assert "This log message won't be shown" in line + pytest.fail("A log message was shown and it shouldn't have been") + except AssertionError: + continue + + # make sure that that we get a '0' exit code for the testsuite + assert result.ret == 0 + + +def test_log_file_cli(testdir): + # Default log file level + testdir.makepyfile(''' + import pytest + import logging + def test_log_file(request): + plugin = request.config.pluginmanager.getplugin('logging-plugin') + assert plugin.log_file_handler.level == logging.WARNING + logging.getLogger('catchlog').info("This log message won't be shown") + logging.getLogger('catchlog').warning("This log message will be shown") + print('PASSED') + ''') + + log_file = testdir.tmpdir.join('pytest.log').strpath + + result = testdir.runpytest('-s', '--log-file={0}'.format(log_file)) + + # fnmatch_lines does an assertion internally + result.stdout.fnmatch_lines([ + 'test_log_file_cli.py PASSED', + ]) + + # make sure that that we get a '0' exit code for the testsuite + assert result.ret == 0 + assert os.path.isfile(log_file) + with open(log_file) as rfh: + contents = rfh.read() + assert "This log message will be shown" in contents + assert "This log message won't be shown" not in contents + + +def test_log_file_cli_level(testdir): + # Default log file level + testdir.makepyfile(''' + import pytest + import logging + def test_log_file(request): + plugin = request.config.pluginmanager.getplugin('logging-plugin') + assert plugin.log_file_handler.level == logging.INFO + logging.getLogger('catchlog').debug("This log message won't be shown") + logging.getLogger('catchlog').info("This log message will be shown") + print('PASSED') + ''') + + log_file = testdir.tmpdir.join('pytest.log').strpath + + result = testdir.runpytest('-s', + '--log-file={0}'.format(log_file), + '--log-file-level=INFO') + + # fnmatch_lines does an assertion internally + result.stdout.fnmatch_lines([ + 'test_log_file_cli_level.py PASSED', + ]) + + # make sure that that we get a '0' exit code for the testsuite + assert result.ret == 0 + assert os.path.isfile(log_file) + with open(log_file) as rfh: + contents = rfh.read() + assert "This log message will be shown" in contents + assert "This log message won't be shown" not in contents + + +def test_log_file_ini(testdir): + log_file = testdir.tmpdir.join('pytest.log').strpath + + testdir.makeini( + """ + [pytest] + log_file={0} + """.format(log_file)) + testdir.makepyfile(''' + import pytest + import logging + def test_log_file(request): + plugin = request.config.pluginmanager.getplugin('logging-plugin') + assert plugin.log_file_handler.level == logging.WARNING + logging.getLogger('catchlog').info("This log message won't be shown") + logging.getLogger('catchlog').warning("This log message will be shown") + print('PASSED') + ''') + + result = testdir.runpytest('-s') + + # fnmatch_lines does an assertion internally + result.stdout.fnmatch_lines([ + 'test_log_file_ini.py PASSED', + ]) + + # make sure that that we get a '0' exit code for the testsuite + assert result.ret == 0 + assert os.path.isfile(log_file) + with open(log_file) as rfh: + contents = rfh.read() + assert "This log message will be shown" in contents + assert "This log message won't be shown" not in contents + + +def test_log_file_ini_level(testdir): + log_file = testdir.tmpdir.join('pytest.log').strpath + + testdir.makeini( + """ + [pytest] + log_file={0} + log_file_level = INFO + """.format(log_file)) + testdir.makepyfile(''' + import pytest + import logging + def test_log_file(request): + plugin = request.config.pluginmanager.getplugin('logging-plugin') + assert plugin.log_file_handler.level == logging.INFO + logging.getLogger('catchlog').debug("This log message won't be shown") + logging.getLogger('catchlog').info("This log message will be shown") + print('PASSED') + ''') + + result = testdir.runpytest('-s') + + # fnmatch_lines does an assertion internally + result.stdout.fnmatch_lines([ + 'test_log_file_ini_level.py PASSED', + ]) + + # make sure that that we get a '0' exit code for the testsuite + assert result.ret == 0 + assert os.path.isfile(log_file) + with open(log_file) as rfh: + contents = rfh.read() + assert "This log message will be shown" in contents + assert "This log message won't be shown" not in contents diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/approx.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/approx.py new file mode 100644 index 00000000000..300e1ce86f7 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/approx.py @@ -0,0 +1,392 @@ +# encoding: utf-8 +import operator +import sys +import pytest +import doctest + +from pytest import approx +from operator import eq, ne +from decimal import Decimal +from fractions import Fraction +inf, nan = float('inf'), float('nan') + + +class MyDocTestRunner(doctest.DocTestRunner): + + def __init__(self): + doctest.DocTestRunner.__init__(self) + + def report_failure(self, out, test, example, got): + raise AssertionError("'{}' evaluates to '{}', not '{}'".format( + example.source.strip(), got.strip(), example.want.strip())) + + +class TestApprox(object): + + def test_repr_string(self): + plus_minus = u'\u00b1' if sys.version_info[0] > 2 else u'+-' + tol1, tol2, infr = '1.0e-06', '2.0e-06', 'inf' + assert repr(approx(1.0)) == '1.0 {pm} {tol1}'.format(pm=plus_minus, tol1=tol1) + assert repr(approx([1.0, 2.0])) == 'approx([1.0 {pm} {tol1}, 2.0 {pm} {tol2}])'.format( + pm=plus_minus, tol1=tol1, tol2=tol2) + assert repr(approx((1.0, 2.0))) == 'approx((1.0 {pm} {tol1}, 2.0 {pm} {tol2}))'.format( + pm=plus_minus, tol1=tol1, tol2=tol2) + assert repr(approx(inf)) == 'inf' + assert repr(approx(1.0, rel=nan)) == '1.0 {pm} ???'.format(pm=plus_minus) + assert repr(approx(1.0, rel=inf)) == '1.0 {pm} {infr}'.format(pm=plus_minus, infr=infr) + assert repr(approx(1.0j, rel=inf)) == '1j' + + # Dictionaries aren't ordered, so we need to check both orders. + assert repr(approx({'a': 1.0, 'b': 2.0})) in ( + "approx({{'a': 1.0 {pm} {tol1}, 'b': 2.0 {pm} {tol2}}})".format(pm=plus_minus, tol1=tol1, tol2=tol2), + "approx({{'b': 2.0 {pm} {tol2}, 'a': 1.0 {pm} {tol1}}})".format(pm=plus_minus, tol1=tol1, tol2=tol2), + ) + + def test_operator_overloading(self): + assert 1 == approx(1, rel=1e-6, abs=1e-12) + assert not (1 != approx(1, rel=1e-6, abs=1e-12)) + assert 10 != approx(1, rel=1e-6, abs=1e-12) + assert not (10 == approx(1, rel=1e-6, abs=1e-12)) + + def test_exactly_equal(self): + examples = [ + (2.0, 2.0), + (0.1e200, 0.1e200), + (1.123e-300, 1.123e-300), + (12345, 12345.0), + (0.0, -0.0), + (345678, 345678), + (Decimal('1.0001'), Decimal('1.0001')), + (Fraction(1, 3), Fraction(-1, -3)), + ] + for a, x in examples: + assert a == approx(x) + + def test_opposite_sign(self): + examples = [ + (eq, 1e-100, -1e-100), + (ne, 1e100, -1e100), + ] + for op, a, x in examples: + assert op(a, approx(x)) + + def test_zero_tolerance(self): + within_1e10 = [ + (1.1e-100, 1e-100), + (-1.1e-100, -1e-100), + ] + for a, x in within_1e10: + assert x == approx(x, rel=0.0, abs=0.0) + assert a != approx(x, rel=0.0, abs=0.0) + assert a == approx(x, rel=0.0, abs=5e-101) + assert a != approx(x, rel=0.0, abs=5e-102) + assert a == approx(x, rel=5e-1, abs=0.0) + assert a != approx(x, rel=5e-2, abs=0.0) + + def test_negative_tolerance(self): + # Negative tolerances are not allowed. + illegal_kwargs = [ + dict(rel=-1e100), + dict(abs=-1e100), + dict(rel=1e100, abs=-1e100), + dict(rel=-1e100, abs=1e100), + dict(rel=-1e100, abs=-1e100), + ] + for kwargs in illegal_kwargs: + with pytest.raises(ValueError): + 1.1 == approx(1, **kwargs) + + def test_inf_tolerance(self): + # Everything should be equal if the tolerance is infinite. + large_diffs = [ + (1, 1000), + (1e-50, 1e50), + (-1.0, -1e300), + (0.0, 10), + ] + for a, x in large_diffs: + assert a != approx(x, rel=0.0, abs=0.0) + assert a == approx(x, rel=inf, abs=0.0) + assert a == approx(x, rel=0.0, abs=inf) + assert a == approx(x, rel=inf, abs=inf) + + def test_inf_tolerance_expecting_zero(self): + # If the relative tolerance is zero but the expected value is infinite, + # the actual tolerance is a NaN, which should be an error. + illegal_kwargs = [ + dict(rel=inf, abs=0.0), + dict(rel=inf, abs=inf), + ] + for kwargs in illegal_kwargs: + with pytest.raises(ValueError): + 1 == approx(0, **kwargs) + + def test_nan_tolerance(self): + illegal_kwargs = [ + dict(rel=nan), + dict(abs=nan), + dict(rel=nan, abs=nan), + ] + for kwargs in illegal_kwargs: + with pytest.raises(ValueError): + 1.1 == approx(1, **kwargs) + + def test_reasonable_defaults(self): + # Whatever the defaults are, they should work for numbers close to 1 + # than have a small amount of floating-point error. + assert 0.1 + 0.2 == approx(0.3) + + def test_default_tolerances(self): + # This tests the defaults as they are currently set. If you change the + # defaults, this test will fail but you should feel free to change it. + # None of the other tests (except the doctests) should be affected by + # the choice of defaults. + examples = [ + # Relative tolerance used. + (eq, 1e100 + 1e94, 1e100), + (ne, 1e100 + 2e94, 1e100), + (eq, 1e0 + 1e-6, 1e0), + (ne, 1e0 + 2e-6, 1e0), + # Absolute tolerance used. + (eq, 1e-100, + 1e-106), + (eq, 1e-100, + 2e-106), + (eq, 1e-100, 0), + ] + for op, a, x in examples: + assert op(a, approx(x)) + + def test_custom_tolerances(self): + assert 1e8 + 1e0 == approx(1e8, rel=5e-8, abs=5e0) + assert 1e8 + 1e0 == approx(1e8, rel=5e-9, abs=5e0) + assert 1e8 + 1e0 == approx(1e8, rel=5e-8, abs=5e-1) + assert 1e8 + 1e0 != approx(1e8, rel=5e-9, abs=5e-1) + + assert 1e0 + 1e-8 == approx(1e0, rel=5e-8, abs=5e-8) + assert 1e0 + 1e-8 == approx(1e0, rel=5e-9, abs=5e-8) + assert 1e0 + 1e-8 == approx(1e0, rel=5e-8, abs=5e-9) + assert 1e0 + 1e-8 != approx(1e0, rel=5e-9, abs=5e-9) + + assert 1e-8 + 1e-16 == approx(1e-8, rel=5e-8, abs=5e-16) + assert 1e-8 + 1e-16 == approx(1e-8, rel=5e-9, abs=5e-16) + assert 1e-8 + 1e-16 == approx(1e-8, rel=5e-8, abs=5e-17) + assert 1e-8 + 1e-16 != approx(1e-8, rel=5e-9, abs=5e-17) + + def test_relative_tolerance(self): + within_1e8_rel = [ + (1e8 + 1e0, 1e8), + (1e0 + 1e-8, 1e0), + (1e-8 + 1e-16, 1e-8), + ] + for a, x in within_1e8_rel: + assert a == approx(x, rel=5e-8, abs=0.0) + assert a != approx(x, rel=5e-9, abs=0.0) + + def test_absolute_tolerance(self): + within_1e8_abs = [ + (1e8 + 9e-9, 1e8), + (1e0 + 9e-9, 1e0), + (1e-8 + 9e-9, 1e-8), + ] + for a, x in within_1e8_abs: + assert a == approx(x, rel=0, abs=5e-8) + assert a != approx(x, rel=0, abs=5e-9) + + def test_expecting_zero(self): + examples = [ + (ne, 1e-6, 0.0), + (ne, -1e-6, 0.0), + (eq, 1e-12, 0.0), + (eq, -1e-12, 0.0), + (ne, 2e-12, 0.0), + (ne, -2e-12, 0.0), + (ne, inf, 0.0), + (ne, nan, 0.0), + ] + for op, a, x in examples: + assert op(a, approx(x, rel=0.0, abs=1e-12)) + assert op(a, approx(x, rel=1e-6, abs=1e-12)) + + def test_expecting_inf(self): + examples = [ + (eq, inf, inf), + (eq, -inf, -inf), + (ne, inf, -inf), + (ne, 0.0, inf), + (ne, nan, inf), + ] + for op, a, x in examples: + assert op(a, approx(x)) + + def test_expecting_nan(self): + examples = [ + (eq, nan, nan), + (eq, -nan, -nan), + (eq, nan, -nan), + (ne, 0.0, nan), + (ne, inf, nan), + ] + for op, a, x in examples: + # Nothing is equal to NaN by default. + assert a != approx(x) + + # If ``nan_ok=True``, then NaN is equal to NaN. + assert op(a, approx(x, nan_ok=True)) + + def test_int(self): + within_1e6 = [ + (1000001, 1000000), + (-1000001, -1000000), + ] + for a, x in within_1e6: + assert a == approx(x, rel=5e-6, abs=0) + assert a != approx(x, rel=5e-7, abs=0) + assert approx(x, rel=5e-6, abs=0) == a + assert approx(x, rel=5e-7, abs=0) != a + + def test_decimal(self): + within_1e6 = [ + (Decimal('1.000001'), Decimal('1.0')), + (Decimal('-1.000001'), Decimal('-1.0')), + ] + for a, x in within_1e6: + assert a == approx(x, rel=Decimal('5e-6'), abs=0) + assert a != approx(x, rel=Decimal('5e-7'), abs=0) + assert approx(x, rel=Decimal('5e-6'), abs=0) == a + assert approx(x, rel=Decimal('5e-7'), abs=0) != a + + def test_fraction(self): + within_1e6 = [ + (1 + Fraction(1, 1000000), Fraction(1)), + (-1 - Fraction(-1, 1000000), Fraction(-1)), + ] + for a, x in within_1e6: + assert a == approx(x, rel=5e-6, abs=0) + assert a != approx(x, rel=5e-7, abs=0) + assert approx(x, rel=5e-6, abs=0) == a + assert approx(x, rel=5e-7, abs=0) != a + + def test_complex(self): + within_1e6 = [ + (1.000001 + 1.0j, 1.0 + 1.0j), + (1.0 + 1.000001j, 1.0 + 1.0j), + (-1.000001 + 1.0j, -1.0 + 1.0j), + (1.0 - 1.000001j, 1.0 - 1.0j), + ] + for a, x in within_1e6: + assert a == approx(x, rel=5e-6, abs=0) + assert a != approx(x, rel=5e-7, abs=0) + assert approx(x, rel=5e-6, abs=0) == a + assert approx(x, rel=5e-7, abs=0) != a + + def test_list(self): + actual = [1 + 1e-7, 2 + 1e-8] + expected = [1, 2] + + # Return false if any element is outside the tolerance. + assert actual == approx(expected, rel=5e-7, abs=0) + assert actual != approx(expected, rel=5e-8, abs=0) + assert approx(expected, rel=5e-7, abs=0) == actual + assert approx(expected, rel=5e-8, abs=0) != actual + + def test_list_wrong_len(self): + assert [1, 2] != approx([1]) + assert [1, 2] != approx([1, 2, 3]) + + def test_tuple(self): + actual = (1 + 1e-7, 2 + 1e-8) + expected = (1, 2) + + # Return false if any element is outside the tolerance. + assert actual == approx(expected, rel=5e-7, abs=0) + assert actual != approx(expected, rel=5e-8, abs=0) + assert approx(expected, rel=5e-7, abs=0) == actual + assert approx(expected, rel=5e-8, abs=0) != actual + + def test_tuple_wrong_len(self): + assert (1, 2) != approx((1,)) + assert (1, 2) != approx((1, 2, 3)) + + def test_dict(self): + actual = {'a': 1 + 1e-7, 'b': 2 + 1e-8} + # Dictionaries became ordered in python3.6, so switch up the order here + # to make sure it doesn't matter. + expected = {'b': 2, 'a': 1} + + # Return false if any element is outside the tolerance. + assert actual == approx(expected, rel=5e-7, abs=0) + assert actual != approx(expected, rel=5e-8, abs=0) + assert approx(expected, rel=5e-7, abs=0) == actual + assert approx(expected, rel=5e-8, abs=0) != actual + + def test_dict_wrong_len(self): + assert {'a': 1, 'b': 2} != approx({'a': 1}) + assert {'a': 1, 'b': 2} != approx({'a': 1, 'c': 2}) + assert {'a': 1, 'b': 2} != approx({'a': 1, 'b': 2, 'c': 3}) + + def test_numpy_array(self): + np = pytest.importorskip('numpy') + + actual = np.array([1 + 1e-7, 2 + 1e-8]) + expected = np.array([1, 2]) + + # Return false if any element is outside the tolerance. + assert actual == approx(expected, rel=5e-7, abs=0) + assert actual != approx(expected, rel=5e-8, abs=0) + assert approx(expected, rel=5e-7, abs=0) == expected + assert approx(expected, rel=5e-8, abs=0) != actual + + # Should be able to compare lists with numpy arrays. + assert list(actual) == approx(expected, rel=5e-7, abs=0) + assert list(actual) != approx(expected, rel=5e-8, abs=0) + assert actual == approx(list(expected), rel=5e-7, abs=0) + assert actual != approx(list(expected), rel=5e-8, abs=0) + + def test_numpy_array_wrong_shape(self): + np = pytest.importorskip('numpy') + + a12 = np.array([[1, 2]]) + a21 = np.array([[1], [2]]) + + assert a12 != approx(a21) + assert a21 != approx(a12) + + def test_doctests(self): + parser = doctest.DocTestParser() + test = parser.get_doctest( + approx.__doc__, + {'approx': approx}, + approx.__name__, + None, None, + ) + runner = MyDocTestRunner() + runner.run(test) + + def test_unicode_plus_minus(self, testdir): + """ + Comparing approx instances inside lists should not produce an error in the detailed diff. + Integration test for issue #2111. + """ + testdir.makepyfile(""" + import pytest + def test_foo(): + assert [3] == [pytest.approx(4)] + """) + expected = '4.0e-06' + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + '*At index 0 diff: 3 != 4 * {0}'.format(expected), + '=* 1 failed in *=', + ]) + + @pytest.mark.parametrize('op', [ + pytest.param(operator.le, id='<='), + pytest.param(operator.lt, id='<'), + pytest.param(operator.ge, id='>='), + pytest.param(operator.gt, id='>'), + ]) + def test_comparison_operator_type_error(self, op): + """ + pytest.approx should raise TypeError for operators other than == and != (#2003). + """ + with pytest.raises(TypeError): + op(1, approx(1, rel=1e-6, abs=1e-12)) diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/python/collect.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/collect.py similarity index 80% rename from tests/wpt/web-platform-tests/tools/pytest/testing/python/collect.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/collect.py index 22433da7716..16c2154b8c1 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/python/collect.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/collect.py @@ -1,18 +1,24 @@ # -*- coding: utf-8 -*- +import os import sys from textwrap import dedent import _pytest._code import py import pytest -from _pytest.main import EXIT_NOTESTSCOLLECTED +from _pytest.main import ( + Collector, + EXIT_NOTESTSCOLLECTED +) -class TestModule: +ignore_parametrized_marks = pytest.mark.filterwarnings('ignore:Applying marks directly to parameters') + + +class TestModule(object): def test_failing_import(self, testdir): modcol = testdir.getmodulecol("import alksdjalskdjalkjals") - pytest.raises(ImportError, modcol.collect) - pytest.raises(ImportError, modcol.collect) + pytest.raises(Collector.CollectError, modcol.collect) def test_import_duplicate(self, testdir): a = testdir.mkdir("a") @@ -60,17 +66,75 @@ class TestModule: modcol = testdir.getmodulecol("pytest_plugins='xasdlkj',") pytest.raises(ImportError, lambda: modcol.obj) -class TestClass: + def test_invalid_test_module_name(self, testdir): + a = testdir.mkdir('a') + a.ensure('test_one.part1.py') + result = testdir.runpytest("-rw") + result.stdout.fnmatch_lines([ + "ImportError while importing test module*test_one.part1*", + "Hint: make sure your test modules/packages have valid Python names.", + ]) + + @pytest.mark.parametrize('verbose', [0, 1, 2]) + def test_show_traceback_import_error(self, testdir, verbose): + """Import errors when collecting modules should display the traceback (#1976). + + With low verbosity we omit pytest and internal modules, otherwise show all traceback entries. + """ + testdir.makepyfile( + foo_traceback_import_error=""" + from bar_traceback_import_error import NOT_AVAILABLE + """, + bar_traceback_import_error="", + ) + testdir.makepyfile(""" + import foo_traceback_import_error + """) + args = ('-v',) * verbose + result = testdir.runpytest(*args) + result.stdout.fnmatch_lines([ + "ImportError while importing test module*", + "Traceback:", + "*from bar_traceback_import_error import NOT_AVAILABLE", + "*cannot import name *NOT_AVAILABLE*", + ]) + assert result.ret == 2 + + stdout = result.stdout.str() + for name in ('_pytest', os.path.join('py', '_path')): + if verbose == 2: + assert name in stdout + else: + assert name not in stdout + + def test_show_traceback_import_error_unicode(self, testdir): + """Check test modules collected which raise ImportError with unicode messages + are handled properly (#2336). + """ + testdir.makepyfile(u""" + # -*- coding: utf-8 -*- + raise ImportError(u'Something bad happened ☺') + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + "ImportError while importing test module*", + "Traceback:", + "*raise ImportError*Something bad happened*", + ]) + assert result.ret == 2 + + +class TestClass(object): def test_class_with_init_warning(self, testdir): testdir.makepyfile(""" - class TestClass1: + class TestClass1(object): def __init__(self): pass """) result = testdir.runpytest("-rw") - result.stdout.fnmatch_lines_random(""" - WC1*test_class_with_init_warning.py*__init__* - """) + result.stdout.fnmatch_lines([ + "*cannot collect test class 'TestClass1' because it has a __init__ constructor", + ]) def test_class_subclassobject(self, testdir): testdir.getmodulecol(""" @@ -82,9 +146,32 @@ class TestClass: "*collected 0*", ]) + def test_static_method(self, testdir): + """Support for collecting staticmethod tests (#2528, #2699)""" + testdir.getmodulecol(""" + import pytest + class Test(object): + @staticmethod + def test_something(): + pass + + @pytest.fixture + def fix(self): + return 1 + + @staticmethod + def test_fix(fix): + assert fix == 1 + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + "*collected 2 items*", + "*2 passed in*", + ]) + def test_setup_teardown_class_as_classmethod(self, testdir): testdir.makepyfile(test_mod1=""" - class TestClassMethod: + class TestClassMethod(object): @classmethod def setup_class(cls): pass @@ -109,8 +196,30 @@ class TestClass: colitems = modcol.collect() assert len(colitems) == 0 + def test_issue1579_namedtuple(self, testdir): + testdir.makepyfile(""" + import collections -class TestGenerator: + TestCase = collections.namedtuple('TestCase', ['a']) + """) + result = testdir.runpytest('-rw') + result.stdout.fnmatch_lines( + "*cannot collect test class 'TestCase' " + "because it has a __new__ constructor*" + ) + + def test_issue2234_property(self, testdir): + testdir.makepyfile(""" + class TestCase(object): + @property + def prop(self): + raise NotImplementedError() + """) + result = testdir.runpytest() + assert result.ret == EXIT_NOTESTSCOLLECTED + + +class TestGenerator(object): def test_generative_functions(self, testdir): modcol = testdir.getmodulecol(""" def func1(arg, arg2): @@ -135,7 +244,7 @@ class TestGenerator: modcol = testdir.getmodulecol(""" def func1(arg, arg2): assert arg == arg2 - class TestGenMethods: + class TestGenMethods(object): def test_gen(self): yield func1, 17, 3*5 yield func1, 42, 6*7 @@ -189,7 +298,7 @@ class TestGenerator: modcol = testdir.getmodulecol(""" def func1(arg, arg2): assert arg == arg2 - class TestGenMethods: + class TestGenMethods(object): def test_gen(self): yield "m1", func1, 17, 3*5 yield "m2", func1, 42, 6*7 @@ -207,6 +316,7 @@ class TestGenerator: def test_order_of_execution_generator_same_codeline(self, testdir, tmpdir): o = testdir.makepyfile(""" + from __future__ import print_function def test_generative_order_of_execution(): import py, pytest test_list = [] @@ -216,8 +326,8 @@ class TestGenerator: test_list.append(item) def assert_order_of_execution(): - py.builtin.print_('expected order', expected_list) - py.builtin.print_('but got ', test_list) + print('expected order', expected_list) + print('but got ', test_list) assert test_list == expected_list for i in expected_list: @@ -231,6 +341,7 @@ class TestGenerator: def test_order_of_execution_generator_different_codeline(self, testdir): o = testdir.makepyfile(""" + from __future__ import print_function def test_generative_tests_different_codeline(): import py, pytest test_list = [] @@ -246,8 +357,8 @@ class TestGenerator: test_list.append(0) def assert_order_of_execution(): - py.builtin.print_('expected order', expected_list) - py.builtin.print_('but got ', test_list) + print('expected order', expected_list) + print('but got ', test_list) assert test_list == expected_list yield list_append_0 @@ -269,7 +380,7 @@ class TestGenerator: # has been used during collection. o = testdir.makepyfile(""" setuplist = [] - class TestClass: + class TestClass(object): def setup_method(self, func): #print "setup_method", self, func setuplist.append(self) @@ -303,7 +414,7 @@ class TestGenerator: assert not skipped and not failed -class TestFunction: +class TestFunction(object): def test_getmodulecollector(self, testdir): item = testdir.getitem("def test_func(): pass") modcol = item.getparent(pytest.Module) @@ -312,7 +423,7 @@ class TestFunction: def test_function_as_object_instance_ignored(self, testdir): testdir.makepyfile(""" - class A: + class A(object): def __call__(self, tmpdir): 0/0 @@ -322,19 +433,22 @@ class TestFunction: reprec.assertoutcome() def test_function_equality(self, testdir, tmpdir): - from _pytest.python import FixtureManager + from _pytest.fixtures import FixtureManager config = testdir.parseconfigure() session = testdir.Session(config) session._fixturemanager = FixtureManager(session) + def func1(): pass + def func2(): pass + f1 = pytest.Function(name="name", parent=session, config=config, - args=(1,), callobj=func1) + args=(1,), callobj=func1) assert f1 == f1 - f2 = pytest.Function(name="name",config=config, - callobj=func2, parent=session) + f2 = pytest.Function(name="name", config=config, + callobj=func2, parent=session) assert f1 != f2 def test_issue197_parametrize_emptyset(self, testdir): @@ -360,7 +474,7 @@ class TestFunction: def test_issue213_parametrize_value_no_equal(self, testdir): testdir.makepyfile(""" import pytest - class A: + class A(object): def __eq__(self, other): raise ValueError("not possible") @pytest.mark.parametrize('arg', [A()]) @@ -388,7 +502,6 @@ class TestFunction: rec = testdir.inline_run() rec.assertoutcome(passed=2) - def test_parametrize_with_non_hashable_values_indirect(self, testdir): """Test parametrization with non-hashable values with indirect parametrization.""" testdir.makepyfile(""" @@ -416,7 +529,6 @@ class TestFunction: rec = testdir.inline_run() rec.assertoutcome(passed=2) - def test_parametrize_overrides_fixture(self, testdir): """Test parametrization when parameter overrides existing fixture with same name.""" testdir.makepyfile(""" @@ -444,7 +556,6 @@ class TestFunction: rec = testdir.inline_run() rec.assertoutcome(passed=3) - def test_parametrize_overrides_parametrized_fixture(self, testdir): """Test parametrization when parameter overrides existing parametrized fixture with same name.""" testdir.makepyfile(""" @@ -462,7 +573,8 @@ class TestFunction: rec = testdir.inline_run() rec.assertoutcome(passed=1) - def test_parametrize_with_mark(selfself, testdir): + @ignore_parametrized_marks + def test_parametrize_with_mark(self, testdir): items = testdir.getitems(""" import pytest @pytest.mark.foo @@ -490,12 +602,15 @@ class TestFunction: def test_pyfunc_call(self, testdir): item = testdir.getitem("def test_func(): raise ValueError") config = item.config - class MyPlugin1: + + class MyPlugin1(object): def pytest_pyfunc_call(self, pyfuncitem): raise ValueError - class MyPlugin2: + + class MyPlugin2(object): def pytest_pyfunc_call(self, pyfuncitem): return True + config.pluginmanager.register(MyPlugin1()) config.pluginmanager.register(MyPlugin2()) config.hook.pytest_runtest_setup(item=item) @@ -532,6 +647,7 @@ class TestFunction: assert colitems[2].name == 'test2[a-c]' assert colitems[3].name == 'test2[b-c]' + @ignore_parametrized_marks def test_parametrize_skipif(self, testdir): testdir.makepyfile(""" import pytest @@ -545,6 +661,7 @@ class TestFunction: result = testdir.runpytest() result.stdout.fnmatch_lines('* 2 passed, 1 skipped in *') + @ignore_parametrized_marks def test_parametrize_skip(self, testdir): testdir.makepyfile(""" import pytest @@ -558,6 +675,7 @@ class TestFunction: result = testdir.runpytest() result.stdout.fnmatch_lines('* 2 passed, 1 skipped in *') + @ignore_parametrized_marks def test_parametrize_skipif_no_skip(self, testdir): testdir.makepyfile(""" import pytest @@ -571,6 +689,7 @@ class TestFunction: result = testdir.runpytest() result.stdout.fnmatch_lines('* 1 failed, 2 passed in *') + @ignore_parametrized_marks def test_parametrize_xfail(self, testdir): testdir.makepyfile(""" import pytest @@ -584,6 +703,7 @@ class TestFunction: result = testdir.runpytest() result.stdout.fnmatch_lines('* 2 passed, 1 xfailed in *') + @ignore_parametrized_marks def test_parametrize_passed(self, testdir): testdir.makepyfile(""" import pytest @@ -597,6 +717,7 @@ class TestFunction: result = testdir.runpytest() result.stdout.fnmatch_lines('* 2 passed, 1 xpassed in *') + @ignore_parametrized_marks def test_parametrize_xfail_passed(self, testdir): testdir.makepyfile(""" import pytest @@ -610,8 +731,17 @@ class TestFunction: result = testdir.runpytest() result.stdout.fnmatch_lines('* 3 passed in *') + def test_function_original_name(self, testdir): + items = testdir.getitems(""" + import pytest + @pytest.mark.parametrize('arg', [1,2]) + def test_func(arg): + pass + """) + assert [x.originalname for x in items] == ['test_func', 'test_func'] -class TestSorting: + +class TestSorting(object): def test_check_equality(self, testdir): modcol = testdir.getmodulecol(""" def test_pass(): pass @@ -633,11 +763,11 @@ class TestSorting: assert not (fn1 == fn3) assert fn1 != fn3 - for fn in fn1,fn2,fn3: + for fn in fn1, fn2, fn3: assert fn != 3 assert fn != modcol - assert fn != [1,2,3] - assert [1,2,3] != fn + assert fn != [1, 2, 3] + assert [1, 2, 3] != fn assert modcol != fn def test_allow_sane_sorting_for_decorators(self, testdir): @@ -661,7 +791,7 @@ class TestSorting: assert [item.name for item in colitems] == ['test_b', 'test_a'] -class TestConftestCustomization: +class TestConftestCustomization(object): def test_pytest_pycollect_module(self, testdir): testdir.makeconftest(""" import pytest @@ -682,10 +812,12 @@ class TestConftestCustomization: def test_customized_pymakemodule_issue205_subdir(self, testdir): b = testdir.mkdir("a").mkdir("b") b.join("conftest.py").write(_pytest._code.Source(""" - def pytest_pycollect_makemodule(__multicall__): - mod = __multicall__.execute() + import pytest + @pytest.hookimpl(hookwrapper=True) + def pytest_pycollect_makemodule(): + outcome = yield + mod = outcome.get_result() mod.obj.hello = "world" - return mod """)) b.join("test_module.py").write(_pytest._code.Source(""" def test_hello(): @@ -702,7 +834,7 @@ class TestConftestCustomization: def pytest_pycollect_makeitem(): outcome = yield if outcome.excinfo is None: - result = outcome.result + result = outcome.get_result() if result: for func in result: func._some123 = "world" @@ -736,11 +868,40 @@ class TestConftestCustomization: def test_makeitem_non_underscore(self, testdir, monkeypatch): modcol = testdir.getmodulecol("def _hello(): pass") - l = [] + values = [] monkeypatch.setattr(pytest.Module, 'makeitem', - lambda self, name, obj: l.append(name)) - l = modcol.collect() - assert '_hello' not in l + lambda self, name, obj: values.append(name)) + values = modcol.collect() + assert '_hello' not in values + + def test_issue2369_collect_module_fileext(self, testdir): + """Ensure we can collect files with weird file extensions as Python + modules (#2369)""" + # We'll implement a little finder and loader to import files containing + # Python source code whose file extension is ".narf". + testdir.makeconftest(""" + import sys, os, imp + from _pytest.python import Module + + class Loader: + def load_module(self, name): + return imp.load_source(name, name + ".narf") + class Finder: + def find_module(self, name, path=None): + if os.path.exists(name + ".narf"): + return Loader() + sys.meta_path.append(Finder()) + + def pytest_collect_file(path, parent): + if path.ext == ".narf": + return Module(path, parent)""") + testdir.makefile(".narf", """ + def test_something(): + assert 1 + 1 == 2""") + # Use runpytest_subprocess, since we're futzing with sys.meta_path. + result = testdir.runpytest_subprocess() + result.stdout.fnmatch_lines('*1 passed*') + def test_setup_only_available_in_subdir(testdir): sub1 = testdir.mkpydir("sub1") @@ -768,6 +929,7 @@ def test_setup_only_available_in_subdir(testdir): result = testdir.runpytest("-v", "-s") result.assert_outcomes(passed=2) + def test_modulecol_roundtrip(testdir): modcol = testdir.getmodulecol("pass", withinit=True) trail = modcol.nodeid @@ -775,7 +937,7 @@ def test_modulecol_roundtrip(testdir): assert modcol.name == newcol.name -class TestTracebackCutting: +class TestTracebackCutting(object): def test_skip_simple(self): excinfo = pytest.raises(pytest.skip.Exception, 'pytest.skip("xxx")') assert excinfo.traceback[-1].frame.code.name == "skip" @@ -783,22 +945,25 @@ class TestTracebackCutting: def test_traceback_argsetup(self, testdir): testdir.makeconftest(""" - def pytest_funcarg__hello(request): + import pytest + + @pytest.fixture + def hello(request): raise ValueError("xyz") """) p = testdir.makepyfile("def test(hello): pass") result = testdir.runpytest(p) assert result.ret != 0 out = result.stdout.str() - assert out.find("xyz") != -1 - assert out.find("conftest.py:2: ValueError") != -1 - numentries = out.count("_ _ _") # separator for traceback entries + assert "xyz" in out + assert "conftest.py:5: ValueError" in out + numentries = out.count("_ _ _") # separator for traceback entries assert numentries == 0 result = testdir.runpytest("--fulltrace", p) out = result.stdout.str() - assert out.find("conftest.py:2: ValueError") != -1 - numentries = out.count("_ _ _ _") # separator for traceback entries + assert "conftest.py:5: ValueError" in out + numentries = out.count("_ _ _ _") # separator for traceback entries assert numentries > 3 def test_traceback_error_during_import(self, testdir): @@ -898,7 +1063,7 @@ class TestTracebackCutting: assert filter_traceback(tb[-1]) -class TestReportInfo: +class TestReportInfo(object): def test_itemreport_reportinfo(self, testdir, linecomp): testdir.makeconftest(""" import pytest @@ -923,7 +1088,7 @@ class TestReportInfo: def test_class_reportinfo(self, testdir): modcol = testdir.getmodulecol(""" # lineno 0 - class TestClass: + class TestClass(object): def test_hello(self): pass """) classcol = testdir.collect_by_name(modcol, "TestClass") @@ -958,7 +1123,7 @@ class TestReportInfo: def check(x): pass yield check, 3 - class TestClass: + class TestClass(object): def test_method(self): pass """ @@ -967,7 +1132,7 @@ class TestReportInfo: # https://github.com/pytest-dev/pytest/issues/1204 modcol = testdir.getmodulecol(""" # lineno 0 - class TestClass: + class TestClass(object): def __getattr__(self, name): return "this is not an int" @@ -989,7 +1154,7 @@ def test_customized_python_discovery(testdir): p = testdir.makepyfile(""" def check_simple(): pass - class CheckMyApp: + class CheckMyApp(object): def check_meth(self): pass """) @@ -1049,6 +1214,7 @@ def test_collector_attributes(testdir): "*1 passed*", ]) + def test_customize_through_attributes(testdir): testdir.makeconftest(""" import pytest @@ -1064,7 +1230,7 @@ def test_customize_through_attributes(testdir): return MyClass(name, parent=collector) """) testdir.makepyfile(""" - class MyTestClass: + class MyTestClass(object): def test_hello(self): pass """) @@ -1078,11 +1244,11 @@ def test_customize_through_attributes(testdir): def test_unorderable_types(testdir): testdir.makepyfile(""" - class TestJoinEmpty: + class TestJoinEmpty(object): pass def make_test(): - class Test: + class Test(object): pass Test.__name__ = "TestFoo" return Test @@ -1156,8 +1322,8 @@ def test_dont_collect_non_function_callable(testdir): result = testdir.runpytest('-rw') result.stdout.fnmatch_lines([ '*collected 1 item*', - 'WC2 *', - '*1 passed, 1 pytest-warnings in *', + "*cannot collect 'test_a' because it is not a function*", + '*1 passed, 1 warnings in *', ]) @@ -1198,3 +1364,39 @@ def test_syntax_error_with_non_ascii_chars(testdir): '*SyntaxError*', '*1 error in*', ]) + + +def test_skip_duplicates_by_default(testdir): + """Test for issue https://github.com/pytest-dev/pytest/issues/1609 (#1609) + + Ignore duplicate directories. + """ + a = testdir.mkdir("a") + fh = a.join("test_a.py") + fh.write(_pytest._code.Source(""" + import pytest + def test_real(): + pass + """)) + result = testdir.runpytest(a.strpath, a.strpath) + result.stdout.fnmatch_lines([ + '*collected 1 item*', + ]) + + +def test_keep_duplicates(testdir): + """Test for issue https://github.com/pytest-dev/pytest/issues/1609 (#1609) + + Use --keep-duplicates to collect tests from duplicate directories. + """ + a = testdir.mkdir("a") + fh = a.join("test_a.py") + fh.write(_pytest._code.Source(""" + import pytest + def test_real(): + pass + """)) + result = testdir.runpytest("--keep-duplicates", a.strpath, a.strpath) + result.stdout.fnmatch_lines([ + '*collected 2 item*', + ]) diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/python/fixture.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/fixture.py similarity index 69% rename from tests/wpt/web-platform-tests/tools/pytest/testing/python/fixture.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/fixture.py index 506d8426e3c..b159e8ebb8e 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/python/fixture.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/fixture.py @@ -2,42 +2,57 @@ from textwrap import dedent import _pytest._code import pytest -import sys -from _pytest import python as funcargs from _pytest.pytester import get_public_names -from _pytest.python import FixtureLookupError +from _pytest.fixtures import FixtureLookupError +from _pytest import fixtures def test_getfuncargnames(): - def f(): pass - assert not funcargs.getfuncargnames(f) - def g(arg): pass - assert funcargs.getfuncargnames(g) == ('arg',) - def h(arg1, arg2="hello"): pass - assert funcargs.getfuncargnames(h) == ('arg1',) - def h(arg1, arg2, arg3="hello"): pass - assert funcargs.getfuncargnames(h) == ('arg1', 'arg2') - class A: + def f(): + pass + assert not fixtures.getfuncargnames(f) + + def g(arg): + pass + assert fixtures.getfuncargnames(g) == ('arg',) + + def h(arg1, arg2="hello"): + pass + assert fixtures.getfuncargnames(h) == ('arg1',) + + def h(arg1, arg2, arg3="hello"): + pass + assert fixtures.getfuncargnames(h) == ('arg1', 'arg2') + + class A(object): def f(self, arg1, arg2="hello"): pass - assert funcargs.getfuncargnames(A().f) == ('arg1',) - if sys.version_info < (3,0): - assert funcargs.getfuncargnames(A.f) == ('arg1',) -class TestFillFixtures: + @staticmethod + def static(arg1, arg2): + pass + + assert fixtures.getfuncargnames(A().f) == ('arg1',) + assert fixtures.getfuncargnames(A.static, cls=A) == ('arg1', 'arg2') + + +class TestFillFixtures(object): def test_fillfuncargs_exposed(self): # used by oejskit, kept for compatibility - assert pytest._fillfuncargs == funcargs.fillfixtures + assert pytest._fillfuncargs == fixtures.fillfixtures def test_funcarg_lookupfails(self, testdir): testdir.makepyfile(""" - def pytest_funcarg__xyzsomething(request): + import pytest + + @pytest.fixture + def xyzsomething(request): return 42 def test_func(some): pass """) - result = testdir.runpytest() # "--collect-only") + result = testdir.runpytest() # "--collect-only") assert result.ret != 0 result.stdout.fnmatch_lines([ "*def test_func(some)*", @@ -47,14 +62,18 @@ class TestFillFixtures: def test_funcarg_basic(self, testdir): item = testdir.getitem(""" - def pytest_funcarg__some(request): + import pytest + + @pytest.fixture + def some(request): return request.function.__name__ - def pytest_funcarg__other(request): + @pytest.fixture + def other(request): return 42 def test_func(some, other): pass """) - funcargs.fillfixtures(item) + fixtures.fillfixtures(item) del item.funcargs["request"] assert len(get_public_names(item.funcargs)) == 2 assert item.funcargs['some'] == "test_func" @@ -62,10 +81,13 @@ class TestFillFixtures: def test_funcarg_lookup_modulelevel(self, testdir): testdir.makepyfile(""" - def pytest_funcarg__something(request): + import pytest + + @pytest.fixture + def something(request): return request.function.__name__ - class TestClass: + class TestClass(object): def test_method(self, something): assert something == "test_method" def test_func(something): @@ -76,9 +98,13 @@ class TestFillFixtures: def test_funcarg_lookup_classlevel(self, testdir): p = testdir.makepyfile(""" - class TestClass: - def pytest_funcarg__something(self, request): + import pytest + class TestClass(object): + + @pytest.fixture + def something(self, request): return request.instance + def test_method(self, something): assert something is self """) @@ -92,13 +118,15 @@ class TestFillFixtures: sub2 = testdir.mkpydir("sub2") sub1.join("conftest.py").write(_pytest._code.Source(""" import pytest - def pytest_funcarg__arg1(request): - pytest.raises(Exception, "request.getfuncargvalue('arg2')") + @pytest.fixture + def arg1(request): + pytest.raises(Exception, "request.getfixturevalue('arg2')") """)) sub2.join("conftest.py").write(_pytest._code.Source(""" import pytest - def pytest_funcarg__arg2(request): - pytest.raises(Exception, "request.getfuncargvalue('arg1')") + @pytest.fixture + def arg2(request): + pytest.raises(Exception, "request.getfixturevalue('arg1')") """)) sub1.join("test_in_sub1.py").write("def test_1(arg1): pass") @@ -114,7 +142,7 @@ class TestFillFixtures: def spam(): return 'spam' - class TestSpam: + class TestSpam(object): @pytest.fixture def spam(self, spam): @@ -336,6 +364,38 @@ class TestFillFixtures: result = testdir.runpytest(testfile) result.stdout.fnmatch_lines(["*3 passed*"]) + def test_override_autouse_fixture_with_parametrized_fixture_conftest_conftest(self, testdir): + """Test override of the autouse fixture with parametrized one on the conftest level. + This test covers the issue explained in issue 1601 + """ + testdir.makeconftest(""" + import pytest + + @pytest.fixture(autouse=True) + def spam(): + return 'spam' + """) + subdir = testdir.mkpydir('subdir') + subdir.join("conftest.py").write(_pytest._code.Source(""" + import pytest + + @pytest.fixture(params=[1, 2, 3]) + def spam(request): + return request.param + """)) + testfile = subdir.join("test_spam.py") + testfile.write(_pytest._code.Source(""" + params = {'spam': 1} + + def test_spam(spam): + assert spam == params['spam'] + params['spam'] += 1 + """)) + result = testdir.runpytest() + result.stdout.fnmatch_lines(["*3 passed*"]) + result = testdir.runpytest(testfile) + result.stdout.fnmatch_lines(["*3 passed*"]) + def test_autouse_fixture_plugin(self, testdir): # A fixture from a plugin has no baseid set, which screwed up # the autouse fixture handling. @@ -357,16 +417,32 @@ class TestFillFixtures: assert result.ret == 0 def test_funcarg_lookup_error(self, testdir): + testdir.makeconftest(""" + import pytest + + @pytest.fixture + def a_fixture(): pass + + @pytest.fixture + def b_fixture(): pass + + @pytest.fixture + def c_fixture(): pass + + @pytest.fixture + def d_fixture(): pass + """) testdir.makepyfile(""" def test_lookup_error(unknown): pass """) result = testdir.runpytest() result.stdout.fnmatch_lines([ - "*ERROR*test_lookup_error*", - "*def test_lookup_error(unknown):*", - "*fixture*unknown*not found*", - "*available fixtures*", + "*ERROR at setup of test_lookup_error*", + " def test_lookup_error(unknown):*", + "E fixture 'unknown' not found", + "> available fixtures:*a_fixture,*b_fixture,*c_fixture,*d_fixture*monkeypatch,*", # sorted + "> use 'py*test --fixtures *' for help on them.", "*1 error*", ]) assert "INTERNAL" not in result.stdout.str() @@ -394,13 +470,16 @@ class TestFillFixtures: assert result.ret == 0 -class TestRequestBasic: +class TestRequestBasic(object): def test_request_attributes(self, testdir): item = testdir.getitem(""" - def pytest_funcarg__something(request): pass + import pytest + + @pytest.fixture + def something(request): pass def test_func(something): pass """) - req = funcargs.FixtureRequest(item) + req = fixtures.FixtureRequest(item) assert req.function == item.obj assert req.keywords == item.keywords assert hasattr(req.module, 'test_func') @@ -411,8 +490,11 @@ class TestRequestBasic: def test_request_attributes_method(self, testdir): item, = testdir.getitems(""" - class TestB: - def pytest_funcarg__something(self, request): + import pytest + class TestB(object): + + @pytest.fixture + def something(self, request): return 1 def test_func(self, something): pass @@ -421,62 +503,90 @@ class TestRequestBasic: assert req.cls.__name__ == "TestB" assert req.instance.__class__ == req.cls - def XXXtest_request_contains_funcarg_arg2fixturedefs(self, testdir): + def test_request_contains_funcarg_arg2fixturedefs(self, testdir): modcol = testdir.getmodulecol(""" - def pytest_funcarg__something(request): + import pytest + @pytest.fixture + def something(request): pass - class TestClass: + class TestClass(object): def test_method(self, something): pass """) item1, = testdir.genitems([modcol]) assert item1.name == "test_method" - arg2fixturedefs = funcargs.FixtureRequest(item1)._arg2fixturedefs + arg2fixturedefs = fixtures.FixtureRequest(item1)._arg2fixturedefs assert len(arg2fixturedefs) == 1 - assert arg2fixturedefs[0].__name__ == "pytest_funcarg__something" + assert arg2fixturedefs['something'][0].argname == "something" - def test_getfuncargvalue_recursive(self, testdir): + def test_getfixturevalue_recursive(self, testdir): testdir.makeconftest(""" - def pytest_funcarg__something(request): + import pytest + + @pytest.fixture + def something(request): return 1 """) testdir.makepyfile(""" - def pytest_funcarg__something(request): - return request.getfuncargvalue("something") + 1 + import pytest + + @pytest.fixture + def something(request): + return request.getfixturevalue("something") + 1 def test_func(something): assert something == 2 """) reprec = testdir.inline_run() reprec.assertoutcome(passed=1) - def test_getfuncargvalue(self, testdir): + @pytest.mark.parametrize( + 'getfixmethod', ('getfixturevalue', 'getfuncargvalue')) + def test_getfixturevalue(self, testdir, getfixmethod): item = testdir.getitem(""" - l = [2] - def pytest_funcarg__something(request): return 1 - def pytest_funcarg__other(request): - return l.pop() + import pytest + values = [2] + @pytest.fixture + def something(request): return 1 + @pytest.fixture + def other(request): + return values.pop() def test_func(something): pass """) + import contextlib + if getfixmethod == 'getfuncargvalue': + warning_expectation = pytest.warns(DeprecationWarning) + else: + # see #1830 for a cleaner way to accomplish this + @contextlib.contextmanager + def expecting_no_warning(): + yield + + warning_expectation = expecting_no_warning() + req = item._request - pytest.raises(FixtureLookupError, req.getfuncargvalue, "notexists") - val = req.getfuncargvalue("something") - assert val == 1 - val = req.getfuncargvalue("something") - assert val == 1 - val2 = req.getfuncargvalue("other") - assert val2 == 2 - val2 = req.getfuncargvalue("other") # see about caching - assert val2 == 2 - pytest._fillfuncargs(item) - assert item.funcargs["something"] == 1 - assert len(get_public_names(item.funcargs)) == 2 - assert "request" in item.funcargs - #assert item.funcargs == {'something': 1, "other": 2} + with warning_expectation: + fixture_fetcher = getattr(req, getfixmethod) + with pytest.raises(FixtureLookupError): + fixture_fetcher("notexists") + val = fixture_fetcher("something") + assert val == 1 + val = fixture_fetcher("something") + assert val == 1 + val2 = fixture_fetcher("other") + assert val2 == 2 + val2 = fixture_fetcher("other") # see about caching + assert val2 == 2 + pytest._fillfuncargs(item) + assert item.funcargs["something"] == 1 + assert len(get_public_names(item.funcargs)) == 2 + assert "request" in item.funcargs def test_request_addfinalizer(self, testdir): item = testdir.getitem(""" + import pytest teardownlist = [] - def pytest_funcarg__something(request): + @pytest.fixture + def something(request): request.addfinalizer(lambda: teardownlist.append(1)) def test_func(something): pass """) @@ -490,18 +600,33 @@ class TestRequestBasic: print(ss.stack) assert teardownlist == [1] + def test_mark_as_fixture_with_prefix_and_decorator_fails(self, testdir): + testdir.makeconftest(""" + import pytest + + @pytest.fixture + def pytest_funcarg__marked_with_prefix_and_decorator(): + pass + """) + result = testdir.runpytest_subprocess() + assert result.ret != 0 + result.stdout.fnmatch_lines([ + "*AssertionError: fixtures cannot have*@pytest.fixture*", + "*pytest_funcarg__marked_with_prefix_and_decorator*" + ]) + def test_request_addfinalizer_failing_setup(self, testdir): testdir.makepyfile(""" import pytest - l = [1] + values = [1] @pytest.fixture def myfix(request): - request.addfinalizer(l.pop) + request.addfinalizer(values.pop) assert 0 def test_fix(myfix): pass def test_finalizer_ran(): - assert not l + assert not values """) reprec = testdir.inline_run("-s") reprec.assertoutcome(failed=1, passed=1) @@ -509,39 +634,73 @@ class TestRequestBasic: def test_request_addfinalizer_failing_setup_module(self, testdir): testdir.makepyfile(""" import pytest - l = [1, 2] + values = [1, 2] @pytest.fixture(scope="module") def myfix(request): - request.addfinalizer(l.pop) - request.addfinalizer(l.pop) + request.addfinalizer(values.pop) + request.addfinalizer(values.pop) assert 0 def test_fix(myfix): pass """) reprec = testdir.inline_run("-s") mod = reprec.getcalls("pytest_runtest_setup")[0].item.module - assert not mod.l - + assert not mod.values def test_request_addfinalizer_partial_setup_failure(self, testdir): p = testdir.makepyfile(""" - l = [] - def pytest_funcarg__something(request): - request.addfinalizer(lambda: l.append(None)) + import pytest + values = [] + @pytest.fixture + def something(request): + request.addfinalizer(lambda: values.append(None)) def test_func(something, missingarg): pass def test_second(): - assert len(l) == 1 + assert len(values) == 1 """) result = testdir.runpytest(p) result.stdout.fnmatch_lines([ "*1 error*" # XXX the whole module collection fails - ]) + ]) + + def test_request_subrequest_addfinalizer_exceptions(self, testdir): + """ + Ensure exceptions raised during teardown by a finalizer are suppressed + until all finalizers are called, re-raising the first exception (#2440) + """ + testdir.makepyfile(""" + import pytest + values = [] + def _excepts(where): + raise Exception('Error in %s fixture' % where) + @pytest.fixture + def subrequest(request): + return request + @pytest.fixture + def something(subrequest): + subrequest.addfinalizer(lambda: values.append(1)) + subrequest.addfinalizer(lambda: values.append(2)) + subrequest.addfinalizer(lambda: _excepts('something')) + @pytest.fixture + def excepts(subrequest): + subrequest.addfinalizer(lambda: _excepts('excepts')) + subrequest.addfinalizer(lambda: values.append(3)) + def test_first(something, excepts): + pass + def test_second(): + assert values == [3, 2, 1] + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + '*Exception: Error in excepts fixture', + '* 2 passed, 1 error in *', + ]) def test_request_getmodulepath(self, testdir): modcol = testdir.getmodulecol("def test_somefunc(): pass") item, = testdir.genitems([modcol]) - req = funcargs.FixtureRequest(item) + req = fixtures.FixtureRequest(item) assert req.fspath == modcol.fspath def test_request_fixturenames(self, testdir): @@ -567,9 +726,11 @@ class TestRequestBasic: def test_funcargnames_compatattr(self, testdir): testdir.makepyfile(""" + import pytest def pytest_generate_tests(metafunc): assert metafunc.funcargnames == metafunc.fixturenames - def pytest_funcarg__fn(request): + @pytest.fixture + def fn(request): assert request._pyfuncitem.funcargnames == \ request._pyfuncitem.fixturenames return request.funcargnames, request.fixturenames @@ -583,28 +744,28 @@ class TestRequestBasic: def test_setupdecorator_and_xunit(self, testdir): testdir.makepyfile(""" import pytest - l = [] + values = [] @pytest.fixture(scope='module', autouse=True) def setup_module(): - l.append("module") + values.append("module") @pytest.fixture(autouse=True) def setup_function(): - l.append("function") + values.append("function") def test_func(): pass - class TestClass: + class TestClass(object): @pytest.fixture(scope="class", autouse=True) def setup_class(self): - l.append("class") + values.append("class") @pytest.fixture(autouse=True) def setup_method(self): - l.append("method") + values.append("method") def test_method(self): pass def test_all(): - assert l == ["module", "function", "class", + assert values == ["module", "function", "class", "function", "method", "function"] """) reprec = testdir.inline_run("-v") @@ -614,7 +775,9 @@ class TestRequestBasic: # this tests that normalization of nodeids takes place b = testdir.mkdir("tests").mkdir("unit") b.join("conftest.py").write(_pytest._code.Source(""" - def pytest_funcarg__arg1(): + import pytest + @pytest.fixture + def arg1(): pass """)) p = b.join("test_module.py") @@ -659,18 +822,22 @@ class TestRequestBasic: reprec = testdir.inline_run() reprec.assertoutcome(passed=2) -class TestRequestMarking: + +class TestRequestMarking(object): def test_applymarker(self, testdir): - item1,item2 = testdir.getitems(""" - def pytest_funcarg__something(request): + item1, item2 = testdir.getitems(""" + import pytest + + @pytest.fixture + def something(request): pass - class TestClass: + class TestClass(object): def test_func1(self, something): pass def test_func2(self, something): pass """) - req1 = funcargs.FixtureRequest(item1) + req1 = fixtures.FixtureRequest(item1) assert 'xfail' not in item1.keywords req1.applymarker(pytest.mark.xfail) assert 'xfail' in item1.keywords @@ -716,17 +883,21 @@ class TestRequestMarking: reprec = testdir.inline_run() reprec.assertoutcome(passed=2) -class TestRequestCachedSetup: + +class TestRequestCachedSetup(object): def test_request_cachedsetup_defaultmodule(self, testdir): reprec = testdir.inline_runsource(""" mysetup = ["hello",].pop - def pytest_funcarg__something(request): + import pytest + + @pytest.fixture + def something(request): return request.cached_setup(mysetup, scope="module") def test_func1(something): assert something == "hello" - class TestClass: + class TestClass(object): def test_func1a(self, something): assert something == "hello" """) @@ -736,13 +907,15 @@ class TestRequestCachedSetup: reprec = testdir.inline_runsource(""" mysetup = ["hello", "hello2", "hello3"].pop - def pytest_funcarg__something(request): + import pytest + @pytest.fixture + def something(request): return request.cached_setup(mysetup, scope="class") def test_func1(something): assert something == "hello3" def test_func2(something): assert something == "hello2" - class TestClass: + class TestClass(object): def test_func1a(self, something): assert something == "hello" def test_func2b(self, something): @@ -752,10 +925,12 @@ class TestRequestCachedSetup: def test_request_cachedsetup_extrakey(self, testdir): item1 = testdir.getitem("def test_func(): pass") - req1 = funcargs.FixtureRequest(item1) - l = ["hello", "world"] + req1 = fixtures.FixtureRequest(item1) + values = ["hello", "world"] + def setup(): - return l.pop() + return values.pop() + ret1 = req1.cached_setup(setup, extrakey=1) ret2 = req1.cached_setup(setup, extrakey=2) assert ret2 == "hello" @@ -767,28 +942,35 @@ class TestRequestCachedSetup: def test_request_cachedsetup_cache_deletion(self, testdir): item1 = testdir.getitem("def test_func(): pass") - req1 = funcargs.FixtureRequest(item1) - l = [] + req1 = fixtures.FixtureRequest(item1) + values = [] + def setup(): - l.append("setup") + values.append("setup") + def teardown(val): - l.append("teardown") + values.append("teardown") + req1.cached_setup(setup, teardown, scope="function") - assert l == ['setup'] + assert values == ['setup'] # artificial call of finalizer setupstate = req1._pyfuncitem.session._setupstate setupstate._callfinalizers(item1) - assert l == ["setup", "teardown"] + assert values == ["setup", "teardown"] req1.cached_setup(setup, teardown, scope="function") - assert l == ["setup", "teardown", "setup"] + assert values == ["setup", "teardown", "setup"] setupstate._callfinalizers(item1) - assert l == ["setup", "teardown", "setup", "teardown"] + assert values == ["setup", "teardown", "setup", "teardown"] def test_request_cached_setup_two_args(self, testdir): testdir.makepyfile(""" - def pytest_funcarg__arg1(request): + import pytest + + @pytest.fixture + def arg1(request): return request.cached_setup(lambda: 42) - def pytest_funcarg__arg2(request): + @pytest.fixture + def arg2(request): return request.cached_setup(lambda: 17) def test_two_different_setups(arg1, arg2): assert arg1 != arg2 @@ -798,12 +980,16 @@ class TestRequestCachedSetup: "*1 passed*" ]) - def test_request_cached_setup_getfuncargvalue(self, testdir): + def test_request_cached_setup_getfixturevalue(self, testdir): testdir.makepyfile(""" - def pytest_funcarg__arg1(request): - arg1 = request.getfuncargvalue("arg2") + import pytest + + @pytest.fixture + def arg1(request): + arg1 = request.getfixturevalue("arg2") return request.cached_setup(lambda: arg1 + 1) - def pytest_funcarg__arg2(request): + @pytest.fixture + def arg2(request): return request.cached_setup(lambda: 10) def test_two_funcarg(arg1): assert arg1 == 11 @@ -815,16 +1001,18 @@ class TestRequestCachedSetup: def test_request_cached_setup_functional(self, testdir): testdir.makepyfile(test_0=""" - l = [] - def pytest_funcarg__something(request): + import pytest + values = [] + @pytest.fixture + def something(request): val = request.cached_setup(fsetup, fteardown) return val def fsetup(mycache=[1]): - l.append(mycache.pop()) - return l + values.append(mycache.pop()) + return values def fteardown(something): - l.remove(something[0]) - l.append(2) + values.remove(something[0]) + values.append(2) def test_list_once(something): assert something == [1] def test_list_twice(something): @@ -833,7 +1021,7 @@ class TestRequestCachedSetup: testdir.makepyfile(test_1=""" import test_0 # should have run already def test_check_test0_has_teardown_correct(): - assert test_0.l == [2] + assert test_0.values == [2] """) result = testdir.runpytest("-v") result.stdout.fnmatch_lines([ @@ -842,7 +1030,10 @@ class TestRequestCachedSetup: def test_issue117_sessionscopeteardown(self, testdir): testdir.makepyfile(""" - def pytest_funcarg__app(request): + import pytest + + @pytest.fixture + def app(request): app = request.cached_setup( scope='session', setup=lambda: 0, @@ -858,7 +1049,8 @@ class TestRequestCachedSetup: "*ZeroDivisionError*", ]) -class TestFixtureUsages: + +class TestFixtureUsages(object): def test_noargfixturedec(self, testdir): testdir.makepyfile(""" import pytest @@ -935,13 +1127,29 @@ class TestFixtureUsages: "*1 error*" ]) + def test_invalid_scope(self, testdir): + testdir.makepyfile(""" + import pytest + @pytest.fixture(scope="functions") + def badscope(): + pass + + def test_nothing(badscope): + pass + """) + result = testdir.runpytest_inprocess() + result.stdout.fnmatch_lines( + ("*ValueError: fixture badscope from test_invalid_scope.py has an unsupported" + " scope value 'functions'") + ) + def test_funcarg_parametrized_and_used_twice(self, testdir): testdir.makepyfile(""" import pytest - l = [] + values = [] @pytest.fixture(params=[1,2]) def arg1(request): - l.append(1) + values.append(1) return request.param @pytest.fixture() @@ -950,7 +1158,7 @@ class TestFixtureUsages: def test_add(arg1, arg2): assert arg2 == arg1 + 1 - assert len(l) == arg1 + assert len(values) == arg1 """) result = testdir.runpytest() result.stdout.fnmatch_lines([ @@ -984,15 +1192,15 @@ class TestFixtureUsages: def test_factory_setup_as_classes_fails(self, testdir): testdir.makepyfile(""" import pytest - class arg1: + class arg1(object): def __init__(self, request): self.x = 1 arg1 = pytest.fixture()(arg1) """) reprec = testdir.inline_run() - l = reprec.getfailedcollections() - assert len(l) == 1 + values = reprec.getfailedcollections() + assert len(values) == 1 def test_request_can_be_overridden(self, testdir): testdir.makepyfile(""" @@ -1011,20 +1219,20 @@ class TestFixtureUsages: testdir.makepyfile(""" import pytest - l = [] + values = [] @pytest.fixture(scope="class") def myfix(request): request.cls.hello = "world" - l.append(1) + values.append(1) - class TestClass: + class TestClass(object): def test_one(self): assert self.hello == "world" - assert len(l) == 1 + assert len(values) == 1 def test_two(self): assert self.hello == "world" - assert len(l) == 1 + assert len(values) == 1 pytest.mark.usefixtures("myfix")(TestClass) """) reprec = testdir.inline_run() @@ -1044,7 +1252,7 @@ class TestFixtureUsages: """) testdir.makepyfile(""" - class TestClass: + class TestClass(object): def test_one(self): assert self.hello == "world" def test_two(self): @@ -1063,7 +1271,7 @@ class TestFixtureUsages: testdir.makepyfile(""" import pytest - class TestClass: + class TestClass(object): @pytest.fixture def setup1(self, request): assert self == request.instance @@ -1078,7 +1286,7 @@ class TestFixtureUsages: testdir.makepyfile(""" import pytest - l = [] + values = [] def f(): yield 1 yield 2 @@ -1092,34 +1300,41 @@ class TestFixtureUsages: return request.param def test_1(arg): - l.append(arg) + values.append(arg) def test_2(arg2): - l.append(arg2*10) + values.append(arg2*10) """) reprec = testdir.inline_run("-v") reprec.assertoutcome(passed=4) - l = reprec.getcalls("pytest_runtest_call")[0].item.module.l - assert l == [1,2, 10,20] + values = reprec.getcalls("pytest_runtest_call")[0].item.module.values + assert values == [1, 2, 10, 20] -class TestFixtureManagerParseFactories: - def pytest_funcarg__testdir(self, request): - testdir = request.getfuncargvalue("testdir") +class TestFixtureManagerParseFactories(object): + + @pytest.fixture + def testdir(self, request): + testdir = request.getfixturevalue("testdir") testdir.makeconftest(""" - def pytest_funcarg__hello(request): + import pytest + + @pytest.fixture + def hello(request): return "conftest" - def pytest_funcarg__fm(request): + @pytest.fixture + def fm(request): return request._fixturemanager - def pytest_funcarg__item(request): + @pytest.fixture + def item(request): return request._pyfuncitem """) return testdir def test_parsefactories_evil_objects_issue214(self, testdir): testdir.makepyfile(""" - class A: + class A(object): def __call__(self): pass def __getattr__(self, name): @@ -1138,17 +1353,21 @@ class TestFixtureManagerParseFactories: faclist = fm.getfixturedefs(name, item.nodeid) assert len(faclist) == 1 fac = faclist[0] - assert fac.func.__name__ == "pytest_funcarg__" + name + assert fac.func.__name__ == name """) reprec = testdir.inline_run("-s") reprec.assertoutcome(passed=1) def test_parsefactories_conftest_and_module_and_class(self, testdir): testdir.makepyfile(""" - def pytest_funcarg__hello(request): + import pytest + + @pytest.fixture + def hello(request): return "module" - class TestClass: - def pytest_funcarg__hello(self, request): + class TestClass(object): + @pytest.fixture + def hello(self, request): return "class" def test_hello(self, item, fm): faclist = fm.getfixturedefs("hello", item.nodeid) @@ -1195,8 +1414,10 @@ class TestFixtureManagerParseFactories: reprec.assertoutcome(passed=2) -class TestAutouseDiscovery: - def pytest_funcarg__testdir(self, testdir): +class TestAutouseDiscovery(object): + + @pytest.fixture + def testdir(self, testdir): testdir.makeconftest(""" import pytest @pytest.fixture(autouse=True) @@ -1210,10 +1431,12 @@ class TestAutouseDiscovery: def perfunction2(arg1): pass - def pytest_funcarg__fm(request): + @pytest.fixture + def fm(request): return request._fixturemanager - def pytest_funcarg__item(request): + @pytest.fixture + def item(request): return request._pyfuncitem """) return testdir @@ -1233,20 +1456,20 @@ class TestAutouseDiscovery: def test_two_classes_separated_autouse(self, testdir): testdir.makepyfile(""" import pytest - class TestA: - l = [] + class TestA(object): + values = [] @pytest.fixture(autouse=True) def setup1(self): - self.l.append(1) + self.values.append(1) def test_setup1(self): - assert self.l == [1] - class TestB: - l = [] + assert self.values == [1] + class TestB(object): + values = [] @pytest.fixture(autouse=True) def setup2(self): - self.l.append(1) + self.values.append(1) def test_setup2(self): - assert self.l == [1] + assert self.values == [1] """) reprec = testdir.inline_run() reprec.assertoutcome(passed=2) @@ -1254,7 +1477,7 @@ class TestAutouseDiscovery: def test_setup_at_classlevel(self, testdir): testdir.makepyfile(""" import pytest - class TestClass: + class TestClass(object): @pytest.fixture(autouse=True) def permethod(self, request): request.instance.funcname = request.function.__name__ @@ -1329,28 +1552,28 @@ class TestAutouseDiscovery: def test_autouse_in_module_and_two_classes(self, testdir): testdir.makepyfile(""" import pytest - l = [] + values = [] @pytest.fixture(autouse=True) def append1(): - l.append("module") + values.append("module") def test_x(): - assert l == ["module"] + assert values == ["module"] - class TestA: + class TestA(object): @pytest.fixture(autouse=True) def append2(self): - l.append("A") + values.append("A") def test_hello(self): - assert l == ["module", "module", "A"], l - class TestA2: + assert values == ["module", "module", "A"], values + class TestA2(object): def test_world(self): - assert l == ["module", "module", "A", "module"], l + assert values == ["module", "module", "A", "module"], values """) reprec = testdir.inline_run() reprec.assertoutcome(passed=3) -class TestAutouseManagement: +class TestAutouseManagement(object): def test_autouse_conftest_mid_directory(self, testdir): pkgdir = testdir.mkpydir("xyz123") pkgdir.join("conftest.py").write(_pytest._code.Source(""" @@ -1385,28 +1608,26 @@ class TestAutouseManagement: reprec = testdir.inline_run() reprec.assertoutcome(passed=2) - - def test_funcarg_and_setup(self, testdir): testdir.makepyfile(""" import pytest - l = [] + values = [] @pytest.fixture(scope="module") def arg(): - l.append(1) + values.append(1) return 0 @pytest.fixture(scope="module", autouse=True) def something(arg): - l.append(2) + values.append(2) def test_hello(arg): - assert len(l) == 2 - assert l == [1,2] + assert len(values) == 2 + assert values == [1,2] assert arg == 0 def test_hello2(arg): - assert len(l) == 2 - assert l == [1,2] + assert len(values) == 2 + assert values == [1,2] assert arg == 0 """) reprec = testdir.inline_run() @@ -1415,20 +1636,20 @@ class TestAutouseManagement: def test_uses_parametrized_resource(self, testdir): testdir.makepyfile(""" import pytest - l = [] + values = [] @pytest.fixture(params=[1,2]) def arg(request): return request.param @pytest.fixture(autouse=True) def something(arg): - l.append(arg) + values.append(arg) def test_hello(): - if len(l) == 1: - assert l == [1] - elif len(l) == 2: - assert l == [1, 2] + if len(values) == 1: + assert values == [1] + elif len(values) == 2: + assert values == [1, 2] else: 0/0 @@ -1440,7 +1661,7 @@ class TestAutouseManagement: testdir.makepyfile(""" import pytest - l = [] + values = [] @pytest.fixture(scope="session", params=[1,2]) def arg(request): @@ -1449,14 +1670,14 @@ class TestAutouseManagement: @pytest.fixture(scope="function", autouse=True) def append(request, arg): if request.function.__name__ == "test_some": - l.append(arg) + values.append(arg) def test_some(): pass def test_result(arg): - assert len(l) == arg - assert l[:arg] == [1,2][:arg] + assert len(values) == arg + assert values[:arg] == [1,2][:arg] """) reprec = testdir.inline_run("-v", "-s") reprec.assertoutcome(passed=4) @@ -1466,7 +1687,7 @@ class TestAutouseManagement: import pytest import pprint - l = [] + values = [] @pytest.fixture(scope="function", params=[1,2]) def farg(request): @@ -1479,42 +1700,43 @@ class TestAutouseManagement: @pytest.fixture(scope="function", autouse=True) def append(request, farg, carg): def fin(): - l.append("fin_%s%s" % (carg, farg)) + values.append("fin_%s%s" % (carg, farg)) request.addfinalizer(fin) """) testdir.makepyfile(""" import pytest - class TestClass: + class TestClass(object): def test_1(self): pass - class TestClass2: + class TestClass2(object): def test_2(self): pass """) - reprec = testdir.inline_run("-v","-s") + confcut = "--confcutdir={0}".format(testdir.tmpdir) + reprec = testdir.inline_run("-v", "-s", confcut) reprec.assertoutcome(passed=8) config = reprec.getcalls("pytest_unconfigure")[0].config - l = config.pluginmanager._getconftestmodules(p)[0].l - assert l == ["fin_a1", "fin_a2", "fin_b1", "fin_b2"] * 2 + values = config.pluginmanager._getconftestmodules(p)[0].values + assert values == ["fin_a1", "fin_a2", "fin_b1", "fin_b2"] * 2 def test_scope_ordering(self, testdir): testdir.makepyfile(""" import pytest - l = [] + values = [] @pytest.fixture(scope="function", autouse=True) def fappend2(): - l.append(2) + values.append(2) @pytest.fixture(scope="class", autouse=True) def classappend3(): - l.append(3) + values.append(3) @pytest.fixture(scope="module", autouse=True) def mappend(): - l.append(1) + values.append(1) - class TestHallo: + class TestHallo(object): def test_method(self): - assert l == [1,3,2] + assert values == [1,3,2] """) reprec = testdir.inline_run() reprec.assertoutcome(passed=1) @@ -1522,23 +1744,23 @@ class TestAutouseManagement: def test_parametrization_setup_teardown_ordering(self, testdir): testdir.makepyfile(""" import pytest - l = [] + values = [] def pytest_generate_tests(metafunc): if metafunc.cls is not None: metafunc.parametrize("item", [1,2], scope="class") - class TestClass: + class TestClass(object): @pytest.fixture(scope="class", autouse=True) def addteardown(self, item, request): - l.append("setup-%d" % item) - request.addfinalizer(lambda: l.append("teardown-%d" % item)) + values.append("setup-%d" % item) + request.addfinalizer(lambda: values.append("teardown-%d" % item)) def test_step1(self, item): - l.append("step1-%d" % item) + values.append("step1-%d" % item) def test_step2(self, item): - l.append("step2-%d" % item) + values.append("step2-%d" % item) def test_finish(): - print (l) - assert l == ["setup-1", "step1-1", "step2-1", "teardown-1", + print (values) + assert values == ["setup-1", "step1-1", "step2-1", "teardown-1", "setup-2", "step1-2", "step2-2", "teardown-2",] """) reprec = testdir.inline_run() @@ -1548,56 +1770,56 @@ class TestAutouseManagement: testdir.makepyfile(""" import pytest - l = [] + values = [] @pytest.fixture(autouse=True) def fix1(): - l.append(1) + values.append(1) @pytest.fixture() def arg1(): - l.append(2) + values.append(2) def test_hello(arg1): - assert l == [1,2] + assert values == [1,2] """) reprec = testdir.inline_run() reprec.assertoutcome(passed=1) @pytest.mark.issue226 - @pytest.mark.parametrize("param1", ["", "params=[1]"], ids=["p00","p01"]) - @pytest.mark.parametrize("param2", ["", "params=[1]"], ids=["p10","p11"]) + @pytest.mark.parametrize("param1", ["", "params=[1]"], ids=["p00", "p01"]) + @pytest.mark.parametrize("param2", ["", "params=[1]"], ids=["p10", "p11"]) def test_ordering_dependencies_torndown_first(self, testdir, param1, param2): testdir.makepyfile(""" import pytest - l = [] + values = [] @pytest.fixture(%(param1)s) def arg1(request): - request.addfinalizer(lambda: l.append("fin1")) - l.append("new1") + request.addfinalizer(lambda: values.append("fin1")) + values.append("new1") @pytest.fixture(%(param2)s) def arg2(request, arg1): - request.addfinalizer(lambda: l.append("fin2")) - l.append("new2") + request.addfinalizer(lambda: values.append("fin2")) + values.append("new2") def test_arg(arg2): pass def test_check(): - assert l == ["new1", "new2", "fin2", "fin1"] + assert values == ["new1", "new2", "fin2", "fin1"] """ % locals()) reprec = testdir.inline_run("-s") reprec.assertoutcome(passed=2) -class TestFixtureMarker: +class TestFixtureMarker(object): def test_parametrize(self, testdir): testdir.makepyfile(""" import pytest @pytest.fixture(params=["a", "b", "c"]) def arg(request): return request.param - l = [] + values = [] def test_param(arg): - l.append(arg) + values.append(arg) def test_result(): - assert l == list("abc") + assert values == list("abc") """) reprec = testdir.inline_run() reprec.assertoutcome(passed=4) @@ -1641,21 +1863,21 @@ class TestFixtureMarker: def test_scope_session(self, testdir): testdir.makepyfile(""" import pytest - l = [] + values = [] @pytest.fixture(scope="module") def arg(): - l.append(1) + values.append(1) return 1 def test_1(arg): assert arg == 1 def test_2(arg): assert arg == 1 - assert len(l) == 1 - class TestClass: + assert len(values) == 1 + class TestClass(object): def test3(self, arg): assert arg == 1 - assert len(l) == 1 + assert len(values) == 1 """) reprec = testdir.inline_run() reprec.assertoutcome(passed=3) @@ -1663,10 +1885,10 @@ class TestFixtureMarker: def test_scope_session_exc(self, testdir): testdir.makepyfile(""" import pytest - l = [] + values = [] @pytest.fixture(scope="session") def fix(): - l.append(1) + values.append(1) pytest.skip('skipping') def test_1(fix): @@ -1674,7 +1896,7 @@ class TestFixtureMarker: def test_2(fix): pass def test_last(): - assert l == [1] + assert values == [1] """) reprec = testdir.inline_run() reprec.assertoutcome(skipped=2, passed=1) @@ -1682,11 +1904,11 @@ class TestFixtureMarker: def test_scope_session_exc_two_fix(self, testdir): testdir.makepyfile(""" import pytest - l = [] + values = [] m = [] @pytest.fixture(scope="session") def a(): - l.append(1) + values.append(1) pytest.skip('skipping') @pytest.fixture(scope="session") def b(a): @@ -1697,7 +1919,7 @@ class TestFixtureMarker: def test_2(b): pass def test_last(): - assert l == [1] + assert values == [1] assert m == [] """) reprec = testdir.inline_run() @@ -1735,21 +1957,21 @@ class TestFixtureMarker: def test_scope_module_uses_session(self, testdir): testdir.makepyfile(""" import pytest - l = [] + values = [] @pytest.fixture(scope="module") def arg(): - l.append(1) + values.append(1) return 1 def test_1(arg): assert arg == 1 def test_2(arg): assert arg == 1 - assert len(l) == 1 - class TestClass: + assert len(values) == 1 + class TestClass(object): def test3(self, arg): assert arg == 1 - assert len(l) == 1 + assert len(values) == 1 """) reprec = testdir.inline_run() reprec.assertoutcome(passed=3) @@ -1757,17 +1979,19 @@ class TestFixtureMarker: def test_scope_module_and_finalizer(self, testdir): testdir.makeconftest(""" import pytest - finalized = [] - created = [] + finalized_list = [] + created_list = [] @pytest.fixture(scope="module") def arg(request): - created.append(1) + created_list.append(1) assert request.scope == "module" - request.addfinalizer(lambda: finalized.append(1)) - def pytest_funcarg__created(request): - return len(created) - def pytest_funcarg__finalized(request): - return len(finalized) + request.addfinalizer(lambda: finalized_list.append(1)) + @pytest.fixture + def created(request): + return len(created_list) + @pytest.fixture + def finalized(request): + return len(finalized_list) """) testdir.makepyfile( test_mod1=""" @@ -1790,9 +2014,9 @@ class TestFixtureMarker: reprec.assertoutcome(passed=4) @pytest.mark.parametrize("method", [ - 'request.getfuncargvalue("arg")', + 'request.getfixturevalue("arg")', 'request.cached_setup(lambda: None, scope="function")', - ], ids=["getfuncargvalue", "cached_setup"]) + ], ids=["getfixturevalue", "cached_setup"]) def test_scope_mismatch_various(self, testdir, method): testdir.makeconftest(""" import pytest @@ -1842,17 +2066,17 @@ class TestFixtureMarker: @pytest.fixture(scope="module", params=["a", "b", "c"]) def arg(request): return request.param - l = [] + values = [] def test_param(arg): - l.append(arg) + values.append(arg) """) reprec = testdir.inline_run("-v") reprec.assertoutcome(passed=3) - l = reprec.getcalls("pytest_runtest_call")[0].item.module.l - assert len(l) == 3 - assert "a" in l - assert "b" in l - assert "c" in l + values = reprec.getcalls("pytest_runtest_call")[0].item.module.values + assert len(values) == 3 + assert "a" in values + assert "b" in values + assert "c" in values def test_scope_mismatch(self, testdir): testdir.makeconftest(""" @@ -1883,18 +2107,22 @@ class TestFixtureMarker: def arg(request): return request.param - l = [] + values = [] def test_1(arg): - l.append(arg) + values.append(arg) def test_2(arg): - l.append(arg) + values.append(arg) """) reprec = testdir.inline_run("-v") reprec.assertoutcome(passed=4) - l = reprec.getcalls("pytest_runtest_call")[0].item.module.l - assert l == [1,1,2,2] + values = reprec.getcalls("pytest_runtest_call")[0].item.module.values + assert values == [1, 1, 2, 2] def test_module_parametrized_ordering(self, testdir): + testdir.makeini(""" + [pytest] + console_output_style=classic + """) testdir.makeconftest(""" import pytest @@ -1941,10 +2169,14 @@ class TestFixtureMarker: """) def test_class_ordering(self, testdir): + testdir.makeini(""" + [pytest] + console_output_style=classic + """) testdir.makeconftest(""" import pytest - l = [] + values = [] @pytest.fixture(scope="function", params=[1,2]) def farg(request): @@ -1957,18 +2189,18 @@ class TestFixtureMarker: @pytest.fixture(scope="function", autouse=True) def append(request, farg, carg): def fin(): - l.append("fin_%s%s" % (carg, farg)) + values.append("fin_%s%s" % (carg, farg)) request.addfinalizer(fin) """) testdir.makepyfile(""" import pytest - class TestClass2: + class TestClass2(object): def test_1(self): pass def test_2(self): pass - class TestClass: + class TestClass(object): def test_3(self): pass """) @@ -1995,30 +2227,30 @@ class TestFixtureMarker: @pytest.fixture(scope="function", params=[1, 2]) def arg(request): param = request.param - request.addfinalizer(lambda: l.append("fin:%s" % param)) - l.append("create:%s" % param) + request.addfinalizer(lambda: values.append("fin:%s" % param)) + values.append("create:%s" % param) return request.param @pytest.fixture(scope="module", params=["mod1", "mod2"]) def modarg(request): param = request.param - request.addfinalizer(lambda: l.append("fin:%s" % param)) - l.append("create:%s" % param) + request.addfinalizer(lambda: values.append("fin:%s" % param)) + values.append("create:%s" % param) return request.param - l = [] + values = [] def test_1(arg): - l.append("test1") + values.append("test1") def test_2(modarg): - l.append("test2") + values.append("test2") def test_3(arg, modarg): - l.append("test3") + values.append("test3") def test_4(modarg, arg): - l.append("test4") + values.append("test4") """) reprec = testdir.inline_run("-v") reprec.assertoutcome(passed=12) - l = reprec.getcalls("pytest_runtest_call")[0].item.module.l + values = reprec.getcalls("pytest_runtest_call")[0].item.module.values expected = [ 'create:1', 'test1', 'fin:1', 'create:2', 'test1', 'fin:2', 'create:mod1', 'test2', 'create:1', 'test3', @@ -2027,10 +2259,10 @@ class TestFixtureMarker: 'fin:mod1', 'create:mod2', 'test2', 'create:1', 'test3', 'fin:1', 'create:2', 'test3', 'fin:2', 'create:1', 'test4', 'fin:1', 'create:2', 'test4', 'fin:2', - 'fin:mod2'] + 'fin:mod2'] import pprint - pprint.pprint(list(zip(l, expected))) - assert l == expected + pprint.pprint(list(zip(values, expected))) + assert values == expected def test_parametrized_fixture_teardown_order(self, testdir): testdir.makepyfile(""" @@ -2039,29 +2271,29 @@ class TestFixtureMarker: def param1(request): return request.param - l = [] + values = [] - class TestClass: + class TestClass(object): @classmethod @pytest.fixture(scope="class", autouse=True) def setup1(self, request, param1): - l.append(1) + values.append(1) request.addfinalizer(self.teardown1) @classmethod def teardown1(self): - assert l.pop() == 1 + assert values.pop() == 1 @pytest.fixture(scope="class", autouse=True) def setup2(self, request, param1): - l.append(2) + values.append(2) request.addfinalizer(self.teardown2) @classmethod def teardown2(self): - assert l.pop() == 2 + assert values.pop() == 2 def test(self): pass def test_finish(): - assert not l + assert not values """) result = testdir.runpytest("-v") result.stdout.fnmatch_lines(""" @@ -2083,7 +2315,7 @@ class TestFixtureMarker: return {} """) b = testdir.mkdir("subdir") - b.join("test_overriden_fixture_finalizer.py").write(dedent(""" + b.join("test_overridden_fixture_finalizer.py").write(dedent(""" import pytest @pytest.fixture def browser(browser): @@ -2101,7 +2333,7 @@ class TestFixtureMarker: testpath = testdir.makepyfile(""" import pytest - class Box: + class Box(object): value = 0 @pytest.fixture(scope='class') @@ -2112,11 +2344,11 @@ class TestFixtureMarker: def test_a(a): assert a == 1 - class Test1: + class Test1(object): def test_b(self, a): assert a == 2 - class Test2: + class Test2(object): def test_c(self, a): assert a == 3""") reprec = testdir.inline_run(testpath) @@ -2126,42 +2358,42 @@ class TestFixtureMarker: def test_request_is_clean(self, testdir): testdir.makepyfile(""" import pytest - l = [] + values = [] @pytest.fixture(params=[1, 2]) def fix(request): - request.addfinalizer(lambda: l.append(request.param)) + request.addfinalizer(lambda: values.append(request.param)) def test_fix(fix): pass """) reprec = testdir.inline_run("-s") - l = reprec.getcalls("pytest_runtest_call")[0].item.module.l - assert l == [1,2] + values = reprec.getcalls("pytest_runtest_call")[0].item.module.values + assert values == [1, 2] def test_parametrize_separated_lifecycle(self, testdir): testdir.makepyfile(""" import pytest - l = [] + values = [] @pytest.fixture(scope="module", params=[1, 2]) def arg(request): x = request.param - request.addfinalizer(lambda: l.append("fin%s" % x)) + request.addfinalizer(lambda: values.append("fin%s" % x)) return request.param def test_1(arg): - l.append(arg) + values.append(arg) def test_2(arg): - l.append(arg) + values.append(arg) """) reprec = testdir.inline_run("-vs") reprec.assertoutcome(passed=4) - l = reprec.getcalls("pytest_runtest_call")[0].item.module.l + values = reprec.getcalls("pytest_runtest_call")[0].item.module.values import pprint - pprint.pprint(l) - #assert len(l) == 6 - assert l[0] == l[1] == 1 - assert l[2] == "fin1" - assert l[3] == l[4] == 2 - assert l[5] == "fin2" + pprint.pprint(values) + # assert len(values) == 6 + assert values[0] == values[1] == 1 + assert values[2] == "fin1" + assert values[3] == values[4] == 2 + assert values[5] == "fin2" def test_parametrize_function_scoped_finalizers_called(self, testdir): testdir.makepyfile(""" @@ -2170,28 +2402,27 @@ class TestFixtureMarker: @pytest.fixture(scope="function", params=[1, 2]) def arg(request): x = request.param - request.addfinalizer(lambda: l.append("fin%s" % x)) + request.addfinalizer(lambda: values.append("fin%s" % x)) return request.param - l = [] + values = [] def test_1(arg): - l.append(arg) + values.append(arg) def test_2(arg): - l.append(arg) + values.append(arg) def test_3(): - assert len(l) == 8 - assert l == [1, "fin1", 2, "fin2", 1, "fin1", 2, "fin2"] + assert len(values) == 8 + assert values == [1, "fin1", 2, "fin2", 1, "fin1", 2, "fin2"] """) reprec = testdir.inline_run("-v") reprec.assertoutcome(passed=5) - @pytest.mark.issue246 @pytest.mark.parametrize("scope", ["session", "function", "module"]) def test_finalizer_order_on_parametrization(self, scope, testdir): testdir.makepyfile(""" import pytest - l = [] + values = [] @pytest.fixture(scope=%(scope)r, params=["1"]) def fix1(request): @@ -2200,13 +2431,13 @@ class TestFixtureMarker: @pytest.fixture(scope=%(scope)r) def fix2(request, base): def cleanup_fix2(): - assert not l, "base should not have been finalized" + assert not values, "base should not have been finalized" request.addfinalizer(cleanup_fix2) @pytest.fixture(scope=%(scope)r) def base(request, fix1): def cleanup_base(): - l.append("fin_base") + values.append("fin_base") print ("finalizing base") request.addfinalizer(cleanup_base) @@ -2224,29 +2455,29 @@ class TestFixtureMarker: def test_class_scope_parametrization_ordering(self, testdir): testdir.makepyfile(""" import pytest - l = [] + values = [] @pytest.fixture(params=["John", "Doe"], scope="class") def human(request): - request.addfinalizer(lambda: l.append("fin %s" % request.param)) + request.addfinalizer(lambda: values.append("fin %s" % request.param)) return request.param - class TestGreetings: + class TestGreetings(object): def test_hello(self, human): - l.append("test_hello") + values.append("test_hello") - class TestMetrics: + class TestMetrics(object): def test_name(self, human): - l.append("test_name") + values.append("test_name") def test_population(self, human): - l.append("test_population") + values.append("test_population") """) reprec = testdir.inline_run() reprec.assertoutcome(passed=6) - l = reprec.getcalls("pytest_runtest_call")[0].item.module.l - assert l == ["test_hello", "fin John", "test_hello", "fin Doe", - "test_name", "test_population", "fin John", - "test_name", "test_population", "fin Doe"] + values = reprec.getcalls("pytest_runtest_call")[0].item.module.values + assert values == ["test_hello", "fin John", "test_hello", "fin Doe", + "test_name", "test_population", "fin John", + "test_name", "test_population", "fin Doe"] def test_parametrize_setup_function(self, testdir): testdir.makepyfile(""" @@ -2258,21 +2489,21 @@ class TestFixtureMarker: @pytest.fixture(scope="module", autouse=True) def mysetup(request, arg): - request.addfinalizer(lambda: l.append("fin%s" % arg)) - l.append("setup%s" % arg) + request.addfinalizer(lambda: values.append("fin%s" % arg)) + values.append("setup%s" % arg) - l = [] + values = [] def test_1(arg): - l.append(arg) + values.append(arg) def test_2(arg): - l.append(arg) + values.append(arg) def test_3(): import pprint - pprint.pprint(l) + pprint.pprint(values) if arg == 1: - assert l == ["setup1", 1, 1, ] + assert values == ["setup1", 1, 1, ] elif arg == 2: - assert l == ["setup1", 1, 1, "fin1", + assert values == ["setup1", 1, 1, "fin1", "setup2", 2, 2, ] """) @@ -2326,9 +2557,42 @@ class TestFixtureMarker: '*test_foo*alpha*', '*test_foo*beta*']) + @pytest.mark.issue920 + def test_deterministic_fixture_collection(self, testdir, monkeypatch): + testdir.makepyfile(""" + import pytest -class TestRequestScopeAccess: - pytestmark = pytest.mark.parametrize(("scope", "ok", "error"),[ + @pytest.fixture(scope="module", + params=["A", + "B", + "C"]) + def A(request): + return request.param + + @pytest.fixture(scope="module", + params=["DDDDDDDDD", "EEEEEEEEEEEE", "FFFFFFFFFFF", "banansda"]) + def B(request, A): + return request.param + + def test_foo(B): + # Something funky is going on here. + # Despite specified seeds, on what is collected, + # sometimes we get unexpected passes. hashing B seems + # to help? + assert hash(B) or True + """) + monkeypatch.setenv("PYTHONHASHSEED", "1") + out1 = testdir.runpytest_subprocess("-v") + monkeypatch.setenv("PYTHONHASHSEED", "2") + out2 = testdir.runpytest_subprocess("-v") + out1 = [line for line in out1.outlines if line.startswith("test_deterministic_fixture_collection.py::test_foo")] + out2 = [line for line in out2.outlines if line.startswith("test_deterministic_fixture_collection.py::test_foo")] + assert len(out1) == 12 + assert out1 == out2 + + +class TestRequestScopeAccess(object): + pytestmark = pytest.mark.parametrize(("scope", "ok", "error"), [ ["session", "", "fspath class function module"], ["module", "module fspath", "cls function"], ["class", "module fspath cls", "function"], @@ -2349,7 +2613,7 @@ class TestRequestScopeAccess: assert request.config def test_func(): pass - """ %(scope, ok.split(), error.split())) + """ % (scope, ok.split(), error.split())) reprec = testdir.inline_run("-l") reprec.assertoutcome(passed=1) @@ -2367,11 +2631,12 @@ class TestRequestScopeAccess: assert request.config def test_func(arg): pass - """ %(scope, ok.split(), error.split())) + """ % (scope, ok.split(), error.split())) reprec = testdir.inline_run() reprec.assertoutcome(passed=1) -class TestErrors: + +class TestErrors(object): def test_subfactory_missing_funcarg(self, testdir): testdir.makepyfile(""" import pytest @@ -2399,13 +2664,13 @@ class TestErrors: request.addfinalizer(f) return object() - l = [] + values = [] def test_1(fix1): - l.append(fix1) + values.append(fix1) def test_2(fix1): - l.append(fix1) + values.append(fix1) def test_3(): - assert l[0] != l[1] + assert values[0] != values[1] """) result = testdir.runpytest() result.stdout.fnmatch_lines(""" @@ -2416,8 +2681,6 @@ class TestErrors: *3 pass*2 error* """) - - def test_setupfunc_missing_funcarg(self, testdir): testdir.makepyfile(""" import pytest @@ -2435,7 +2698,8 @@ class TestErrors: "*1 error*", ]) -class TestShowFixtures: + +class TestShowFixtures(object): def test_funcarg_compat(self, testdir): config = testdir.parseconfigure("--funcargs") assert config.option.showfixtures @@ -2443,18 +2707,16 @@ class TestShowFixtures: def test_show_fixtures(self, testdir): result = testdir.runpytest("--fixtures") result.stdout.fnmatch_lines([ - "*tmpdir*", - "*temporary directory*", - ] - ) + "*tmpdir*", + "*temporary directory*", + ]) def test_show_fixtures_verbose(self, testdir): result = testdir.runpytest("--fixtures", "-v") result.stdout.fnmatch_lines([ - "*tmpdir*--*tmpdir.py*", - "*temporary directory*", - ] - ) + "*tmpdir*--*tmpdir.py*", + "*temporary directory*", + ]) def test_show_fixtures_testmodule(self, testdir): p = testdir.makepyfile(''' @@ -2497,7 +2759,7 @@ class TestShowFixtures: """) def test_show_fixtures_trimmed_doc(self, testdir): - p = testdir.makepyfile(''' + p = testdir.makepyfile(dedent(''' import pytest @pytest.fixture def arg1(): @@ -2513,9 +2775,9 @@ class TestShowFixtures: line2 """ - ''') + ''')) result = testdir.runpytest("--fixtures", p) - result.stdout.fnmatch_lines(""" + result.stdout.fnmatch_lines(dedent(""" * fixtures defined from test_show_fixtures_trimmed_doc * arg2 line1 @@ -2524,8 +2786,64 @@ class TestShowFixtures: line1 line2 - """) + """)) + def test_show_fixtures_indented_doc(self, testdir): + p = testdir.makepyfile(dedent(''' + import pytest + @pytest.fixture + def fixture1(): + """ + line1 + indented line + """ + ''')) + result = testdir.runpytest("--fixtures", p) + result.stdout.fnmatch_lines(dedent(""" + * fixtures defined from test_show_fixtures_indented_doc * + fixture1 + line1 + indented line + """)) + + def test_show_fixtures_indented_doc_first_line_unindented(self, testdir): + p = testdir.makepyfile(dedent(''' + import pytest + @pytest.fixture + def fixture1(): + """line1 + line2 + indented line + """ + ''')) + result = testdir.runpytest("--fixtures", p) + result.stdout.fnmatch_lines(dedent(""" + * fixtures defined from test_show_fixtures_indented_doc_first_line_unindented * + fixture1 + line1 + line2 + indented line + """)) + + def test_show_fixtures_indented_in_class(self, testdir): + p = testdir.makepyfile(dedent(''' + import pytest + class TestClass: + @pytest.fixture + def fixture1(self): + """line1 + line2 + indented line + """ + ''')) + result = testdir.runpytest("--fixtures", p) + result.stdout.fnmatch_lines(dedent(""" + * fixtures defined from test_show_fixtures_indented_in_class * + fixture1 + line1 + line2 + indented line + """)) def test_show_fixtures_different_files(self, testdir): """ @@ -2564,12 +2882,46 @@ class TestShowFixtures: Fixture B """) + def test_show_fixtures_with_same_name(self, testdir): + testdir.makeconftest(''' + import pytest + @pytest.fixture + def arg1(): + """Hello World in conftest.py""" + return "Hello World" + ''') + testdir.makepyfile(''' + def test_foo(arg1): + assert arg1 == "Hello World" + ''') + testdir.makepyfile(''' + import pytest + @pytest.fixture + def arg1(): + """Hi from test module""" + return "Hi" + def test_bar(arg1): + assert arg1 == "Hi" + ''') + result = testdir.runpytest("--fixtures") + result.stdout.fnmatch_lines(''' + * fixtures defined from conftest * + arg1 + Hello World in conftest.py -class TestContextManagerFixtureFuncs: - def test_simple(self, testdir): + * fixtures defined from test_show_fixtures_with_same_name * + arg1 + Hi from test module + ''') + + +@pytest.mark.parametrize('flavor', ['fixture', 'yield_fixture']) +class TestContextManagerFixtureFuncs(object): + + def test_simple(self, testdir, flavor): testdir.makepyfile(""" import pytest - @pytest.yield_fixture + @pytest.{flavor} def arg1(): print ("setup") yield 1 @@ -2579,7 +2931,7 @@ class TestContextManagerFixtureFuncs: def test_2(arg1): print ("test2 %s" % arg1) assert 0 - """) + """.format(flavor=flavor)) result = testdir.runpytest("-s") result.stdout.fnmatch_lines(""" *setup* @@ -2590,10 +2942,10 @@ class TestContextManagerFixtureFuncs: *teardown* """) - def test_scoped(self, testdir): + def test_scoped(self, testdir, flavor): testdir.makepyfile(""" import pytest - @pytest.yield_fixture(scope="module") + @pytest.{flavor}(scope="module") def arg1(): print ("setup") yield 1 @@ -2602,7 +2954,7 @@ class TestContextManagerFixtureFuncs: print ("test1 %s" % arg1) def test_2(arg1): print ("test2 %s" % arg1) - """) + """.format(flavor=flavor)) result = testdir.runpytest("-s") result.stdout.fnmatch_lines(""" *setup* @@ -2611,83 +2963,209 @@ class TestContextManagerFixtureFuncs: *teardown* """) - def test_setup_exception(self, testdir): + def test_setup_exception(self, testdir, flavor): testdir.makepyfile(""" import pytest - @pytest.yield_fixture(scope="module") + @pytest.{flavor}(scope="module") def arg1(): pytest.fail("setup") yield 1 def test_1(arg1): pass - """) + """.format(flavor=flavor)) result = testdir.runpytest("-s") result.stdout.fnmatch_lines(""" *pytest.fail*setup* *1 error* """) - def test_teardown_exception(self, testdir): + def test_teardown_exception(self, testdir, flavor): testdir.makepyfile(""" import pytest - @pytest.yield_fixture(scope="module") + @pytest.{flavor}(scope="module") def arg1(): yield 1 pytest.fail("teardown") def test_1(arg1): pass - """) + """.format(flavor=flavor)) result = testdir.runpytest("-s") result.stdout.fnmatch_lines(""" *pytest.fail*teardown* *1 passed*1 error* """) - def test_yields_more_than_one(self, testdir): + def test_yields_more_than_one(self, testdir, flavor): testdir.makepyfile(""" import pytest - @pytest.yield_fixture(scope="module") + @pytest.{flavor}(scope="module") def arg1(): yield 1 yield 2 def test_1(arg1): pass - """) + """.format(flavor=flavor)) result = testdir.runpytest("-s") result.stdout.fnmatch_lines(""" *fixture function* *test_yields*:2* """) - - def test_no_yield(self, testdir): + def test_custom_name(self, testdir, flavor): testdir.makepyfile(""" import pytest - @pytest.yield_fixture(scope="module") + @pytest.{flavor}(name='meow') def arg1(): - return 1 - def test_1(arg1): - pass - """) + return 'mew' + def test_1(meow): + print(meow) + """.format(flavor=flavor)) result = testdir.runpytest("-s") - result.stdout.fnmatch_lines(""" - *yield_fixture*requires*yield* - *yield_fixture* - *def arg1* - """) + result.stdout.fnmatch_lines("*mew*") - def test_yield_not_allowed_in_non_yield(self, testdir): - testdir.makepyfile(""" + +class TestParameterizedSubRequest(object): + def test_call_from_fixture(self, testdir): + testfile = testdir.makepyfile(""" import pytest - @pytest.fixture(scope="module") - def arg1(): - yield 1 - def test_1(arg1): - pass - """) - result = testdir.runpytest("-s") - result.stdout.fnmatch_lines(""" - *fixture*cannot use*yield* - *def arg1* - """) + @pytest.fixture(params=[0, 1, 2]) + def fix_with_param(request): + return request.param + + @pytest.fixture + def get_named_fixture(request): + return request.getfixturevalue('fix_with_param') + + def test_foo(request, get_named_fixture): + pass + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines(""" + E*Failed: The requested fixture has no parameter defined for the current test. + E* + E*Requested fixture 'fix_with_param' defined in: + E*{0}:4 + E*Requested here: + E*{1}:9 + *1 error* + """.format(testfile.basename, testfile.basename)) + + def test_call_from_test(self, testdir): + testfile = testdir.makepyfile(""" + import pytest + + @pytest.fixture(params=[0, 1, 2]) + def fix_with_param(request): + return request.param + + def test_foo(request): + request.getfixturevalue('fix_with_param') + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines(""" + E*Failed: The requested fixture has no parameter defined for the current test. + E* + E*Requested fixture 'fix_with_param' defined in: + E*{0}:4 + E*Requested here: + E*{1}:8 + *1 failed* + """.format(testfile.basename, testfile.basename)) + + def test_external_fixture(self, testdir): + conffile = testdir.makeconftest(""" + import pytest + + @pytest.fixture(params=[0, 1, 2]) + def fix_with_param(request): + return request.param + """) + + testfile = testdir.makepyfile(""" + def test_foo(request): + request.getfixturevalue('fix_with_param') + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines(""" + E*Failed: The requested fixture has no parameter defined for the current test. + E* + E*Requested fixture 'fix_with_param' defined in: + E*{0}:4 + E*Requested here: + E*{1}:2 + *1 failed* + """.format(conffile.basename, testfile.basename)) + + def test_non_relative_path(self, testdir): + tests_dir = testdir.mkdir('tests') + fixdir = testdir.mkdir('fixtures') + fixfile = fixdir.join("fix.py") + fixfile.write(_pytest._code.Source(""" + import pytest + + @pytest.fixture(params=[0, 1, 2]) + def fix_with_param(request): + return request.param + """)) + + testfile = tests_dir.join("test_foos.py") + testfile.write(_pytest._code.Source(""" + from fix import fix_with_param + + def test_foo(request): + request.getfixturevalue('fix_with_param') + """)) + + tests_dir.chdir() + testdir.syspathinsert(fixdir) + result = testdir.runpytest() + result.stdout.fnmatch_lines(""" + E*Failed: The requested fixture has no parameter defined for the current test. + E* + E*Requested fixture 'fix_with_param' defined in: + E*{0}:5 + E*Requested here: + E*{1}:5 + *1 failed* + """.format(fixfile.strpath, testfile.basename)) + + +def test_pytest_fixture_setup_and_post_finalizer_hook(testdir): + testdir.makeconftest(""" + from __future__ import print_function + def pytest_fixture_setup(fixturedef, request): + print('ROOT setup hook called for {0} from {1}'.format(fixturedef.argname, request.node.name)) + def pytest_fixture_post_finalizer(fixturedef, request): + print('ROOT finalizer hook called for {0} from {1}'.format(fixturedef.argname, request.node.name)) + """) + testdir.makepyfile(**{ + 'tests/conftest.py': """ + from __future__ import print_function + def pytest_fixture_setup(fixturedef, request): + print('TESTS setup hook called for {0} from {1}'.format(fixturedef.argname, request.node.name)) + def pytest_fixture_post_finalizer(fixturedef, request): + print('TESTS finalizer hook called for {0} from {1}'.format(fixturedef.argname, request.node.name)) + """, + 'tests/test_hooks.py': """ + from __future__ import print_function + import pytest + + @pytest.fixture() + def my_fixture(): + return 'some' + + def test_func(my_fixture): + print('TEST test_func') + assert my_fixture == 'some' + """ + }) + result = testdir.runpytest("-s") + assert result.ret == 0 + result.stdout.fnmatch_lines([ + "*TESTS setup hook called for my_fixture from test_func*", + "*ROOT setup hook called for my_fixture from test_func*", + "*TEST test_func*", + "*TESTS finalizer hook called for my_fixture from test_func*", + "*ROOT finalizer hook called for my_fixture from test_func*", + ]) diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/python/integration.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/integration.py similarity index 91% rename from tests/wpt/web-platform-tests/tools/pytest/testing/python/integration.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/integration.py index dea86f942fd..6ea29fa98b9 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/python/integration.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/integration.py @@ -3,8 +3,8 @@ from _pytest import python from _pytest import runner -class TestOEJSKITSpecials: - def test_funcarg_non_pycollectobj(self, testdir): # rough jstests usage +class TestOEJSKITSpecials(object): + def test_funcarg_non_pycollectobj(self, testdir): # rough jstests usage testdir.makeconftest(""" import pytest def pytest_pycollect_makeitem(collector, name, obj): @@ -15,9 +15,11 @@ class TestOEJSKITSpecials: return self.fspath, 3, "xyz" """) modcol = testdir.getmodulecol(""" - def pytest_funcarg__arg1(request): + import pytest + @pytest.fixture + def arg1(request): return 42 - class MyClass: + class MyClass(object): pass """) # this hook finds funcarg factories @@ -28,7 +30,7 @@ class TestOEJSKITSpecials: pytest._fillfuncargs(clscol) assert clscol.funcargs['arg1'] == 42 - def test_autouse_fixture(self, testdir): # rough jstests usage + def test_autouse_fixture(self, testdir): # rough jstests usage testdir.makeconftest(""" import pytest def pytest_pycollect_makeitem(collector, name, obj): @@ -43,9 +45,10 @@ class TestOEJSKITSpecials: @pytest.fixture(autouse=True) def hello(): pass - def pytest_funcarg__arg1(request): + @pytest.fixture + def arg1(request): return 42 - class MyClass: + class MyClass(object): pass """) # this hook finds funcarg factories @@ -60,10 +63,12 @@ class TestOEJSKITSpecials: def test_wrapped_getfslineno(): def func(): pass + def wrap(f): func.__wrapped__ = f func.patchings = ["qwe"] return func + @wrap def wrapped_func(x, y, z): pass @@ -71,33 +76,42 @@ def test_wrapped_getfslineno(): fs2, lineno2 = python.getfslineno(wrap) assert lineno > lineno2, "getfslineno does not unwrap correctly" -class TestMockDecoration: + +class TestMockDecoration(object): def test_wrapped_getfuncargnames(self): - from _pytest.python import getfuncargnames + from _pytest.compat import getfuncargnames + def wrap(f): + def func(): pass + func.__wrapped__ = f return func + @wrap def f(x): pass - l = getfuncargnames(f) - assert l == ("x",) + + values = getfuncargnames(f) + assert values == ("x",) def test_wrapped_getfuncargnames_patching(self): - from _pytest.python import getfuncargnames + from _pytest.compat import getfuncargnames + def wrap(f): def func(): pass func.__wrapped__ = f func.patchings = ["qwe"] return func + @wrap def f(x, y, z): pass - l = getfuncargnames(f) - assert l == ("y", "z") + + values = getfuncargnames(f) + assert values == ("y", "z") def test_unittest_mock(self, testdir): pytest.importorskip("unittest.mock") @@ -160,7 +174,7 @@ class TestMockDecoration: reprec.assertoutcome(passed=2) calls = reprec.getcalls("pytest_runtest_logreport") funcnames = [call.report.location[2] for call in calls - if call.report.when == "call"] + if call.report.when == "call"] assert funcnames == ["T.test_hello", "test_someting"] def test_mock_sorting(self, testdir): @@ -194,7 +208,7 @@ class TestMockDecoration: @patch('os.getcwd') @patch('os.path') @mark.slow - class TestSimple: + class TestSimple(object): def test_simple_thing(self, mock_path, mock_getcwd): pass """) @@ -202,7 +216,7 @@ class TestMockDecoration: reprec.assertoutcome(passed=1) -class TestReRunTests: +class TestReRunTests(object): def test_rerun(self, testdir): testdir.makeconftest(""" from _pytest.runner import runtestprotocol @@ -233,12 +247,13 @@ class TestReRunTests: *2 passed* """) + def test_pytestconfig_is_session_scoped(): - from _pytest.python import pytestconfig + from _pytest.fixtures import pytestconfig assert pytestconfig._pytestfixturefunction.scope == "session" -class TestNoselikeTestAttribute: +class TestNoselikeTestAttribute(object): def test_module_with_global_test(self, testdir): testdir.makepyfile(""" __test__ = False @@ -257,7 +272,7 @@ class TestNoselikeTestAttribute: pass test_func.__test__ = False - class TestSome: + class TestSome(object): __test__ = False def test_method(self): pass @@ -315,7 +330,7 @@ class TestNoselikeTestAttribute: @pytest.mark.issue351 -class TestParameterize: +class TestParameterize(object): def test_idfn_marker(self, testdir): testdir.makepyfile(""" diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/python/metafunc.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/metafunc.py similarity index 60% rename from tests/wpt/web-platform-tests/tools/pytest/testing/python/metafunc.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/metafunc.py index faa687f4056..2ffb7bb5da2 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/python/metafunc.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/metafunc.py @@ -1,32 +1,43 @@ # -*- coding: utf-8 -*- import re +import sys import _pytest._code import py import pytest -from _pytest import python as funcargs +from _pytest import python, fixtures -class TestMetafunc: +import hypothesis +from hypothesis import strategies + +PY3 = sys.version_info >= (3, 0) + + +class TestMetafunc(object): def Metafunc(self, func): # the unit tests of this class check if things work correctly # on the funcarg level, so we don't need a full blown # initiliazation - class FixtureInfo: + class FixtureInfo(object): name2fixturedefs = None + def __init__(self, names): self.names_closure = names - names = funcargs.getfuncargnames(func) + + names = fixtures.getfuncargnames(func) fixtureinfo = FixtureInfo(names) - return funcargs.Metafunc(func, fixtureinfo, None) + return python.Metafunc(func, fixtureinfo, None) def test_no_funcargs(self, testdir): - def function(): pass + def function(): + pass metafunc = self.Metafunc(function) assert not metafunc.fixturenames repr(metafunc._calls) def test_function_basic(self): - def func(arg1, arg2="qwe"): pass + def func(arg1, arg2="qwe"): + pass metafunc = self.Metafunc(func) assert len(metafunc.fixturenames) == 1 assert 'arg1' in metafunc.fixturenames @@ -34,7 +45,8 @@ class TestMetafunc: assert metafunc.cls is None def test_addcall_no_args(self): - def func(arg1): pass + def func(arg1): + pass metafunc = self.Metafunc(func) metafunc.addcall() assert len(metafunc._calls) == 1 @@ -43,7 +55,8 @@ class TestMetafunc: assert not hasattr(call, 'param') def test_addcall_id(self): - def func(arg1): pass + def func(arg1): + pass metafunc = self.Metafunc(func) pytest.raises(ValueError, "metafunc.addcall(id=None)") @@ -56,9 +69,13 @@ class TestMetafunc: assert metafunc._calls[1].id == "2" def test_addcall_param(self): - def func(arg1): pass + def func(arg1): + pass metafunc = self.Metafunc(func) - class obj: pass + + class obj(object): + pass + metafunc.addcall(param=obj) metafunc.addcall(param=obj) metafunc.addcall(param=1) @@ -68,9 +85,14 @@ class TestMetafunc: assert metafunc._calls[2].getparam("arg1") == 1 def test_addcall_funcargs(self): - def func(x): pass + def func(x): + pass + metafunc = self.Metafunc(func) - class obj: pass + + class obj(object): + pass + metafunc.addcall(funcargs={"x": 2}) metafunc.addcall(funcargs={"x": 3}) pytest.raises(pytest.fail.Exception, "metafunc.addcall({'xyz': 0})") @@ -80,40 +102,72 @@ class TestMetafunc: assert not hasattr(metafunc._calls[1], 'param') def test_parametrize_error(self): - def func(x, y): pass + def func(x, y): + pass metafunc = self.Metafunc(func) - metafunc.parametrize("x", [1,2]) - pytest.raises(ValueError, lambda: metafunc.parametrize("x", [5,6])) - pytest.raises(ValueError, lambda: metafunc.parametrize("x", [5,6])) - metafunc.parametrize("y", [1,2]) - pytest.raises(ValueError, lambda: metafunc.parametrize("y", [5,6])) - pytest.raises(ValueError, lambda: metafunc.parametrize("y", [5,6])) + metafunc.parametrize("x", [1, 2]) + pytest.raises(ValueError, lambda: metafunc.parametrize("x", [5, 6])) + pytest.raises(ValueError, lambda: metafunc.parametrize("x", [5, 6])) + metafunc.parametrize("y", [1, 2]) + pytest.raises(ValueError, lambda: metafunc.parametrize("y", [5, 6])) + pytest.raises(ValueError, lambda: metafunc.parametrize("y", [5, 6])) + + def test_parametrize_bad_scope(self, testdir): + def func(x): + pass + metafunc = self.Metafunc(func) + try: + metafunc.parametrize("x", [1], scope='doggy') + except ValueError as ve: + assert "has an unsupported scope value 'doggy'" in str(ve) def test_parametrize_and_id(self): - def func(x, y): pass + def func(x, y): + pass metafunc = self.Metafunc(func) - metafunc.parametrize("x", [1,2], ids=['basic', 'advanced']) + metafunc.parametrize("x", [1, 2], ids=['basic', 'advanced']) metafunc.parametrize("y", ["abc", "def"]) ids = [x.id for x in metafunc._calls] assert ids == ["basic-abc", "basic-def", "advanced-abc", "advanced-def"] + def test_parametrize_and_id_unicode(self): + """Allow unicode strings for "ids" parameter in Python 2 (##1905)""" + def func(x): + pass + metafunc = self.Metafunc(func) + metafunc.parametrize("x", [1, 2], ids=[u'basic', u'advanced']) + ids = [x.id for x in metafunc._calls] + assert ids == [u"basic", u"advanced"] + def test_parametrize_with_wrong_number_of_ids(self, testdir): - def func(x, y): pass + def func(x, y): + pass metafunc = self.Metafunc(func) pytest.raises(ValueError, lambda: - metafunc.parametrize("x", [1,2], ids=['basic'])) + metafunc.parametrize("x", [1, 2], ids=['basic'])) pytest.raises(ValueError, lambda: - metafunc.parametrize(("x","y"), [("abc", "def"), - ("ghi", "jkl")], ids=["one"])) + metafunc.parametrize(("x", "y"), [("abc", "def"), + ("ghi", "jkl")], ids=["one"])) + + @pytest.mark.issue510 + def test_parametrize_empty_list(self): + def func(y): + pass + metafunc = self.Metafunc(func) + metafunc.parametrize("y", []) + assert 'skip' == metafunc._calls[0].marks[0].name def test_parametrize_with_userobjects(self): - def func(x, y): pass - metafunc = self.Metafunc(func) - class A: + def func(x, y): pass + metafunc = self.Metafunc(func) + + class A(object): + pass + metafunc.parametrize("x", [A(), A()]) metafunc.parametrize("y", list("ab")) assert metafunc._calls[0].id == "x0-a" @@ -121,20 +175,45 @@ class TestMetafunc: assert metafunc._calls[2].id == "x1-a" assert metafunc._calls[3].id == "x1-b" - @pytest.mark.skipif('sys.version_info[0] >= 3') - def test_unicode_idval_python2(self): - """unittest for the expected behavior to obtain ids for parametrized - unicode values in Python 2: if convertible to ascii, they should appear - as ascii values, otherwise fallback to hide the value behind the name - of the parametrized variable name. #1086 + @hypothesis.given(strategies.text() | strategies.binary()) + def test_idval_hypothesis(self, value): + from _pytest.python import _idval + escaped = _idval(value, 'a', 6, None) + assert isinstance(escaped, str) + if PY3: + escaped.encode('ascii') + else: + escaped.decode('ascii') + + def test_unicode_idval(self): + """This tests that Unicode strings outside the ASCII character set get + escaped, using byte escapes if they're in that range or unicode + escapes if they're not. + """ from _pytest.python import _idval values = [ - (u'', ''), - (u'ascii', 'ascii'), - (u'ação', 'a6'), - (u'josé@blah.com', 'a6'), - (u'δοκ.ιμή@παράδειγμα.δοκιμή', 'a6'), + ( + u'', + '' + ), + ( + u'ascii', + 'ascii' + ), + ( + u'ação', + 'a\\xe7\\xe3o' + ), + ( + u'josé@blah.com', + 'jos\\xe9@blah.com' + ), + ( + u'δοκ.ιμή@παράδειγμα.δοκιμή', + '\\u03b4\\u03bf\\u03ba.\\u03b9\\u03bc\\u03ae@\\u03c0\\u03b1\\u03c1\\u03ac\\u03b4\\u03b5\\u03b9\\u03b3' + '\\u03bc\\u03b1.\\u03b4\\u03bf\\u03ba\\u03b9\\u03bc\\u03ae' + ), ] for val, expected in values: assert _idval(val, 'a', 6, None) == expected @@ -159,37 +238,40 @@ class TestMetafunc: @pytest.mark.issue250 def test_idmaker_autoname(self): from _pytest.python import idmaker - result = idmaker(("a", "b"), [("string", 1.0), - ("st-ring", 2.0)]) + result = idmaker(("a", "b"), [pytest.param("string", 1.0), + pytest.param("st-ring", 2.0)]) assert result == ["string-1.0", "st-ring-2.0"] - result = idmaker(("a", "b"), [(object(), 1.0), - (object(), object())]) + result = idmaker(("a", "b"), [pytest.param(object(), 1.0), + pytest.param(object(), object())]) assert result == ["a0-1.0", "a1-b1"] # unicode mixing, issue250 - result = idmaker((py.builtin._totext("a"), "b"), [({}, b'\xc3\xb4')]) + result = idmaker( + (py.builtin._totext("a"), "b"), + [pytest.param({}, b'\xc3\xb4')]) assert result == ['a0-\\xc3\\xb4'] def test_idmaker_with_bytes_regex(self): from _pytest.python import idmaker - result = idmaker(("a"), [(re.compile(b'foo'), 1.0)]) + result = idmaker(("a"), [pytest.param(re.compile(b'foo'), 1.0)]) assert result == ["foo"] def test_idmaker_native_strings(self): from _pytest.python import idmaker totext = py.builtin._totext - result = idmaker(("a", "b"), [(1.0, -1.1), - (2, -202), - ("three", "three hundred"), - (True, False), - (None, None), - (re.compile('foo'), re.compile('bar')), - (str, int), - (list("six"), [66, 66]), - (set([7]), set("seven")), - (tuple("eight"), (8, -8, 8)), - (b'\xc3\xb4', b"name"), - (b'\xc3\xb4', totext("other")), + result = idmaker(("a", "b"), [ + pytest.param(1.0, -1.1), + pytest.param(2, -202), + pytest.param("three", "three hundred"), + pytest.param(True, False), + pytest.param(None, None), + pytest.param(re.compile('foo'), re.compile('bar')), + pytest.param(str, int), + pytest.param(list("six"), [66, 66]), + pytest.param(set([7]), set("seven")), + pytest.param(tuple("eight"), (8, -8, 8)), + pytest.param(b'\xc3\xb4', b"name"), + pytest.param(b'\xc3\xb4', totext("other")), ]) assert result == ["1.0--1.1", "2--202", @@ -209,60 +291,126 @@ class TestMetafunc: from _pytest.python import idmaker enum = pytest.importorskip("enum") e = enum.Enum("Foo", "one, two") - result = idmaker(("a", "b"), [(e.one, e.two)]) + result = idmaker(("a", "b"), [pytest.param(e.one, e.two)]) assert result == ["Foo.one-Foo.two"] @pytest.mark.issue351 def test_idmaker_idfn(self): from _pytest.python import idmaker + def ids(val): if isinstance(val, Exception): return repr(val) - result = idmaker(("a", "b"), [(10.0, IndexError()), - (20, KeyError()), - ("three", [1, 2, 3]), + result = idmaker(("a", "b"), [ + pytest.param(10.0, IndexError()), + pytest.param(20, KeyError()), + pytest.param("three", [1, 2, 3]), ], idfn=ids) assert result == ["10.0-IndexError()", "20-KeyError()", "three-b2", - ] + ] @pytest.mark.issue351 def test_idmaker_idfn_unique_names(self): from _pytest.python import idmaker + def ids(val): return 'a' - result = idmaker(("a", "b"), [(10.0, IndexError()), - (20, KeyError()), - ("three", [1, 2, 3]), - ], idfn=ids) - assert result == ["0a-a", - "1a-a", - "2a-a", - ] + result = idmaker(("a", "b"), [pytest.param(10.0, IndexError()), + pytest.param(20, KeyError()), + pytest.param("three", [1, 2, 3]), + ], idfn=ids) + assert result == ["a-a0", + "a-a1", + "a-a2", + ] @pytest.mark.issue351 def test_idmaker_idfn_exception(self): from _pytest.python import idmaker - def ids(val): - raise Exception("bad code") + from _pytest.recwarn import WarningsRecorder - result = idmaker(("a", "b"), [(10.0, IndexError()), - (20, KeyError()), - ("three", [1, 2, 3]), - ], idfn=ids) - assert result == ["10.0-b0", - "20-b1", - "three-b2", - ] + class BadIdsException(Exception): + pass + + def ids(val): + raise BadIdsException("ids raised") + + rec = WarningsRecorder() + with rec: + idmaker(("a", "b"), [ + pytest.param(10.0, IndexError()), + pytest.param(20, KeyError()), + pytest.param("three", [1, 2, 3]), + ], idfn=ids) + + assert [str(i.message) for i in rec.list] == [ + "Raised while trying to determine id of parameter a at position 0." + "\nUpdate your code as this will raise an error in pytest-4.0.", + "Raised while trying to determine id of parameter b at position 0." + "\nUpdate your code as this will raise an error in pytest-4.0.", + "Raised while trying to determine id of parameter a at position 1." + "\nUpdate your code as this will raise an error in pytest-4.0.", + "Raised while trying to determine id of parameter b at position 1." + "\nUpdate your code as this will raise an error in pytest-4.0.", + "Raised while trying to determine id of parameter a at position 2." + "\nUpdate your code as this will raise an error in pytest-4.0.", + "Raised while trying to determine id of parameter b at position 2." + "\nUpdate your code as this will raise an error in pytest-4.0.", + ] + + def test_parametrize_ids_exception(self, testdir): + """ + :param testdir: the instance of Testdir class, a temporary + test directory. + """ + testdir.makepyfile(""" + import pytest + + def ids(arg): + raise Exception("bad ids") + + @pytest.mark.parametrize("arg", ["a", "b"], ids=ids) + def test_foo(arg): + pass + """) + with pytest.warns(DeprecationWarning): + result = testdir.runpytest("--collect-only") + result.stdout.fnmatch_lines([ + "", + " ", + " ", + ]) + + def test_idmaker_with_ids(self): + from _pytest.python import idmaker + result = idmaker(("a", "b"), [pytest.param(1, 2), + pytest.param(3, 4)], + ids=["a", None]) + assert result == ["a", "3-4"] + + def test_idmaker_with_paramset_id(self): + from _pytest.python import idmaker + result = idmaker(("a", "b"), [pytest.param(1, 2, id="me"), + pytest.param(3, 4, id="you")], + ids=["a", None]) + assert result == ["me", "you"] + + def test_idmaker_with_ids_unique_names(self): + from _pytest.python import idmaker + result = idmaker(("a"), map(pytest.param, [1, 2, 3, 4, 5]), + ids=["a", "a", "b", "c", "b"]) + assert result == ["a0", "a1", "b0", "c", "b1"] def test_addcall_and_parametrize(self): - def func(x, y): pass + def func(x, y): + pass metafunc = self.Metafunc(func) metafunc.addcall({'x': 1}) - metafunc.parametrize('y', [2,3]) + metafunc.parametrize('y', [2, 3]) assert len(metafunc._calls) == 2 assert metafunc._calls[0].funcargs == {'x': 1, 'y': 2} assert metafunc._calls[1].funcargs == {'x': 1, 'y': 3} @@ -271,19 +419,21 @@ class TestMetafunc: @pytest.mark.issue714 def test_parametrize_indirect(self): - def func(x, y): pass + def func(x, y): + pass metafunc = self.Metafunc(func) metafunc.parametrize('x', [1], indirect=True) - metafunc.parametrize('y', [2,3], indirect=True) + metafunc.parametrize('y', [2, 3], indirect=True) assert len(metafunc._calls) == 2 assert metafunc._calls[0].funcargs == {} assert metafunc._calls[1].funcargs == {} - assert metafunc._calls[0].params == dict(x=1,y=2) - assert metafunc._calls[1].params == dict(x=1,y=3) + assert metafunc._calls[0].params == dict(x=1, y=2) + assert metafunc._calls[1].params == dict(x=1, y=3) @pytest.mark.issue714 def test_parametrize_indirect_list(self): - def func(x, y): pass + def func(x, y): + pass metafunc = self.Metafunc(func) metafunc.parametrize('x, y', [('a', 'b')], indirect=['x']) assert metafunc._calls[0].funcargs == dict(y='b') @@ -291,7 +441,8 @@ class TestMetafunc: @pytest.mark.issue714 def test_parametrize_indirect_list_all(self): - def func(x, y): pass + def func(x, y): + pass metafunc = self.Metafunc(func) metafunc.parametrize('x, y', [('a', 'b')], indirect=['x', 'y']) assert metafunc._calls[0].funcargs == {} @@ -299,7 +450,8 @@ class TestMetafunc: @pytest.mark.issue714 def test_parametrize_indirect_list_empty(self): - def func(x, y): pass + def func(x, y): + pass metafunc = self.Metafunc(func) metafunc.parametrize('x, y', [('a', 'b')], indirect=[]) assert metafunc._calls[0].funcargs == dict(x='a', y='b') @@ -337,7 +489,8 @@ class TestMetafunc: @pytest.mark.issue714 def test_parametrize_indirect_list_error(self, testdir): - def func(x, y): pass + def func(x, y): + pass metafunc = self.Metafunc(func) with pytest.raises(ValueError): metafunc.parametrize('x, y', [('a', 'b')], indirect=['x', 'z']) @@ -358,7 +511,7 @@ class TestMetafunc: """) result = testdir.runpytest("--collect-only") result.stdout.fnmatch_lines([ - "*uses no fixture 'y'*", + "*uses no argument 'y'*", ]) @pytest.mark.issue714 @@ -381,8 +534,42 @@ class TestMetafunc: "*uses no fixture 'y'*", ]) + @pytest.mark.issue714 + def test_parametrize_indirect_uses_no_fixture_error_indirect_string(self, testdir): + testdir.makepyfile(""" + import pytest + @pytest.fixture(scope='function') + def x(request): + return request.param * 3 + + @pytest.mark.parametrize('x, y', [('a', 'b')], indirect='y') + def test_simple(x): + assert len(x) == 3 + """) + result = testdir.runpytest("--collect-only") + result.stdout.fnmatch_lines([ + "*uses no fixture 'y'*", + ]) + @pytest.mark.issue714 def test_parametrize_indirect_uses_no_fixture_error_indirect_list(self, testdir): + testdir.makepyfile(""" + import pytest + @pytest.fixture(scope='function') + def x(request): + return request.param * 3 + + @pytest.mark.parametrize('x, y', [('a', 'b')], indirect=['y']) + def test_simple(x): + assert len(x) == 3 + """) + result = testdir.runpytest("--collect-only") + result.stdout.fnmatch_lines([ + "*uses no fixture 'y'*", + ]) + + @pytest.mark.issue714 + def test_parametrize_argument_not_in_indirect_list(self, testdir): testdir.makepyfile(""" import pytest @pytest.fixture(scope='function') @@ -395,30 +582,31 @@ class TestMetafunc: """) result = testdir.runpytest("--collect-only") result.stdout.fnmatch_lines([ - "*uses no fixture 'y'*", + "*uses no argument 'y'*", ]) def test_addcalls_and_parametrize_indirect(self): - def func(x, y): pass + def func(x, y): + pass metafunc = self.Metafunc(func) metafunc.addcall(param="123") metafunc.parametrize('x', [1], indirect=True) - metafunc.parametrize('y', [2,3], indirect=True) + metafunc.parametrize('y', [2, 3], indirect=True) assert len(metafunc._calls) == 2 assert metafunc._calls[0].funcargs == {} assert metafunc._calls[1].funcargs == {} - assert metafunc._calls[0].params == dict(x=1,y=2) - assert metafunc._calls[1].params == dict(x=1,y=3) + assert metafunc._calls[0].params == dict(x=1, y=2) + assert metafunc._calls[1].params == dict(x=1, y=3) def test_parametrize_functional(self, testdir): testdir.makepyfile(""" + import pytest def pytest_generate_tests(metafunc): metafunc.parametrize('x', [1,2], indirect=True) metafunc.parametrize('y', [2]) - def pytest_funcarg__x(request): + @pytest.fixture + def x(request): return request.param * 10 - #def pytest_funcarg__y(request): - # return request.param def test_simple(x,y): assert x in (10,20) @@ -433,7 +621,7 @@ class TestMetafunc: def test_parametrize_onearg(self): metafunc = self.Metafunc(lambda x: None) - metafunc.parametrize("x", [1,2]) + metafunc.parametrize("x", [1, 2]) assert len(metafunc._calls) == 2 assert metafunc._calls[0].funcargs == dict(x=1) assert metafunc._calls[0].id == "1" @@ -442,15 +630,15 @@ class TestMetafunc: def test_parametrize_onearg_indirect(self): metafunc = self.Metafunc(lambda x: None) - metafunc.parametrize("x", [1,2], indirect=True) + metafunc.parametrize("x", [1, 2], indirect=True) assert metafunc._calls[0].params == dict(x=1) assert metafunc._calls[0].id == "1" assert metafunc._calls[1].params == dict(x=2) assert metafunc._calls[1].id == "2" def test_parametrize_twoargs(self): - metafunc = self.Metafunc(lambda x,y: None) - metafunc.parametrize(("x", "y"), [(1,2), (3,4)]) + metafunc = self.Metafunc(lambda x, y: None) + metafunc.parametrize(("x", "y"), [(1, 2), (3, 4)]) assert len(metafunc._calls) == 2 assert metafunc._calls[0].funcargs == dict(x=1, y=2) assert metafunc._calls[0].id == "1-2" @@ -463,7 +651,7 @@ class TestMetafunc: pytestmark = pytest.mark.parametrize("x", [1,2]) def test_func(x): assert 0, x - class TestClass: + class TestClass(object): pytestmark = pytest.mark.parametrize("y", [3,4]) def test_meth(self, x, y): assert 0, x @@ -521,20 +709,24 @@ class TestMetafunc: """) def test_format_args(self): - def function1(): pass - assert funcargs._format_args(function1) == '()' + def function1(): + pass + assert fixtures._format_args(function1) == '()' - def function2(arg1): pass - assert funcargs._format_args(function2) == "(arg1)" + def function2(arg1): + pass + assert fixtures._format_args(function2) == "(arg1)" - def function3(arg1, arg2="qwe"): pass - assert funcargs._format_args(function3) == "(arg1, arg2='qwe')" + def function3(arg1, arg2="qwe"): + pass + assert fixtures._format_args(function3) == "(arg1, arg2='qwe')" - def function4(arg1, *args, **kwargs): pass - assert funcargs._format_args(function4) == "(arg1, *args, **kwargs)" + def function4(arg1, *args, **kwargs): + pass + assert fixtures._format_args(function4) == "(arg1, *args, **kwargs)" -class TestMetafuncFunctional: +class TestMetafuncFunctional(object): def test_attributes(self, testdir): p = testdir.makepyfile(""" # assumes that generate/provide runs in the same process @@ -542,7 +734,8 @@ class TestMetafuncFunctional: def pytest_generate_tests(metafunc): metafunc.addcall(param=metafunc) - def pytest_funcarg__metafunc(request): + @pytest.fixture + def metafunc(request): assert request._pyfuncitem._genid == "0" return request.param @@ -552,7 +745,7 @@ class TestMetafuncFunctional: assert metafunc.function == test_function assert metafunc.cls is None - class TestClass: + class TestClass(object): def test_method(self, metafunc, pytestconfig): assert metafunc.config == pytestconfig assert metafunc.module.__name__ == __name__ @@ -577,7 +770,7 @@ class TestMetafuncFunctional: def pytest_generate_tests(metafunc): metafunc.addcall(funcargs=dict(arg1=1, arg2=1)) - class TestClass: + class TestClass(object): def test_myfunc(self, arg1, arg2): assert arg1 == arg2 """) @@ -594,7 +787,9 @@ class TestMetafuncFunctional: metafunc.addcall(param=10) metafunc.addcall(param=20) - def pytest_funcarg__arg1(request): + import pytest + @pytest.fixture + def arg1(request): return request.param def test_func1(arg1): @@ -615,14 +810,13 @@ class TestMetafuncFunctional: def pytest_generate_tests(metafunc): assert 'xyz' not in metafunc.fixturenames - class TestHello: + class TestHello(object): def test_hello(xyz): pass """) result = testdir.runpytest(p) result.assert_outcomes(passed=1) - def test_generate_plugin_and_module(self, testdir): testdir.makeconftest(""" def pytest_generate_tests(metafunc): @@ -633,12 +827,15 @@ class TestMetafuncFunctional: def pytest_generate_tests(metafunc): metafunc.addcall(param=(1,1), id="hello") - def pytest_funcarg__arg1(request): + import pytest + @pytest.fixture + def arg1(request): return request.param[0] - def pytest_funcarg__arg2(request): + @pytest.fixture + def arg2(request): return request.param[1] - class TestClass: + class TestClass(object): def test_myfunc(self, arg1, arg2): assert arg1 == arg2 """) @@ -651,7 +848,7 @@ class TestMetafuncFunctional: def test_generate_tests_in_class(self, testdir): p = testdir.makepyfile(""" - class TestClass: + class TestClass(object): def pytest_generate_tests(self, metafunc): metafunc.addcall(funcargs={'hello': 'world'}, id="hello") @@ -670,7 +867,7 @@ class TestMetafuncFunctional: metafunc.addcall({'arg1': 10}) metafunc.addcall({'arg1': 20}) - class TestClass: + class TestClass(object): def test_func(self, arg1): assert not hasattr(self, 'x') self.x = 1 @@ -687,7 +884,7 @@ class TestMetafuncFunctional: def pytest_generate_tests(metafunc): metafunc.addcall({'arg1': 1}) - class TestClass: + class TestClass(object): def test_method(self, arg1): assert arg1 == self.val def setup_method(self, func): @@ -713,17 +910,20 @@ class TestMetafuncFunctional: "*4 failed*", ]) - def test_parametrize_and_inner_getfuncargvalue(self, testdir): + def test_parametrize_and_inner_getfixturevalue(self, testdir): p = testdir.makepyfile(""" def pytest_generate_tests(metafunc): metafunc.parametrize("arg1", [1], indirect=True) metafunc.parametrize("arg2", [10], indirect=True) - def pytest_funcarg__arg1(request): - x = request.getfuncargvalue("arg2") + import pytest + @pytest.fixture + def arg1(request): + x = request.getfixturevalue("arg2") return x + request.param - def pytest_funcarg__arg2(request): + @pytest.fixture + def arg2(request): return request.param def test_func1(arg1, arg2): @@ -741,10 +941,13 @@ class TestMetafuncFunctional: assert "arg1" in metafunc.fixturenames metafunc.parametrize("arg1", [1], indirect=True) - def pytest_funcarg__arg1(request): + import pytest + @pytest.fixture + def arg1(request): return request.param - def pytest_funcarg__arg2(request, arg1): + @pytest.fixture + def arg2(request, arg1): return 10 * arg1 def test_func(arg2): @@ -757,6 +960,10 @@ class TestMetafuncFunctional: ]) def test_parametrize_with_ids(self, testdir): + testdir.makeini(""" + [pytest] + console_output_style=classic + """) testdir.makepyfile(""" import pytest def pytest_generate_tests(metafunc): @@ -789,25 +996,100 @@ class TestMetafuncFunctional: *test_function*1.3-b1* """) + def test_parametrize_with_None_in_ids(self, testdir): + testdir.makepyfile(""" + import pytest + def pytest_generate_tests(metafunc): + metafunc.parametrize(("a", "b"), [(1,1), (1,1), (1,2)], + ids=["basic", None, "advanced"]) + + def test_function(a, b): + assert a == b + """) + result = testdir.runpytest("-v") + assert result.ret == 1 + result.stdout.fnmatch_lines_random([ + "*test_function*basic*PASSED*", + "*test_function*1-1*PASSED*", + "*test_function*advanced*FAILED*", + ]) + + def test_fixture_parametrized_empty_ids(self, testdir): + """Fixtures parametrized with empty ids cause an internal error (#1849).""" + testdir.makepyfile(''' + import pytest + + @pytest.fixture(scope="module", ids=[], params=[]) + def temp(request): + return request.param + + def test_temp(temp): + pass + ''') + result = testdir.runpytest() + result.stdout.fnmatch_lines(['* 1 skipped *']) + + def test_parametrized_empty_ids(self, testdir): + """Tests parametrized with empty ids cause an internal error (#1849).""" + testdir.makepyfile(''' + import pytest + + @pytest.mark.parametrize('temp', [], ids=list()) + def test_temp(temp): + pass + ''') + result = testdir.runpytest() + result.stdout.fnmatch_lines(['* 1 skipped *']) + + def test_parametrized_ids_invalid_type(self, testdir): + """Tests parametrized with ids as non-strings (#1857).""" + testdir.makepyfile(''' + import pytest + + @pytest.mark.parametrize("x, expected", [(10, 20), (40, 80)], ids=(None, 2)) + def test_ids_numbers(x,expected): + assert x * 2 == expected + ''') + result = testdir.runpytest() + result.stdout.fnmatch_lines(['*ids must be list of strings, found: 2 (type: int)*']) + + def test_parametrize_with_identical_ids_get_unique_names(self, testdir): + testdir.makepyfile(""" + import pytest + def pytest_generate_tests(metafunc): + metafunc.parametrize(("a", "b"), [(1,1), (1,2)], + ids=["a", "a"]) + + def test_function(a, b): + assert a == b + """) + result = testdir.runpytest("-v") + assert result.ret == 1 + result.stdout.fnmatch_lines_random([ + "*test_function*a0*PASSED*", + "*test_function*a1*FAILED*" + ]) + @pytest.mark.parametrize(("scope", "length"), [("module", 2), ("function", 4)]) def test_parametrize_scope_overrides(self, testdir, scope, length): testdir.makepyfile(""" import pytest - l = [] + values = [] def pytest_generate_tests(metafunc): if "arg" in metafunc.funcargnames: metafunc.parametrize("arg", [1,2], indirect=True, scope=%r) - def pytest_funcarg__arg(request): - l.append(request.param) + @pytest.fixture + def arg(request): + values.append(request.param) return request.param def test_hello(arg): assert arg in (1,2) def test_world(arg): assert arg in (1,2) def test_checklength(): - assert len(l) == %d + assert len(values) == %d """ % (scope, length)) reprec = testdir.inline_run() reprec.assertoutcome(passed=5) @@ -855,7 +1137,7 @@ class TestMetafuncFunctional: """)) sub1.join("test_in_sub1.py").write("def test_1(): pass") sub2.join("test_in_sub2.py").write("def test_2(): pass") - result = testdir.runpytest("-v", "-s", sub1, sub2, sub1) + result = testdir.runpytest("--keep-duplicates", "-v", "-s", sub1, sub2, sub1) result.assert_outcomes(passed=3) def test_generate_same_function_names_issue403(self, testdir): @@ -876,7 +1158,7 @@ class TestMetafuncFunctional: @pytest.mark.issue463 @pytest.mark.parametrize('attr', ['parametrise', 'parameterize', - 'parameterise']) + 'parameterise']) def test_parametrize_misspelling(self, testdir, attr): testdir.makepyfile(""" import pytest @@ -892,8 +1174,129 @@ class TestMetafuncFunctional: assert expectederror in failures[0].longrepr.reprcrash.message -class TestMarkersWithParametrization: - pytestmark = pytest.mark.issue308 +class TestMetafuncFunctionalAuto(object): + """ + Tests related to automatically find out the correct scope for parametrized tests (#1832). + """ + + def test_parametrize_auto_scope(self, testdir): + testdir.makepyfile(''' + import pytest + + @pytest.fixture(scope='session', autouse=True) + def fixture(): + return 1 + + @pytest.mark.parametrize('animal', ["dog", "cat"]) + def test_1(animal): + assert animal in ('dog', 'cat') + + @pytest.mark.parametrize('animal', ['fish']) + def test_2(animal): + assert animal == 'fish' + + ''') + result = testdir.runpytest() + result.stdout.fnmatch_lines(['* 3 passed *']) + + def test_parametrize_auto_scope_indirect(self, testdir): + testdir.makepyfile(''' + import pytest + + @pytest.fixture(scope='session') + def echo(request): + return request.param + + @pytest.mark.parametrize('animal, echo', [("dog", 1), ("cat", 2)], indirect=['echo']) + def test_1(animal, echo): + assert animal in ('dog', 'cat') + assert echo in (1, 2, 3) + + @pytest.mark.parametrize('animal, echo', [('fish', 3)], indirect=['echo']) + def test_2(animal, echo): + assert animal == 'fish' + assert echo in (1, 2, 3) + ''') + result = testdir.runpytest() + result.stdout.fnmatch_lines(['* 3 passed *']) + + def test_parametrize_auto_scope_override_fixture(self, testdir): + testdir.makepyfile(''' + import pytest + + @pytest.fixture(scope='session', autouse=True) + def animal(): + return 'fox' + + @pytest.mark.parametrize('animal', ["dog", "cat"]) + def test_1(animal): + assert animal in ('dog', 'cat') + ''') + result = testdir.runpytest() + result.stdout.fnmatch_lines(['* 2 passed *']) + + def test_parametrize_all_indirects(self, testdir): + testdir.makepyfile(''' + import pytest + + @pytest.fixture() + def animal(request): + return request.param + + @pytest.fixture(scope='session') + def echo(request): + return request.param + + @pytest.mark.parametrize('animal, echo', [("dog", 1), ("cat", 2)], indirect=True) + def test_1(animal, echo): + assert animal in ('dog', 'cat') + assert echo in (1, 2, 3) + + @pytest.mark.parametrize('animal, echo', [("fish", 3)], indirect=True) + def test_2(animal, echo): + assert animal == 'fish' + assert echo in (1, 2, 3) + ''') + result = testdir.runpytest() + result.stdout.fnmatch_lines(['* 3 passed *']) + + def test_parametrize_issue634(self, testdir): + testdir.makepyfile(''' + import pytest + + @pytest.fixture(scope='module') + def foo(request): + print('preparing foo-%d' % request.param) + return 'foo-%d' % request.param + + def test_one(foo): + pass + + def test_two(foo): + pass + + test_two.test_with = (2, 3) + + def pytest_generate_tests(metafunc): + params = (1, 2, 3, 4) + if not 'foo' in metafunc.fixturenames: + return + + test_with = getattr(metafunc.function, 'test_with', None) + if test_with: + params = test_with + metafunc.parametrize('foo', params, indirect=True) + ''') + result = testdir.runpytest("-s") + output = result.stdout.str() + assert output.count('preparing foo-2') == 1 + assert output.count('preparing foo-3') == 1 + + +@pytest.mark.filterwarnings('ignore:Applying marks directly to parameters') +@pytest.mark.issue308 +class TestMarkersWithParametrization(object): + def test_simple_mark(self, testdir): s = """ import pytest @@ -1036,22 +1439,23 @@ class TestMarkersWithParametrization: reprec = testdir.inline_run() reprec.assertoutcome(passed=2, skipped=1) - def test_xfail_passing_is_xpass(self, testdir): + @pytest.mark.parametrize('strict', [True, False]) + def test_xfail_passing_is_xpass(self, testdir, strict): s = """ import pytest @pytest.mark.parametrize(("n", "expected"), [ (1, 2), - pytest.mark.xfail("sys.version > 0", reason="some bug")((2, 3)), + pytest.mark.xfail("sys.version_info > (0, 0, 0)", reason="some bug", strict={strict})((2, 3)), (3, 4), ]) def test_increment(n, expected): assert n + 1 == expected - """ + """.format(strict=strict) testdir.makepyfile(s) reprec = testdir.inline_run() - # xpass is fail, obviously :) - reprec.assertoutcome(passed=2, failed=1) + passed, failed = (2, 1) if strict else (3, 0) + reprec.assertoutcome(passed=passed, failed=failed) def test_parametrize_called_in_generate_tests(self, testdir): s = """ @@ -1076,7 +1480,6 @@ class TestMarkersWithParametrization: reprec = testdir.inline_run() reprec.assertoutcome(passed=2, skipped=2) - @pytest.mark.issue290 def test_parametrize_ID_generation_string_int_works(self, testdir): testdir.makepyfile(""" @@ -1092,3 +1495,67 @@ class TestMarkersWithParametrization: """) reprec = testdir.inline_run() reprec.assertoutcome(passed=2) + + @pytest.mark.parametrize('strict', [True, False]) + def test_parametrize_marked_value(self, testdir, strict): + s = """ + import pytest + + @pytest.mark.parametrize(("n", "expected"), [ + pytest.param( + 2,3, + marks=pytest.mark.xfail("sys.version_info > (0, 0, 0)", reason="some bug", strict={strict}), + ), + pytest.param( + 2,3, + marks=[pytest.mark.xfail("sys.version_info > (0, 0, 0)", reason="some bug", strict={strict})], + ), + ]) + def test_increment(n, expected): + assert n + 1 == expected + """.format(strict=strict) + testdir.makepyfile(s) + reprec = testdir.inline_run() + passed, failed = (0, 2) if strict else (2, 0) + reprec.assertoutcome(passed=passed, failed=failed) + + def test_pytest_make_parametrize_id(self, testdir): + testdir.makeconftest(""" + def pytest_make_parametrize_id(config, val): + return str(val * 2) + """) + testdir.makepyfile(""" + import pytest + + @pytest.mark.parametrize("x", range(2)) + def test_func(x): + pass + """) + result = testdir.runpytest("-v") + result.stdout.fnmatch_lines([ + "*test_func*0*PASS*", + "*test_func*2*PASS*", + ]) + + def test_pytest_make_parametrize_id_with_argname(self, testdir): + testdir.makeconftest(""" + def pytest_make_parametrize_id(config, val, argname): + return str(val * 2 if argname == 'x' else val * 10) + """) + testdir.makepyfile(""" + import pytest + + @pytest.mark.parametrize("x", range(2)) + def test_func_a(x): + pass + + @pytest.mark.parametrize("y", [1]) + def test_func_b(y): + pass + """) + result = testdir.runpytest("-v") + result.stdout.fnmatch_lines([ + "*test_func_a*0*PASS*", + "*test_func_a*2*PASS*", + "*test_func_b*10*PASS*", + ]) diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/python/raises.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/raises.py similarity index 51% rename from tests/wpt/web-platform-tests/tools/pytest/testing/python/raises.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/raises.py index 0ea7f9bee3e..321ee349ee6 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/python/raises.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/raises.py @@ -1,6 +1,8 @@ import pytest +import sys -class TestRaises: + +class TestRaises(object): def test_raises(self): source = "int('qwe')" excinfo = pytest.raises(ValueError, source) @@ -18,7 +20,7 @@ class TestRaises: pytest.raises(ValueError, int, 'hello') def test_raises_callable_no_exception(self): - class A: + class A(object): def __call__(self): pass try: @@ -26,14 +28,6 @@ class TestRaises: except pytest.raises.Exception: pass - def test_raises_flip_builtin_AssertionError(self): - # we replace AssertionError on python level - # however c code might still raise the builtin one - from _pytest.assertion.util import BuiltinAssertionError # noqa - pytest.raises(AssertionError,""" - raise BuiltinAssertionError - """) - def test_raises_as_contextmanager(self, testdir): testdir.makepyfile(""" from __future__ import with_statement @@ -76,3 +70,65 @@ class TestRaises: pytest.raises(ValueError, int, '0') except pytest.raises.Exception as e: assert e.msg == "DID NOT RAISE {0}".format(repr(ValueError)) + else: + assert False, "Expected pytest.raises.Exception" + + try: + with pytest.raises(ValueError): + pass + except pytest.raises.Exception as e: + assert e.msg == "DID NOT RAISE {0}".format(repr(ValueError)) + else: + assert False, "Expected pytest.raises.Exception" + + def test_custom_raise_message(self): + message = "TEST_MESSAGE" + try: + with pytest.raises(ValueError, message=message): + pass + except pytest.raises.Exception as e: + assert e.msg == message + else: + assert False, "Expected pytest.raises.Exception" + + @pytest.mark.parametrize('method', ['function', 'with']) + def test_raises_cyclic_reference(self, method): + """ + Ensure pytest.raises does not leave a reference cycle (#1965). + """ + import gc + + class T(object): + def __call__(self): + raise ValueError + + t = T() + if method == 'function': + pytest.raises(ValueError, t) + else: + with pytest.raises(ValueError): + t() + + # ensure both forms of pytest.raises don't leave exceptions in sys.exc_info() + assert sys.exc_info() == (None, None, None) + + del t + + # ensure the t instance is not stuck in a cyclic reference + for o in gc.get_objects(): + assert type(o) is not T + + def test_raises_match(self): + msg = r"with base \d+" + with pytest.raises(ValueError, match=msg): + int('asdf') + + msg = "with base 10" + with pytest.raises(ValueError, match=msg): + int('asdf') + + msg = "with base 16" + expr = r"Pattern '{0}' not found in 'invalid literal for int\(\) with base 10: 'asdf''".format(msg) + with pytest.raises(AssertionError, match=expr): + with pytest.raises(ValueError, match=msg): + int('asdf', base=10) diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/setup_only.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/setup_only.py new file mode 100644 index 00000000000..ab34312fcc8 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/setup_only.py @@ -0,0 +1,243 @@ +import pytest + + +@pytest.fixture(params=['--setup-only', '--setup-plan', '--setup-show'], + scope='module') +def mode(request): + return request.param + + +def test_show_only_active_fixtures(testdir, mode): + p = testdir.makepyfile(''' + import pytest + @pytest.fixture + def _arg0(): + """hidden arg0 fixture""" + @pytest.fixture + def arg1(): + """arg1 docstring""" + def test_arg1(arg1): + pass + ''') + + result = testdir.runpytest(mode, p) + assert result.ret == 0 + + result.stdout.fnmatch_lines([ + '*SETUP F arg1*', + '*test_arg1 (fixtures used: arg1)*', + '*TEARDOWN F arg1*', + ]) + assert "_arg0" not in result.stdout.str() + + +def test_show_different_scopes(testdir, mode): + p = testdir.makepyfile(''' + import pytest + @pytest.fixture + def arg_function(): + """function scoped fixture""" + @pytest.fixture(scope='session') + def arg_session(): + """session scoped fixture""" + def test_arg1(arg_session, arg_function): + pass + ''') + + result = testdir.runpytest(mode, p) + assert result.ret == 0 + + result.stdout.fnmatch_lines([ + 'SETUP S arg_session*', + '*SETUP F arg_function*', + '*test_arg1 (fixtures used: arg_function, arg_session)*', + '*TEARDOWN F arg_function*', + 'TEARDOWN S arg_session*', + ]) + + +def test_show_nested_fixtures(testdir, mode): + testdir.makeconftest(''' + import pytest + @pytest.fixture(scope='session') + def arg_same(): + """session scoped fixture""" + ''') + p = testdir.makepyfile(''' + import pytest + @pytest.fixture(scope='function') + def arg_same(arg_same): + """function scoped fixture""" + def test_arg1(arg_same): + pass + ''') + + result = testdir.runpytest(mode, p) + assert result.ret == 0 + + result.stdout.fnmatch_lines([ + 'SETUP S arg_same*', + '*SETUP F arg_same (fixtures used: arg_same)*', + '*test_arg1 (fixtures used: arg_same)*', + '*TEARDOWN F arg_same*', + 'TEARDOWN S arg_same*', + ]) + + +def test_show_fixtures_with_autouse(testdir, mode): + p = testdir.makepyfile(''' + import pytest + @pytest.fixture + def arg_function(): + """function scoped fixture""" + @pytest.fixture(scope='session', autouse=True) + def arg_session(): + """session scoped fixture""" + def test_arg1(arg_function): + pass + ''') + + result = testdir.runpytest(mode, p) + assert result.ret == 0 + + result.stdout.fnmatch_lines([ + 'SETUP S arg_session*', + '*SETUP F arg_function*', + '*test_arg1 (fixtures used: arg_function, arg_session)*', + ]) + + +def test_show_fixtures_with_parameters(testdir, mode): + testdir.makeconftest(''' + import pytest + @pytest.fixture(scope='session', params=['foo', 'bar']) + def arg_same(): + """session scoped fixture""" + ''') + p = testdir.makepyfile(''' + import pytest + @pytest.fixture(scope='function') + def arg_other(arg_same): + """function scoped fixture""" + def test_arg1(arg_other): + pass + ''') + + result = testdir.runpytest(mode, p) + assert result.ret == 0 + + result.stdout.fnmatch_lines([ + 'SETUP S arg_same?foo?', + 'TEARDOWN S arg_same?foo?', + 'SETUP S arg_same?bar?', + 'TEARDOWN S arg_same?bar?', + ]) + + +def test_show_fixtures_with_parameter_ids(testdir, mode): + testdir.makeconftest(''' + import pytest + @pytest.fixture( + scope='session', params=['foo', 'bar'], ids=['spam', 'ham']) + def arg_same(): + """session scoped fixture""" + ''') + p = testdir.makepyfile(''' + import pytest + @pytest.fixture(scope='function') + def arg_other(arg_same): + """function scoped fixture""" + def test_arg1(arg_other): + pass + ''') + + result = testdir.runpytest(mode, p) + assert result.ret == 0 + + result.stdout.fnmatch_lines([ + 'SETUP S arg_same?spam?', + 'SETUP S arg_same?ham?', + ]) + + +def test_show_fixtures_with_parameter_ids_function(testdir, mode): + p = testdir.makepyfile(''' + import pytest + @pytest.fixture(params=['foo', 'bar'], ids=lambda p: p.upper()) + def foobar(): + pass + def test_foobar(foobar): + pass + ''') + + result = testdir.runpytest(mode, p) + assert result.ret == 0 + + result.stdout.fnmatch_lines([ + '*SETUP F foobar?FOO?', + '*SETUP F foobar?BAR?', + ]) + + +def test_dynamic_fixture_request(testdir): + p = testdir.makepyfile(''' + import pytest + @pytest.fixture() + def dynamically_requested_fixture(): + pass + @pytest.fixture() + def dependent_fixture(request): + request.getfixturevalue('dynamically_requested_fixture') + def test_dyn(dependent_fixture): + pass + ''') + + result = testdir.runpytest('--setup-only', p) + assert result.ret == 0 + + result.stdout.fnmatch_lines([ + '*SETUP F dynamically_requested_fixture', + '*TEARDOWN F dynamically_requested_fixture' + ]) + + +def test_capturing(testdir): + p = testdir.makepyfile(''' + import pytest, sys + @pytest.fixture() + def one(): + sys.stdout.write('this should be captured') + sys.stderr.write('this should also be captured') + @pytest.fixture() + def two(one): + assert 0 + def test_capturing(two): + pass + ''') + + result = testdir.runpytest('--setup-only', p) + result.stdout.fnmatch_lines([ + 'this should be captured', + 'this should also be captured' + ]) + + +def test_show_fixtures_and_execute_test(testdir): + """ Verifies that setups are shown and tests are executed. """ + p = testdir.makepyfile(''' + import pytest + @pytest.fixture + def arg(): + assert True + def test_arg(arg): + assert False + ''') + + result = testdir.runpytest("--setup-show", p) + assert result.ret == 1 + + result.stdout.fnmatch_lines([ + '*SETUP F arg*', + '*test_arg (fixtures used: arg)F*', + '*TEARDOWN F arg*', + ]) diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/setup_plan.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/setup_plan.py new file mode 100644 index 00000000000..8c98224692a --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/setup_plan.py @@ -0,0 +1,19 @@ +def test_show_fixtures_and_test(testdir): + """ Verifies that fixtures are not executed. """ + p = testdir.makepyfile(''' + import pytest + @pytest.fixture + def arg(): + assert False + def test_arg(arg): + assert False + ''') + + result = testdir.runpytest("--setup-plan", p) + assert result.ret == 0 + + result.stdout.fnmatch_lines([ + '*SETUP F arg*', + '*test_arg (fixtures used: arg)', + '*TEARDOWN F arg*', + ]) diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/show_fixtures_per_test.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/show_fixtures_per_test.py new file mode 100644 index 00000000000..741f33946a0 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/show_fixtures_per_test.py @@ -0,0 +1,158 @@ +# -*- coding: utf-8 -*- + + +def test_no_items_should_not_show_output(testdir): + result = testdir.runpytest('--fixtures-per-test') + assert 'fixtures used by' not in result.stdout.str() + assert result.ret == 0 + + +def test_fixtures_in_module(testdir): + p = testdir.makepyfile(''' + import pytest + @pytest.fixture + def _arg0(): + """hidden arg0 fixture""" + @pytest.fixture + def arg1(): + """arg1 docstring""" + def test_arg1(arg1): + pass + ''') + + result = testdir.runpytest("--fixtures-per-test", p) + assert result.ret == 0 + + result.stdout.fnmatch_lines([ + '*fixtures used by test_arg1*', + '*(test_fixtures_in_module.py:9)*', + 'arg1', + ' arg1 docstring', + ]) + assert "_arg0" not in result.stdout.str() + + +def test_fixtures_in_conftest(testdir): + testdir.makeconftest(''' + import pytest + @pytest.fixture + def arg1(): + """arg1 docstring""" + @pytest.fixture + def arg2(): + """arg2 docstring""" + @pytest.fixture + def arg3(arg1, arg2): + """arg3 + docstring + """ + ''') + p = testdir.makepyfile(''' + def test_arg2(arg2): + pass + def test_arg3(arg3): + pass + ''') + result = testdir.runpytest("--fixtures-per-test", p) + assert result.ret == 0 + + result.stdout.fnmatch_lines([ + '*fixtures used by test_arg2*', + '*(test_fixtures_in_conftest.py:2)*', + 'arg2', + ' arg2 docstring', + '*fixtures used by test_arg3*', + '*(test_fixtures_in_conftest.py:4)*', + 'arg1', + ' arg1 docstring', + 'arg2', + ' arg2 docstring', + 'arg3', + ' arg3', + ' docstring', + ]) + + +def test_should_show_fixtures_used_by_test(testdir): + testdir.makeconftest(''' + import pytest + @pytest.fixture + def arg1(): + """arg1 from conftest""" + @pytest.fixture + def arg2(): + """arg2 from conftest""" + ''') + p = testdir.makepyfile(''' + import pytest + @pytest.fixture + def arg1(): + """arg1 from testmodule""" + def test_args(arg1, arg2): + pass + ''') + result = testdir.runpytest("--fixtures-per-test", p) + assert result.ret == 0 + + result.stdout.fnmatch_lines([ + '*fixtures used by test_args*', + '*(test_should_show_fixtures_used_by_test.py:6)*', + 'arg1', + ' arg1 from testmodule', + 'arg2', + ' arg2 from conftest', + ]) + + +def test_verbose_include_private_fixtures_and_loc(testdir): + testdir.makeconftest(''' + import pytest + @pytest.fixture + def _arg1(): + """_arg1 from conftest""" + @pytest.fixture + def arg2(_arg1): + """arg2 from conftest""" + ''') + p = testdir.makepyfile(''' + import pytest + @pytest.fixture + def arg3(): + """arg3 from testmodule""" + def test_args(arg2, arg3): + pass + ''') + result = testdir.runpytest("--fixtures-per-test", "-v", p) + assert result.ret == 0 + + result.stdout.fnmatch_lines([ + '*fixtures used by test_args*', + '*(test_verbose_include_private_fixtures_and_loc.py:6)*', + '_arg1 -- conftest.py:3', + ' _arg1 from conftest', + 'arg2 -- conftest.py:6', + ' arg2 from conftest', + 'arg3 -- test_verbose_include_private_fixtures_and_loc.py:3', + ' arg3 from testmodule', + ]) + + +def test_doctest_items(testdir): + testdir.makepyfile(''' + def foo(): + """ + >>> 1 + 1 + 2 + """ + ''') + testdir.maketxtfile(''' + >>> 1 + 1 + 2 + ''') + result = testdir.runpytest("--fixtures-per-test", "--doctest-modules", + "--doctest-glob=*.txt", "-v") + assert result.ret == 0 + + result.stdout.fnmatch_lines([ + '*collected 2 items*', + ]) diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/test_deprecations.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/test_deprecations.py new file mode 100644 index 00000000000..5001f765f6c --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/python/test_deprecations.py @@ -0,0 +1,22 @@ +import pytest + +from _pytest.python import PyCollector + + +class PyCollectorMock(PyCollector): + """evil hack""" + + def __init__(self): + self.called = False + + def _makeitem(self, *k): + """hack to disable the actual behaviour""" + self.called = True + + +def test_pycollector_makeitem_is_deprecated(): + + collector = PyCollectorMock() + with pytest.deprecated_call(): + collector.makeitem('foo', 'bar') + assert collector.called diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_argcomplete.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_argcomplete.py similarity index 76% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_argcomplete.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_argcomplete.py index ace7d8ceb43..c9261257743 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_argcomplete.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_argcomplete.py @@ -1,8 +1,10 @@ -from __future__ import with_statement -import py, pytest +from __future__ import absolute_import, division, print_function +import py +import pytest # test for _argcomplete but not specific for any application + def equal_with_bash(prefix, ffc, fc, out=None): res = ffc(prefix) res_bash = set(fc(prefix)) @@ -17,10 +19,12 @@ def equal_with_bash(prefix, ffc, fc, out=None): # copied from argcomplete.completers as import from there # also pulls in argcomplete.__init__ which opens filedescriptor 9 # this gives an IOError at the end of testrun + + def _wrapcall(*args, **kargs): try: - if py.std.sys.version_info > (2,7): - return py.std.subprocess.check_output(*args,**kargs).decode().splitlines() + if py.std.sys.version_info > (2, 7): + return py.std.subprocess.check_output(*args, **kargs).decode().splitlines() if 'stdout' in kargs: raise ValueError('stdout argument not allowed, it will be overridden.') process = py.std.subprocess.Popen( @@ -36,9 +40,11 @@ def _wrapcall(*args, **kargs): except py.std.subprocess.CalledProcessError: return [] + class FilesCompleter(object): 'File completer class, optionally takes a list of allowed extensions' - def __init__(self,allowednames=(),directories=True): + + def __init__(self, allowednames=(), directories=True): # Fix if someone passes in a string instead of a list if type(allowednames) is str: allowednames = [allowednames] @@ -50,32 +56,33 @@ class FilesCompleter(object): completion = [] if self.allowednames: if self.directories: - files = _wrapcall(['bash','-c', - "compgen -A directory -- '{p}'".format(p=prefix)]) - completion += [ f + '/' for f in files] + files = _wrapcall(['bash', '-c', + "compgen -A directory -- '{p}'".format(p=prefix)]) + completion += [f + '/' for f in files] for x in self.allowednames: completion += _wrapcall(['bash', '-c', - "compgen -A file -X '!*.{0}' -- '{p}'".format(x,p=prefix)]) + "compgen -A file -X '!*.{0}' -- '{p}'".format(x, p=prefix)]) else: completion += _wrapcall(['bash', '-c', - "compgen -A file -- '{p}'".format(p=prefix)]) + "compgen -A file -- '{p}'".format(p=prefix)]) anticomp = _wrapcall(['bash', '-c', - "compgen -A directory -- '{p}'".format(p=prefix)]) + "compgen -A directory -- '{p}'".format(p=prefix)]) - completion = list( set(completion) - set(anticomp)) + completion = list(set(completion) - set(anticomp)) if self.directories: completion += [f + '/' for f in anticomp] return completion -class TestArgComplete: + +class TestArgComplete(object): @pytest.mark.skipif("sys.platform in ('win32', 'darwin')") def test_compare_with_compgen(self): from _pytest._argcomplete import FastFilesCompleter ffc = FastFilesCompleter() fc = FilesCompleter() - for x in '/ /d /data qqq'.split(): + for x in ['/', '/d', '/data', 'qqq', '']: assert equal_with_bash(x, ffc, fc, out=py.std.sys.stdout) @pytest.mark.skipif("sys.platform in ('win32', 'darwin')") diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_assertion.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_assertion.py new file mode 100644 index 00000000000..328fe7fa918 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_assertion.py @@ -0,0 +1,1066 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import, division, print_function +import sys +import textwrap + +import _pytest.assertion as plugin +import py +import pytest +from _pytest.assertion import util +from _pytest.assertion import truncate + +PY3 = sys.version_info >= (3, 0) + + +@pytest.fixture +def mock_config(): + + class Config(object): + verbose = False + + def getoption(self, name): + if name == 'verbose': + return self.verbose + raise KeyError('Not mocked out: %s' % name) + + return Config() + + +class TestImportHookInstallation(object): + + @pytest.mark.parametrize('initial_conftest', [True, False]) + @pytest.mark.parametrize('mode', ['plain', 'rewrite']) + def test_conftest_assertion_rewrite(self, testdir, initial_conftest, mode): + """Test that conftest files are using assertion rewrite on import. + (#1619) + """ + testdir.tmpdir.join('foo/tests').ensure(dir=1) + conftest_path = 'conftest.py' if initial_conftest else 'foo/conftest.py' + contents = { + conftest_path: """ + import pytest + @pytest.fixture + def check_first(): + def check(values, value): + assert values.pop(0) == value + return check + """, + 'foo/tests/test_foo.py': """ + def test(check_first): + check_first([10, 30], 30) + """ + } + testdir.makepyfile(**contents) + result = testdir.runpytest_subprocess('--assert=%s' % mode) + if mode == 'plain': + expected = 'E AssertionError' + elif mode == 'rewrite': + expected = '*assert 10 == 30*' + else: + assert 0 + result.stdout.fnmatch_lines([expected]) + + def test_rewrite_assertions_pytester_plugin(self, testdir): + """ + Assertions in the pytester plugin must also benefit from assertion + rewriting (#1920). + """ + testdir.makepyfile(""" + pytest_plugins = ['pytester'] + def test_dummy_failure(testdir): # how meta! + testdir.makepyfile('def test(): assert 0') + r = testdir.inline_run() + r.assertoutcome(passed=1) + """) + result = testdir.runpytest_subprocess() + result.stdout.fnmatch_lines([ + '*assert 1 == 0*', + ]) + + @pytest.mark.parametrize('mode', ['plain', 'rewrite']) + def test_pytest_plugins_rewrite(self, testdir, mode): + contents = { + 'conftest.py': """ + pytest_plugins = ['ham'] + """, + 'ham.py': """ + import pytest + @pytest.fixture + def check_first(): + def check(values, value): + assert values.pop(0) == value + return check + """, + 'test_foo.py': """ + def test_foo(check_first): + check_first([10, 30], 30) + """, + } + testdir.makepyfile(**contents) + result = testdir.runpytest_subprocess('--assert=%s' % mode) + if mode == 'plain': + expected = 'E AssertionError' + elif mode == 'rewrite': + expected = '*assert 10 == 30*' + else: + assert 0 + result.stdout.fnmatch_lines([expected]) + + @pytest.mark.parametrize('mode', ['str', 'list']) + def test_pytest_plugins_rewrite_module_names(self, testdir, mode): + """Test that pluginmanager correct marks pytest_plugins variables + for assertion rewriting if they are defined as plain strings or + list of strings (#1888). + """ + plugins = '"ham"' if mode == 'str' else '["ham"]' + contents = { + 'conftest.py': """ + pytest_plugins = {plugins} + """.format(plugins=plugins), + 'ham.py': """ + import pytest + """, + 'test_foo.py': """ + def test_foo(pytestconfig): + assert 'ham' in pytestconfig.pluginmanager.rewrite_hook._must_rewrite + """, + } + testdir.makepyfile(**contents) + result = testdir.runpytest_subprocess('--assert=rewrite') + assert result.ret == 0 + + def test_pytest_plugins_rewrite_module_names_correctly(self, testdir): + """Test that we match files correctly when they are marked for rewriting (#2939).""" + contents = { + 'conftest.py': """ + pytest_plugins = "ham" + """, + 'ham.py': "", + 'hamster.py': "", + 'test_foo.py': """ + def test_foo(pytestconfig): + assert pytestconfig.pluginmanager.rewrite_hook.find_module('ham') is not None + assert pytestconfig.pluginmanager.rewrite_hook.find_module('hamster') is None + """, + } + testdir.makepyfile(**contents) + result = testdir.runpytest_subprocess('--assert=rewrite') + assert result.ret == 0 + + @pytest.mark.parametrize('mode', ['plain', 'rewrite']) + @pytest.mark.parametrize('plugin_state', ['development', 'installed']) + def test_installed_plugin_rewrite(self, testdir, mode, plugin_state): + # Make sure the hook is installed early enough so that plugins + # installed via setuptools are rewritten. + testdir.tmpdir.join('hampkg').ensure(dir=1) + contents = { + 'hampkg/__init__.py': """ + import pytest + + @pytest.fixture + def check_first2(): + def check(values, value): + assert values.pop(0) == value + return check + """, + 'spamplugin.py': """ + import pytest + from hampkg import check_first2 + + @pytest.fixture + def check_first(): + def check(values, value): + assert values.pop(0) == value + return check + """, + 'mainwrapper.py': """ + import pytest, pkg_resources + + plugin_state = "{plugin_state}" + + class DummyDistInfo(object): + project_name = 'spam' + version = '1.0' + + def _get_metadata(self, name): + # 'RECORD' meta-data only available in installed plugins + if name == 'RECORD' and plugin_state == "installed": + return ['spamplugin.py,sha256=abc,123', + 'hampkg/__init__.py,sha256=abc,123'] + # 'SOURCES.txt' meta-data only available for plugins in development mode + elif name == 'SOURCES.txt' and plugin_state == "development": + return ['spamplugin.py', + 'hampkg/__init__.py'] + return [] + + class DummyEntryPoint(object): + name = 'spam' + module_name = 'spam.py' + attrs = () + extras = None + dist = DummyDistInfo() + + def load(self, require=True, *args, **kwargs): + import spamplugin + return spamplugin + + def iter_entry_points(name): + yield DummyEntryPoint() + + pkg_resources.iter_entry_points = iter_entry_points + pytest.main() + """.format(plugin_state=plugin_state), + 'test_foo.py': """ + def test(check_first): + check_first([10, 30], 30) + + def test2(check_first2): + check_first([10, 30], 30) + """, + } + testdir.makepyfile(**contents) + result = testdir.run(sys.executable, 'mainwrapper.py', '-s', '--assert=%s' % mode) + if mode == 'plain': + expected = 'E AssertionError' + elif mode == 'rewrite': + expected = '*assert 10 == 30*' + else: + assert 0 + result.stdout.fnmatch_lines([expected]) + + def test_rewrite_ast(self, testdir): + testdir.tmpdir.join('pkg').ensure(dir=1) + contents = { + 'pkg/__init__.py': """ + import pytest + pytest.register_assert_rewrite('pkg.helper') + """, + 'pkg/helper.py': """ + def tool(): + a, b = 2, 3 + assert a == b + """, + 'pkg/plugin.py': """ + import pytest, pkg.helper + @pytest.fixture + def tool(): + return pkg.helper.tool + """, + 'pkg/other.py': """ + values = [3, 2] + def tool(): + assert values.pop() == 3 + """, + 'conftest.py': """ + pytest_plugins = ['pkg.plugin'] + """, + 'test_pkg.py': """ + import pkg.other + def test_tool(tool): + tool() + def test_other(): + pkg.other.tool() + """, + } + testdir.makepyfile(**contents) + result = testdir.runpytest_subprocess('--assert=rewrite') + result.stdout.fnmatch_lines(['>*assert a == b*', + 'E*assert 2 == 3*', + '>*assert values.pop() == 3*', + 'E*AssertionError']) + + def test_register_assert_rewrite_checks_types(self): + with pytest.raises(TypeError): + pytest.register_assert_rewrite(['pytest_tests_internal_non_existing']) + pytest.register_assert_rewrite('pytest_tests_internal_non_existing', + 'pytest_tests_internal_non_existing2') + + +class TestBinReprIntegration(object): + + def test_pytest_assertrepr_compare_called(self, testdir): + testdir.makeconftest(""" + import pytest + values = [] + def pytest_assertrepr_compare(op, left, right): + values.append((op, left, right)) + + @pytest.fixture + def list(request): + return values + """) + testdir.makepyfile(""" + def test_hello(): + assert 0 == 1 + def test_check(list): + assert list == [("==", 0, 1)] + """) + result = testdir.runpytest("-v") + result.stdout.fnmatch_lines([ + "*test_hello*FAIL*", + "*test_check*PASS*", + ]) + + +def callequal(left, right, verbose=False): + config = mock_config() + config.verbose = verbose + return plugin.pytest_assertrepr_compare(config, '==', left, right) + + +class TestAssert_reprcompare(object): + def test_different_types(self): + assert callequal([0, 1], 'foo') is None + + def test_summary(self): + summary = callequal([0, 1], [0, 2])[0] + assert len(summary) < 65 + + def test_text_diff(self): + diff = callequal('spam', 'eggs')[1:] + assert '- spam' in diff + assert '+ eggs' in diff + + def test_text_skipping(self): + lines = callequal('a' * 50 + 'spam', 'a' * 50 + 'eggs') + assert 'Skipping' in lines[1] + for line in lines: + assert 'a' * 50 not in line + + def test_text_skipping_verbose(self): + lines = callequal('a' * 50 + 'spam', 'a' * 50 + 'eggs', verbose=True) + assert '- ' + 'a' * 50 + 'spam' in lines + assert '+ ' + 'a' * 50 + 'eggs' in lines + + def test_multiline_text_diff(self): + left = 'foo\nspam\nbar' + right = 'foo\neggs\nbar' + diff = callequal(left, right) + assert '- spam' in diff + assert '+ eggs' in diff + + def test_list(self): + expl = callequal([0, 1], [0, 2]) + assert len(expl) > 1 + + @pytest.mark.parametrize( + ['left', 'right', 'expected'], [ + ([0, 1], [0, 2], """ + Full diff: + - [0, 1] + ? ^ + + [0, 2] + ? ^ + """), + ({0: 1}, {0: 2}, """ + Full diff: + - {0: 1} + ? ^ + + {0: 2} + ? ^ + """), + (set([0, 1]), set([0, 2]), """ + Full diff: + - set([0, 1]) + ? ^ + + set([0, 2]) + ? ^ + """ if not PY3 else """ + Full diff: + - {0, 1} + ? ^ + + {0, 2} + ? ^ + """) + ] + ) + def test_iterable_full_diff(self, left, right, expected): + """Test the full diff assertion failure explanation. + + When verbose is False, then just a -v notice to get the diff is rendered, + when verbose is True, then ndiff of the pprint is returned. + """ + expl = callequal(left, right, verbose=False) + assert expl[-1] == 'Use -v to get the full diff' + expl = '\n'.join(callequal(left, right, verbose=True)) + assert expl.endswith(textwrap.dedent(expected).strip()) + + def test_list_different_lengths(self): + expl = callequal([0, 1], [0, 1, 2]) + assert len(expl) > 1 + expl = callequal([0, 1, 2], [0, 1]) + assert len(expl) > 1 + + def test_dict(self): + expl = callequal({'a': 0}, {'a': 1}) + assert len(expl) > 1 + + def test_dict_omitting(self): + lines = callequal({'a': 0, 'b': 1}, {'a': 1, 'b': 1}) + assert lines[1].startswith('Omitting 1 identical item') + assert 'Common items' not in lines + for line in lines[1:]: + assert 'b' not in line + + def test_dict_omitting_with_verbosity_1(self): + """ Ensure differing items are visible for verbosity=1 (#1512) """ + lines = callequal({'a': 0, 'b': 1}, {'a': 1, 'b': 1}, verbose=1) + assert lines[1].startswith('Omitting 1 identical item') + assert lines[2].startswith('Differing items') + assert lines[3] == "{'a': 0} != {'a': 1}" + assert 'Common items' not in lines + + def test_dict_omitting_with_verbosity_2(self): + lines = callequal({'a': 0, 'b': 1}, {'a': 1, 'b': 1}, verbose=2) + assert lines[1].startswith('Common items:') + assert 'Omitting' not in lines[1] + assert lines[2] == "{'b': 1}" + + def test_set(self): + expl = callequal(set([0, 1]), set([0, 2])) + assert len(expl) > 1 + + def test_frozenzet(self): + expl = callequal(frozenset([0, 1]), set([0, 2])) + assert len(expl) > 1 + + def test_Sequence(self): + col = py.builtin._tryimport( + "collections.abc", + "collections", + "sys") + if not hasattr(col, "MutableSequence"): + pytest.skip("cannot import MutableSequence") + MutableSequence = col.MutableSequence + + class TestSequence(MutableSequence): # works with a Sequence subclass + def __init__(self, iterable): + self.elements = list(iterable) + + def __getitem__(self, item): + return self.elements[item] + + def __len__(self): + return len(self.elements) + + def __setitem__(self, item, value): + pass + + def __delitem__(self, item): + pass + + def insert(self, item, index): + pass + + expl = callequal(TestSequence([0, 1]), list([0, 2])) + assert len(expl) > 1 + + def test_list_tuples(self): + expl = callequal([], [(1, 2)]) + assert len(expl) > 1 + expl = callequal([(1, 2)], []) + assert len(expl) > 1 + + def test_list_bad_repr(self): + class A(object): + def __repr__(self): + raise ValueError(42) + expl = callequal([], [A()]) + assert 'ValueError' in "".join(expl) + expl = callequal({}, {'1': A()}) + assert 'faulty' in "".join(expl) + + def test_one_repr_empty(self): + """ + the faulty empty string repr did trigger + a unbound local error in _diff_text + """ + class A(str): + def __repr__(self): + return '' + expl = callequal(A(), '') + assert not expl + + def test_repr_no_exc(self): + expl = ' '.join(callequal('foo', 'bar')) + assert 'raised in repr()' not in expl + + def test_unicode(self): + left = py.builtin._totext('£€', 'utf-8') + right = py.builtin._totext('£', 'utf-8') + expl = callequal(left, right) + assert expl[0] == py.builtin._totext("'£€' == '£'", 'utf-8') + assert expl[1] == py.builtin._totext('- £€', 'utf-8') + assert expl[2] == py.builtin._totext('+ £', 'utf-8') + + def test_nonascii_text(self): + """ + :issue: 877 + non ascii python2 str caused a UnicodeDecodeError + """ + class A(str): + def __repr__(self): + return '\xff' + expl = callequal(A(), '1') + assert expl + + def test_format_nonascii_explanation(self): + assert util.format_explanation('λ') + + def test_mojibake(self): + # issue 429 + left = 'e' + right = '\xc3\xa9' + if not isinstance(left, py.builtin.bytes): + left = py.builtin.bytes(left, 'utf-8') + right = py.builtin.bytes(right, 'utf-8') + expl = callequal(left, right) + for line in expl: + assert isinstance(line, py.builtin.text) + msg = py.builtin._totext('\n').join(expl) + assert msg + + +class TestFormatExplanation(object): + + def test_special_chars_full(self, testdir): + # Issue 453, for the bug this would raise IndexError + testdir.makepyfile(""" + def test_foo(): + assert '\\n}' == '' + """) + result = testdir.runpytest() + assert result.ret == 1 + result.stdout.fnmatch_lines([ + "*AssertionError*", + ]) + + def test_fmt_simple(self): + expl = 'assert foo' + assert util.format_explanation(expl) == 'assert foo' + + def test_fmt_where(self): + expl = '\n'.join(['assert 1', + '{1 = foo', + '} == 2']) + res = '\n'.join(['assert 1 == 2', + ' + where 1 = foo']) + assert util.format_explanation(expl) == res + + def test_fmt_and(self): + expl = '\n'.join(['assert 1', + '{1 = foo', + '} == 2', + '{2 = bar', + '}']) + res = '\n'.join(['assert 1 == 2', + ' + where 1 = foo', + ' + and 2 = bar']) + assert util.format_explanation(expl) == res + + def test_fmt_where_nested(self): + expl = '\n'.join(['assert 1', + '{1 = foo', + '{foo = bar', + '}', + '} == 2']) + res = '\n'.join(['assert 1 == 2', + ' + where 1 = foo', + ' + where foo = bar']) + assert util.format_explanation(expl) == res + + def test_fmt_newline(self): + expl = '\n'.join(['assert "foo" == "bar"', + '~- foo', + '~+ bar']) + res = '\n'.join(['assert "foo" == "bar"', + ' - foo', + ' + bar']) + assert util.format_explanation(expl) == res + + def test_fmt_newline_escaped(self): + expl = '\n'.join(['assert foo == bar', + 'baz']) + res = 'assert foo == bar\\nbaz' + assert util.format_explanation(expl) == res + + def test_fmt_newline_before_where(self): + expl = '\n'.join(['the assertion message here', + '>assert 1', + '{1 = foo', + '} == 2', + '{2 = bar', + '}']) + res = '\n'.join(['the assertion message here', + 'assert 1 == 2', + ' + where 1 = foo', + ' + and 2 = bar']) + assert util.format_explanation(expl) == res + + def test_fmt_multi_newline_before_where(self): + expl = '\n'.join(['the assertion', + '~message here', + '>assert 1', + '{1 = foo', + '} == 2', + '{2 = bar', + '}']) + res = '\n'.join(['the assertion', + ' message here', + 'assert 1 == 2', + ' + where 1 = foo', + ' + and 2 = bar']) + assert util.format_explanation(expl) == res + + +class TestTruncateExplanation(object): + + """ Confirm assertion output is truncated as expected """ + + # The number of lines in the truncation explanation message. Used + # to calculate that results have the expected length. + LINES_IN_TRUNCATION_MSG = 2 + + def test_doesnt_truncate_when_input_is_empty_list(self): + expl = [] + result = truncate._truncate_explanation(expl, max_lines=8, max_chars=100) + assert result == expl + + def test_doesnt_truncate_at_when_input_is_5_lines_and_LT_max_chars(self): + expl = ['a' * 100 for x in range(5)] + result = truncate._truncate_explanation(expl, max_lines=8, max_chars=8 * 80) + assert result == expl + + def test_truncates_at_8_lines_when_given_list_of_empty_strings(self): + expl = ['' for x in range(50)] + result = truncate._truncate_explanation(expl, max_lines=8, max_chars=100) + assert result != expl + assert len(result) == 8 + self.LINES_IN_TRUNCATION_MSG + assert "Full output truncated" in result[-1] + assert "43 lines hidden" in result[-1] + last_line_before_trunc_msg = result[- self.LINES_IN_TRUNCATION_MSG - 1] + assert last_line_before_trunc_msg.endswith("...") + + def test_truncates_at_8_lines_when_first_8_lines_are_LT_max_chars(self): + expl = ['a' for x in range(100)] + result = truncate._truncate_explanation(expl, max_lines=8, max_chars=8 * 80) + assert result != expl + assert len(result) == 8 + self.LINES_IN_TRUNCATION_MSG + assert "Full output truncated" in result[-1] + assert "93 lines hidden" in result[-1] + last_line_before_trunc_msg = result[- self.LINES_IN_TRUNCATION_MSG - 1] + assert last_line_before_trunc_msg.endswith("...") + + def test_truncates_at_8_lines_when_first_8_lines_are_EQ_max_chars(self): + expl = ['a' * 80 for x in range(16)] + result = truncate._truncate_explanation(expl, max_lines=8, max_chars=8 * 80) + assert result != expl + assert len(result) == 8 + self.LINES_IN_TRUNCATION_MSG + assert "Full output truncated" in result[-1] + assert "9 lines hidden" in result[-1] + last_line_before_trunc_msg = result[- self.LINES_IN_TRUNCATION_MSG - 1] + assert last_line_before_trunc_msg.endswith("...") + + def test_truncates_at_4_lines_when_first_4_lines_are_GT_max_chars(self): + expl = ['a' * 250 for x in range(10)] + result = truncate._truncate_explanation(expl, max_lines=8, max_chars=999) + assert result != expl + assert len(result) == 4 + self.LINES_IN_TRUNCATION_MSG + assert "Full output truncated" in result[-1] + assert "7 lines hidden" in result[-1] + last_line_before_trunc_msg = result[- self.LINES_IN_TRUNCATION_MSG - 1] + assert last_line_before_trunc_msg.endswith("...") + + def test_truncates_at_1_line_when_first_line_is_GT_max_chars(self): + expl = ['a' * 250 for x in range(1000)] + result = truncate._truncate_explanation(expl, max_lines=8, max_chars=100) + assert result != expl + assert len(result) == 1 + self.LINES_IN_TRUNCATION_MSG + assert "Full output truncated" in result[-1] + assert "1000 lines hidden" in result[-1] + last_line_before_trunc_msg = result[- self.LINES_IN_TRUNCATION_MSG - 1] + assert last_line_before_trunc_msg.endswith("...") + + def test_full_output_truncated(self, monkeypatch, testdir): + """ Test against full runpytest() output. """ + + line_count = 7 + line_len = 100 + expected_truncated_lines = 2 + testdir.makepyfile(r""" + def test_many_lines(): + a = list([str(i)[0] * %d for i in range(%d)]) + b = a[::2] + a = '\n'.join(map(str, a)) + b = '\n'.join(map(str, b)) + assert a == b + """ % (line_len, line_count)) + monkeypatch.delenv('CI', raising=False) + + result = testdir.runpytest() + # without -vv, truncate the message showing a few diff lines only + result.stdout.fnmatch_lines([ + "*- 1*", + "*- 3*", + "*- 5*", + "*truncated (%d lines hidden)*use*-vv*" % expected_truncated_lines, + ]) + + result = testdir.runpytest('-vv') + result.stdout.fnmatch_lines([ + "* 6*", + ]) + + monkeypatch.setenv('CI', '1') + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + "* 6*", + ]) + + +def test_python25_compile_issue257(testdir): + testdir.makepyfile(""" + def test_rewritten(): + assert 1 == 2 + # some comment + """) + result = testdir.runpytest() + assert result.ret == 1 + result.stdout.fnmatch_lines(""" + *E*assert 1 == 2* + *1 failed* + """) + + +def test_rewritten(testdir): + testdir.makepyfile(""" + def test_rewritten(): + assert "@py_builtins" in globals() + """) + assert testdir.runpytest().ret == 0 + + +def test_reprcompare_notin(mock_config): + detail = plugin.pytest_assertrepr_compare( + mock_config, 'not in', 'foo', 'aaafoobbb')[1:] + assert detail == ["'foo' is contained here:", ' aaafoobbb', '? +++'] + + +def test_pytest_assertrepr_compare_integration(testdir): + testdir.makepyfile(""" + def test_hello(): + x = set(range(100)) + y = x.copy() + y.remove(50) + assert x == y + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + "*def test_hello():*", + "*assert x == y*", + "*E*Extra items*left*", + "*E*50*", + ]) + + +def test_sequence_comparison_uses_repr(testdir): + testdir.makepyfile(""" + def test_hello(): + x = set("hello x") + y = set("hello y") + assert x == y + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + "*def test_hello():*", + "*assert x == y*", + "*E*Extra items*left*", + "*E*'x'*", + "*E*Extra items*right*", + "*E*'y'*", + ]) + + +def test_assertrepr_loaded_per_dir(testdir): + testdir.makepyfile(test_base=['def test_base(): assert 1 == 2']) + a = testdir.mkdir('a') + a_test = a.join('test_a.py') + a_test.write('def test_a(): assert 1 == 2') + a_conftest = a.join('conftest.py') + a_conftest.write('def pytest_assertrepr_compare(): return ["summary a"]') + b = testdir.mkdir('b') + b_test = b.join('test_b.py') + b_test.write('def test_b(): assert 1 == 2') + b_conftest = b.join('conftest.py') + b_conftest.write('def pytest_assertrepr_compare(): return ["summary b"]') + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + '*def test_base():*', + '*E*assert 1 == 2*', + '*def test_a():*', + '*E*assert summary a*', + '*def test_b():*', + '*E*assert summary b*']) + + +def test_assertion_options(testdir): + testdir.makepyfile(""" + def test_hello(): + x = 3 + assert x == 4 + """) + result = testdir.runpytest() + assert "3 == 4" in result.stdout.str() + result = testdir.runpytest_subprocess("--assert=plain") + assert "3 == 4" not in result.stdout.str() + + +def test_triple_quoted_string_issue113(testdir): + testdir.makepyfile(""" + def test_hello(): + assert "" == ''' + '''""") + result = testdir.runpytest("--fulltrace") + result.stdout.fnmatch_lines([ + "*1 failed*", + ]) + assert 'SyntaxError' not in result.stdout.str() + + +def test_traceback_failure(testdir): + p1 = testdir.makepyfile(""" + def g(): + return 2 + def f(x): + assert x == g() + def test_onefails(): + f(3) + """) + result = testdir.runpytest(p1, "--tb=long") + result.stdout.fnmatch_lines([ + "*test_traceback_failure.py F*", + "====* FAILURES *====", + "____*____", + "", + " def test_onefails():", + "> f(3)", + "", + "*test_*.py:6: ", + "_ _ _ *", + # "", + " def f(x):", + "> assert x == g()", + "E assert 3 == 2", + "E + where 2 = g()", + "", + "*test_traceback_failure.py:4: AssertionError" + ]) + + result = testdir.runpytest(p1) # "auto" + result.stdout.fnmatch_lines([ + "*test_traceback_failure.py F*", + "====* FAILURES *====", + "____*____", + "", + " def test_onefails():", + "> f(3)", + "", + "*test_*.py:6: ", + "", + " def f(x):", + "> assert x == g()", + "E assert 3 == 2", + "E + where 2 = g()", + "", + "*test_traceback_failure.py:4: AssertionError" + ]) + + +@pytest.mark.skipif(sys.version_info[:2] <= (3, 3), reason='Python 3.4+ shows chained exceptions on multiprocess') +def test_exception_handling_no_traceback(testdir): + """ + Handle chain exceptions in tasks submitted by the multiprocess module (#1984). + """ + p1 = testdir.makepyfile(""" + from multiprocessing import Pool + + def process_task(n): + assert n == 10 + + def multitask_job(): + tasks = [1] + with Pool(processes=1) as pool: + pool.map(process_task, tasks) + + def test_multitask_job(): + multitask_job() + """) + result = testdir.runpytest(p1, "--tb=long") + result.stdout.fnmatch_lines([ + "====* FAILURES *====", + "*multiprocessing.pool.RemoteTraceback:*", + "Traceback (most recent call last):", + "*assert n == 10", + "The above exception was the direct cause of the following exception:", + "> * multitask_job()", + ]) + + +@pytest.mark.skipif("'__pypy__' in sys.builtin_module_names or sys.platform.startswith('java')") +def test_warn_missing(testdir): + testdir.makepyfile("") + result = testdir.run(sys.executable, "-OO", "-m", "pytest", "-h") + result.stderr.fnmatch_lines([ + "*WARNING*assert statements are not executed*", + ]) + result = testdir.run(sys.executable, "-OO", "-m", "pytest") + result.stderr.fnmatch_lines([ + "*WARNING*assert statements are not executed*", + ]) + + +def test_recursion_source_decode(testdir): + testdir.makepyfile(""" + def test_something(): + pass + """) + testdir.makeini(""" + [pytest] + python_files = *.py + """) + result = testdir.runpytest("--collect-only") + result.stdout.fnmatch_lines(""" + + """) + + +def test_AssertionError_message(testdir): + testdir.makepyfile(""" + def test_hello(): + x,y = 1,2 + assert 0, (x,y) + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines(""" + *def test_hello* + *assert 0, (x,y)* + *AssertionError: (1, 2)* + """) + + +@pytest.mark.skipif(PY3, reason='This bug does not exist on PY3') +def test_set_with_unsortable_elements(): + # issue #718 + class UnsortableKey(object): + def __init__(self, name): + self.name = name + + def __lt__(self, other): + raise RuntimeError() + + def __repr__(self): + return 'repr({0})'.format(self.name) + + def __eq__(self, other): + return self.name == other.name + + def __hash__(self): + return hash(self.name) + + left_set = set(UnsortableKey(str(i)) for i in range(1, 3)) + right_set = set(UnsortableKey(str(i)) for i in range(2, 4)) + expl = callequal(left_set, right_set, verbose=True) + # skip first line because it contains the "construction" of the set, which does not have a guaranteed order + expl = expl[1:] + dedent = textwrap.dedent(""" + Extra items in the left set: + repr(1) + Extra items in the right set: + repr(3) + Full diff (fallback to calling repr on each item): + - repr(1) + repr(2) + + repr(3) + """).strip() + assert '\n'.join(expl) == dedent + + +def test_diff_newline_at_end(monkeypatch, testdir): + testdir.makepyfile(r""" + def test_diff(): + assert 'asdf' == 'asdf\n' + """) + + result = testdir.runpytest() + result.stdout.fnmatch_lines(r""" + *assert 'asdf' == 'asdf\n' + * - asdf + * + asdf + * ? + + """) + + +def test_assert_tuple_warning(testdir): + testdir.makepyfile(""" + def test_tuple(): + assert(False, 'you shall not pass') + """) + result = testdir.runpytest('-rw') + result.stdout.fnmatch_lines([ + '*test_assert_tuple_warning.py:2', + '*assertion is always true*', + ]) + + +def test_assert_indirect_tuple_no_warning(testdir): + testdir.makepyfile(""" + def test_tuple(): + tpl = ('foo', 'bar') + assert tpl + """) + result = testdir.runpytest('-rw') + output = '\n'.join(result.stdout.lines) + assert 'WR1' not in output + + +def test_assert_with_unicode(monkeypatch, testdir): + testdir.makepyfile(u""" + # -*- coding: utf-8 -*- + def test_unicode(): + assert u'유니코드' == u'Unicode' + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines(['*AssertionError*']) + + +def test_raise_unprintable_assertion_error(testdir): + testdir.makepyfile(r""" + def test_raise_assertion_error(): + raise AssertionError('\xff') + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines([r"> raise AssertionError('\xff')", 'E AssertionError: *']) + + +def test_raise_assertion_error_raisin_repr(testdir): + testdir.makepyfile(u""" + class RaisingRepr(object): + def __repr__(self): + raise Exception() + def test_raising_repr(): + raise AssertionError(RaisingRepr()) + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines(['E AssertionError: ']) + + +def test_issue_1944(testdir): + testdir.makepyfile(""" + def f(): + return + + assert f() == 10 + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines(["*1 error*"]) + assert "AttributeError: 'Module' object has no attribute '_obj'" not in result.stdout.str() diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_assertrewrite.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_assertrewrite.py similarity index 70% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_assertrewrite.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_assertrewrite.py index f43c424ca94..0e22c6dac47 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_assertrewrite.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_assertrewrite.py @@ -1,25 +1,30 @@ +from __future__ import absolute_import, division, print_function + +import glob import os +import py_compile import stat import sys import zipfile import py import pytest +import _pytest._code +from _pytest.assertion import util +from _pytest.assertion.rewrite import rewrite_asserts, PYTEST_TAG, AssertionRewritingHook +from _pytest.main import EXIT_NOTESTSCOLLECTED + ast = pytest.importorskip("ast") if sys.platform.startswith("java"): # XXX should be xfail pytest.skip("assert rewrite does currently not work on jython") -import _pytest._code -from _pytest.assertion import util -from _pytest.assertion.rewrite import rewrite_asserts, PYTEST_TAG -from _pytest.main import EXIT_NOTESTSCOLLECTED - def setup_module(mod): mod._old_reprcompare = util._reprcompare _pytest._code._reprcompare = None + def teardown_module(mod): util._reprcompare = mod._old_reprcompare del mod._old_reprcompare @@ -30,6 +35,7 @@ def rewrite(src): rewrite_asserts(tree) return tree + def getmsg(f, extra_ns=None, must_pass=False): """Rewrite the assertions in f, run it, and get the failure message.""" src = '\n'.join(_pytest._code.Code(f).source().lines) @@ -54,18 +60,23 @@ def getmsg(f, extra_ns=None, must_pass=False): pytest.fail("function didn't raise at all") -class TestAssertionRewrite: +class TestAssertionRewrite(object): def test_place_initial_imports(self): s = """'Doc string'\nother = stuff""" m = rewrite(s) - assert isinstance(m.body[0], ast.Expr) - assert isinstance(m.body[0].value, ast.Str) - for imp in m.body[1:3]: + # Module docstrings in 3.7 are part of Module node, it's not in the body + # so we remove it so the following body items have the same indexes on + # all Python versions + if sys.version_info < (3, 7): + assert isinstance(m.body[0], ast.Expr) + assert isinstance(m.body[0].value, ast.Str) + del m.body[0] + for imp in m.body[0:2]: assert isinstance(imp, ast.Import) assert imp.lineno == 2 assert imp.col_offset == 0 - assert isinstance(m.body[3], ast.Assign) + assert isinstance(m.body[2], ast.Assign) s = """from __future__ import with_statement\nother_stuff""" m = rewrite(s) assert isinstance(m.body[0], ast.ImportFrom) @@ -74,16 +85,29 @@ class TestAssertionRewrite: assert imp.lineno == 2 assert imp.col_offset == 0 assert isinstance(m.body[3], ast.Expr) + s = """'doc string'\nfrom __future__ import with_statement""" + m = rewrite(s) + if sys.version_info < (3, 7): + assert isinstance(m.body[0], ast.Expr) + assert isinstance(m.body[0].value, ast.Str) + del m.body[0] + assert isinstance(m.body[0], ast.ImportFrom) + for imp in m.body[1:3]: + assert isinstance(imp, ast.Import) + assert imp.lineno == 2 + assert imp.col_offset == 0 s = """'doc string'\nfrom __future__ import with_statement\nother""" m = rewrite(s) - assert isinstance(m.body[0], ast.Expr) - assert isinstance(m.body[0].value, ast.Str) - assert isinstance(m.body[1], ast.ImportFrom) - for imp in m.body[2:4]: + if sys.version_info < (3, 7): + assert isinstance(m.body[0], ast.Expr) + assert isinstance(m.body[0].value, ast.Str) + del m.body[0] + assert isinstance(m.body[0], ast.ImportFrom) + for imp in m.body[1:3]: assert isinstance(imp, ast.Import) assert imp.lineno == 3 assert imp.col_offset == 0 - assert isinstance(m.body[4], ast.Expr) + assert isinstance(m.body[3], ast.Expr) s = """from . import relative\nother_stuff""" m = rewrite(s) for imp in m.body[0:2]: @@ -95,30 +119,43 @@ class TestAssertionRewrite: def test_dont_rewrite(self): s = """'PYTEST_DONT_REWRITE'\nassert 14""" m = rewrite(s) - assert len(m.body) == 2 - assert isinstance(m.body[0].value, ast.Str) - assert isinstance(m.body[1], ast.Assert) - assert m.body[1].msg is None + if sys.version_info < (3, 7): + assert len(m.body) == 2 + assert isinstance(m.body[0], ast.Expr) + assert isinstance(m.body[0].value, ast.Str) + del m.body[0] + else: + assert len(m.body) == 1 + assert m.body[0].msg is None def test_name(self): def f(): assert False assert getmsg(f) == "assert False" + def f(): f = False assert f + assert getmsg(f) == "assert False" + def f(): assert a_global # noqa - assert getmsg(f, {"a_global" : False}) == "assert False" + + assert getmsg(f, {"a_global": False}) == "assert False" + def f(): assert sys == 42 - assert getmsg(f, {"sys" : sys}) == "assert sys == 42" + + assert getmsg(f, {"sys": sys}) == "assert sys == 42" + def f(): assert cls == 42 # noqa + class X(object): pass - assert getmsg(f, {"cls" : X}) == "assert cls == 42" + + assert getmsg(f, {"cls": X}) == "assert cls == 42" def test_assert_already_has_message(self): def f(): @@ -190,76 +227,110 @@ class TestAssertionRewrite: def f(): f = g = False assert f and g + assert getmsg(f) == "assert (False)" + def f(): f = True g = False assert f and g + assert getmsg(f) == "assert (True and False)" + def f(): f = False g = True assert f and g + assert getmsg(f) == "assert (False)" + def f(): f = g = False assert f or g + assert getmsg(f) == "assert (False or False)" + def f(): f = g = False assert not f and not g + getmsg(f, must_pass=True) + def x(): return False + def f(): assert x() and x() - assert getmsg(f, {"x" : x}) == "assert (x())" + + assert getmsg(f, {"x": x}) == """assert (False) + + where False = x()""" + def f(): assert False or x() - assert getmsg(f, {"x" : x}) == "assert (False or x())" + + assert getmsg(f, {"x": x}) == """assert (False or False) + + where False = x()""" + def f(): assert 1 in {} and 2 in {} + assert getmsg(f) == "assert (1 in {})" + def f(): x = 1 y = 2 - assert x in {1 : None} and y in {} + assert x in {1: None} and y in {} + assert getmsg(f) == "assert (1 in {1: None} and 2 in {})" + def f(): f = True g = False assert f or g + getmsg(f, must_pass=True) + def f(): f = g = h = lambda: True assert f() and g() and h() + getmsg(f, must_pass=True) - def test_short_circut_evaluation(self): + def test_short_circuit_evaluation(self): def f(): assert True or explode # noqa + getmsg(f, must_pass=True) + def f(): x = 1 assert x == 1 or x == 2 + getmsg(f, must_pass=True) def test_unary_op(self): def f(): x = True assert not x + assert getmsg(f) == "assert not True" + def f(): x = 0 assert ~x + 1 + assert getmsg(f) == "assert (~0 + 1)" + def f(): x = 3 assert -x + x + assert getmsg(f) == "assert (-3 + 3)" + def f(): x = 0 assert +x + x + assert getmsg(f) == "assert (+0 + 0)" def test_binary_op(self): @@ -267,7 +338,9 @@ class TestAssertionRewrite: x = 1 y = -1 assert x + y + assert getmsg(f) == "assert (1 + -1)" + def f(): assert not 5 % 4 assert getmsg(f) == "assert not (5 % 4)" @@ -275,7 +348,9 @@ class TestAssertionRewrite: def test_boolop_percent(self): def f(): assert 3 % 2 and False + assert getmsg(f) == "assert ((3 % 2) and False)" + def f(): assert False or 4 % 2 assert getmsg(f) == "assert (False or (4 % 2))" @@ -283,7 +358,7 @@ class TestAssertionRewrite: @pytest.mark.skipif("sys.version_info < (3,5)") def test_at_operator_issue1290(self, testdir): testdir.makepyfile(""" - class Matrix: + class Matrix(object): def __init__(self, num): self.num = num def __matmul__(self, other): @@ -296,105 +371,159 @@ class TestAssertionRewrite: def test_call(self): def g(a=42, *args, **kwargs): return False - ns = {"g" : g} + + ns = {"g": g} + def f(): assert g() - assert getmsg(f, ns) == """assert g()""" + + assert getmsg(f, ns) == """assert False + + where False = g()""" + def f(): assert g(1) - assert getmsg(f, ns) == """assert g(1)""" + + assert getmsg(f, ns) == """assert False + + where False = g(1)""" + def f(): assert g(1, 2) - assert getmsg(f, ns) == """assert g(1, 2)""" + + assert getmsg(f, ns) == """assert False + + where False = g(1, 2)""" + def f(): assert g(1, g=42) - assert getmsg(f, ns) == """assert g(1, g=42)""" + + assert getmsg(f, ns) == """assert False + + where False = g(1, g=42)""" + def f(): assert g(1, 3, g=23) - assert getmsg(f, ns) == """assert g(1, 3, g=23)""" + + assert getmsg(f, ns) == """assert False + + where False = g(1, 3, g=23)""" + def f(): seq = [1, 2, 3] assert g(*seq) - assert getmsg(f, ns) == """assert g(*[1, 2, 3])""" + + assert getmsg(f, ns) == """assert False + + where False = g(*[1, 2, 3])""" + def f(): x = "a" - assert g(**{x : 2}) - assert getmsg(f, ns) == """assert g(**{'a': 2})""" + assert g(**{x: 2}) + + assert getmsg(f, ns) == """assert False + + where False = g(**{'a': 2})""" def test_attribute(self): class X(object): g = 3 - ns = {"x" : X} + + ns = {"x": X} + def f(): - assert not x.g # noqa + assert not x.g # noqa + assert getmsg(f, ns) == """assert not 3 + where 3 = x.g""" + def f(): x.a = False # noqa assert x.a # noqa - assert getmsg(f, ns) == """assert x.a""" + + assert getmsg(f, ns) == """assert False + + where False = x.a""" def test_comparisons(self): + def f(): a, b = range(2) assert b < a + assert getmsg(f) == """assert 1 < 0""" + def f(): a, b, c = range(3) assert a > b > c + assert getmsg(f) == """assert 0 > 1""" + def f(): a, b, c = range(3) assert a < b > c + assert getmsg(f) == """assert 1 > 2""" + def f(): a, b, c = range(3) assert a < b <= c + getmsg(f, must_pass=True) + def f(): a, b, c = range(3) assert a < b assert b < c + getmsg(f, must_pass=True) def test_len(self): + def f(): - l = list(range(10)) - assert len(l) == 11 + values = list(range(10)) + assert len(values) == 11 + assert getmsg(f).startswith("""assert 10 == 11 + where 10 = len([""") def test_custom_reprcompare(self, monkeypatch): def my_reprcompare(op, left, right): return "42" + monkeypatch.setattr(util, "_reprcompare", my_reprcompare) + def f(): assert 42 < 3 + assert getmsg(f) == "assert 42" + def my_reprcompare(op, left, right): return "%s %s %s" % (left, op, right) + monkeypatch.setattr(util, "_reprcompare", my_reprcompare) + def f(): assert 1 < 3 < 5 <= 4 < 7 + assert getmsg(f) == "assert 5 <= 4" def test_assert_raising_nonzero_in_comparison(self): def f(): class A(object): + def __nonzero__(self): raise ValueError(42) + def __lt__(self, other): return A() + def __repr__(self): return "" + def myany(x): return False + assert myany(A() < 0) + assert " < 0" in getmsg(f) def test_formatchar(self): def f(): assert "%test" == "test" + assert getmsg(f).startswith("assert '%test' == 'test'") def test_custom_repr(self): @@ -404,12 +533,14 @@ class TestAssertionRewrite: def __repr__(self): return "\n{ \n~ \n}" + f = Foo() assert 0 == f.a + assert r"where 1 = \n{ \n~ \n}.a" in util._format_lines([getmsg(f)])[0] -class TestRewriteOnImport: +class TestRewriteOnImport(object): def test_pycache_is_a_file(self, testdir): testdir.tmpdir.join("__pycache__").write("Hello") @@ -449,7 +580,7 @@ class TestRewriteOnImport: def test_readonly(self, testdir): sub = testdir.mkdir("testing") sub.join("test_readonly.py").write( - py.builtin._totext(""" + py.builtin._totext(""" def test_rewritten(): assert "@py_builtins" in globals() """).encode("utf-8"), "wb") @@ -470,6 +601,31 @@ def test_rewritten(): monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", "1") assert testdir.runpytest_subprocess().ret == 0 + def test_orphaned_pyc_file(self, testdir): + if sys.version_info < (3, 0) and hasattr(sys, 'pypy_version_info'): + pytest.skip("pypy2 doesn't run orphaned pyc files") + + testdir.makepyfile(""" + import orphan + def test_it(): + assert orphan.value == 17 + """) + testdir.makepyfile(orphan=""" + value = 17 + """) + py_compile.compile("orphan.py") + os.remove("orphan.py") + + # Python 3 puts the .pyc files in a __pycache__ directory, and will + # not import from there without source. It will import a .pyc from + # the source location though. + if not os.path.exists("orphan.pyc"): + pycs = glob.glob("__pycache__/orphan.*.pyc") + assert len(pycs) == 1 + os.rename(pycs[0], "orphan.pyc") + + assert testdir.runpytest().ret == 0 + @pytest.mark.skipif('"__pypy__" in sys.modules') def test_pyc_vs_pyo(self, testdir, monkeypatch): testdir.makepyfile(""" @@ -477,7 +633,7 @@ def test_rewritten(): def test_optimized(): "hello" assert test_optimized.__doc__ is None""" - ) + ) p = py.path.local.make_numbered_dir(prefix="runpytest-", keep=None, rootdir=testdir.tmpdir) tmp = "--basetemp=%s" % p @@ -506,14 +662,99 @@ def test_rewritten(): testdir.tmpdir.join("test_newlines.py").write(b, "wb") assert testdir.runpytest().ret == 0 - @pytest.mark.skipif(sys.version_info < (3,3), - reason='packages without __init__.py not supported on python 2') + @pytest.mark.skipif(sys.version_info < (3, 4), + reason='packages without __init__.py not supported on python 2') def test_package_without__init__py(self, testdir): pkg = testdir.mkdir('a_package_without_init_py') pkg.join('module.py').ensure() testdir.makepyfile("import a_package_without_init_py.module") assert testdir.runpytest().ret == EXIT_NOTESTSCOLLECTED + def test_rewrite_warning(self, pytestconfig, monkeypatch): + hook = AssertionRewritingHook(pytestconfig) + warnings = [] + + def mywarn(code, msg): + warnings.append((code, msg)) + + monkeypatch.setattr(hook.config, 'warn', mywarn) + hook.mark_rewrite('_pytest') + assert '_pytest' in warnings[0][1] + + def test_rewrite_module_imported_from_conftest(self, testdir): + testdir.makeconftest(''' + import test_rewrite_module_imported + ''') + testdir.makepyfile(test_rewrite_module_imported=''' + def test_rewritten(): + assert "@py_builtins" in globals() + ''') + assert testdir.runpytest_subprocess().ret == 0 + + def test_remember_rewritten_modules(self, pytestconfig, testdir, monkeypatch): + """ + AssertionRewriteHook should remember rewritten modules so it + doesn't give false positives (#2005). + """ + monkeypatch.syspath_prepend(testdir.tmpdir) + testdir.makepyfile(test_remember_rewritten_modules='') + warnings = [] + hook = AssertionRewritingHook(pytestconfig) + monkeypatch.setattr(hook.config, 'warn', lambda code, msg: warnings.append(msg)) + hook.find_module('test_remember_rewritten_modules') + hook.load_module('test_remember_rewritten_modules') + hook.mark_rewrite('test_remember_rewritten_modules') + hook.mark_rewrite('test_remember_rewritten_modules') + assert warnings == [] + + def test_rewrite_warning_using_pytest_plugins(self, testdir): + testdir.makepyfile(**{ + 'conftest.py': "pytest_plugins = ['core', 'gui', 'sci']", + 'core.py': "", + 'gui.py': "pytest_plugins = ['core', 'sci']", + 'sci.py': "pytest_plugins = ['core']", + 'test_rewrite_warning_pytest_plugins.py': "def test(): pass", + }) + testdir.chdir() + result = testdir.runpytest_subprocess() + result.stdout.fnmatch_lines(['*= 1 passed in *=*']) + assert 'pytest-warning summary' not in result.stdout.str() + + def test_rewrite_warning_using_pytest_plugins_env_var(self, testdir, monkeypatch): + monkeypatch.setenv('PYTEST_PLUGINS', 'plugin') + testdir.makepyfile(**{ + 'plugin.py': "", + 'test_rewrite_warning_using_pytest_plugins_env_var.py': """ + import plugin + pytest_plugins = ['plugin'] + def test(): + pass + """, + }) + testdir.chdir() + result = testdir.runpytest_subprocess() + result.stdout.fnmatch_lines(['*= 1 passed in *=*']) + assert 'pytest-warning summary' not in result.stdout.str() + + @pytest.mark.skipif(sys.version_info[0] > 2, reason='python 2 only') + def test_rewrite_future_imports(self, testdir): + """Test that rewritten modules don't inherit the __future__ flags + from the assertrewrite module. + + assertion.rewrite imports __future__.division (and others), so + ensure rewritten modules don't inherit those flags. + + The test below will fail if __future__.division is enabled + """ + testdir.makepyfile(''' + def test(): + x = 1 / 2 + assert type(x) is int + ''') + result = testdir.runpytest() + assert result.ret == 0 + + class TestAssertionRewriteHookDetails(object): def test_loader_is_package_false_for_module(self, testdir): testdir.makepyfile(test_fun=""" @@ -596,10 +837,12 @@ class TestAssertionRewriteHookDetails(object): source_path = tmpdir.ensure("source.py") pycpath = tmpdir.join("pyc").strpath assert _write_pyc(state, [1], source_path.stat(), pycpath) + def open(*args): e = IOError() e.errno = 10 raise e + monkeypatch.setattr(b, "open", open) assert not _write_pyc(state, [1], source_path.stat(), pycpath) @@ -684,7 +927,7 @@ class TestAssertionRewriteHookDetails(object): """ path = testdir.mkpydir("foo") path.join("test_foo.py").write(_pytest._code.Source(""" - class Test: + class Test(object): def test_foo(self): import pkgutil data = pkgutil.get_data('foo.test_foo', 'data.txt') @@ -712,5 +955,42 @@ def test_issue731(testdir): assert 'unbalanced braces' not in result.stdout.str() -def test_collapse_false_unbalanced_braces(): - util._collapse_false('some text{ False\n{False = some more text\n}') +class TestIssue925(object): + def test_simple_case(self, testdir): + testdir.makepyfile(""" + def test_ternary_display(): + assert (False == False) == False + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines('*E*assert (False == False) == False') + + def test_long_case(self, testdir): + testdir.makepyfile(""" + def test_ternary_display(): + assert False == (False == True) == True + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines('*E*assert (False == True) == True') + + def test_many_brackets(self, testdir): + testdir.makepyfile(""" + def test_ternary_display(): + assert True == ((False == True) == True) + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines('*E*assert True == ((False == True) == True)') + + +class TestIssue2121(): + def test_simple(self, testdir): + testdir.tmpdir.join("tests/file.py").ensure().write(""" +def test_simple_failure(): + assert 1 + 1 == 3 +""") + testdir.tmpdir.join("pytest.ini").write(py.std.textwrap.dedent(""" + [pytest] + python_files = tests/**.py + """)) + + result = testdir.runpytest() + result.stdout.fnmatch_lines('*E*assert (1 + 1) == 3') diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_cache.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_cache.py similarity index 60% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_cache.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_cache.py index 98053f86947..a37170cdd2b 100755 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_cache.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_cache.py @@ -1,5 +1,6 @@ +from __future__ import absolute_import, division, print_function import sys - +import py import _pytest import pytest import os @@ -7,7 +8,8 @@ import shutil pytest_plugins = "pytester", -class TestNewAPI: + +class TestNewAPI(object): def test_config_cache_makedir(self, testdir): testdir.makeini("[pytest]") config = testdir.parseconfigure() @@ -54,7 +56,7 @@ class TestNewAPI: assert result.ret == 1 result.stdout.fnmatch_lines([ "*could not create cache path*", - "*1 pytest-warnings*", + "*1 warnings*", ]) def test_config_cache(self, testdir): @@ -86,6 +88,36 @@ class TestNewAPI: assert result.ret == 0 result.stdout.fnmatch_lines(["*1 passed*"]) + def test_custom_rel_cache_dir(self, testdir): + rel_cache_dir = os.path.join('custom_cache_dir', 'subdir') + testdir.makeini(""" + [pytest] + cache_dir = {cache_dir} + """.format(cache_dir=rel_cache_dir)) + testdir.makepyfile(test_errored='def test_error():\n assert False') + testdir.runpytest() + assert testdir.tmpdir.join(rel_cache_dir).isdir() + + def test_custom_abs_cache_dir(self, testdir, tmpdir_factory): + tmp = str(tmpdir_factory.mktemp('tmp')) + abs_cache_dir = os.path.join(tmp, 'custom_cache_dir') + testdir.makeini(""" + [pytest] + cache_dir = {cache_dir} + """.format(cache_dir=abs_cache_dir)) + testdir.makepyfile(test_errored='def test_error():\n assert False') + testdir.runpytest() + assert py.path.local(abs_cache_dir).isdir() + + def test_custom_cache_dir_with_env_var(self, testdir, monkeypatch): + monkeypatch.setenv('env_var', 'custom_cache_dir') + testdir.makeini(""" + [pytest] + cache_dir = {cache_dir} + """.format(cache_dir='$env_var')) + testdir.makepyfile(test_errored='def test_error():\n assert False') + testdir.runpytest() + assert testdir.tmpdir.join('custom_cache_dir').isdir() def test_cache_reportheader(testdir): @@ -129,7 +161,7 @@ def test_cache_show(testdir): ]) -class TestLastFailed: +class TestLastFailed(object): def test_lastfailed_usecase(self, testdir, monkeypatch): monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", 1) @@ -191,13 +223,37 @@ class TestLastFailed: "test_a.py*", "test_b.py*", ]) - result = testdir.runpytest("--lf", "--ff") + result = testdir.runpytest("--ff") # Test order will be failing tests firs result.stdout.fnmatch_lines([ "test_b.py*", "test_a.py*", ]) + def test_lastfailed_failedfirst_order(self, testdir): + testdir.makepyfile(**{ + 'test_a.py': """ + def test_always_passes(): + assert 1 + """, + 'test_b.py': """ + def test_always_fails(): + assert 0 + """, + }) + result = testdir.runpytest() + # Test order will be collection order; alphabetical + result.stdout.fnmatch_lines([ + "test_a.py*", + "test_b.py*", + ]) + result = testdir.runpytest("--lf", "--ff") + # Test order will be failing tests firs + result.stdout.fnmatch_lines([ + "test_b.py*", + ]) + assert 'test_a.py' not in result.stdout.str() + def test_lastfailed_difference_invocations(self, testdir, monkeypatch): monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", 1) testdir.makepyfile(test_a=""" @@ -284,6 +340,73 @@ class TestLastFailed: result = testdir.runpytest() result.stdout.fnmatch_lines('*1 failed in*') + def test_terminal_report_lastfailed(self, testdir): + test_a = testdir.makepyfile(test_a=""" + def test_a1(): + pass + def test_a2(): + pass + """) + test_b = testdir.makepyfile(test_b=""" + def test_b1(): + assert 0 + def test_b2(): + assert 0 + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + 'collected 4 items', + '*2 failed, 2 passed in*', + ]) + + result = testdir.runpytest('--lf') + result.stdout.fnmatch_lines([ + 'collected 4 items', + 'run-last-failure: rerun previous 2 failures', + '*2 failed, 2 deselected in*', + ]) + + result = testdir.runpytest(test_a, '--lf') + result.stdout.fnmatch_lines([ + 'collected 2 items', + 'run-last-failure: run all (no recorded failures)', + '*2 passed in*', + ]) + + result = testdir.runpytest(test_b, '--lf') + result.stdout.fnmatch_lines([ + 'collected 2 items', + 'run-last-failure: rerun previous 2 failures', + '*2 failed in*', + ]) + + result = testdir.runpytest('test_b.py::test_b1', '--lf') + result.stdout.fnmatch_lines([ + 'collected 1 item', + 'run-last-failure: rerun previous 1 failure', + '*1 failed in*', + ]) + + def test_terminal_report_failedfirst(self, testdir): + testdir.makepyfile(test_a=""" + def test_a1(): + assert 0 + def test_a2(): + pass + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + 'collected 2 items', + '*1 failed, 1 passed in*', + ]) + + result = testdir.runpytest('--ff') + result.stdout.fnmatch_lines([ + 'collected 2 items', + 'run-last-failure: rerun previous 1 failure first', + '*1 failed, 1 passed in*', + ]) + def test_lastfailed_collectfailure(self, testdir, monkeypatch): testdir.makepyfile(test_maybe=""" @@ -313,7 +436,6 @@ class TestLastFailed: lastfailed = rlf(fail_import=0, fail_run=1) assert list(lastfailed) == ['test_maybe.py::test_hello'] - def test_lastfailed_failure_subset(self, testdir, monkeypatch): testdir.makepyfile(test_maybe=""" @@ -355,12 +477,10 @@ class TestLastFailed: result, lastfailed = rlf(fail_import=1, fail_run=0) assert sorted(list(lastfailed)) == ['test_maybe.py', 'test_maybe2.py'] - result, lastfailed = rlf(fail_import=0, fail_run=0, args=('test_maybe2.py',)) assert list(lastfailed) == ['test_maybe.py'] - # edge case of test selection - even if we remember failures # from other tests we still need to run all tests if no test # matches the failures @@ -384,3 +504,102 @@ class TestLastFailed: testdir.makepyfile(test_errored='def test_error():\n assert False') testdir.runpytest('-q', '--lf') assert os.path.exists('.cache') + + def test_xfail_not_considered_failure(self, testdir): + testdir.makepyfile(''' + import pytest + @pytest.mark.xfail + def test(): + assert 0 + ''') + result = testdir.runpytest() + result.stdout.fnmatch_lines('*1 xfailed*') + assert self.get_cached_last_failed(testdir) == [] + + def test_xfail_strict_considered_failure(self, testdir): + testdir.makepyfile(''' + import pytest + @pytest.mark.xfail(strict=True) + def test(): + pass + ''') + result = testdir.runpytest() + result.stdout.fnmatch_lines('*1 failed*') + assert self.get_cached_last_failed(testdir) == ['test_xfail_strict_considered_failure.py::test'] + + @pytest.mark.parametrize('mark', ['mark.xfail', 'mark.skip']) + def test_failed_changed_to_xfail_or_skip(self, testdir, mark): + testdir.makepyfile(''' + import pytest + def test(): + assert 0 + ''') + result = testdir.runpytest() + assert self.get_cached_last_failed(testdir) == ['test_failed_changed_to_xfail_or_skip.py::test'] + assert result.ret == 1 + + testdir.makepyfile(''' + import pytest + @pytest.{mark} + def test(): + assert 0 + '''.format(mark=mark)) + result = testdir.runpytest() + assert result.ret == 0 + assert self.get_cached_last_failed(testdir) == [] + assert result.ret == 0 + + def get_cached_last_failed(self, testdir): + config = testdir.parseconfigure() + return sorted(config.cache.get("cache/lastfailed", {})) + + def test_cache_cumulative(self, testdir): + """ + Test workflow where user fixes errors gradually file by file using --lf. + """ + # 1. initial run + test_bar = testdir.makepyfile(test_bar=""" + def test_bar_1(): + pass + def test_bar_2(): + assert 0 + """) + test_foo = testdir.makepyfile(test_foo=""" + def test_foo_3(): + pass + def test_foo_4(): + assert 0 + """) + testdir.runpytest() + assert self.get_cached_last_failed(testdir) == ['test_bar.py::test_bar_2', 'test_foo.py::test_foo_4'] + + # 2. fix test_bar_2, run only test_bar.py + testdir.makepyfile(test_bar=""" + def test_bar_1(): + pass + def test_bar_2(): + pass + """) + result = testdir.runpytest(test_bar) + result.stdout.fnmatch_lines('*2 passed*') + # ensure cache does not forget that test_foo_4 failed once before + assert self.get_cached_last_failed(testdir) == ['test_foo.py::test_foo_4'] + + result = testdir.runpytest('--last-failed') + result.stdout.fnmatch_lines('*1 failed, 3 deselected*') + assert self.get_cached_last_failed(testdir) == ['test_foo.py::test_foo_4'] + + # 3. fix test_foo_4, run only test_foo.py + test_foo = testdir.makepyfile(test_foo=""" + def test_foo_3(): + pass + def test_foo_4(): + pass + """) + result = testdir.runpytest(test_foo, '--last-failed') + result.stdout.fnmatch_lines('*1 passed, 1 deselected*') + assert self.get_cached_last_failed(testdir) == [] + + result = testdir.runpytest('--last-failed') + result.stdout.fnmatch_lines('*4 passed*') + assert self.get_cached_last_failed(testdir) == [] diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_capture.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_capture.py similarity index 75% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_capture.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_capture.py index 73660692b8e..f769a725dc4 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_capture.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_capture.py @@ -1,9 +1,11 @@ +from __future__ import absolute_import, division, print_function # note: py.io capture tests where copied from # pylib 1.4.20.dev2 (rev 13d9af95547e) from __future__ import with_statement import pickle import os import sys +from io import UnsupportedOperation import _pytest._code import py @@ -13,7 +15,7 @@ import contextlib from _pytest import capture from _pytest.capture import CaptureManager from _pytest.main import EXIT_NOTESTSCOLLECTED -from py.builtin import print_ + needsosdup = pytest.mark.xfail("not hasattr(os, 'dup')") @@ -47,15 +49,15 @@ def oswritebytes(fd, obj): os.write(fd, tobytes(obj)) - def StdCaptureFD(out=True, err=True, in_=True): return capture.MultiCapture(out, err, in_, Capture=capture.FDCapture) + def StdCapture(out=True, err=True, in_=True): return capture.MultiCapture(out, err, in_, Capture=capture.SysCapture) -class TestCaptureManager: +class TestCaptureManager(object): def test_getmethod_default_no_fd(self, monkeypatch): from _pytest.capture import pytest_addoption from _pytest.config import Parser @@ -70,29 +72,29 @@ class TestCaptureManager: @needsosdup @pytest.mark.parametrize("method", - ['no', 'sys', pytest.mark.skipif('not hasattr(os, "dup")', 'fd')]) + ['no', 'sys', pytest.mark.skipif('not hasattr(os, "dup")', 'fd')]) def test_capturing_basic_api(self, method): capouter = StdCaptureFD() old = sys.stdout, sys.stderr, sys.stdin try: capman = CaptureManager(method) - capman.init_capturings() - outerr = capman.suspendcapture() + capman.start_global_capturing() + outerr = capman.suspend_global_capture() assert outerr == ("", "") - outerr = capman.suspendcapture() + outerr = capman.suspend_global_capture() assert outerr == ("", "") - print ("hello") - out, err = capman.suspendcapture() + print("hello") + out, err = capman.suspend_global_capture() if method == "no": assert old == (sys.stdout, sys.stderr, sys.stdin) else: assert not out - capman.resumecapture() - print ("hello") - out, err = capman.suspendcapture() + capman.resume_global_capture() + print("hello") + out, err = capman.suspend_global_capture() if method != "no": assert out == "hello\n" - capman.reset_capturings() + capman.stop_global_capturing() finally: capouter.stop_capturing() @@ -101,16 +103,16 @@ class TestCaptureManager: capouter = StdCaptureFD() try: capman = CaptureManager("fd") - capman.init_capturings() - pytest.raises(AssertionError, "capman.init_capturings()") - capman.reset_capturings() + capman.start_global_capturing() + pytest.raises(AssertionError, "capman.start_global_capturing()") + capman.stop_global_capturing() finally: capouter.stop_capturing() @pytest.mark.parametrize("method", ['fd', 'sys']) def test_capturing_unicode(testdir, method): - if hasattr(sys, "pypy_version_info") and sys.pypy_version_info < (2,2): + if hasattr(sys, "pypy_version_info") and sys.pypy_version_info < (2, 2): pytest.xfail("does not work on pypy < 2.2") if sys.version_info >= (3, 0): obj = "'b\u00f6y'" @@ -154,7 +156,7 @@ def test_collect_capturing(testdir): ]) -class TestPerTestCapturing: +class TestPerTestCapturing(object): def test_capture_and_fixtures(self, testdir): p = testdir.makepyfile(""" def setup_module(mod): @@ -232,7 +234,7 @@ class TestPerTestCapturing: "setup func1*", "in func1*", "teardown func1*", - #"*1 fixture failure*" + # "*1 fixture failure*" ]) def test_teardown_capturing_final(self, testdir): @@ -264,7 +266,7 @@ class TestPerTestCapturing: """) result = testdir.runpytest(p1) result.stdout.fnmatch_lines([ - "*test_capturing_outerr.py .F", + "*test_capturing_outerr.py .F*", "====* FAILURES *====", "____*____", "*test_capturing_outerr.py:8: ValueError", @@ -275,18 +277,18 @@ class TestPerTestCapturing: ]) -class TestLoggingInteraction: +class TestLoggingInteraction(object): def test_logging_stream_ownership(self, testdir): p = testdir.makepyfile(""" def test_logging(): import logging import pytest - stream = capture.TextIO() + stream = capture.CaptureIO() logging.basicConfig(stream=stream) stream.close() # to free memory/release resources """) result = testdir.runpytest_subprocess(p) - result.stderr.str().find("atexit") == -1 + assert result.stderr.str().find("atexit") == -1 def test_logging_and_immediate_setupteardown(self, testdir): p = testdir.makepyfile(""" @@ -303,7 +305,7 @@ class TestLoggingInteraction: assert 0 """) for optargs in (('--capture=sys',), ('--capture=fd',)): - print (optargs) + print(optargs) result = testdir.runpytest_subprocess(p, *optargs) s = result.stdout.str() result.stdout.fnmatch_lines([ @@ -329,7 +331,7 @@ class TestLoggingInteraction: assert 0 """) for optargs in (('--capture=sys',), ('--capture=fd',)): - print (optargs) + print(optargs) result = testdir.runpytest_subprocess(p, *optargs) s = result.stdout.str() result.stdout.fnmatch_lines([ @@ -340,26 +342,6 @@ class TestLoggingInteraction: # verify proper termination assert "closed" not in s - def test_logging_initialized_in_test(self, testdir): - p = testdir.makepyfile(""" - import sys - def test_something(): - # pytest does not import logging - assert 'logging' not in sys.modules - import logging - logging.basicConfig() - logging.warn("hello432") - assert 0 - """) - result = testdir.runpytest_subprocess( - p, "--traceconfig", - "-p", "no:capturelog") - assert result.ret != 0 - result.stdout.fnmatch_lines([ - "*hello432*", - ]) - assert 'operation on closed file' not in result.stderr.str() - def test_conftestlogging_is_shown(self, testdir): testdir.makeconftest(""" import logging @@ -395,7 +377,7 @@ class TestLoggingInteraction: assert 'operation on closed file' not in result.stderr.str() -class TestCaptureFixture: +class TestCaptureFixture(object): @pytest.mark.parametrize("opt", [[], ["-s"]]) def test_std_functional(self, testdir, opt): reprec = testdir.inline_runsource(""" @@ -416,11 +398,41 @@ class TestCaptureFixture: result = testdir.runpytest(p) result.stdout.fnmatch_lines([ "*ERROR*setup*test_one*", - "*capsys*capfd*same*time*", + "E*capfd*capsys*same*time*", "*ERROR*setup*test_two*", - "*capsys*capfd*same*time*", + "E*capsys*capfd*same*time*", "*2 error*"]) + def test_capturing_getfixturevalue(self, testdir): + """Test that asking for "capfd" and "capsys" using request.getfixturevalue + in the same test is an error. + """ + testdir.makepyfile(""" + def test_one(capsys, request): + request.getfixturevalue("capfd") + def test_two(capfd, request): + request.getfixturevalue("capsys") + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + "*test_one*", + "*capsys*capfd*same*time*", + "*test_two*", + "*capfd*capsys*same*time*", + "*2 failed in*", + ]) + + def test_capsyscapfdbinary(self, testdir): + p = testdir.makepyfile(""" + def test_one(capsys, capfdbinary): + pass + """) + result = testdir.runpytest(p) + result.stdout.fnmatch_lines([ + "*ERROR*setup*test_one*", + "E*capfdbinary*capsys*same*time*", + "*1 error*"]) + @pytest.mark.parametrize("method", ["sys", "fd"]) def test_capture_is_represented_on_failure_issue128(self, testdir, method): p = testdir.makepyfile(""" @@ -445,6 +457,51 @@ class TestCaptureFixture: """) reprec.assertoutcome(passed=1) + @needsosdup + def test_capfdbinary(self, testdir): + reprec = testdir.inline_runsource(""" + def test_hello(capfdbinary): + import os + # some likely un-decodable bytes + os.write(1, b'\\xfe\\x98\\x20') + out, err = capfdbinary.readouterr() + assert out == b'\\xfe\\x98\\x20' + assert err == b'' + """) + reprec.assertoutcome(passed=1) + + @pytest.mark.skipif( + sys.version_info < (3,), + reason='only have capsysbinary in python 3', + ) + def test_capsysbinary(self, testdir): + reprec = testdir.inline_runsource(""" + def test_hello(capsysbinary): + import sys + # some likely un-decodable bytes + sys.stdout.buffer.write(b'\\xfe\\x98\\x20') + out, err = capsysbinary.readouterr() + assert out == b'\\xfe\\x98\\x20' + assert err == b'' + """) + reprec.assertoutcome(passed=1) + + @pytest.mark.skipif( + sys.version_info >= (3,), + reason='only have capsysbinary in python 3', + ) + def test_capsysbinary_forbidden_in_python2(self, testdir): + testdir.makepyfile(""" + def test_hello(capsysbinary): + pass + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + "*test_hello*", + "*capsysbinary is only supported on python 3*", + "*1 error in*", + ]) + def test_partial_setup_failure(self, testdir): p = testdir.makepyfile(""" def test_hello(capsys, missingarg): @@ -480,6 +537,66 @@ class TestCaptureFixture: result = testdir.runpytest_subprocess(p) assert 'closed' not in result.stderr.str() + @pytest.mark.parametrize('fixture', ['capsys', 'capfd']) + @pytest.mark.parametrize('no_capture', [True, False]) + def test_disabled_capture_fixture(self, testdir, fixture, no_capture): + testdir.makepyfile(""" + def test_disabled({fixture}): + print('captured before') + with {fixture}.disabled(): + print('while capture is disabled') + print('captured after') + assert {fixture}.readouterr() == ('captured before\\ncaptured after\\n', '') + + def test_normal(): + print('test_normal executed') + """.format(fixture=fixture)) + args = ('-s',) if no_capture else () + result = testdir.runpytest_subprocess(*args) + result.stdout.fnmatch_lines(""" + *while capture is disabled* + """) + assert 'captured before' not in result.stdout.str() + assert 'captured after' not in result.stdout.str() + if no_capture: + assert 'test_normal executed' in result.stdout.str() + else: + assert 'test_normal executed' not in result.stdout.str() + + @pytest.mark.parametrize('fixture', ['capsys', 'capfd']) + def test_fixture_use_by_other_fixtures(self, testdir, fixture): + """ + Ensure that capsys and capfd can be used by other fixtures during setup and teardown. + """ + testdir.makepyfile(""" + from __future__ import print_function + import sys + import pytest + + @pytest.fixture + def captured_print({fixture}): + print('stdout contents begin') + print('stderr contents begin', file=sys.stderr) + out, err = {fixture}.readouterr() + + yield out, err + + print('stdout contents end') + print('stderr contents end', file=sys.stderr) + out, err = {fixture}.readouterr() + assert out == 'stdout contents end\\n' + assert err == 'stderr contents end\\n' + + def test_captured_print(captured_print): + out, err = captured_print + assert out == 'stdout contents begin\\n' + assert err == 'stderr contents begin\\n' + """.format(fixture=fixture)) + result = testdir.runpytest_subprocess() + result.stdout.fnmatch_lines("*1 passed*") + assert 'stdout contents begin' not in result.stdout.str() + assert 'stderr contents begin' not in result.stdout.str() + def test_setup_failure_does_not_kill_capturing(testdir): sub1 = testdir.mkpydir("sub1") @@ -569,7 +686,7 @@ def test_capture_binary_output(testdir): def test_error_during_readouterr(testdir): - """Make sure we suspend capturing if errors occurr during readouterr""" + """Make sure we suspend capturing if errors occur during readouterr""" testdir.makepyfile(pytest_xyz=""" from _pytest.capture import FDCapture def bad_snap(self): @@ -587,16 +704,16 @@ def test_error_during_readouterr(testdir): ]) -class TestTextIO: +class TestCaptureIO(object): def test_text(self): - f = capture.TextIO() + f = capture.CaptureIO() f.write("hello") s = f.getvalue() assert s == "hello" f.close() def test_unicode_and_str_mixture(self): - f = capture.TextIO() + f = capture.CaptureIO() if sys.version_info >= (3, 0): f.write("\u00f6") pytest.raises(TypeError, "f.write(bytes('hello', 'UTF-8'))") @@ -607,6 +724,18 @@ class TestTextIO: f.close() assert isinstance(s, unicode) + @pytest.mark.skipif( + sys.version_info[0] == 2, + reason='python 3 only behaviour', + ) + def test_write_bytes_to_buffer(self): + """In python3, stdout / stderr are text io wrappers (exposing a buffer + property of the underlying bytestream). See issue #1407 + """ + f = capture.CaptureIO() + f.buffer.write(b'foo\r\n') + assert f.getvalue() == 'foo\r\n' + def test_bytes_io(): f = py.io.BytesIO() @@ -623,7 +752,29 @@ def test_dontreadfrominput(): pytest.raises(IOError, f.read) pytest.raises(IOError, f.readlines) pytest.raises(IOError, iter, f) - pytest.raises(ValueError, f.fileno) + pytest.raises(UnsupportedOperation, f.fileno) + f.close() # just for completeness + + +@pytest.mark.skipif('sys.version_info < (3,)', reason='python2 has no buffer') +def test_dontreadfrominput_buffer_python3(): + from _pytest.capture import DontReadFromInput + f = DontReadFromInput() + fb = f.buffer + assert not fb.isatty() + pytest.raises(IOError, fb.read) + pytest.raises(IOError, fb.readlines) + pytest.raises(IOError, iter, fb) + pytest.raises(ValueError, fb.fileno) + f.close() # just for completeness + + +@pytest.mark.skipif('sys.version_info >= (3,)', reason='python2 has no buffer') +def test_dontreadfrominput_buffer_python2(): + from _pytest.capture import DontReadFromInput + f = DontReadFromInput() + with pytest.raises(AttributeError): + f.buffer f.close() # just for completeness @@ -634,6 +785,7 @@ def tmpfile(testdir): if not f.closed: f.close() + @needsosdup def test_dupfile(tmpfile): flist = [] @@ -642,27 +794,39 @@ def test_dupfile(tmpfile): assert nf != tmpfile assert nf.fileno() != tmpfile.fileno() assert nf not in flist - print_(i, end="", file=nf) + print(i, end="", file=nf) flist.append(nf) + + fname_open = flist[0].name + assert fname_open == repr(flist[0].buffer) + for i in range(5): f = flist[i] f.close() + fname_closed = flist[0].name + assert fname_closed == repr(flist[0].buffer) + assert fname_closed != fname_open tmpfile.seek(0) s = tmpfile.read() assert "01234" in repr(s) tmpfile.close() + assert fname_closed == repr(flist[0].buffer) + def test_dupfile_on_bytesio(): io = py.io.BytesIO() f = capture.safe_text_dupfile(io, "wb") f.write("hello") assert io.getvalue() == b"hello" + assert 'BytesIO object' in f.name + def test_dupfile_on_textio(): io = py.io.TextIO() f = capture.safe_text_dupfile(io, "wb") f.write("hello") assert io.getvalue() == "hello" + assert not hasattr(f, 'name') @contextlib.contextmanager @@ -680,7 +844,7 @@ def lsof_check(): assert len2 < len1 + 3, out2 -class TestFDCapture: +class TestFDCapture(object): pytestmark = needsosdup def test_simple(self, tmpfile): @@ -716,7 +880,7 @@ class TestFDCapture: def test_stderr(self): cap = capture.FDCapture(2) cap.start() - print_("hello", file=sys.stderr) + print("hello", file=sys.stderr) s = cap.snap() cap.done() assert s == "hello\n" @@ -775,7 +939,7 @@ def saved_fd(fd): os.close(new_fd) -class TestStdCapture: +class TestStdCapture(object): captureclass = staticmethod(StdCapture) @contextlib.contextmanager @@ -805,7 +969,7 @@ class TestStdCapture: def test_capturing_readouterr(self): with self.getcapture() as cap: - print ("hello world") + print("hello world") sys.stderr.write("hello error\n") out, err = cap.readouterr() assert out == "hello world\n" @@ -814,9 +978,17 @@ class TestStdCapture: out, err = cap.readouterr() assert err == "error2" + def test_capture_results_accessible_by_attribute(self): + with self.getcapture() as cap: + sys.stdout.write("hello") + sys.stderr.write("world") + capture_result = cap.readouterr() + assert capture_result.out == "hello" + assert capture_result.err == "world" + def test_capturing_readouterr_unicode(self): with self.getcapture() as cap: - print ("hx\xc4\x85\xc4\x87") + print("hx\xc4\x85\xc4\x87") out, err = cap.readouterr() assert out == py.builtin._totext("hx\xc4\x85\xc4\x87\n", "utf8") @@ -831,7 +1003,7 @@ class TestStdCapture: def test_reset_twice_error(self): with self.getcapture() as cap: - print ("hello") + print("hello") out, err = cap.readouterr() pytest.raises(ValueError, cap.stop_capturing) assert out == "hello\n" @@ -843,9 +1015,9 @@ class TestStdCapture: with self.getcapture() as cap: sys.stdout.write("hello") sys.stderr.write("world") - sys.stdout = capture.TextIO() - sys.stderr = capture.TextIO() - print ("not seen") + sys.stdout = capture.CaptureIO() + sys.stderr = capture.CaptureIO() + print("not seen") sys.stderr.write("not seen\n") out, err = cap.readouterr() assert out == "hello" @@ -855,9 +1027,9 @@ class TestStdCapture: def test_capturing_error_recursive(self): with self.getcapture() as cap1: - print ("cap1") + print("cap1") with self.getcapture() as cap2: - print ("cap2") + print("cap2") out2, err2 = cap2.readouterr() out1, err1 = cap1.readouterr() assert out1 == "cap1\n" @@ -887,9 +1059,9 @@ class TestStdCapture: assert sys.stdin is old def test_stdin_nulled_by_default(self): - print ("XXX this test may well hang instead of crashing") - print ("XXX which indicates an error in the underlying capturing") - print ("XXX mechanisms") + print("XXX this test may well hang instead of crashing") + print("XXX which indicates an error in the underlying capturing") + print("XXX mechanisms") with self.getcapture(): pytest.raises(IOError, "sys.stdin.read()") @@ -933,7 +1105,7 @@ class TestStdCaptureFD(TestStdCapture): cap.stop_capturing() -class TestStdCaptureFDinvalidFD: +class TestStdCaptureFDinvalidFD(object): pytestmark = needsosdup def test_stdcapture_fd_invalid_fd(self, testdir): @@ -966,6 +1138,23 @@ def test_capture_not_started_but_reset(): capsys.stop_capturing() +def test_using_capsys_fixture_works_with_sys_stdout_encoding(capsys): + test_text = 'test text' + + print(test_text.encode(sys.stdout.encoding, 'replace')) + (out, err) = capsys.readouterr() + assert out + assert err == '' + + +def test_capsys_results_accessible_by_attribute(capsys): + sys.stdout.write("spam") + sys.stderr.write("eggs") + capture_result = capsys.readouterr() + assert capture_result.out == "spam" + assert capture_result.err == "eggs" + + @needsosdup @pytest.mark.parametrize('use', [True, False]) def test_fdcapture_tmpfile_remains_the_same(tmpfile, use): @@ -981,6 +1170,7 @@ def test_fdcapture_tmpfile_remains_the_same(tmpfile, use): capfile2 = cap.err.tmpfile assert capfile2 == capfile + @needsosdup def test_close_and_capture_again(testdir): testdir.makepyfile(""" @@ -1000,7 +1190,6 @@ def test_close_and_capture_again(testdir): """) - @pytest.mark.parametrize('method', ['SysCapture', 'FDCapture']) def test_capturing_and_logging_fundamentals(testdir, method): if method == "StdCaptureFD" and not hasattr(os, 'dup'): @@ -1047,6 +1236,23 @@ def test_error_attribute_issue555(testdir): reprec.assertoutcome(passed=1) +@pytest.mark.skipif(not sys.platform.startswith('win') and sys.version_info[:2] >= (3, 6), + reason='only py3.6+ on windows') +def test_py36_windowsconsoleio_workaround_non_standard_streams(): + """ + Ensure _py36_windowsconsoleio_workaround function works with objects that + do not implement the full ``io``-based stream protocol, for example execnet channels (#2666). + """ + from _pytest.capture import _py36_windowsconsoleio_workaround + + class DummyStream: + def write(self, s): + pass + + stream = DummyStream() + _py36_windowsconsoleio_workaround(stream) + + def test_dontreadfrominput_has_encoding(testdir): testdir.makepyfile(""" import sys @@ -1059,7 +1265,7 @@ def test_dontreadfrominput_has_encoding(testdir): reprec.assertoutcome(passed=1) -def test_pickling_and_unpickling_enocded_file(): +def test_pickling_and_unpickling_encoded_file(): # See https://bitbucket.org/pytest-dev/pytest/pull-request/194 # pickle.loads() raises infinite recursion if # EncodedFile.__getattr__ is not implemented properly diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_collection.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_collection.py similarity index 68% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_collection.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_collection.py index 749c5b7ce45..563ed0439c0 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_collection.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_collection.py @@ -1,8 +1,12 @@ -import pytest, py +from __future__ import absolute_import, division, print_function +import pytest +import py -from _pytest.main import Session, EXIT_NOTESTSCOLLECTED +import _pytest._code +from _pytest.main import Session, EXIT_NOTESTSCOLLECTED, _in_venv -class TestCollector: + +class TestCollector(object): def test_collect_versus_item(self): from pytest import Collector, Item assert not issubclass(Collector, Item) @@ -41,16 +45,16 @@ class TestCollector: assert not (fn1 == fn3) assert fn1 != fn3 - for fn in fn1,fn2,fn3: + for fn in fn1, fn2, fn3: assert fn != 3 assert fn != modcol - assert fn != [1,2,3] - assert [1,2,3] != fn + assert fn != [1, 2, 3] + assert [1, 2, 3] != fn assert modcol != fn def test_getparent(self, testdir): modcol = testdir.getmodulecol(""" - class TestClass: + class TestClass(object): def test_foo(): pass """) @@ -67,7 +71,6 @@ class TestCollector: parent = fn.getparent(pytest.Class) assert parent is cls - def test_getcustomfile_roundtrip(self, testdir): hello = testdir.makefile(".xxx", hello="world") testdir.makepyfile(conftest=""" @@ -85,9 +88,28 @@ class TestCollector: assert len(nodes) == 1 assert isinstance(nodes[0], pytest.File) -class TestCollectFS: + def test_can_skip_class_with_test_attr(self, testdir): + """Assure test class is skipped when using `__test__=False` (See #2007).""" + testdir.makepyfile(""" + class TestFoo(object): + __test__ = False + def __init__(self): + pass + def test_foo(): + assert True + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + 'collected 0 items', + '*no tests ran in*', + ]) + + +class TestCollectFS(object): def test_ignored_certain_directories(self, testdir): tmpdir = testdir.tmpdir + tmpdir.ensure("build", 'test_notfound.py') + tmpdir.ensure("dist", 'test_notfound.py') tmpdir.ensure("_darcs", 'test_notfound.py') tmpdir.ensure("CVS", 'test_notfound.py') tmpdir.ensure("{arch}", 'test_notfound.py') @@ -102,6 +124,53 @@ class TestCollectFS: assert "test_notfound" not in s assert "test_found" in s + @pytest.mark.parametrize('fname', + ("activate", "activate.csh", "activate.fish", + "Activate", "Activate.bat", "Activate.ps1")) + def test_ignored_virtualenvs(self, testdir, fname): + bindir = "Scripts" if py.std.sys.platform.startswith("win") else "bin" + testdir.tmpdir.ensure("virtual", bindir, fname) + testfile = testdir.tmpdir.ensure("virtual", "test_invenv.py") + testfile.write("def test_hello(): pass") + + # by default, ignore tests inside a virtualenv + result = testdir.runpytest() + assert "test_invenv" not in result.stdout.str() + # allow test collection if user insists + result = testdir.runpytest("--collect-in-virtualenv") + assert "test_invenv" in result.stdout.str() + # allow test collection if user directly passes in the directory + result = testdir.runpytest("virtual") + assert "test_invenv" in result.stdout.str() + + @pytest.mark.parametrize('fname', + ("activate", "activate.csh", "activate.fish", + "Activate", "Activate.bat", "Activate.ps1")) + def test_ignored_virtualenvs_norecursedirs_precedence(self, testdir, fname): + bindir = "Scripts" if py.std.sys.platform.startswith("win") else "bin" + # norecursedirs takes priority + testdir.tmpdir.ensure(".virtual", bindir, fname) + testfile = testdir.tmpdir.ensure(".virtual", "test_invenv.py") + testfile.write("def test_hello(): pass") + result = testdir.runpytest("--collect-in-virtualenv") + assert "test_invenv" not in result.stdout.str() + # ...unless the virtualenv is explicitly given on the CLI + result = testdir.runpytest("--collect-in-virtualenv", ".virtual") + assert "test_invenv" in result.stdout.str() + + @pytest.mark.parametrize('fname', + ("activate", "activate.csh", "activate.fish", + "Activate", "Activate.bat", "Activate.ps1")) + def test__in_venv(self, testdir, fname): + """Directly test the virtual env detection function""" + bindir = "Scripts" if py.std.sys.platform.startswith("win") else "bin" + # no bin/activate, not a virtualenv + base_path = testdir.tmpdir.mkdir('venv') + assert _in_venv(base_path) is False + # with bin/activate, totally a virtualenv + base_path.ensure(bindir, fname) + assert _in_venv(base_path) is True + def test_custom_norecursedirs(self, testdir): testdir.makeini(""" [pytest] @@ -145,12 +214,16 @@ class TestCollectFS: assert [x.name for x in items] == ['test_%s' % dirname] -class TestCollectPluginHookRelay: +class TestCollectPluginHookRelay(object): def test_pytest_collect_file(self, testdir): wascalled = [] - class Plugin: + + class Plugin(object): def pytest_collect_file(self, path, parent): - wascalled.append(path) + if not path.basename.startswith("."): + # Ignore hidden files, e.g. .testmondata. + wascalled.append(path) + testdir.makefile(".abc", "xyz") pytest.main([testdir.tmpdir], plugins=[Plugin()]) assert len(wascalled) == 1 @@ -158,26 +231,19 @@ class TestCollectPluginHookRelay: def test_pytest_collect_directory(self, testdir): wascalled = [] - class Plugin: + + class Plugin(object): def pytest_collect_directory(self, path, parent): wascalled.append(path.basename) + testdir.mkdir("hello") testdir.mkdir("world") pytest.main(testdir.tmpdir, plugins=[Plugin()]) assert "hello" in wascalled assert "world" in wascalled -class TestPrunetraceback: - def test_collection_error(self, testdir): - p = testdir.makepyfile(""" - import not_exists - """) - result = testdir.runpytest(p) - assert "__import__" not in result.stdout.str(), "too long traceback" - result.stdout.fnmatch_lines([ - "*ERROR collecting*", - "*mport*not_exists*" - ]) + +class TestPrunetraceback(object): def test_custom_repr_failure(self, testdir): p = testdir.makepyfile(""" @@ -211,10 +277,12 @@ class TestPrunetraceback: """) testdir.makeconftest(""" import pytest - def pytest_make_collect_report(__multicall__): - rep = __multicall__.execute() + @pytest.hookimpl(hookwrapper=True) + def pytest_make_collect_report(): + outcome = yield + rep = outcome.get_result() rep.headerlines += ["header1"] - return rep + outcome.force_result(rep) """) result = testdir.runpytest(p) result.stdout.fnmatch_lines([ @@ -223,7 +291,7 @@ class TestPrunetraceback: ]) -class TestCustomConftests: +class TestCustomConftests(object): def test_ignore_collect_path(self, testdir): testdir.makeconftest(""" def pytest_ignore_collect(path, config): @@ -318,7 +386,8 @@ class TestCustomConftests: "*test_x*" ]) -class TestSession: + +class TestSession(object): def test_parsearg(self, testdir): p = testdir.makepyfile("def test_func(): pass") subdir = testdir.mkdir("sub") @@ -331,11 +400,11 @@ class TestSession: assert rcol.fspath == subdir parts = rcol._parsearg(p.basename) - assert parts[0] == target + assert parts[0] == target assert len(parts) == 1 parts = rcol._parsearg(p.basename + "::test_func") - assert parts[0] == target - assert parts[1] == "test_func" + assert parts[0] == target + assert parts[1] == "test_func" assert len(parts) == 2 def test_collect_topdir(self, testdir): @@ -346,13 +415,18 @@ class TestSession: topdir = testdir.tmpdir rcol = Session(config) assert topdir == rcol.fspath - #rootid = rcol.nodeid - #root2 = rcol.perform_collect([rcol.nodeid], genitems=False)[0] - #assert root2 == rcol, rootid + # rootid = rcol.nodeid + # root2 = rcol.perform_collect([rcol.nodeid], genitems=False)[0] + # assert root2 == rcol, rootid colitems = rcol.perform_collect([rcol.nodeid], genitems=False) assert len(colitems) == 1 assert colitems[0].fspath == p + def get_reported_items(self, hookrec): + """Return pytest.Item instances reported by the pytest_collectreport hook""" + calls = hookrec.getcalls('pytest_collectreport') + return [x for call in calls for x in call.report.result + if isinstance(x, pytest.Item)] def test_collect_protocol_single_function(self, testdir): p = testdir.makepyfile("def test_func(): pass") @@ -370,13 +444,14 @@ class TestSession: ("pytest_collectstart", "collector.fspath == p"), ("pytest_make_collect_report", "collector.fspath == p"), ("pytest_pycollect_makeitem", "name == 'test_func'"), - ("pytest_collectreport", "report.nodeid.startswith(p.basename)"), - ("pytest_collectreport", "report.nodeid == ''") + ("pytest_collectreport", "report.result[0].name == 'test_func'"), ]) + # ensure we are reporting the collection of the single test item (#2464) + assert [x.name for x in self.get_reported_items(hookrec)] == ['test_func'] def test_collect_protocol_method(self, testdir): p = testdir.makepyfile(""" - class TestClass: + class TestClass(object): def test_method(self): pass """) @@ -391,6 +466,8 @@ class TestSession: assert items[0].name == "test_method" newid = items[0].nodeid assert newid == normid + # ensure we are reporting the collection of the single test item (#2464) + assert [x.name for x in self.get_reported_items(hookrec)] == ['test_method'] def test_collect_custom_nodes_multi_id(self, testdir): p = testdir.makepyfile("def test_func(): pass") @@ -420,9 +497,8 @@ class TestSession: "collector.__class__.__name__ == 'Module'"), ("pytest_pycollect_makeitem", "name == 'test_func'"), ("pytest_collectreport", "report.nodeid.startswith(p.basename)"), - #("pytest_collectreport", - # "report.fspath == %r" % str(rcol.fspath)), ]) + assert len(self.get_reported_items(hookrec)) == 2 def test_collect_subdir_event_ordering(self, testdir): p = testdir.makepyfile("def test_func(): pass") @@ -437,7 +513,7 @@ class TestSession: ("pytest_collectstart", "collector.fspath == test_aaa"), ("pytest_pycollect_makeitem", "name == 'test_func'"), ("pytest_collectreport", - "report.nodeid.startswith('aaa/test_aaa.py')"), + "report.nodeid.startswith('aaa/test_aaa.py')"), ]) def test_collect_two_commandline_args(self, testdir): @@ -475,24 +551,27 @@ class TestSession: def test_find_byid_without_instance_parents(self, testdir): p = testdir.makepyfile(""" - class TestClass: + class TestClass(object): def test_method(self): pass """) - arg = p.basename + ("::TestClass::test_method") + arg = p.basename + "::TestClass::test_method" items, hookrec = testdir.inline_genitems(arg) assert len(items) == 1 item, = items assert item.nodeid.endswith("TestClass::()::test_method") + # ensure we are reporting the collection of the single test item (#2464) + assert [x.name for x in self.get_reported_items(hookrec)] == ['test_method'] -class Test_getinitialnodes: + +class Test_getinitialnodes(object): def test_global_file(self, testdir, tmpdir): x = tmpdir.ensure("x.py") - config = testdir.parseconfigure(x) + with tmpdir.as_cwd(): + config = testdir.parseconfigure(x) col = testdir.getnode(config, x) assert isinstance(col, pytest.Module) assert col.name == 'x.py' - assert col.parent.name == testdir.tmpdir.basename assert col.parent.parent is None for col in col.listchain(): assert col.config is config @@ -502,7 +581,8 @@ class Test_getinitialnodes: subdir = tmpdir.join("subdir") x = subdir.ensure("x.py") subdir.ensure("__init__.py") - config = testdir.parseconfigure(x) + with subdir.as_cwd(): + config = testdir.parseconfigure(x) col = testdir.getnode(config, x) assert isinstance(col, pytest.Module) assert col.name == 'x.py' @@ -510,7 +590,8 @@ class Test_getinitialnodes: for col in col.listchain(): assert col.config is config -class Test_genitems: + +class Test_genitems(object): def test_check_collect_hashes(self, testdir): p = testdir.makepyfile(""" def test_1(): @@ -533,7 +614,7 @@ class Test_genitems: def testone(): pass - class TestX: + class TestX(object): def testmethod_one(self): pass @@ -566,11 +647,11 @@ class Test_genitems: python_functions = *_test test """) p = testdir.makepyfile(''' - class MyTestSuite: + class MyTestSuite(object): def x_test(self): pass - class TestCase: + class TestCase(object): def test_y(self): pass ''') @@ -585,7 +666,7 @@ def test_matchnodes_two_collections_same_file(testdir): def pytest_configure(config): config.pluginmanager.register(Plugin2()) - class Plugin2: + class Plugin2(object): def pytest_collect_file(self, path, parent): if path.ext == ".abc": return MyFile2(path, parent) @@ -617,15 +698,15 @@ def test_matchnodes_two_collections_same_file(testdir): ]) -class TestNodekeywords: +class TestNodekeywords(object): def test_no_under(self, testdir): modcol = testdir.getmodulecol(""" def test_pass(): pass def test_fail(): assert 0 """) - l = list(modcol.keywords) - assert modcol.name in l - for x in l: + values = list(modcol.keywords) + assert modcol.name in values + for x in values: assert not x.startswith("_") assert modcol.name in repr(modcol.keywords) @@ -639,3 +720,138 @@ class TestNodekeywords: """) reprec = testdir.inline_run("-k repr") reprec.assertoutcome(passed=1, failed=0) + + +COLLECTION_ERROR_PY_FILES = dict( + test_01_failure=""" + def test_1(): + assert False + """, + test_02_import_error=""" + import asdfasdfasdf + def test_2(): + assert True + """, + test_03_import_error=""" + import asdfasdfasdf + def test_3(): + assert True + """, + test_04_success=""" + def test_4(): + assert True + """, +) + + +def test_exit_on_collection_error(testdir): + """Verify that all collection errors are collected and no tests executed""" + testdir.makepyfile(**COLLECTION_ERROR_PY_FILES) + + res = testdir.runpytest() + assert res.ret == 2 + + res.stdout.fnmatch_lines([ + "collected 2 items / 2 errors", + "*ERROR collecting test_02_import_error.py*", + "*No module named *asdfa*", + "*ERROR collecting test_03_import_error.py*", + "*No module named *asdfa*", + ]) + + +def test_exit_on_collection_with_maxfail_smaller_than_n_errors(testdir): + """ + Verify collection is aborted once maxfail errors are encountered ignoring + further modules which would cause more collection errors. + """ + testdir.makepyfile(**COLLECTION_ERROR_PY_FILES) + + res = testdir.runpytest("--maxfail=1") + assert res.ret == 1 + + res.stdout.fnmatch_lines([ + "*ERROR collecting test_02_import_error.py*", + "*No module named *asdfa*", + ]) + + assert 'test_03' not in res.stdout.str() + + +def test_exit_on_collection_with_maxfail_bigger_than_n_errors(testdir): + """ + Verify the test run aborts due to collection errors even if maxfail count of + errors was not reached. + """ + testdir.makepyfile(**COLLECTION_ERROR_PY_FILES) + + res = testdir.runpytest("--maxfail=4") + assert res.ret == 2 + + res.stdout.fnmatch_lines([ + "collected 2 items / 2 errors", + "*ERROR collecting test_02_import_error.py*", + "*No module named *asdfa*", + "*ERROR collecting test_03_import_error.py*", + "*No module named *asdfa*", + ]) + + +def test_continue_on_collection_errors(testdir): + """ + Verify tests are executed even when collection errors occur when the + --continue-on-collection-errors flag is set + """ + testdir.makepyfile(**COLLECTION_ERROR_PY_FILES) + + res = testdir.runpytest("--continue-on-collection-errors") + assert res.ret == 1 + + res.stdout.fnmatch_lines([ + "collected 2 items / 2 errors", + "*1 failed, 1 passed, 2 error*", + ]) + + +def test_continue_on_collection_errors_maxfail(testdir): + """ + Verify tests are executed even when collection errors occur and that maxfail + is honoured (including the collection error count). + 4 tests: 2 collection errors + 1 failure + 1 success + test_4 is never executed because the test run is with --maxfail=3 which + means it is interrupted after the 2 collection errors + 1 failure. + """ + testdir.makepyfile(**COLLECTION_ERROR_PY_FILES) + + res = testdir.runpytest("--continue-on-collection-errors", "--maxfail=3") + assert res.ret == 1 + + res.stdout.fnmatch_lines([ + "collected 2 items / 2 errors", + "*1 failed, 2 error*", + ]) + + +def test_fixture_scope_sibling_conftests(testdir): + """Regression test case for https://github.com/pytest-dev/pytest/issues/2836""" + foo_path = testdir.mkpydir("foo") + foo_path.join("conftest.py").write(_pytest._code.Source(""" + import pytest + @pytest.fixture + def fix(): + return 1 + """)) + foo_path.join("test_foo.py").write("def test_foo(fix): assert fix == 1") + + # Tests in `food/` should not see the conftest fixture from `foo/` + food_path = testdir.mkpydir("food") + food_path.join("test_food.py").write("def test_food(fix): assert fix == 1") + + res = testdir.runpytest() + assert res.ret == 1 + + res.stdout.fnmatch_lines([ + "*ERROR at setup of test_food*", + "E*fixture 'fix' not found", + "*1 passed, 1 error*", + ]) diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_compat.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_compat.py new file mode 100644 index 00000000000..c74801c6c85 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_compat.py @@ -0,0 +1,101 @@ +from __future__ import absolute_import, division, print_function +import sys + +import pytest +from _pytest.compat import is_generator, get_real_func, safe_getattr +from _pytest.outcomes import OutcomeException + + +def test_is_generator(): + def zap(): + yield + + def foo(): + pass + + assert is_generator(zap) + assert not is_generator(foo) + + +def test_real_func_loop_limit(): + + class Evil(object): + def __init__(self): + self.left = 1000 + + def __repr__(self): + return "".format(left=self.left) + + def __getattr__(self, attr): + if not self.left: + raise RuntimeError('its over') + self.left -= 1 + return self + + evil = Evil() + + with pytest.raises(ValueError): + res = get_real_func(evil) + print(res) + + +@pytest.mark.skipif(sys.version_info < (3, 4), + reason='asyncio available in Python 3.4+') +def test_is_generator_asyncio(testdir): + testdir.makepyfile(""" + from _pytest.compat import is_generator + import asyncio + @asyncio.coroutine + def baz(): + yield from [1,2,3] + + def test_is_generator_asyncio(): + assert not is_generator(baz) + """) + # avoid importing asyncio into pytest's own process, + # which in turn imports logging (#8) + result = testdir.runpytest_subprocess() + result.stdout.fnmatch_lines(['*1 passed*']) + + +@pytest.mark.skipif(sys.version_info < (3, 5), + reason='async syntax available in Python 3.5+') +def test_is_generator_async_syntax(testdir): + testdir.makepyfile(""" + from _pytest.compat import is_generator + def test_is_generator_py35(): + async def foo(): + await foo() + + async def bar(): + pass + + assert not is_generator(foo) + assert not is_generator(bar) + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines(['*1 passed*']) + + +class ErrorsHelper(object): + @property + def raise_exception(self): + raise Exception('exception should be catched') + + @property + def raise_fail(self): + pytest.fail('fail should be catched') + + +def test_helper_failures(): + helper = ErrorsHelper() + with pytest.raises(Exception): + helper.raise_exception + with pytest.raises(OutcomeException): + helper.raise_fail + + +def test_safe_getattr(): + helper = ErrorsHelper() + assert safe_getattr(helper, 'raise_exception', 'default') == 'default' + assert safe_getattr(helper, 'raise_fail', 'default') == 'default' diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_config.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_config.py similarity index 53% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_config.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_config.py index 92c9bdb8b08..44b8c317a28 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_config.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_config.py @@ -1,28 +1,36 @@ -import py, pytest +from __future__ import absolute_import, division, print_function +import sys +import py +import pytest import _pytest._code -from _pytest.config import getcfg, get_common_ancestor, determine_setup +from _pytest.config import getcfg, get_common_ancestor, determine_setup, _iter_rewritable_modules from _pytest.main import EXIT_NOTESTSCOLLECTED -class TestParseIni: - def test_getcfg_and_config(self, testdir, tmpdir): + +class TestParseIni(object): + + @pytest.mark.parametrize('section, filename', + [('pytest', 'pytest.ini'), ('tool:pytest', 'setup.cfg')]) + def test_getcfg_and_config(self, testdir, tmpdir, section, filename): sub = tmpdir.mkdir("sub") sub.chdir() - tmpdir.join("setup.cfg").write(_pytest._code.Source(""" - [pytest] + tmpdir.join(filename).write(_pytest._code.Source(""" + [{section}] name = value - """)) - rootdir, inifile, cfg = getcfg([sub], ["setup.cfg"]) + """.format(section=section))) + rootdir, inifile, cfg = getcfg([sub]) assert cfg['name'] == "value" config = testdir.parseconfigure(sub) assert config.inicfg['name'] == 'value' - def test_getcfg_empty_path(self, tmpdir): - getcfg([''], ['setup.cfg']) #happens on py.test "" + def test_getcfg_empty_path(self): + """correctly handle zero length arguments (a la pytest '')""" + getcfg(['']) def test_append_parse_args(self, testdir, tmpdir, monkeypatch): monkeypatch.setenv('PYTEST_ADDOPTS', '--color no -rs --tb="short"') - tmpdir.join("setup.cfg").write(_pytest._code.Source(""" + tmpdir.join("pytest.ini").write(_pytest._code.Source(""" [pytest] addopts = --verbose """)) @@ -31,10 +39,6 @@ class TestParseIni: assert config.option.reportchars == 's' assert config.option.tbstyle == 'short' assert config.option.verbose - #config = testdir.Config() - #args = [tmpdir,] - #config._preparse(args, addopts=False) - #assert len(args) == 1 def test_tox_ini_wrong_version(self, testdir): testdir.makefile('.ini', tox=""" @@ -47,12 +51,16 @@ class TestParseIni: "*tox.ini:2*requires*9.0*actual*" ]) - @pytest.mark.parametrize("name", "setup.cfg tox.ini pytest.ini".split()) - def test_ini_names(self, testdir, name): + @pytest.mark.parametrize("section, name", [ + ('tool:pytest', 'setup.cfg'), + ('pytest', 'tox.ini'), + ('pytest', 'pytest.ini')], + ) + def test_ini_names(self, testdir, name, section): testdir.tmpdir.join(name).write(py.std.textwrap.dedent(""" - [pytest] + [{section}] minversion = 1.0 - """)) + """.format(section=section))) config = testdir.parseconfig() assert config.getini("minversion") == "1.0" @@ -80,7 +88,8 @@ class TestParseIni: result = testdir.inline_run("--confcutdir=.") assert result.ret == 0 -class TestConfigCmdlineParsing: + +class TestConfigCmdlineParsing(object): def test_parsing_again_fails(self, testdir): config = testdir.parseconfig() pytest.raises(AssertionError, lambda: config.parse([])) @@ -94,21 +103,32 @@ class TestConfigCmdlineParsing: [pytest] custom = 0 """) - testdir.makefile(".cfg", custom = """ + testdir.makefile(".cfg", custom=""" [pytest] custom = 1 """) config = testdir.parseconfig("-c", "custom.cfg") assert config.getini("custom") == "1" -class TestConfigAPI: + def test_absolute_win32_path(self, testdir): + temp_cfg_file = testdir.makefile(".cfg", custom=""" + [pytest] + addopts = --version + """) + from os.path import normpath + temp_cfg_file = normpath(str(temp_cfg_file)) + ret = pytest.main("-c " + temp_cfg_file) + assert ret == _pytest.main.EXIT_OK + + +class TestConfigAPI(object): def test_config_trace(self, testdir): config = testdir.parseconfig() - l = [] - config.trace.root.setwriter(l.append) + values = [] + config.trace.root.setwriter(values.append) config.trace("hello") - assert len(l) == 1 - assert l[0] == "hello [config]\n" + assert len(values) == 1 + assert values[0] == "hello [config]\n" def test_config_getoption(self, testdir): testdir.makeconftest(""" @@ -120,13 +140,13 @@ class TestConfigAPI: assert config.getoption(x) == "this" pytest.raises(ValueError, "config.getoption('qweqwe')") - @pytest.mark.skipif('sys.version_info[:2] not in [(2, 6), (2, 7)]') + @pytest.mark.skipif('sys.version_info[0] < 3') def test_config_getoption_unicode(self, testdir): testdir.makeconftest(""" from __future__ import unicode_literals def pytest_addoption(parser): - parser.addoption('--hello', type='string') + parser.addoption('--hello', type=str) """) config = testdir.parseconfig('--hello=this') assert config.getoption('hello') == 'this' @@ -134,7 +154,7 @@ class TestConfigAPI: def test_config_getvalueorskip(self, testdir): config = testdir.parseconfig() pytest.raises(pytest.skip.Exception, - "config.getvalueorskip('hello')") + "config.getvalueorskip('hello')") verbose = config.getvalueorskip("verbose") assert verbose == config.option.verbose @@ -190,10 +210,10 @@ class TestConfigAPI: paths=hello world/sub.py """) config = testdir.parseconfig() - l = config.getini("paths") - assert len(l) == 2 - assert l[0] == p.dirpath('hello') - assert l[1] == p.dirpath('world/sub.py') + values = config.getini("paths") + assert len(values) == 2 + assert values[0] == p.dirpath('hello') + assert values[1] == p.dirpath('world/sub.py') pytest.raises(ValueError, config.getini, 'other') def test_addini_args(self, testdir): @@ -207,11 +227,11 @@ class TestConfigAPI: args=123 "123 hello" "this" """) config = testdir.parseconfig() - l = config.getini("args") - assert len(l) == 3 - assert l == ["123", "123 hello", "this"] - l = config.getini("a2") - assert l == list("123") + values = config.getini("args") + assert len(values) == 3 + assert values == ["123", "123 hello", "this"] + values = config.getini("a2") + assert values == list("123") def test_addini_linelist(self, testdir): testdir.makeconftest(""" @@ -225,11 +245,11 @@ class TestConfigAPI: second line """) config = testdir.parseconfig() - l = config.getini("xy") - assert len(l) == 2 - assert l == ["123 345", "second line"] - l = config.getini("a2") - assert l == [] + values = config.getini("xy") + assert len(values) == 2 + assert values == ["123 345", "second line"] + values = config.getini("a2") + assert values == [] @pytest.mark.parametrize('str_val, bool_val', [('True', True), ('no', False), ('no-ini', True)]) @@ -256,13 +276,13 @@ class TestConfigAPI: xy= 123 """) config = testdir.parseconfig() - l = config.getini("xy") - assert len(l) == 1 - assert l == ["123"] + values = config.getini("xy") + assert len(values) == 1 + assert values == ["123"] config.addinivalue_line("xy", "456") - l = config.getini("xy") - assert len(l) == 2 - assert l == ["123", "456"] + values = config.getini("xy") + assert len(values) == 2 + assert values == ["123", "456"] def test_addinivalue_line_new(self, testdir): testdir.makeconftest(""" @@ -272,16 +292,35 @@ class TestConfigAPI: config = testdir.parseconfig() assert not config.getini("xy") config.addinivalue_line("xy", "456") - l = config.getini("xy") - assert len(l) == 1 - assert l == ["456"] + values = config.getini("xy") + assert len(values) == 1 + assert values == ["456"] config.addinivalue_line("xy", "123") - l = config.getini("xy") - assert len(l) == 2 - assert l == ["456", "123"] + values = config.getini("xy") + assert len(values) == 2 + assert values == ["456", "123"] + + def test_confcutdir_check_isdir(self, testdir): + """Give an error if --confcutdir is not a valid directory (#2078)""" + with pytest.raises(pytest.UsageError): + testdir.parseconfig('--confcutdir', testdir.tmpdir.join('file').ensure(file=1)) + with pytest.raises(pytest.UsageError): + testdir.parseconfig('--confcutdir', testdir.tmpdir.join('inexistant')) + config = testdir.parseconfig('--confcutdir', testdir.tmpdir.join('dir').ensure(dir=1)) + assert config.getoption('confcutdir') == str(testdir.tmpdir.join('dir')) + + @pytest.mark.parametrize('names, expected', [ + (['bar.py'], ['bar']), + (['foo', 'bar.py'], []), + (['foo', 'bar.pyc'], []), + (['foo', '__init__.py'], ['foo']), + (['foo', 'bar', '__init__.py'], []), + ]) + def test_iter_rewritable_modules(self, names, expected): + assert list(_iter_rewritable_modules(['/'.join(names)])) == expected -class TestConfigFromdictargs: +class TestConfigFromdictargs(object): def test_basic_behavior(self): from _pytest.config import Config option_dict = { @@ -355,23 +394,35 @@ def test_options_on_small_file_do_not_blow_up(testdir): """) for opts in ([], ['-l'], ['-s'], ['--tb=no'], ['--tb=short'], - ['--tb=long'], ['--fulltrace'], ['--nomagic'], + ['--tb=long'], ['--fulltrace'], ['--traceconfig'], ['-v'], ['-v', '-v']): runfiletest(opts + [path]) + def test_preparse_ordering_with_setuptools(testdir, monkeypatch): pkg_resources = pytest.importorskip("pkg_resources") + def my_iter(name): assert name == "pytest11" - class EntryPoint: + + class Dist(object): + project_name = 'spam' + version = '1.0' + + def _get_metadata(self, name): + return ['foo.txt,sha256=abc,123'] + + class EntryPoint(object): name = "mytestplugin" - class dist: - pass + dist = Dist() + def load(self): - class PseudoPlugin: + class PseudoPlugin(object): x = 42 return PseudoPlugin() + return iter([EntryPoint()]) + monkeypatch.setattr(pkg_resources, 'iter_entry_points', my_iter) testdir.makeconftest(""" pytest_plugins = "mytestplugin", @@ -381,19 +432,69 @@ def test_preparse_ordering_with_setuptools(testdir, monkeypatch): plugin = config.pluginmanager.getplugin("mytestplugin") assert plugin.x == 42 -def test_plugin_preparse_prevents_setuptools_loading(testdir, monkeypatch): + +def test_setuptools_importerror_issue1479(testdir, monkeypatch): pkg_resources = pytest.importorskip("pkg_resources") + def my_iter(name): assert name == "pytest11" - class EntryPoint: + + class Dist(object): + project_name = 'spam' + version = '1.0' + + def _get_metadata(self, name): + return ['foo.txt,sha256=abc,123'] + + class EntryPoint(object): name = "mytestplugin" + dist = Dist() + def load(self): - assert 0, "should not arrive here" + raise ImportError("Don't hide me!") + return iter([EntryPoint()]) + monkeypatch.setattr(pkg_resources, 'iter_entry_points', my_iter) - config = testdir.parseconfig("-p", "no:mytestplugin") - plugin = config.pluginmanager.getplugin("mytestplugin") - assert plugin is None + with pytest.raises(ImportError): + testdir.parseconfig() + + +@pytest.mark.parametrize('block_it', [True, False]) +def test_plugin_preparse_prevents_setuptools_loading(testdir, monkeypatch, block_it): + pkg_resources = pytest.importorskip("pkg_resources") + + plugin_module_placeholder = object() + + def my_iter(name): + assert name == "pytest11" + + class Dist(object): + project_name = 'spam' + version = '1.0' + + def _get_metadata(self, name): + return ['foo.txt,sha256=abc,123'] + + class EntryPoint(object): + name = "mytestplugin" + dist = Dist() + + def load(self): + return plugin_module_placeholder + + return iter([EntryPoint()]) + + monkeypatch.setattr(pkg_resources, 'iter_entry_points', my_iter) + args = ("-p", "no:mytestplugin") if block_it else () + config = testdir.parseconfig(*args) + config.pluginmanager.import_plugin("mytestplugin") + if block_it: + assert "mytestplugin" not in sys.modules + assert config.pluginmanager.get_plugin('mytestplugin') is None + else: + assert config.pluginmanager.get_plugin('mytestplugin') is plugin_module_placeholder + def test_cmdline_processargs_simple(testdir): testdir.makeconftest(""" @@ -406,6 +507,7 @@ def test_cmdline_processargs_simple(testdir): "*-h*", ]) + def test_invalid_options_show_extra_information(testdir): """display extra information when pytest exits due to unrecognized options in the command-line""" @@ -441,8 +543,9 @@ def test_consider_args_after_options_for_rootdir_and_inifile(testdir, args): args[i] = d1 elif arg == 'dir2': args[i] = d2 - result = testdir.runpytest(*args) - result.stdout.fnmatch_lines(['*rootdir: *myroot, inifile: ']) + with root.as_cwd(): + result = testdir.runpytest(*args) + result.stdout.fnmatch_lines(['*rootdir: *myroot, inifile:']) @pytest.mark.skipif("sys.platform == 'win32'") @@ -450,15 +553,41 @@ def test_toolongargs_issue224(testdir): result = testdir.runpytest("-m", "hello" * 500) assert result.ret == EXIT_NOTESTSCOLLECTED + +def test_config_in_subdirectory_colon_command_line_issue2148(testdir): + conftest_source = ''' + def pytest_addoption(parser): + parser.addini('foo', 'foo') + ''' + + testdir.makefile('.ini', **{ + 'pytest': '[pytest]\nfoo = root', + 'subdir/pytest': '[pytest]\nfoo = subdir', + }) + + testdir.makepyfile(**{ + 'conftest': conftest_source, + 'subdir/conftest': conftest_source, + 'subdir/test_foo': ''' + def test_foo(pytestconfig): + assert pytestconfig.getini('foo') == 'subdir' + '''}) + + result = testdir.runpytest('subdir/test_foo.py::test_foo') + assert result.ret == 0 + + def test_notify_exception(testdir, capfd): config = testdir.parseconfig() excinfo = pytest.raises(ValueError, "raise ValueError(1)") config.notify_exception(excinfo) out, err = capfd.readouterr() assert "ValueError" in err - class A: + + class A(object): def pytest_internalerror(self, excrepr): return True + config.pluginmanager.register(A()) config.notify_exception(excinfo) out, err = capfd.readouterr() @@ -466,64 +595,92 @@ def test_notify_exception(testdir, capfd): def test_load_initial_conftest_last_ordering(testdir): - from _pytest.config import get_config + from _pytest.config import get_config pm = get_config().pluginmanager - class My: + + class My(object): def pytest_load_initial_conftests(self): pass + m = My() pm.register(m) hc = pm.hook.pytest_load_initial_conftests - l = hc._nonwrappers + hc._wrappers - assert l[-1].function.__module__ == "_pytest.capture" - assert l[-2].function == m.pytest_load_initial_conftests - assert l[-3].function.__module__ == "_pytest.config" + values = hc._nonwrappers + hc._wrappers + expected = [ + "_pytest.config", + 'test_config', + '_pytest.capture', + ] + assert [x.function.__module__ for x in values] == expected -class TestWarning: + +def test_get_plugin_specs_as_list(): + from _pytest.config import _get_plugin_specs_as_list + with pytest.raises(pytest.UsageError): + _get_plugin_specs_as_list(set(['foo'])) + with pytest.raises(pytest.UsageError): + _get_plugin_specs_as_list(dict()) + + assert _get_plugin_specs_as_list(None) == [] + assert _get_plugin_specs_as_list('') == [] + assert _get_plugin_specs_as_list('foo') == ['foo'] + assert _get_plugin_specs_as_list('foo,bar') == ['foo', 'bar'] + assert _get_plugin_specs_as_list(['foo', 'bar']) == ['foo', 'bar'] + assert _get_plugin_specs_as_list(('foo', 'bar')) == ['foo', 'bar'] + + +class TestWarning(object): def test_warn_config(self, testdir): testdir.makeconftest(""" - l = [] + values = [] def pytest_configure(config): config.warn("C1", "hello") def pytest_logwarning(code, message): if message == "hello" and code == "C1": - l.append(1) + values.append(1) """) testdir.makepyfile(""" def test_proper(pytestconfig): import conftest - assert conftest.l == [1] + assert conftest.values == [1] """) reprec = testdir.inline_run() reprec.assertoutcome(passed=1) - def test_warn_on_test_item_from_request(self, testdir): + def test_warn_on_test_item_from_request(self, testdir, request): testdir.makepyfile(""" import pytest @pytest.fixture def fix(request): request.node.warn("T1", "hello") + def test_hello(fix): pass """) - result = testdir.runpytest() - assert result.parseoutcomes()["pytest-warnings"] > 0 + result = testdir.runpytest("--disable-pytest-warnings") + assert result.parseoutcomes()["warnings"] > 0 assert "hello" not in result.stdout.str() - result = testdir.runpytest("-rw") + result = testdir.runpytest() result.stdout.fnmatch_lines(""" - ===*pytest-warning summary*=== - *WT1*test_warn_on_test_item*:5*hello* + ===*warnings summary*=== + *test_warn_on_test_item_from_request.py::test_hello* + *hello* """) -class TestRootdir: + +class TestRootdir(object): def test_simple_noini(self, tmpdir): assert get_common_ancestor([tmpdir]) == tmpdir - assert get_common_ancestor([tmpdir.mkdir("a"), tmpdir]) == tmpdir - assert get_common_ancestor([tmpdir, tmpdir.join("a")]) == tmpdir + a = tmpdir.mkdir("a") + assert get_common_ancestor([a, tmpdir]) == tmpdir + assert get_common_ancestor([tmpdir, a]) == tmpdir with tmpdir.as_cwd(): assert get_common_ancestor([]) == tmpdir + no_path = tmpdir.join('does-not-exist') + assert get_common_ancestor([no_path]) == tmpdir + assert get_common_ancestor([no_path.join('a')]) == tmpdir @pytest.mark.parametrize("name", "setup.cfg tox.ini pytest.ini".split()) def test_with_ini(self, tmpdir, name): @@ -536,7 +693,7 @@ class TestRootdir: rootdir, inifile, inicfg = determine_setup(None, args) assert rootdir == tmpdir assert inifile == inifile - rootdir, inifile, inicfg = determine_setup(None, [b,a]) + rootdir, inifile, inicfg = determine_setup(None, [b, a]) assert rootdir == tmpdir assert inifile == inifile @@ -558,7 +715,8 @@ class TestRootdir: assert inifile is None assert inicfg == {} - def test_nothing(self, tmpdir): + def test_nothing(self, tmpdir, monkeypatch): + monkeypatch.chdir(str(tmpdir)) rootdir, inifile, inicfg = determine_setup(None, [tmpdir]) assert rootdir == tmpdir assert inifile is None @@ -568,3 +726,137 @@ class TestRootdir: inifile = tmpdir.ensure("pytest.ini") rootdir, inifile, inicfg = determine_setup(inifile, [tmpdir]) assert rootdir == tmpdir + + +class TestOverrideIniArgs(object): + @pytest.mark.parametrize("name", "setup.cfg tox.ini pytest.ini".split()) + def test_override_ini_names(self, testdir, name): + testdir.tmpdir.join(name).write(py.std.textwrap.dedent(""" + [pytest] + custom = 1.0""")) + testdir.makeconftest(""" + def pytest_addoption(parser): + parser.addini("custom", "")""") + testdir.makepyfile(""" + def test_pass(pytestconfig): + ini_val = pytestconfig.getini("custom") + print('\\ncustom_option:%s\\n' % ini_val)""") + + result = testdir.runpytest("--override-ini", "custom=2.0", "-s") + assert result.ret == 0 + result.stdout.fnmatch_lines(["custom_option:2.0"]) + + result = testdir.runpytest("--override-ini", "custom=2.0", + "--override-ini=custom=3.0", "-s") + assert result.ret == 0 + result.stdout.fnmatch_lines(["custom_option:3.0"]) + + def test_override_ini_pathlist(self, testdir): + testdir.makeconftest(""" + def pytest_addoption(parser): + parser.addini("paths", "my new ini value", type="pathlist")""") + testdir.makeini(""" + [pytest] + paths=blah.py""") + testdir.makepyfile(""" + import py.path + def test_pathlist(pytestconfig): + config_paths = pytestconfig.getini("paths") + print(config_paths) + for cpf in config_paths: + print('\\nuser_path:%s' % cpf.basename)""") + result = testdir.runpytest("--override-ini", + 'paths=foo/bar1.py foo/bar2.py', "-s") + result.stdout.fnmatch_lines(["user_path:bar1.py", + "user_path:bar2.py"]) + + def test_override_multiple_and_default(self, testdir): + testdir.makeconftest(""" + def pytest_addoption(parser): + addini = parser.addini + addini("custom_option_1", "", default="o1") + addini("custom_option_2", "", default="o2") + addini("custom_option_3", "", default=False, type="bool") + addini("custom_option_4", "", default=True, type="bool")""") + testdir.makeini(""" + [pytest] + custom_option_1=custom_option_1 + custom_option_2=custom_option_2""") + testdir.makepyfile(""" + def test_multiple_options(pytestconfig): + prefix = "custom_option" + for x in range(1, 5): + ini_value=pytestconfig.getini("%s_%d" % (prefix, x)) + print('\\nini%d:%s' % (x, ini_value))""") + result = testdir.runpytest( + "--override-ini", 'custom_option_1=fulldir=/tmp/user1', + 'custom_option_2=url=/tmp/user2?a=b&d=e', + "-o", 'custom_option_3=True', + "-o", 'custom_option_4=no', "-s") + result.stdout.fnmatch_lines(["ini1:fulldir=/tmp/user1", + "ini2:url=/tmp/user2?a=b&d=e", + "ini3:True", + "ini4:False"]) + + def test_override_ini_usage_error_bad_style(self, testdir): + testdir.makeini(""" + [pytest] + xdist_strict=False + """) + result = testdir.runpytest("--override-ini", 'xdist_strict True', "-s") + result.stderr.fnmatch_lines(["*ERROR* *expects option=value*"]) + + @pytest.mark.parametrize('with_ini', [True, False]) + def test_override_ini_handled_asap(self, testdir, with_ini): + """-o should be handled as soon as possible and always override what's in ini files (#2238)""" + if with_ini: + testdir.makeini(""" + [pytest] + python_files=test_*.py + """) + testdir.makepyfile(unittest_ini_handle=""" + def test(): + pass + """) + result = testdir.runpytest("--override-ini", 'python_files=unittest_*.py') + result.stdout.fnmatch_lines(["*1 passed in*"]) + + def test_with_arg_outside_cwd_without_inifile(self, tmpdir, monkeypatch): + monkeypatch.chdir(str(tmpdir)) + a = tmpdir.mkdir("a") + b = tmpdir.mkdir("b") + rootdir, inifile, inicfg = determine_setup(None, [a, b]) + assert rootdir == tmpdir + assert inifile is None + + def test_with_arg_outside_cwd_with_inifile(self, tmpdir): + a = tmpdir.mkdir("a") + b = tmpdir.mkdir("b") + inifile = a.ensure("pytest.ini") + rootdir, parsed_inifile, inicfg = determine_setup(None, [a, b]) + assert rootdir == a + assert inifile == parsed_inifile + + @pytest.mark.parametrize('dirs', ([], ['does-not-exist'], + ['a/does-not-exist'])) + def test_with_non_dir_arg(self, dirs, tmpdir): + with tmpdir.ensure(dir=True).as_cwd(): + rootdir, inifile, inicfg = determine_setup(None, dirs) + assert rootdir == tmpdir + assert inifile is None + + def test_with_existing_file_in_subdir(self, tmpdir): + a = tmpdir.mkdir("a") + a.ensure("exist") + with tmpdir.as_cwd(): + rootdir, inifile, inicfg = determine_setup(None, ['a/exist']) + assert rootdir == tmpdir + assert inifile is None + + def test_addopts_before_initini(self, testdir, tmpdir, monkeypatch): + cache_dir = '.custom_cache' + monkeypatch.setenv('PYTEST_ADDOPTS', '-o cache_dir=%s' % cache_dir) + from _pytest.config import get_config + config = get_config() + config._preparse([], addopts=True) + assert config._override_ini == [['cache_dir=%s' % cache_dir]] diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_conftest.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_conftest.py similarity index 77% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_conftest.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_conftest.py index 6f5e77f6d49..c0411b72321 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_conftest.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_conftest.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import, division, print_function from textwrap import dedent import _pytest._code @@ -18,20 +19,23 @@ def basedir(request, tmpdir_factory): tmpdir.ensure("adir/b/__init__.py") return tmpdir + def ConftestWithSetinitial(path): conftest = PytestPluginManager() conftest_setinitial(conftest, [path]) return conftest + def conftest_setinitial(conftest, args, confcutdir=None): - class Namespace: + class Namespace(object): def __init__(self): self.file_or_dir = args self.confcutdir = str(confcutdir) self.noconftest = False conftest._set_initial_conftests(Namespace()) -class TestConftestValueAccessGlobal: + +class TestConftestValueAccessGlobal(object): def test_basic_init(self, basedir): conftest = PytestPluginManager() p = basedir.join("adir") @@ -42,7 +46,7 @@ class TestConftestValueAccessGlobal: len(conftest._path2confmods) conftest._getconftestmodules(basedir) snap1 = len(conftest._path2confmods) - #assert len(conftest._path2confmods) == snap1 + 1 + # assert len(conftest._path2confmods) == snap1 + 1 conftest._getconftestmodules(basedir.join('adir')) assert len(conftest._path2confmods) == snap1 + 1 conftest._getconftestmodules(basedir.join('b')) @@ -64,11 +68,12 @@ class TestConftestValueAccessGlobal: startdir.ensure("xx", dir=True) conftest = ConftestWithSetinitial(startdir) mod, value = conftest._rget_with_confmod("a", startdir) - assert value == 1.5 + assert value == 1.5 path = py.path.local(mod.__file__) assert path.dirpath() == basedir.join("adir", "b") assert path.purebasename.startswith("conftest") + def test_conftest_in_nonpkg_with_init(tmpdir): tmpdir.ensure("adir-1.0/conftest.py").write("a=1 ; Directory = 3") tmpdir.ensure("adir-1.0/b/conftest.py").write("b=2 ; a = 1.5") @@ -76,13 +81,15 @@ def test_conftest_in_nonpkg_with_init(tmpdir): tmpdir.ensure("adir-1.0/__init__.py") ConftestWithSetinitial(tmpdir.join("adir-1.0", "b")) + def test_doubledash_considered(testdir): conf = testdir.mkdir("--option") conf.join("conftest.py").ensure() conftest = PytestPluginManager() conftest_setinitial(conftest, [conf.basename, conf.basename]) - l = conftest._getconftestmodules(conf) - assert len(l) == 1 + values = conftest._getconftestmodules(conf) + assert len(values) == 1 + def test_issue151_load_all_conftests(testdir): names = "code proj src".split() @@ -95,6 +102,7 @@ def test_issue151_load_all_conftests(testdir): d = list(conftest._conftestpath2mod.values()) assert len(d) == len(names) + def test_conftest_global_import(testdir): testdir.makeconftest("x=3") p = testdir.makepyfile(""" @@ -116,32 +124,35 @@ def test_conftest_global_import(testdir): res = testdir.runpython(p) assert res.ret == 0 + def test_conftestcutdir(testdir): conf = testdir.makeconftest("") p = testdir.mkdir("x") conftest = PytestPluginManager() conftest_setinitial(conftest, [testdir.tmpdir], confcutdir=p) - l = conftest._getconftestmodules(p) - assert len(l) == 0 - l = conftest._getconftestmodules(conf.dirpath()) - assert len(l) == 0 + values = conftest._getconftestmodules(p) + assert len(values) == 0 + values = conftest._getconftestmodules(conf.dirpath()) + assert len(values) == 0 assert conf not in conftest._conftestpath2mod # but we can still import a conftest directly conftest._importconftest(conf) - l = conftest._getconftestmodules(conf.dirpath()) - assert l[0].__file__.startswith(str(conf)) + values = conftest._getconftestmodules(conf.dirpath()) + assert values[0].__file__.startswith(str(conf)) # and all sub paths get updated properly - l = conftest._getconftestmodules(p) - assert len(l) == 1 - assert l[0].__file__.startswith(str(conf)) + values = conftest._getconftestmodules(p) + assert len(values) == 1 + assert values[0].__file__.startswith(str(conf)) + def test_conftestcutdir_inplace_considered(testdir): conf = testdir.makeconftest("") conftest = PytestPluginManager() conftest_setinitial(conftest, [conf.dirpath()], confcutdir=conf.dirpath()) - l = conftest._getconftestmodules(conf.dirpath()) - assert len(l) == 1 - assert l[0].__file__.startswith(str(conf)) + values = conftest._getconftestmodules(conf.dirpath()) + assert len(values) == 1 + assert values[0].__file__.startswith(str(conf)) + @pytest.mark.parametrize("name", 'test tests whatever .dotdir'.split()) def test_setinitial_conftest_subdirs(testdir, name): @@ -150,12 +161,13 @@ def test_setinitial_conftest_subdirs(testdir, name): conftest = PytestPluginManager() conftest_setinitial(conftest, [sub.dirpath()], confcutdir=testdir.tmpdir) if name not in ('whatever', '.dotdir'): - assert subconftest in conftest._conftestpath2mod + assert subconftest in conftest._conftestpath2mod assert len(conftest._conftestpath2mod) == 1 else: - assert subconftest not in conftest._conftestpath2mod + assert subconftest not in conftest._conftestpath2mod assert len(conftest._conftestpath2mod) == 0 + def test_conftest_confcutdir(testdir): testdir.makeconftest("assert 0") x = testdir.mkdir("x") @@ -167,6 +179,7 @@ def test_conftest_confcutdir(testdir): result.stdout.fnmatch_lines(["*--xyz*"]) assert 'warning: could not load initial' not in result.stdout.str() + def test_no_conftest(testdir): testdir.makeconftest("assert 0") result = testdir.runpytest("--noconftest") @@ -175,6 +188,7 @@ def test_no_conftest(testdir): result = testdir.runpytest() assert result.ret == EXIT_USAGEERROR + def test_conftest_existing_resultlog(testdir): x = testdir.mkdir("tests") x.join("conftest.py").write(_pytest._code.Source(""" @@ -185,6 +199,7 @@ def test_conftest_existing_resultlog(testdir): result = testdir.runpytest("-h", "--resultlog", "result.log") result.stdout.fnmatch_lines(["*--xyz*"]) + def test_conftest_existing_junitxml(testdir): x = testdir.mkdir("tests") x.join("conftest.py").write(_pytest._code.Source(""" @@ -195,14 +210,18 @@ def test_conftest_existing_junitxml(testdir): result = testdir.runpytest("-h", "--junitxml", "junit.xml") result.stdout.fnmatch_lines(["*--xyz*"]) + def test_conftest_import_order(testdir, monkeypatch): ct1 = testdir.makeconftest("") sub = testdir.mkdir("sub") ct2 = sub.join("conftest.py") ct2.write("") + def impct(p): return p + conftest = PytestPluginManager() + conftest._confcutdir = testdir.tmpdir monkeypatch.setattr(conftest, '_importconftest', impct) assert conftest._getconftestmodules(sub) == [ct1, ct2] @@ -262,7 +281,7 @@ def test_conftest_found_with_double_dash(testdir): """) -class TestConftestVisibility: +class TestConftestVisibility(object): def _setup_tree(self, testdir): # for issue616 # example mostly taken from: # https://mail.python.org/pipermail/pytest-dev/2014-September/002617.html @@ -302,9 +321,9 @@ class TestConftestVisibility: # use value from parent dir's """)) - print ("created directory structure:") + print("created directory structure:") for x in testdir.tmpdir.visit(): - print (" " + x.relto(testdir.tmpdir)) + print(" " + x.relto(testdir.tmpdir)) return { "runner": runner, @@ -315,38 +334,38 @@ class TestConftestVisibility: # N.B.: "swc" stands for "subdir with conftest.py" # "snc" stands for "subdir no [i.e. without] conftest.py" @pytest.mark.parametrize("chdir,testarg,expect_ntests_passed", [ - # Effective target: package/.. - ("runner", "..", 3), - ("package", "..", 3), - ("swc", "../..", 3), - ("snc", "../..", 3), + # Effective target: package/.. + ("runner", "..", 3), + ("package", "..", 3), + ("swc", "../..", 3), + ("snc", "../..", 3), - # Effective target: package - ("runner", "../package", 3), - ("package", ".", 3), - ("swc", "..", 3), - ("snc", "..", 3), + # Effective target: package + ("runner", "../package", 3), + ("package", ".", 3), + ("swc", "..", 3), + ("snc", "..", 3), - # Effective target: package/swc - ("runner", "../package/swc", 1), - ("package", "./swc", 1), - ("swc", ".", 1), - ("snc", "../swc", 1), + # Effective target: package/swc + ("runner", "../package/swc", 1), + ("package", "./swc", 1), + ("swc", ".", 1), + ("snc", "../swc", 1), - # Effective target: package/snc - ("runner", "../package/snc", 1), - ("package", "./snc", 1), - ("swc", "../snc", 1), - ("snc", ".", 1), + # Effective target: package/snc + ("runner", "../package/snc", 1), + ("package", "./snc", 1), + ("swc", "../snc", 1), + ("snc", ".", 1), ]) @pytest.mark.issue616 def test_parsefactories_relative_node_ids( - self, testdir, chdir,testarg, expect_ntests_passed): + self, testdir, chdir, testarg, expect_ntests_passed): dirs = self._setup_tree(testdir) - print("pytest run in cwd: %s" %( + print("pytest run in cwd: %s" % ( dirs[chdir].relto(testdir.tmpdir))) - print("pytestarg : %s" %(testarg)) - print("expected pass : %s" %(expect_ntests_passed)) + print("pytestarg : %s" % (testarg)) + print("expected pass : %s" % (expect_ntests_passed)) with dirs[chdir].as_cwd(): reprec = testdir.inline_run(testarg, "-q", "--traceconfig") reprec.assertoutcome(passed=expect_ntests_passed) @@ -395,7 +414,7 @@ def test_search_conftest_up_to_inifile(testdir, confcutdir, passed, error): def test_issue1073_conftest_special_objects(testdir): testdir.makeconftest(""" - class DontTouchMe: + class DontTouchMe(object): def __getattr__(self, x): raise Exception('cant touch me') @@ -407,3 +426,53 @@ def test_issue1073_conftest_special_objects(testdir): """) res = testdir.runpytest() assert res.ret == 0 + + +def test_conftest_exception_handling(testdir): + testdir.makeconftest(''' + raise ValueError() + ''') + testdir.makepyfile(""" + def test_some(): + pass + """) + res = testdir.runpytest() + assert res.ret == 4 + assert 'raise ValueError()' in [line.strip() for line in res.errlines] + + +def test_hook_proxy(testdir): + """Session's gethookproxy() would cache conftests incorrectly (#2016). + It was decided to remove the cache altogether. + """ + testdir.makepyfile(**{ + 'root/demo-0/test_foo1.py': "def test1(): pass", + + 'root/demo-a/test_foo2.py': "def test1(): pass", + 'root/demo-a/conftest.py': """ + def pytest_ignore_collect(path, config): + return True + """, + + 'root/demo-b/test_foo3.py': "def test1(): pass", + 'root/demo-c/test_foo4.py': "def test1(): pass", + }) + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + '*test_foo1.py*', + '*test_foo3.py*', + '*test_foo4.py*', + '*3 passed*', + ]) + + +def test_required_option_help(testdir): + testdir.makeconftest("assert 0") + x = testdir.mkdir("x") + x.join("conftest.py").write(_pytest._code.Source(""" + def pytest_addoption(parser): + parser.addoption("--xyz", action="store_true", required=True) + """)) + result = testdir.runpytest("-h", x) + assert 'argument --xyz is required' not in result.stdout.str() + assert 'general:' in result.stdout.str() diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_doctest.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_doctest.py similarity index 67% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_doctest.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_doctest.py index a4821ee4c9e..b15067f15e9 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_doctest.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_doctest.py @@ -1,10 +1,13 @@ # encoding: utf-8 +from __future__ import absolute_import, division, print_function import sys import _pytest._code +from _pytest.compat import MODULE_NOT_FOUND_ERROR from _pytest.doctest import DoctestItem, DoctestModule, DoctestTextfile import pytest -class TestDoctests: + +class TestDoctests(object): def test_collect_testtextfile(self, testdir): w = testdir.maketxtfile(whatever="") @@ -14,26 +17,29 @@ class TestDoctests: >>> i-1 4 """) + for x in (testdir.tmpdir, checkfile): - #print "checking that %s returns custom items" % (x,) + # print "checking that %s returns custom items" % (x,) items, reprec = testdir.inline_genitems(x) assert len(items) == 1 - assert isinstance(items[0], DoctestTextfile) + assert isinstance(items[0], DoctestItem) + assert isinstance(items[0].parent, DoctestTextfile) + # Empty file has no items. items, reprec = testdir.inline_genitems(w) - assert len(items) == 1 + assert len(items) == 0 def test_collect_module_empty(self, testdir): path = testdir.makepyfile(whatever="#") for p in (path, testdir.tmpdir): items, reprec = testdir.inline_genitems(p, - '--doctest-modules') + '--doctest-modules') assert len(items) == 0 def test_collect_module_single_modulelevel_doctest(self, testdir): path = testdir.makepyfile(whatever='""">>> pass"""') for p in (path, testdir.tmpdir): items, reprec = testdir.inline_genitems(p, - '--doctest-modules') + '--doctest-modules') assert len(items) == 1 assert isinstance(items[0], DoctestItem) assert isinstance(items[0].parent, DoctestModule) @@ -46,7 +52,7 @@ class TestDoctests: """) for p in (path, testdir.tmpdir): items, reprec = testdir.inline_genitems(p, - '--doctest-modules') + '--doctest-modules') assert len(items) == 2 assert isinstance(items[0], DoctestItem) assert isinstance(items[1], DoctestItem) @@ -71,7 +77,7 @@ class TestDoctests: """) for p in (path, testdir.tmpdir): items, reprec = testdir.inline_genitems(p, - '--doctest-modules') + '--doctest-modules') assert len(items) == 2 assert isinstance(items[0], DoctestItem) assert isinstance(items[1], DoctestItem) @@ -126,6 +132,33 @@ class TestDoctests: '*1 passed*', ]) + @pytest.mark.parametrize( + ' test_string, encoding', + [ + (u'foo', 'ascii'), + (u'öäü', 'latin1'), + (u'öäü', 'utf-8') + ] + ) + def test_encoding(self, testdir, test_string, encoding): + """Test support for doctest_encoding ini option. + """ + testdir.makeini(""" + [pytest] + doctest_encoding={0} + """.format(encoding)) + doctest = u""" + >>> u"{0}" + {1} + """.format(test_string, repr(test_string)) + testdir._makefile(".txt", [doctest], {}, encoding=encoding) + + result = testdir.runpytest() + + result.stdout.fnmatch_lines([ + '*1 passed*', + ]) + def test_doctest_unexpected_exception(self, testdir): testdir.maketxtfile(""" >>> i = 0 @@ -140,7 +173,7 @@ class TestDoctests: "*UNEXPECTED*ZeroDivision*", ]) - def test_docstring_context_around_error(self, testdir): + def test_docstring_partial_context_around_error(self, testdir): """Test that we show some context before the actual line of a failing doctest. """ @@ -166,7 +199,7 @@ class TestDoctests: ''') result = testdir.runpytest('--doctest-modules') result.stdout.fnmatch_lines([ - '*docstring_context_around_error*', + '*docstring_partial_context_around_error*', '005*text-line-3', '006*text-line-4', '013*text-line-11', @@ -180,6 +213,32 @@ class TestDoctests: assert 'text-line-2' not in result.stdout.str() assert 'text-line-after' not in result.stdout.str() + def test_docstring_full_context_around_error(self, testdir): + """Test that we show the whole context before the actual line of a failing + doctest, provided that the context is up to 10 lines long. + """ + testdir.makepyfile(''' + def foo(): + """ + text-line-1 + text-line-2 + + >>> 1 + 1 + 3 + """ + ''') + result = testdir.runpytest('--doctest-modules') + result.stdout.fnmatch_lines([ + '*docstring_full_context_around_error*', + '003*text-line-1', + '004*text-line-2', + '006*>>> 1 + 1', + 'Expected:', + ' 3', + 'Got:', + ' 2', + ]) + def test_doctest_linedata_missing(self, testdir): testdir.tmpdir.join('hello.py').write(_pytest._code.Source(""" class Fun(object): @@ -199,8 +258,20 @@ class TestDoctests: "*1 failed*", ]) + def test_doctest_unex_importerror_only_txt(self, testdir): + testdir.maketxtfile(""" + >>> import asdalsdkjaslkdjasd + >>> + """) + result = testdir.runpytest() + # doctest is never executed because of error during hello.py collection + result.stdout.fnmatch_lines([ + "*>>> import asdals*", + "*UNEXPECTED*{e}*".format(e=MODULE_NOT_FOUND_ERROR), + "{e}: No module named *asdal*".format(e=MODULE_NOT_FOUND_ERROR), + ]) - def test_doctest_unex_importerror(self, testdir): + def test_doctest_unex_importerror_with_module(self, testdir): testdir.tmpdir.join("hello.py").write(_pytest._code.Source(""" import asdalsdkjaslkdjasd """)) @@ -209,10 +280,11 @@ class TestDoctests: >>> """) result = testdir.runpytest("--doctest-modules") + # doctest is never executed because of error during hello.py collection result.stdout.fnmatch_lines([ - "*>>> import hello", - "*UNEXPECTED*ImportError*", - "*import asdals*", + "*ERROR collecting hello.py*", + "*{e}: No module named *asdals*".format(e=MODULE_NOT_FOUND_ERROR), + "*Interrupted: 1 errors during collection*", ]) def test_doctestmodule(self, testdir): @@ -248,7 +320,6 @@ class TestDoctests: "*:5: DocTestFailure" ]) - def test_txtfile_failing(self, testdir): p = testdir.maketxtfile(""" >>> i = 0 @@ -333,7 +404,7 @@ class TestDoctests: def test_doctestmodule_two_tests_one_fail(self, testdir): p = testdir.makepyfile(""" - class MyClass: + class MyClass(object): def bad_meth(self): ''' >>> magic = 42 @@ -356,7 +427,7 @@ class TestDoctests: doctest_optionflags = ELLIPSIS NORMALIZE_WHITESPACE """) p = testdir.makepyfile(""" - class MyClass: + class MyClass(object): ''' >>> a = "foo " >>> print(a) @@ -373,7 +444,7 @@ class TestDoctests: doctest_optionflags = ELLIPSIS """) p = testdir.makepyfile(""" - class MyClass: + class MyClass(object): ''' >>> a = "foo " >>> print(a) @@ -459,8 +530,93 @@ class TestDoctests: "--junit-xml=junit.xml") reprec.assertoutcome(failed=1) + def test_unicode_doctest(self, testdir): + """ + Test case for issue 2434: DecodeError on Python 2 when doctest contains non-ascii + characters. + """ + p = testdir.maketxtfile(test_unicode_doctest=""" + .. doctest:: -class TestLiterals: + >>> print( + ... "Hi\\n\\nByé") + Hi + ... + Byé + >>> 1/0 # Byé + 1 + """) + result = testdir.runpytest(p) + result.stdout.fnmatch_lines([ + '*UNEXPECTED EXCEPTION: ZeroDivisionError*', + '*1 failed*', + ]) + + def test_unicode_doctest_module(self, testdir): + """ + Test case for issue 2434: DecodeError on Python 2 when doctest docstring + contains non-ascii characters. + """ + p = testdir.makepyfile(test_unicode_doctest_module=""" + # -*- encoding: utf-8 -*- + from __future__ import unicode_literals + + def fix_bad_unicode(text): + ''' + >>> print(fix_bad_unicode('único')) + único + ''' + return "único" + """) + result = testdir.runpytest(p, '--doctest-modules') + result.stdout.fnmatch_lines(['* 1 passed *']) + + def test_reportinfo(self, testdir): + ''' + Test case to make sure that DoctestItem.reportinfo() returns lineno. + ''' + p = testdir.makepyfile(test_reportinfo=""" + def foo(x): + ''' + >>> foo('a') + 'b' + ''' + return 'c' + """) + items, reprec = testdir.inline_genitems(p, '--doctest-modules') + reportinfo = items[0].reportinfo() + assert reportinfo[1] == 1 + + def test_valid_setup_py(self, testdir): + ''' + Test to make sure that pytest ignores valid setup.py files when ran + with --doctest-modules + ''' + p = testdir.makepyfile(setup=""" + from setuptools import setup, find_packages + setup(name='sample', + version='0.0', + description='description', + packages=find_packages() + ) + """) + result = testdir.runpytest(p, '--doctest-modules') + result.stdout.fnmatch_lines(['*collected 0 items*']) + + def test_invalid_setup_py(self, testdir): + ''' + Test to make sure that pytest reads setup.py files that are not used + for python packages when ran with --doctest-modules + ''' + p = testdir.makepyfile(setup=""" + def test_foo(): + return 'bar' + """) + result = testdir.runpytest(p, '--doctest-modules') + result.stdout.fnmatch_lines(['*collected 1 item*']) + + +class TestLiterals(object): @pytest.mark.parametrize('config_mode', ['ini', 'comment']) def test_allow_unicode(self, testdir, config_mode): @@ -547,7 +703,7 @@ class TestLiterals: reprec.assertoutcome(passed=passed, failed=int(not passed)) -class TestDoctestSkips: +class TestDoctestSkips(object): """ If all examples in a doctest are skipped due to the SKIP option, then the tests should be SKIPPED rather than PASSED. (#957) @@ -595,8 +751,13 @@ class TestDoctestSkips: reprec = testdir.inline_run("--doctest-modules") reprec.assertoutcome(skipped=1) + def test_vacuous_all_skipped(self, testdir, makedoctest): + makedoctest('') + reprec = testdir.inline_run("--doctest-modules") + reprec.assertoutcome(passed=0, skipped=0) -class TestDoctestAutoUseFixtures: + +class TestDoctestAutoUseFixtures(object): SCOPES = ['module', 'session', 'class', 'function'] @@ -713,3 +874,130 @@ class TestDoctestAutoUseFixtures: result = testdir.runpytest('--doctest-modules') assert 'FAILURES' not in str(result.stdout.str()) result.stdout.fnmatch_lines(['*=== 1 passed in *']) + + +class TestDoctestNamespaceFixture(object): + + SCOPES = ['module', 'session', 'class', 'function'] + + @pytest.mark.parametrize('scope', SCOPES) + def test_namespace_doctestfile(self, testdir, scope): + """ + Check that inserting something into the namespace works in a + simple text file doctest + """ + testdir.makeconftest(""" + import pytest + import contextlib + + @pytest.fixture(autouse=True, scope="{scope}") + def add_contextlib(doctest_namespace): + doctest_namespace['cl'] = contextlib + """.format(scope=scope)) + p = testdir.maketxtfile(""" + >>> print(cl.__name__) + contextlib + """) + reprec = testdir.inline_run(p) + reprec.assertoutcome(passed=1) + + @pytest.mark.parametrize('scope', SCOPES) + def test_namespace_pyfile(self, testdir, scope): + """ + Check that inserting something into the namespace works in a + simple Python file docstring doctest + """ + testdir.makeconftest(""" + import pytest + import contextlib + + @pytest.fixture(autouse=True, scope="{scope}") + def add_contextlib(doctest_namespace): + doctest_namespace['cl'] = contextlib + """.format(scope=scope)) + p = testdir.makepyfile(""" + def foo(): + ''' + >>> print(cl.__name__) + contextlib + ''' + """) + reprec = testdir.inline_run(p, "--doctest-modules") + reprec.assertoutcome(passed=1) + + +class TestDoctestReportingOption(object): + def _run_doctest_report(self, testdir, format): + testdir.makepyfile(""" + def foo(): + ''' + >>> foo() + a b + 0 1 4 + 1 2 4 + 2 3 6 + ''' + print(' a b\\n' + '0 1 4\\n' + '1 2 5\\n' + '2 3 6') + """) + return testdir.runpytest("--doctest-modules", "--doctest-report", format) + + @pytest.mark.parametrize('format', ['udiff', 'UDIFF', 'uDiFf']) + def test_doctest_report_udiff(self, testdir, format): + result = self._run_doctest_report(testdir, format) + result.stdout.fnmatch_lines([ + ' 0 1 4', + ' -1 2 4', + ' +1 2 5', + ' 2 3 6', + ]) + + def test_doctest_report_cdiff(self, testdir): + result = self._run_doctest_report(testdir, 'cdiff') + result.stdout.fnmatch_lines([ + ' a b', + ' 0 1 4', + ' ! 1 2 4', + ' 2 3 6', + ' --- 1,4 ----', + ' a b', + ' 0 1 4', + ' ! 1 2 5', + ' 2 3 6', + ]) + + def test_doctest_report_ndiff(self, testdir): + result = self._run_doctest_report(testdir, 'ndiff') + result.stdout.fnmatch_lines([ + ' a b', + ' 0 1 4', + ' - 1 2 4', + ' ? ^', + ' + 1 2 5', + ' ? ^', + ' 2 3 6', + ]) + + @pytest.mark.parametrize('format', ['none', 'only_first_failure']) + def test_doctest_report_none_or_only_first_failure(self, testdir, format): + result = self._run_doctest_report(testdir, format) + result.stdout.fnmatch_lines([ + 'Expected:', + ' a b', + ' 0 1 4', + ' 1 2 4', + ' 2 3 6', + 'Got:', + ' a b', + ' 0 1 4', + ' 1 2 5', + ' 2 3 6', + ]) + + def test_doctest_report_invalid(self, testdir): + result = self._run_doctest_report(testdir, 'obviously_invalid_format') + result.stderr.fnmatch_lines([ + "*error: argument --doctest-report: invalid choice: 'obviously_invalid_format' (choose from*" + ]) diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_entry_points.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_entry_points.py new file mode 100644 index 00000000000..6ca68b481fa --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_entry_points.py @@ -0,0 +1,14 @@ +from __future__ import absolute_import, division, print_function +import pkg_resources + +import pytest + + +@pytest.mark.parametrize("entrypoint", ['py.test', 'pytest']) +def test_entry_point_exist(entrypoint): + assert entrypoint in pkg_resources.get_entry_map('pytest')['console_scripts'] + + +def test_pytest_entry_points_are_identical(): + entryMap = pkg_resources.get_entry_map('pytest')['console_scripts'] + assert entryMap['pytest'].module_name == entryMap['py.test'].module_name diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_helpconfig.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_helpconfig.py similarity index 88% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_helpconfig.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_helpconfig.py index 9f8d87b7cb5..845005a0575 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_helpconfig.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_helpconfig.py @@ -1,10 +1,12 @@ +from __future__ import absolute_import, division, print_function from _pytest.main import EXIT_NOTESTSCOLLECTED import pytest + def test_version(testdir, pytestconfig): result = testdir.runpytest("--version") assert result.ret == 0 - #p = py.path.local(py.__file__).dirpath() + # p = py.path.local(py.__file__).dirpath() result.stderr.fnmatch_lines([ '*pytest*%s*imported from*' % (pytest.__version__, ) ]) @@ -14,6 +16,7 @@ def test_version(testdir, pytestconfig): "*at*", ]) + def test_help(testdir): result = testdir.runpytest("--help") assert result.ret == 0 @@ -21,10 +24,11 @@ def test_help(testdir): *-v*verbose* *setup.cfg* *minversion* - *to see*markers*py.test --markers* - *to see*fixtures*py.test --fixtures* + *to see*markers*pytest --markers* + *to see*fixtures*pytest --fixtures* """) + def test_hookvalidation_unknown(testdir): testdir.makeconftest(""" def pytest_hello(xyz): @@ -32,10 +36,11 @@ def test_hookvalidation_unknown(testdir): """) result = testdir.runpytest() assert result.ret != 0 - result.stderr.fnmatch_lines([ + result.stdout.fnmatch_lines([ '*unknown hook*pytest_hello*' ]) + def test_hookvalidation_optional(testdir): testdir.makeconftest(""" import pytest @@ -46,6 +51,7 @@ def test_hookvalidation_optional(testdir): result = testdir.runpytest() assert result.ret == EXIT_NOTESTSCOLLECTED + def test_traceconfig(testdir): result = testdir.runpytest("--traceconfig") result.stdout.fnmatch_lines([ @@ -53,12 +59,14 @@ def test_traceconfig(testdir): "*active plugins*", ]) + def test_debug(testdir, monkeypatch): result = testdir.runpytest_subprocess("--debug") assert result.ret == EXIT_NOTESTSCOLLECTED p = testdir.tmpdir.join("pytestdebug.log") assert "pytest_sessionstart" in p.read() + def test_PYTEST_DEBUG(testdir, monkeypatch): monkeypatch.setenv("PYTEST_DEBUG", "1") result = testdir.runpytest_subprocess() diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_junitxml.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_junitxml.py similarity index 73% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_junitxml.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_junitxml.py index 5960f882535..b604c02a3de 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_junitxml.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_junitxml.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- - +from __future__ import absolute_import, division, print_function from xml.dom import minidom -from _pytest.main import EXIT_NOTESTSCOLLECTED import py import sys import os @@ -80,7 +79,7 @@ class DomNode(object): return type(self)(self.__node.nextSibling) -class TestPython: +class TestPython(object): def test_summing_simple(self, testdir): testdir.makepyfile(""" import pytest @@ -100,7 +99,31 @@ class TestPython: result, dom = runandparse(testdir) assert result.ret node = dom.find_first_by_tag("testsuite") - node.assert_attr(name="pytest", errors=0, failures=1, skips=3, tests=2) + node.assert_attr(name="pytest", errors=0, failures=1, skips=2, tests=5) + + def test_summing_simple_with_errors(self, testdir): + testdir.makepyfile(""" + import pytest + @pytest.fixture + def fixture(): + raise Exception() + def test_pass(): + pass + def test_fail(): + assert 0 + def test_error(fixture): + pass + @pytest.mark.xfail + def test_xfail(): + assert False + @pytest.mark.xfail(strict=True) + def test_xpass(): + assert True + """) + result, dom = runandparse(testdir) + assert result.ret + node = dom.find_first_by_tag("testsuite") + node.assert_attr(name="pytest", errors=1, failures=2, skips=1, tests=5) def test_timing_function(self, testdir): testdir.makepyfile(""" @@ -120,7 +143,10 @@ class TestPython: def test_setup_error(self, testdir): testdir.makepyfile(""" - def pytest_funcarg__arg(request): + import pytest + + @pytest.fixture + def arg(request): raise ValueError() def test_function(arg): pass @@ -128,17 +154,64 @@ class TestPython: result, dom = runandparse(testdir) assert result.ret node = dom.find_first_by_tag("testsuite") - node.assert_attr(errors=1, tests=0) + node.assert_attr(errors=1, tests=1) tnode = node.find_first_by_tag("testcase") tnode.assert_attr( file="test_setup_error.py", - line="2", + line="5", classname="test_setup_error", name="test_function") fnode = tnode.find_first_by_tag("error") fnode.assert_attr(message="test setup failure") assert "ValueError" in fnode.toxml() + def test_teardown_error(self, testdir): + testdir.makepyfile(""" + import pytest + + @pytest.fixture + def arg(): + yield + raise ValueError() + def test_function(arg): + pass + """) + result, dom = runandparse(testdir) + assert result.ret + node = dom.find_first_by_tag("testsuite") + tnode = node.find_first_by_tag("testcase") + tnode.assert_attr( + file="test_teardown_error.py", + line="6", + classname="test_teardown_error", + name="test_function") + fnode = tnode.find_first_by_tag("error") + fnode.assert_attr(message="test teardown failure") + assert "ValueError" in fnode.toxml() + + def test_call_failure_teardown_error(self, testdir): + testdir.makepyfile(""" + import pytest + + @pytest.fixture + def arg(): + yield + raise Exception("Teardown Exception") + def test_function(arg): + raise Exception("Call Exception") + """) + result, dom = runandparse(testdir) + assert result.ret + node = dom.find_first_by_tag("testsuite") + node.assert_attr(errors=1, failures=1, tests=1) + first, second = dom.find_by_tag("testcase") + if not first or not second or first == second: + assert 0 + fnode = first.find_first_by_tag("failure") + fnode.assert_attr(message="Exception: Call Exception") + snode = second.find_first_by_tag("error") + snode.assert_attr(message="test teardown failure") + def test_skip_contains_name_reason(self, testdir): testdir.makepyfile(""" import pytest @@ -158,9 +231,62 @@ class TestPython: snode = tnode.find_first_by_tag("skipped") snode.assert_attr(type="pytest.skip", message="hello23", ) + def test_mark_skip_contains_name_reason(self, testdir): + testdir.makepyfile(""" + import pytest + @pytest.mark.skip(reason="hello24") + def test_skip(): + assert True + """) + result, dom = runandparse(testdir) + assert result.ret == 0 + node = dom.find_first_by_tag("testsuite") + node.assert_attr(skips=1) + tnode = node.find_first_by_tag("testcase") + tnode.assert_attr( + file="test_mark_skip_contains_name_reason.py", + line="1", + classname="test_mark_skip_contains_name_reason", + name="test_skip") + snode = tnode.find_first_by_tag("skipped") + snode.assert_attr(type="pytest.skip", message="hello24", ) + + def test_mark_skipif_contains_name_reason(self, testdir): + testdir.makepyfile(""" + import pytest + GLOBAL_CONDITION = True + @pytest.mark.skipif(GLOBAL_CONDITION, reason="hello25") + def test_skip(): + assert True + """) + result, dom = runandparse(testdir) + assert result.ret == 0 + node = dom.find_first_by_tag("testsuite") + node.assert_attr(skips=1) + tnode = node.find_first_by_tag("testcase") + tnode.assert_attr( + file="test_mark_skipif_contains_name_reason.py", + line="2", + classname="test_mark_skipif_contains_name_reason", + name="test_skip") + snode = tnode.find_first_by_tag("skipped") + snode.assert_attr(type="pytest.skip", message="hello25", ) + + def test_mark_skip_doesnt_capture_output(self, testdir): + testdir.makepyfile(""" + import pytest + @pytest.mark.skip(reason="foo") + def test_skip(): + print("bar!") + """) + result, dom = runandparse(testdir) + assert result.ret == 0 + node_xml = dom.find_first_by_tag("testsuite").toxml() + assert "bar!" not in node_xml + def test_classname_instance(self, testdir): testdir.makepyfile(""" - class TestClass: + class TestClass(object): def test_method(self): assert 0 """) @@ -195,7 +321,7 @@ class TestPython: result, dom = runandparse(testdir) assert result.ret node = dom.find_first_by_tag("testsuite") - node.assert_attr(errors=1, tests=0) + node.assert_attr(errors=1, tests=1) tnode = node.find_first_by_tag("testcase") tnode.assert_attr(classname="pytest", name="internal") fnode = tnode.find_first_by_tag("error") @@ -273,7 +399,7 @@ class TestPython: testdir.makepyfile(""" def test_func(): assert 0 - class TestHello: + class TestHello(object): def test_hello(self): pass """) @@ -304,7 +430,7 @@ class TestPython: result, dom = runandparse(testdir) assert not result.ret node = dom.find_first_by_tag("testsuite") - node.assert_attr(skips=1, tests=0) + node.assert_attr(skips=1, tests=1) tnode = node.find_first_by_tag("testcase") tnode.assert_attr( file="test_xfailure_function.py", @@ -325,23 +451,40 @@ class TestPython: result, dom = runandparse(testdir) # assert result.ret node = dom.find_first_by_tag("testsuite") - node.assert_attr(skips=1, tests=0) + node.assert_attr(skips=0, tests=1) tnode = node.find_first_by_tag("testcase") tnode.assert_attr( file="test_xfailure_xpass.py", line="1", classname="test_xfailure_xpass", name="test_xpass") - fnode = tnode.find_first_by_tag("skipped") - fnode.assert_attr(message="xfail-marked test passes unexpectedly") - # assert "ValueError" in fnode.toxml() + + def test_xfailure_xpass_strict(self, testdir): + testdir.makepyfile(""" + import pytest + @pytest.mark.xfail(strict=True, reason="This needs to fail!") + def test_xpass(): + pass + """) + result, dom = runandparse(testdir) + # assert result.ret + node = dom.find_first_by_tag("testsuite") + node.assert_attr(skips=0, tests=1) + tnode = node.find_first_by_tag("testcase") + tnode.assert_attr( + file="test_xfailure_xpass_strict.py", + line="1", + classname="test_xfailure_xpass_strict", + name="test_xpass") + fnode = tnode.find_first_by_tag("failure") + fnode.assert_attr(message="[XPASS(strict)] This needs to fail!") def test_collect_error(self, testdir): testdir.makepyfile("syntax error") result, dom = runandparse(testdir) assert result.ret node = dom.find_first_by_tag("testsuite") - node.assert_attr(errors=1, tests=0) + node.assert_attr(errors=1, tests=1) tnode = node.find_first_by_tag("testcase") tnode.assert_attr( file="test_collect_error.py", @@ -351,23 +494,6 @@ class TestPython: fnode.assert_attr(message="collection failure") assert "SyntaxError" in fnode.toxml() - def test_collect_skipped(self, testdir): - testdir.makepyfile("import pytest; pytest.skip('xyz')") - result, dom = runandparse(testdir) - assert result.ret == EXIT_NOTESTSCOLLECTED - node = dom.find_first_by_tag("testsuite") - node.assert_attr(skips=1, tests=0) - tnode = node.find_first_by_tag("testcase") - tnode.assert_attr( - file="test_collect_skipped.py", - name="test_collect_skipped") - - # py.test doesn't give us a line here. - assert tnode["line"] is None - - fnode = tnode.find_first_by_tag("skipped") - fnode.assert_attr(message="collection skipped") - def test_unicode(self, testdir): value = 'hx\xc4\x85\xc4\x87\n' testdir.makepyfile(""" @@ -421,7 +547,10 @@ class TestPython: def test_setup_error_captures_stdout(self, testdir): testdir.makepyfile(""" - def pytest_funcarg__arg(request): + import pytest + + @pytest.fixture + def arg(request): print('hello-stdout') raise ValueError() def test_function(arg): @@ -436,7 +565,10 @@ class TestPython: def test_setup_error_captures_stderr(self, testdir): testdir.makepyfile(""" import sys - def pytest_funcarg__arg(request): + import pytest + + @pytest.fixture + def arg(request): sys.stderr.write('hello-stderr') raise ValueError() def test_function(arg): @@ -448,6 +580,26 @@ class TestPython: systemout = pnode.find_first_by_tag("system-err") assert "hello-stderr" in systemout.toxml() + def test_avoid_double_stdout(self, testdir): + testdir.makepyfile(""" + import sys + import pytest + + @pytest.fixture + def arg(request): + yield + sys.stdout.write('hello-stdout teardown') + raise ValueError() + def test_function(arg): + sys.stdout.write('hello-stdout call') + """) + result, dom = runandparse(testdir) + node = dom.find_first_by_tag("testsuite") + pnode = node.find_first_by_tag("testcase") + systemout = pnode.find_first_by_tag("system-out") + assert "hello-stdout call" in systemout.toxml() + assert "hello-stdout teardown" in systemout.toxml() + def test_mangle_test_address(): from _pytest.junitxml import mangle_test_address @@ -460,11 +612,14 @@ def test_mangle_test_address(): def test_dont_configure_on_slaves(tmpdir): gotten = [] - class FakeConfig: + class FakeConfig(object): def __init__(self): self.pluginmanager = self self.option = self + def getini(self, name): + return "pytest" + junitprefix = None # XXX: shouldnt need tmpdir ? xmlpath = str(tmpdir.join('junix.xml')) @@ -479,7 +634,7 @@ def test_dont_configure_on_slaves(tmpdir): assert len(gotten) == 1 -class TestNonPython: +class TestNonPython(object): def test_summing_simple(self, testdir): testdir.makeconftest(""" import pytest @@ -607,17 +762,23 @@ def test_logxml_makedir(testdir): assert testdir.tmpdir.join("path/to/results.xml").check() +def test_logxml_check_isdir(testdir): + """Give an error if --junit-xml is a directory (#2089)""" + result = testdir.runpytest("--junit-xml=.") + result.stderr.fnmatch_lines(["*--junitxml must be a filename*"]) + + def test_escaped_parametrized_names_xml(testdir): testdir.makepyfile(""" import pytest - @pytest.mark.parametrize('char', ["\\x00"]) + @pytest.mark.parametrize('char', [u"\\x00"]) def test_func(char): assert char """) result, dom = runandparse(testdir) assert result.ret == 0 node = dom.find_first_by_tag("testcase") - node.assert_attr(name="test_func[#x00]") + node.assert_attr(name="test_func[\\x00]") def test_double_colon_split_function_issue469(testdir): @@ -637,7 +798,7 @@ def test_double_colon_split_function_issue469(testdir): def test_double_colon_split_method_issue469(testdir): testdir.makepyfile(""" import pytest - class TestClass: + class TestClass(object): @pytest.mark.parametrize('param', ["double::colon"]) def test_func(self, param): pass @@ -697,7 +858,10 @@ def test_record_property(testdir): pnodes = psnode.find_by_tag('property') pnodes[0].assert_attr(name="bar", value="1") pnodes[1].assert_attr(name="foo", value="<1") - result.stdout.fnmatch_lines('*C3*test_record_property.py*experimental*') + result.stdout.fnmatch_lines([ + 'test_record_property.py::test_record', + '*record_xml_property*experimental*', + ]) def test_record_property_same_name(testdir): @@ -814,3 +978,85 @@ def test_fancy_items_regression(testdir): u'test_fancy_items_regression test_pass' u' test_fancy_items_regression.py', ] + + +def test_global_properties(testdir): + path = testdir.tmpdir.join("test_global_properties.xml") + log = LogXML(str(path), None) + from _pytest.runner import BaseReport + + class Report(BaseReport): + sections = [] + nodeid = "test_node_id" + + log.pytest_sessionstart() + log.add_global_property('foo', 1) + log.add_global_property('bar', 2) + log.pytest_sessionfinish() + + dom = minidom.parse(str(path)) + + properties = dom.getElementsByTagName('properties') + + assert (properties.length == 1), "There must be one node" + + property_list = dom.getElementsByTagName('property') + + assert (property_list.length == 2), "There most be only 2 property nodes" + + expected = {'foo': '1', 'bar': '2'} + actual = {} + + for p in property_list: + k = str(p.getAttribute('name')) + v = str(p.getAttribute('value')) + actual[k] = v + + assert actual == expected + + +def test_url_property(testdir): + test_url = "http://www.github.com/pytest-dev" + path = testdir.tmpdir.join("test_url_property.xml") + log = LogXML(str(path), None) + from _pytest.runner import BaseReport + + class Report(BaseReport): + longrepr = "FooBarBaz" + sections = [] + nodeid = "something" + location = 'tests/filename.py', 42, 'TestClass.method' + url = test_url + + test_report = Report() + + log.pytest_sessionstart() + node_reporter = log._opentestcase(test_report) + node_reporter.append_failure(test_report) + log.pytest_sessionfinish() + + test_case = minidom.parse(str(path)).getElementsByTagName('testcase')[0] + + assert (test_case.getAttribute('url') == test_url), "The URL did not get written to the xml" + + +@pytest.mark.parametrize('suite_name', ['my_suite', '']) +def test_set_suite_name(testdir, suite_name): + if suite_name: + testdir.makeini(""" + [pytest] + junit_suite_name={0} + """.format(suite_name)) + expected = suite_name + else: + expected = 'pytest' + testdir.makepyfile(""" + import pytest + + def test_func(): + pass + """) + result, dom = runandparse(testdir) + assert result.ret == 0 + node = dom.find_first_by_tag("testsuite") + node.assert_attr(name=expected) diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_mark.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_mark.py similarity index 73% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_mark.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_mark.py index aa1be6f7c66..46bf0b0e778 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_mark.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_mark.py @@ -1,37 +1,59 @@ +from __future__ import absolute_import, division, print_function import os +import sys -import py, pytest -from _pytest.mark import MarkGenerator as Mark +import pytest +from _pytest.mark import MarkGenerator as Mark, ParameterSet, transfer_markers -class TestMark: + +class TestMark(object): def test_markinfo_repr(self): - from _pytest.mark import MarkInfo - m = MarkInfo("hello", (1,2), {}) + from _pytest.mark import MarkInfo, Mark + m = MarkInfo(Mark("hello", (1, 2), {})) repr(m) - def test_pytest_exists_in_namespace_all(self): - assert 'mark' in py.test.__all__ - assert 'mark' in pytest.__all__ + @pytest.mark.parametrize('attr', ['mark', 'param']) + @pytest.mark.parametrize('modulename', ['py.test', 'pytest']) + def test_pytest_exists_in_namespace_all(self, attr, modulename): + module = sys.modules[modulename] + assert attr in module.__all__ def test_pytest_mark_notcallable(self): mark = Mark() pytest.raises((AttributeError, TypeError), mark) + def test_mark_with_param(self): + def some_function(abc): + pass + + class SomeClass(object): + pass + + assert pytest.mark.fun(some_function) is some_function + assert pytest.mark.fun.with_args(some_function) is not some_function + + assert pytest.mark.fun(SomeClass) is SomeClass + assert pytest.mark.fun.with_args(SomeClass) is not SomeClass + def test_pytest_mark_name_starts_with_underscore(self): mark = Mark() pytest.raises(AttributeError, getattr, mark, '_some_name') def test_pytest_mark_bare(self): mark = Mark() + def f(): pass + mark.hello(f) assert f.hello def test_pytest_mark_keywords(self): mark = Mark() + def f(): pass + mark.world(x=3, y=4)(f) assert f.world assert f.world.kwargs['x'] == 3 @@ -39,8 +61,10 @@ class TestMark: def test_apply_multiple_and_merge(self): mark = Mark() + def f(): pass + mark.world mark.world(x=3)(f) assert f.world.kwargs['x'] == 3 @@ -53,33 +77,43 @@ class TestMark: def test_pytest_mark_positional(self): mark = Mark() + def f(): pass + mark.world("hello")(f) assert f.world.args[0] == "hello" mark.world("world")(f) def test_pytest_mark_positional_func_and_keyword(self): mark = Mark() + def f(): raise Exception + m = mark.world(f, omega="hello") + def g(): pass + assert m(g) == g assert g.world.args[0] is f assert g.world.kwargs["omega"] == "hello" def test_pytest_mark_reuse(self): mark = Mark() + def f(): pass + w = mark.some w("hello", reason="123")(f) assert f.some.args[0] == "hello" assert f.some.kwargs['reason'] == "123" + def g(): pass + w("world", reason2="456")(g) assert g.some.args[0] == "world" assert 'reason' not in g.some.kwargs @@ -120,19 +154,55 @@ def test_ini_markers(testdir): rec = testdir.inline_run() rec.assertoutcome(passed=1) + def test_markers_option(testdir): testdir.makeini(""" [pytest] markers = a1: this is a webtest marker a1some: another marker + nodescription """) result = testdir.runpytest("--markers", ) result.stdout.fnmatch_lines([ "*a1*this is a webtest*", "*a1some*another marker", + "*nodescription*", ]) + +def test_ini_markers_whitespace(testdir): + testdir.makeini(""" + [pytest] + markers = + a1 : this is a whitespace marker + """) + testdir.makepyfile(""" + import pytest + + @pytest.mark.a1 + def test_markers(): + assert True + """) + rec = testdir.inline_run("--strict", "-m", "a1") + rec.assertoutcome(passed=1) + + +def test_marker_without_description(testdir): + testdir.makefile(".cfg", setup=""" + [tool:pytest] + markers=slow + """) + testdir.makeconftest(""" + import pytest + pytest.mark.xfail('FAIL') + """) + ftdir = testdir.mkdir("ft1_dummy") + testdir.tmpdir.join("conftest.py").move(ftdir.join("conftest.py")) + rec = testdir.runpytest_subprocess("--strict") + rec.assert_outcomes() + + def test_markers_option_with_plugin_in_current_dir(testdir): testdir.makeconftest('pytest_plugins = "flip_flop"') testdir.makepyfile(flip_flop="""\ @@ -166,6 +236,7 @@ def test_mark_on_pseudo_function(testdir): reprec = testdir.inline_run() reprec.assertoutcome(passed=1) + def test_strict_prohibits_unregistered_markers(testdir): testdir.makepyfile(""" import pytest @@ -179,11 +250,12 @@ def test_strict_prohibits_unregistered_markers(testdir): "*unregisteredmark*not*registered*", ]) + @pytest.mark.parametrize("spec", [ - ("xyz", ("test_one",)), - ("xyz and xyz2", ()), - ("xyz2", ("test_two",)), - ("xyz or xyz2", ("test_one", "test_two"),) + ("xyz", ("test_one",)), + ("xyz and xyz2", ()), + ("xyz2", ("test_two",)), + ("xyz or xyz2", ("test_one", "test_two"),) ]) def test_mark_option(spec, testdir): testdir.makepyfile(""" @@ -202,9 +274,10 @@ def test_mark_option(spec, testdir): assert len(passed) == len(passed_result) assert list(passed) == list(passed_result) + @pytest.mark.parametrize("spec", [ - ("interface", ("test_interface",)), - ("not interface", ("test_nointer",)), + ("interface", ("test_interface",)), + ("not interface", ("test_nointer",)), ]) def test_mark_option_custom(spec, testdir): testdir.makeconftest(""" @@ -227,11 +300,12 @@ def test_mark_option_custom(spec, testdir): assert len(passed) == len(passed_result) assert list(passed) == list(passed_result) + @pytest.mark.parametrize("spec", [ - ("interface", ("test_interface",)), - ("not interface", ("test_nointer", "test_pass")), - ("pass", ("test_pass",)), - ("not pass", ("test_interface", "test_nointer")), + ("interface", ("test_interface",)), + ("not interface", ("test_nointer", "test_pass")), + ("pass", ("test_pass",)), + ("not pass", ("test_interface", "test_nointer")), ]) def test_keyword_option_custom(spec, testdir): testdir.makepyfile(""" @@ -251,9 +325,9 @@ def test_keyword_option_custom(spec, testdir): @pytest.mark.parametrize("spec", [ - ("None", ("test_func[None]",)), - ("1.3", ("test_func[1.3]",)), - ("2-3", ("test_func[2-3]",)) + ("None", ("test_func[None]",)), + ("1.3", ("test_func[1.3]",)), + ("2-3", ("test_func[2-3]",)) ]) def test_keyword_option_parametrize(spec, testdir): testdir.makepyfile(""" @@ -285,7 +359,42 @@ def test_parametrized_collected_from_command_line(testdir): rec.assertoutcome(passed=3) -class TestFunctional: +def test_parametrized_collect_with_wrong_args(testdir): + """Test collect parametrized func with wrong number of args.""" + py_file = testdir.makepyfile(""" + import pytest + + @pytest.mark.parametrize('foo, bar', [(1, 2, 3)]) + def test_func(foo, bar): + pass + """) + + result = testdir.runpytest(py_file) + result.stdout.fnmatch_lines([ + 'E ValueError: In "parametrize" the number of values ((1, 2, 3)) ' + 'must be equal to the number of names ([\'foo\', \'bar\'])' + ]) + + +def test_parametrized_with_kwargs(testdir): + """Test collect parametrized func with wrong number of args.""" + py_file = testdir.makepyfile(""" + import pytest + + @pytest.fixture(params=[1,2]) + def a(request): + return request.param + + @pytest.mark.parametrize(argnames='b', argvalues=[1, 2]) + def test_func(a, b): + pass + """) + + result = testdir.runpytest(py_file) + assert(result.ret == 0) + + +class TestFunctional(object): def test_mark_per_function(self, testdir): p = testdir.makepyfile(""" @@ -310,7 +419,7 @@ class TestFunctional: def test_marklist_per_class(self, testdir): item = testdir.getitem(""" import pytest - class TestClass: + class TestClass(object): pytestmark = [pytest.mark.hello, pytest.mark.world] def test_func(self): assert TestClass.test_func.hello @@ -323,7 +432,7 @@ class TestFunctional: item = testdir.getitem(""" import pytest pytestmark = [pytest.mark.hello, pytest.mark.world] - class TestClass: + class TestClass(object): def test_func(self): assert TestClass.test_func.hello assert TestClass.test_func.world @@ -336,7 +445,7 @@ class TestFunctional: item = testdir.getitem(""" import pytest @pytest.mark.hello - class TestClass: + class TestClass(object): def test_func(self): assert TestClass.test_func.hello """) @@ -347,7 +456,7 @@ class TestFunctional: item = testdir.getitem(""" import pytest @pytest.mark.hello - class TestClass: + class TestClass(object): pytestmark = pytest.mark.world def test_func(self): assert TestClass.test_func.hello @@ -361,7 +470,7 @@ class TestFunctional: p = testdir.makepyfile(""" import pytest pytestmark = pytest.mark.hello("pos1", x=1, y=2) - class TestClass: + class TestClass(object): # classlevel overrides module level pytestmark = pytest.mark.hello(x=3) @pytest.mark.hello("pos0", z=4) @@ -376,29 +485,29 @@ class TestFunctional: assert marker.kwargs == {'x': 1, 'y': 2, 'z': 4} # test the new __iter__ interface - l = list(marker) - assert len(l) == 3 - assert l[0].args == ("pos0",) - assert l[1].args == () - assert l[2].args == ("pos1", ) + values = list(marker) + assert len(values) == 3 + assert values[0].args == ("pos0",) + assert values[1].args == () + assert values[2].args == ("pos1", ) @pytest.mark.xfail(reason='unfixed') def test_merging_markers_deep(self, testdir): # issue 199 - propagate markers into nested classes p = testdir.makepyfile(""" import pytest - class TestA: + class TestA(object): pytestmark = pytest.mark.a def test_b(self): assert True - class TestC: + class TestC(object): # this one didnt get marked def test_d(self): assert True """) items, rec = testdir.inline_genitems(p) for item in items: - print (item, item.keywords) + print(item, item.keywords) assert 'a' in item.keywords def test_mark_decorator_subclass_does_not_propagate_to_base(self, testdir): @@ -406,7 +515,7 @@ class TestFunctional: import pytest @pytest.mark.a - class Base: pass + class Base(object): pass @pytest.mark.b class Test1(Base): @@ -418,12 +527,36 @@ class TestFunctional: items, rec = testdir.inline_genitems(p) self.assert_markers(items, test_foo=('a', 'b'), test_bar=('a',)) + @pytest.mark.issue568 + @pytest.mark.xfail(reason="markers smear on methods of base classes") + def test_mark_should_not_pass_to_siebling_class(self, testdir): + p = testdir.makepyfile(""" + import pytest + + class TestBase(object): + def test_foo(self): + pass + + @pytest.mark.b + class TestSub(TestBase): + pass + + + class TestOtherSub(TestBase): + pass + + """) + items, rec = testdir.inline_genitems(p) + base_item, sub_item, sub_item_other = items + assert not hasattr(base_item.obj, 'b') + assert not hasattr(sub_item_other.obj, 'b') + def test_mark_decorator_baseclasses_merged(self, testdir): p = testdir.makepyfile(""" import pytest @pytest.mark.a - class Base: pass + class Base(object): pass @pytest.mark.b class Base2(Base): pass @@ -443,23 +576,24 @@ class TestFunctional: def test_mark_with_wrong_marker(self, testdir): reprec = testdir.inline_runsource(""" import pytest - class pytestmark: + class pytestmark(object): pass def test_func(): pass """) - l = reprec.getfailedcollections() - assert len(l) == 1 - assert "TypeError" in str(l[0].longrepr) + values = reprec.getfailedcollections() + assert len(values) == 1 + assert "TypeError" in str(values[0].longrepr) def test_mark_dynamically_in_funcarg(self, testdir): testdir.makeconftest(""" import pytest - def pytest_funcarg__arg(request): + @pytest.fixture + def arg(request): request.applymarker(pytest.mark.hello) def pytest_terminal_summary(terminalreporter): - l = terminalreporter.stats['passed'] - terminalreporter.writer.line("keyword: %s" % l[0].keywords) + values = terminalreporter.stats['passed'] + terminalreporter._tw.line("keyword: %s" % values[0].keywords) """) testdir.makepyfile(""" def test_func(arg): @@ -482,10 +616,10 @@ class TestFunctional: item, = items keywords = item.keywords marker = keywords['hello'] - l = list(marker) - assert len(l) == 2 - assert l[0].args == ("pos0",) - assert l[1].args == ("pos1",) + values = list(marker) + assert len(values) == 2 + assert values[0].args == ("pos0",) + assert values[1].args == ("pos1",) def test_no_marker_match_on_unmarked_names(self, testdir): p = testdir.makepyfile(""" @@ -563,8 +697,32 @@ class TestFunctional: if isinstance(v, MarkInfo)]) assert marker_names == set(expected_markers) + @pytest.mark.xfail(reason='callspec2.setmulti misuses keywords') + @pytest.mark.issue1540 + def test_mark_from_parameters(self, testdir): + testdir.makepyfile(""" + import pytest + + pytestmark = pytest.mark.skipif(True, reason='skip all') + + # skipifs inside fixture params + params = [pytest.mark.skipif(False, reason='dont skip')('parameter')] + + + @pytest.fixture(params=params) + def parameter(request): + return request.param + + + def test_1(parameter): + assert True + """) + reprec = testdir.inline_run() + reprec.assertoutcome(skipped=1) + + +class TestKeywordSelection(object): -class TestKeywordSelection: def test_select_simple(self, testdir): file_test = testdir.makepyfile(""" def test_one(): @@ -573,6 +731,7 @@ class TestKeywordSelection: def test_method_one(self): assert 42 == 43 """) + def check(keyword, name): reprec = testdir.inline_run("-s", "-k", keyword, file_test) passed, skipped, failed = reprec.listoutcomes() @@ -591,7 +750,7 @@ class TestKeywordSelection: p = testdir.makepyfile(test_select=""" def test_1(): pass - class TestClass: + class TestClass(object): def test_2(self): pass """) @@ -605,7 +764,7 @@ class TestKeywordSelection: item.extra_keyword_matches.add("xxx") """) reprec = testdir.inline_run(p.dirpath(), '-s', '-k', keyword) - py.builtin.print_("keyword", repr(keyword)) + print("keyword", repr(keyword)) passed, skipped, failed = reprec.listoutcomes() assert len(passed) == 1 assert passed[0].nodeid.endswith("test_2") @@ -659,6 +818,7 @@ class TestKeywordSelection: p = testdir.makepyfile(""" def test_one(): assert 1 """) + def assert_test_is_not_selected(keyword): reprec = testdir.inline_run("-k", keyword, p) passed, skipped, failed = reprec.countoutcomes() @@ -670,3 +830,49 @@ class TestKeywordSelection: assert_test_is_not_selected("__") assert_test_is_not_selected("()") + +@pytest.mark.parametrize('argval, expected', [ + (pytest.mark.skip()((1, 2)), + ParameterSet(values=(1, 2), marks=[pytest.mark.skip], id=None)), + (pytest.mark.xfail(pytest.mark.skip()((1, 2))), + ParameterSet(values=(1, 2), + marks=[pytest.mark.xfail, pytest.mark.skip], id=None)), + +]) +@pytest.mark.filterwarnings('ignore') +def test_parameterset_extractfrom(argval, expected): + extracted = ParameterSet.extract_from(argval) + assert extracted == expected + + +def test_legacy_transfer(): + + class FakeModule(object): + pytestmark = [] + + class FakeClass(object): + pytestmark = pytest.mark.nofun + + @pytest.mark.fun + def fake_method(self): + pass + + transfer_markers(fake_method, FakeClass, FakeModule) + + # legacy marks transfer smeared + assert fake_method.nofun + assert fake_method.fun + # pristine marks dont transfer + assert fake_method.pytestmark == [pytest.mark.fun.mark] + + +class TestMarkDecorator(object): + + @pytest.mark.parametrize('lhs, rhs, expected', [ + (pytest.mark.foo(), pytest.mark.foo(), True), + (pytest.mark.foo(), pytest.mark.bar(), False), + (pytest.mark.foo(), 'bar', False), + ('foo', pytest.mark.bar(), False) + ]) + def test__eq__(self, lhs, rhs, expected): + assert (lhs == rhs) == expected diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_modimport.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_modimport.py new file mode 100644 index 00000000000..2ab86bf7af1 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_modimport.py @@ -0,0 +1,25 @@ +import py +import subprocess +import sys +import pytest +import _pytest + +MODSET = [ + x for x in py.path.local(_pytest.__file__).dirpath().visit('*.py') + if x.purebasename != '__init__' +] + + +@pytest.mark.parametrize('modfile', MODSET, ids=lambda x: x.purebasename) +def test_fileimport(modfile): + # this test ensures all internal packages can import + # without needing the pytest namespace being set + # this is critical for the initialization of xdist + + res = subprocess.call([ + sys.executable, + '-c', 'import sys, py; py.path.local(sys.argv[1]).pyimport()', + modfile.strpath, + ]) + if res: + pytest.fail("command result %s" % res) diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_monkeypatch.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_monkeypatch.py similarity index 94% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_monkeypatch.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_monkeypatch.py index 048c942c867..4427908ab3b 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_monkeypatch.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_monkeypatch.py @@ -1,25 +1,23 @@ +from __future__ import absolute_import, division, print_function import os import sys import textwrap import pytest -from _pytest.monkeypatch import monkeypatch as MonkeyPatch +from _pytest.monkeypatch import MonkeyPatch -def pytest_funcarg__mp(request): +@pytest.fixture +def mp(): cwd = os.getcwd() sys_path = list(sys.path) - - def cleanup(): - sys.path[:] = sys_path - os.chdir(cwd) - - request.addfinalizer(cleanup) - return MonkeyPatch() + yield MonkeyPatch() + sys.path[:] = sys_path + os.chdir(cwd) def test_setattr(): - class A: + class A(object): x = 1 monkeypatch = MonkeyPatch() @@ -42,7 +40,7 @@ def test_setattr(): assert A.x == 5 -class TestSetattrWithImportPath: +class TestSetattrWithImportPath(object): def test_string_expression(self, monkeypatch): monkeypatch.setattr("os.path.abspath", lambda x: "hello2") assert os.path.abspath("123") == "hello2" @@ -82,7 +80,7 @@ class TestSetattrWithImportPath: def test_delattr(): - class A: + class A(object): x = 1 monkeypatch = MonkeyPatch() @@ -205,7 +203,7 @@ def test_setenv_prepend(): def test_monkeypatch_plugin(testdir): reprec = testdir.inline_runsource(""" def test_method(monkeypatch): - assert monkeypatch.__class__.__name__ == "monkeypatch" + assert monkeypatch.__class__.__name__ == "MonkeyPatch" """) res = reprec.countoutcomes() assert tuple(res) == (1, 0, 0), res @@ -297,7 +295,7 @@ class SampleNewInherit(SampleNew): pass -class SampleOld: +class SampleOld(object): # oldstyle on python2 @staticmethod def hello(): @@ -321,10 +319,11 @@ def test_issue156_undo_staticmethod(Sample): monkeypatch.undo() assert Sample.hello() + def test_issue1338_name_resolving(): pytest.importorskip('requests') monkeypatch = MonkeyPatch() try: - monkeypatch.delattr('requests.sessions.Session.request') + monkeypatch.delattr('requests.sessions.Session.request') finally: - monkeypatch.undo() \ No newline at end of file + monkeypatch.undo() diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_nodes.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_nodes.py new file mode 100644 index 00000000000..6f4540f99b9 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_nodes.py @@ -0,0 +1,18 @@ +import pytest + +from _pytest import nodes + + +@pytest.mark.parametrize("baseid, nodeid, expected", ( + ('', '', True), + ('', 'foo', True), + ('', 'foo/bar', True), + ('', 'foo/bar::TestBaz::()', True), + ('foo', 'food', False), + ('foo/bar::TestBaz::()', 'foo/bar', False), + ('foo/bar::TestBaz::()', 'foo/bar::TestBop::()', False), + ('foo/bar', 'foo/bar::TestBop::()', True), +)) +def test_ischildnode(baseid, nodeid, expected): + result = nodes.ischildnode(baseid, nodeid) + assert result is expected diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_nose.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_nose.py similarity index 87% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_nose.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_nose.py index a5162381e47..df3e1a94b05 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_nose.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_nose.py @@ -1,22 +1,25 @@ +from __future__ import absolute_import, division, print_function import pytest + def setup_module(mod): mod.nose = pytest.importorskip("nose") + def test_nose_setup(testdir): p = testdir.makepyfile(""" - l = [] + values = [] from nose.tools import with_setup - @with_setup(lambda: l.append(1), lambda: l.append(2)) + @with_setup(lambda: values.append(1), lambda: values.append(2)) def test_hello(): - assert l == [1] + assert values == [1] def test_world(): - assert l == [1,2] + assert values == [1,2] - test_hello.setup = lambda: l.append(1) - test_hello.teardown = lambda: l.append(2) + test_hello.setup = lambda: values.append(1) + test_hello.teardown = lambda: values.append(2) """) result = testdir.runpytest(p, '-p', 'nose') result.assert_outcomes(passed=2) @@ -24,43 +27,48 @@ def test_nose_setup(testdir): def test_setup_func_with_setup_decorator(): from _pytest.nose import call_optional - l = [] - class A: + values = [] + + class A(object): @pytest.fixture(autouse=True) def f(self): - l.append(1) + values.append(1) + call_optional(A(), "f") - assert not l + assert not values def test_setup_func_not_callable(): from _pytest.nose import call_optional - class A: + + class A(object): f = 1 + call_optional(A(), "f") + def test_nose_setup_func(testdir): p = testdir.makepyfile(""" from nose.tools import with_setup - l = [] + values = [] def my_setup(): a = 1 - l.append(a) + values.append(a) def my_teardown(): b = 2 - l.append(b) + values.append(b) @with_setup(my_setup, my_teardown) def test_hello(): - print (l) - assert l == [1] + print (values) + assert values == [1] def test_world(): - print (l) - assert l == [1,2] + print (values) + assert values == [1,2] """) result = testdir.runpytest(p, '-p', 'nose') @@ -71,18 +79,18 @@ def test_nose_setup_func_failure(testdir): p = testdir.makepyfile(""" from nose.tools import with_setup - l = [] + values = [] my_setup = lambda x: 1 my_teardown = lambda x: 2 @with_setup(my_setup, my_teardown) def test_hello(): - print (l) - assert l == [1] + print (values) + assert values == [1] def test_world(): - print (l) - assert l == [1,2] + print (values) + assert values == [1,2] """) result = testdir.runpytest(p, '-p', 'nose') @@ -93,13 +101,13 @@ def test_nose_setup_func_failure(testdir): def test_nose_setup_func_failure_2(testdir): testdir.makepyfile(""" - l = [] + values = [] my_setup = 1 my_teardown = 2 def test_hello(): - assert l == [] + assert values == [] test_hello.setup = my_setup test_hello.teardown = my_teardown @@ -107,31 +115,32 @@ def test_nose_setup_func_failure_2(testdir): reprec = testdir.inline_run() reprec.assertoutcome(passed=1) + def test_nose_setup_partial(testdir): pytest.importorskip("functools") p = testdir.makepyfile(""" from functools import partial - l = [] + values = [] def my_setup(x): a = x - l.append(a) + values.append(a) def my_teardown(x): b = x - l.append(b) + values.append(b) my_setup_partial = partial(my_setup, 1) my_teardown_partial = partial(my_teardown, 2) def test_hello(): - print (l) - assert l == [1] + print (values) + assert values == [1] def test_world(): - print (l) - assert l == [1,2] + print (values) + assert values == [1,2] test_hello.setup = my_setup_partial test_hello.teardown = my_teardown_partial @@ -242,31 +251,32 @@ def test_module_level_setup(testdir): def test_nose_style_setup_teardown(testdir): testdir.makepyfile(""" - l = [] + values = [] def setup_module(): - l.append(1) + values.append(1) def teardown_module(): - del l[0] + del values[0] def test_hello(): - assert l == [1] + assert values == [1] def test_world(): - assert l == [1] + assert values == [1] """) result = testdir.runpytest('-p', 'nose') result.stdout.fnmatch_lines([ "*2 passed*", ]) + def test_nose_setup_ordering(testdir): testdir.makepyfile(""" def setup_module(mod): mod.visited = True - class TestClass: + class TestClass(object): def setup(self): assert visited def test_first(self): @@ -300,6 +310,7 @@ def test_apiwrapper_problem_issue260(testdir): result = testdir.runpytest() result.assert_outcomes(passed=1) + def test_setup_teardown_linking_issue265(testdir): # we accidentally didnt integrate nose setupstate with normal setupstate # this test ensures that won't happen again @@ -347,6 +358,7 @@ def test_SkipTest_in_test(testdir): reprec = testdir.inline_run() reprec.assertoutcome(skipped=1) + def test_istest_function_decorator(testdir): p = testdir.makepyfile(""" import nose.tools @@ -357,6 +369,7 @@ def test_istest_function_decorator(testdir): result = testdir.runpytest(p) result.assert_outcomes(passed=1) + def test_nottest_function_decorator(testdir): testdir.makepyfile(""" import nose.tools @@ -369,22 +382,24 @@ def test_nottest_function_decorator(testdir): calls = reprec.getreports("pytest_runtest_logreport") assert not calls + def test_istest_class_decorator(testdir): p = testdir.makepyfile(""" import nose.tools @nose.tools.istest - class NotTestPrefix: + class NotTestPrefix(object): def test_method(self): pass """) result = testdir.runpytest(p) result.assert_outcomes(passed=1) + def test_nottest_class_decorator(testdir): testdir.makepyfile(""" import nose.tools @nose.tools.nottest - class TestPrefix: + class TestPrefix(object): def test_method(self): pass """) diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_parseopt.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_parseopt.py similarity index 80% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_parseopt.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_parseopt.py index e45ee285409..92159257019 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_parseopt.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_parseopt.py @@ -1,14 +1,17 @@ -from __future__ import with_statement +from __future__ import absolute_import, division, print_function import sys import os -import py, pytest +import py +import pytest from _pytest import config as parseopt + @pytest.fixture def parser(): return parseopt.Parser() -class TestParser: + +class TestParser(object): def test_no_help_by_default(self, capsys): parser = parseopt.Parser(usage="xyz") pytest.raises(SystemExit, lambda: parser.parse(["-h"])) @@ -29,17 +32,21 @@ class TestParser: assert argument.dest == 'test' argument = parseopt.Argument('-t', '--test', dest='abc') assert argument.dest == 'abc' + assert str(argument) == ( + "Argument(_short_opts: ['-t'], _long_opts: ['--test'], dest: 'abc')" + ) def test_argument_type(self): - argument = parseopt.Argument('-t', dest='abc', type='int') + argument = parseopt.Argument('-t', dest='abc', type=int) assert argument.type is int - argument = parseopt.Argument('-t', dest='abc', type='string') + argument = parseopt.Argument('-t', dest='abc', type=str) assert argument.type is str argument = parseopt.Argument('-t', dest='abc', type=float) assert argument.type is float - with pytest.raises(KeyError): - argument = parseopt.Argument('-t', dest='abc', type='choice') - argument = parseopt.Argument('-t', dest='abc', type='choice', + with pytest.warns(DeprecationWarning): + with pytest.raises(KeyError): + argument = parseopt.Argument('-t', dest='abc', type='choice') + argument = parseopt.Argument('-t', dest='abc', type=str, choices=['red', 'blue']) assert argument.type is str @@ -77,6 +84,13 @@ class TestParser: assert len(group.options) == 1 assert isinstance(group.options[0], parseopt.Argument) + def test_group_addoption_conflict(self): + group = parseopt.OptionGroup("hello again") + group.addoption("--option1", "--option-1", action="store_true") + with pytest.raises(ValueError) as err: + group.addoption("--option1", "--option-one", action="store_true") + assert str(set(["--option1"])) in str(err.value) + def test_group_shortopt_lowercase(self, parser): group = parser.getgroup("hello") pytest.raises(ValueError, """ @@ -128,7 +142,10 @@ class TestParser: def test_parse_setoption(self, parser): parser.addoption("--hello", dest="hello", action="store") parser.addoption("--world", dest="world", default=42) - class A: pass + + class A(object): + pass + option = A() args = parser.parse_setoption(['--hello', 'world'], option) assert option.hello == "world" @@ -147,12 +164,12 @@ class TestParser: assert getattr(args, parseopt.FILE_OR_DIR) == ['4', '2'] args = parser.parse(['-R', '-S', '4', '2', '-R']) assert getattr(args, parseopt.FILE_OR_DIR) == ['4', '2'] - assert args.R == True - assert args.S == False + assert args.R is True + assert args.S is False args = parser.parse(['-R', '4', '-S', '2']) assert getattr(args, parseopt.FILE_OR_DIR) == ['4', '2'] - assert args.R == True - assert args.S == False + assert args.R is True + assert args.S is False def test_parse_defaultgetter(self): def defaultget(option): @@ -163,8 +180,8 @@ class TestParser: elif option.type is str: option.default = "world" parser = parseopt.Parser(processopt=defaultget) - parser.addoption("--this", dest="this", type="int", action="store") - parser.addoption("--hello", dest="hello", type="string", action="store") + parser.addoption("--this", dest="this", type=int, action="store") + parser.addoption("--hello", dest="hello", type=str, action="store") parser.addoption("--no", dest="no", action="store_true") option = parser.parse([]) assert option.hello == "world" @@ -174,7 +191,7 @@ class TestParser: def test_drop_short_helper(self): parser = py.std.argparse.ArgumentParser(formatter_class=parseopt.DropShorterLongHelpFormatter) parser.add_argument('-t', '--twoword', '--duo', '--two-word', '--two', - help='foo').map_long_option = {'two': 'two-word'} + help='foo').map_long_option = {'two': 'two-word'} # throws error on --deux only! parser.add_argument('-d', '--deuxmots', '--deux-mots', action='store_true', help='foo').map_long_option = {'deux': 'deux-mots'} @@ -224,21 +241,33 @@ class TestParser: assert args.file_or_dir == ['abcd'] def test_drop_short_help0(self, parser, capsys): - parser.addoption('--func-args', '--doit', help = 'foo', + parser.addoption('--func-args', '--doit', help='foo', action='store_true') parser.parse([]) help = parser.optparser.format_help() - assert '--func-args, --doit foo' in help + assert '--func-args, --doit foo' in help # testing would be more helpful with all help generated def test_drop_short_help1(self, parser, capsys): group = parser.getgroup("general") group.addoption('--doit', '--func-args', action='store_true', help='foo') group._addoption("-h", "--help", action="store_true", dest="help", - help="show help message and configuration info") + help="show help message and configuration info") parser.parse(['-h']) help = parser.optparser.format_help() - assert '-doit, --func-args foo' in help + assert '-doit, --func-args foo' in help + + def test_multiple_metavar_help(self, parser): + """ + Help text for options with a metavar tuple should display help + in the form "--preferences=value1 value2 value3" (#2004). + """ + group = parser.getgroup("general") + group.addoption('--preferences', metavar=('value1', 'value2', 'value3'), nargs=3) + group._addoption("-h", "--help", action="store_true", dest="help") + parser.parse(['-h']) + help = parser.optparser.format_help() + assert '--preferences=value1 value2 value3' in help def test_argcomplete(testdir, monkeypatch): @@ -246,8 +275,8 @@ def test_argcomplete(testdir, monkeypatch): pytest.skip("bash not available") script = str(testdir.tmpdir.join("test_argcomplete")) pytest_bin = sys.argv[0] - if "py.test" not in os.path.basename(pytest_bin): - pytest.skip("need to be run with py.test executable, not %s" %(pytest_bin,)) + if "pytest" not in os.path.basename(pytest_bin): + pytest.skip("need to be run with pytest executable, not %s" % (pytest_bin,)) with open(str(script), 'w') as fp: # redirect output from argcomplete to stdin and stderr is not trivial @@ -258,12 +287,12 @@ def test_argcomplete(testdir, monkeypatch): # to handle a keyword argument env that replaces os.environ in popen or # extends the copy, advantage: could not forget to restore monkeypatch.setenv('_ARGCOMPLETE', "1") - monkeypatch.setenv('_ARGCOMPLETE_IFS',"\x0b") + monkeypatch.setenv('_ARGCOMPLETE_IFS', "\x0b") monkeypatch.setenv('COMP_WORDBREAKS', ' \\t\\n"\\\'><=;|&(:') arg = '--fu' - monkeypatch.setenv('COMP_LINE', "py.test " + arg) - monkeypatch.setenv('COMP_POINT', str(len("py.test " + arg))) + monkeypatch.setenv('COMP_LINE', "pytest " + arg) + monkeypatch.setenv('COMP_POINT', str(len("pytest " + arg))) result = testdir.run('bash', str(script), arg) if result.ret == 255: # argcomplete not found @@ -271,17 +300,10 @@ def test_argcomplete(testdir, monkeypatch): elif not result.stdout.str(): pytest.skip("bash provided no output, argcomplete not available?") else: - if py.std.sys.version_info < (2,7): - result.stdout.lines = result.stdout.lines[0].split('\x0b') - result.stdout.fnmatch_lines(["--funcargs", "--fulltrace"]) - else: - result.stdout.fnmatch_lines(["--funcargs", "--fulltrace"]) - if py.std.sys.version_info < (2,7): - return + result.stdout.fnmatch_lines(["--funcargs", "--fulltrace"]) os.mkdir('test_argcomplete.d') arg = 'test_argc' - monkeypatch.setenv('COMP_LINE', "py.test " + arg) - monkeypatch.setenv('COMP_POINT', str(len('py.test ' + arg))) + monkeypatch.setenv('COMP_LINE', "pytest " + arg) + monkeypatch.setenv('COMP_POINT', str(len('pytest ' + arg))) result = testdir.run('bash', str(script), arg) result.stdout.fnmatch_lines(["test_argcomplete", "test_argcomplete.d/"]) - diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_pastebin.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_pastebin.py similarity index 93% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_pastebin.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_pastebin.py index 03570a5c70b..6b1742d1415 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_pastebin.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_pastebin.py @@ -1,8 +1,10 @@ # encoding: utf-8 +from __future__ import absolute_import, division, print_function import sys import pytest -class TestPasteCapture: + +class TestPasteCapture(object): @pytest.fixture def pastebinlist(self, monkeypatch, request): @@ -25,7 +27,7 @@ class TestPasteCapture: assert len(pastebinlist) == 1 s = pastebinlist[0] assert s.find("def test_fail") != -1 - assert reprec.countoutcomes() == [1,1,1] + assert reprec.countoutcomes() == [1, 1, 1] def test_all(self, testdir, pastebinlist): from _pytest.pytester import LineMatcher @@ -39,7 +41,7 @@ class TestPasteCapture: pytest.skip("") """) reprec = testdir.inline_run(testpath, "--pastebin=all", '-v') - assert reprec.countoutcomes() == [1,1,1] + assert reprec.countoutcomes() == [1, 1, 1] assert len(pastebinlist) == 1 contents = pastebinlist[0].decode('utf-8') matcher = LineMatcher(contents.splitlines()) @@ -71,7 +73,7 @@ class TestPasteCapture: ]) -class TestPaste: +class TestPaste(object): @pytest.fixture def pastebin(self, request): @@ -84,9 +86,11 @@ class TestPaste: function that connects to bpaste service. """ calls = [] + def mocked(url, data): calls.append((url, data)) - class DummyFile: + + class DummyFile(object): def read(self): # part of html of a normal response return b'View raw.' @@ -111,5 +115,3 @@ class TestPaste: assert 'lexer=%s' % lexer in data.decode() assert 'code=full-paste-contents' in data.decode() assert 'expiry=1week' in data.decode() - - diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_pdb.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_pdb.py similarity index 67% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_pdb.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_pdb.py index eeddcf0ae80..70a5c3c5bdb 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_pdb.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_pdb.py @@ -1,23 +1,49 @@ +from __future__ import absolute_import, division, print_function import sys +import platform import _pytest._code +import pytest def runpdb_and_get_report(testdir, source): p = testdir.makepyfile(source) result = testdir.runpytest_inprocess("--pdb", p) reports = result.reprec.getreports("pytest_runtest_logreport") - assert len(reports) == 3, reports # setup/call/teardown + assert len(reports) == 3, reports # setup/call/teardown return reports[1] -class TestPDB: - def pytest_funcarg__pdblist(self, request): - monkeypatch = request.getfuncargvalue("monkeypatch") +@pytest.fixture +def custom_pdb_calls(): + called = [] + + # install dummy debugger class and track which methods were called on it + class _CustomPdb(object): + def __init__(self, *args, **kwargs): + called.append("init") + + def reset(self): + called.append("reset") + + def interaction(self, *args): + called.append("interaction") + + _pytest._CustomPdb = _CustomPdb + return called + + +class TestPDB(object): + + @pytest.fixture + def pdblist(self, request): + monkeypatch = request.getfixturevalue("monkeypatch") pdblist = [] + def mypdb(*args): pdblist.append(args) - plugin = request.config.pluginmanager.getplugin('pdb') + + plugin = request.config.pluginmanager.getplugin('debugging') monkeypatch.setattr(plugin, 'post_mortem', mypdb) return pdblist @@ -73,9 +99,48 @@ class TestPDB: rest = child.read().decode("utf8") assert "1 failed" in rest assert "def test_1" not in rest + self.flush(child) + + @staticmethod + def flush(child): + if platform.system() == 'Darwin': + return if child.isalive(): child.wait() + def test_pdb_unittest_postmortem(self, testdir): + p1 = testdir.makepyfile(""" + import unittest + class Blub(unittest.TestCase): + def tearDown(self): + self.filename = None + def test_false(self): + self.filename = 'debug' + '.me' + assert 0 + """) + child = testdir.spawn_pytest("--pdb %s" % p1) + child.expect('(Pdb)') + child.sendline('p self.filename') + child.sendeof() + rest = child.read().decode("utf8") + assert 'debug.me' in rest + self.flush(child) + + def test_pdb_unittest_skip(self, testdir): + """Test for issue #2137""" + p1 = testdir.makepyfile(""" + import unittest + @unittest.skipIf(True, 'Skipping also with pdb active') + class MyTestCase(unittest.TestCase): + def test_one(self): + assert 0 + """) + child = testdir.spawn_pytest("-rs --pdb %s" % p1) + child.expect('Skipping also with pdb active') + child.expect('1 skipped in') + child.sendeof() + self.flush(child) + def test_pdb_interaction_capture(self, testdir): p1 = testdir.makepyfile(""" def test_1(): @@ -89,8 +154,7 @@ class TestPDB: rest = child.read().decode("utf8") assert "1 failed" in rest assert "getrekt" not in rest - if child.isalive(): - child.wait() + self.flush(child) def test_pdb_interaction_exception(self, testdir): p1 = testdir.makepyfile(""" @@ -108,8 +172,7 @@ class TestPDB: child.expect(".*function") child.sendeof() child.expect("1 failed") - if child.isalive(): - child.wait() + self.flush(child) def test_pdb_interaction_on_collection_issue181(self, testdir): p1 = testdir.makepyfile(""" @@ -117,12 +180,11 @@ class TestPDB: xxx """) child = testdir.spawn_pytest("--pdb %s" % p1) - #child.expect(".*import pytest.*") + # child.expect(".*import pytest.*") child.expect("(Pdb)") child.sendeof() child.expect("1 error") - if child.isalive(): - child.wait() + self.flush(child) def test_pdb_interaction_on_internal_error(self, testdir): testdir.makeconftest(""" @@ -131,11 +193,10 @@ class TestPDB: """) p1 = testdir.makepyfile("def test_func(): pass") child = testdir.spawn_pytest("--pdb %s" % p1) - #child.expect(".*import pytest.*") + # child.expect(".*import pytest.*") child.expect("(Pdb)") child.sendeof() - if child.isalive(): - child.wait() + self.flush(child) def test_pdb_interaction_capturing_simple(self, testdir): p1 = testdir.makepyfile(""" @@ -154,9 +215,8 @@ class TestPDB: rest = child.read().decode("utf-8") assert "1 failed" in rest assert "def test_1" in rest - assert "hello17" in rest # out is captured - if child.isalive(): - child.wait() + assert "hello17" in rest # out is captured + self.flush(child) def test_pdb_set_trace_interception(self, testdir): p1 = testdir.makepyfile(""" @@ -171,8 +231,7 @@ class TestPDB: rest = child.read().decode("utf8") assert "1 failed" in rest assert "reading from stdin while output" not in rest - if child.isalive(): - child.wait() + self.flush(child) def test_pdb_and_capsys(self, testdir): p1 = testdir.makepyfile(""" @@ -187,8 +246,7 @@ class TestPDB: child.expect("hello1") child.sendeof() child.read() - if child.isalive(): - child.wait() + self.flush(child) def test_set_trace_capturing_afterwards(self, testdir): p1 = testdir.makepyfile(""" @@ -207,8 +265,7 @@ class TestPDB: child.expect("hello") child.sendeof() child.read() - if child.isalive(): - child.wait() + self.flush(child) def test_pdb_interaction_doctest(self, testdir): p1 = testdir.makepyfile(""" @@ -227,8 +284,7 @@ class TestPDB: child.sendeof() rest = child.read().decode("utf8") assert "1 failed" in rest - if child.isalive(): - child.wait() + self.flush(child) def test_pdb_interaction_capturing_twice(self, testdir): p1 = testdir.makepyfile(""" @@ -252,10 +308,9 @@ class TestPDB: rest = child.read().decode("utf8") assert "1 failed" in rest assert "def test_1" in rest - assert "hello17" in rest # out is captured - assert "hello18" in rest # out is captured - if child.isalive(): - child.wait() + assert "hello17" in rest # out is captured + assert "hello18" in rest # out is captured + self.flush(child) def test_pdb_used_outside_test(self, testdir): p1 = testdir.makepyfile(""" @@ -263,10 +318,10 @@ class TestPDB: pytest.set_trace() x = 5 """) - child = testdir.spawn("%s %s" %(sys.executable, p1)) + child = testdir.spawn("%s %s" % (sys.executable, p1)) child.expect("x = 5") child.sendeof() - child.wait() + self.flush(child) def test_pdb_used_in_generate_tests(self, testdir): p1 = testdir.makepyfile(""" @@ -280,7 +335,7 @@ class TestPDB: child = testdir.spawn_pytest(str(p1)) child.expect("x = 5") child.sendeof() - child.wait() + self.flush(child) def test_pdb_collection_failure_is_shown(self, testdir): p1 = testdir.makepyfile("""xxx """) @@ -309,5 +364,43 @@ class TestPDB: child.expect("enter_pdb_hook") child.send('c\n') child.sendeof() + self.flush(child) + + def test_pdb_custom_cls(self, testdir, custom_pdb_calls): + p1 = testdir.makepyfile("""xxx """) + result = testdir.runpytest_inprocess( + "--pdb", "--pdbcls=_pytest:_CustomPdb", p1) + result.stdout.fnmatch_lines([ + "*NameError*xxx*", + "*1 error*", + ]) + assert custom_pdb_calls == ["init", "reset", "interaction"] + + def test_pdb_custom_cls_without_pdb(self, testdir, custom_pdb_calls): + p1 = testdir.makepyfile("""xxx """) + result = testdir.runpytest_inprocess( + "--pdbcls=_pytest:_CustomPdb", p1) + result.stdout.fnmatch_lines([ + "*NameError*xxx*", + "*1 error*", + ]) + assert custom_pdb_calls == [] + + def test_pdb_custom_cls_with_settrace(self, testdir, monkeypatch): + testdir.makepyfile(custom_pdb=""" + class CustomPdb(object): + def set_trace(*args, **kwargs): + print 'custom set_trace>' + """) + p1 = testdir.makepyfile(""" + import pytest + + def test_foo(): + pytest.set_trace() + """) + monkeypatch.setenv('PYTHONPATH', str(testdir.tmpdir)) + child = testdir.spawn_pytest("--pdbcls=custom_pdb:CustomPdb %s" % str(p1)) + + child.expect('custom set_trace>') if child.isalive(): child.wait() diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_pluginmanager.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_pluginmanager.py similarity index 78% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_pluginmanager.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_pluginmanager.py index 36847638d48..6192176e8a8 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_pluginmanager.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_pluginmanager.py @@ -1,15 +1,19 @@ +# encoding: UTF-8 +from __future__ import absolute_import, division, print_function import pytest import py import os from _pytest.config import get_config, PytestPluginManager -from _pytest.main import EXIT_NOTESTSCOLLECTED +from _pytest.main import EXIT_NOTESTSCOLLECTED, Session + @pytest.fixture def pytestpm(): return PytestPluginManager() -class TestPytestPluginInteractions: + +class TestPytestPluginInteractions(object): def test_addhooks_conftestplugin(self, testdir): testdir.makepyfile(newhooks=""" def pytest_myhook(xyz): @@ -26,9 +30,9 @@ class TestPytestPluginInteractions: config = get_config() pm = config.pluginmanager pm.hook.pytest_addhooks.call_historic( - kwargs=dict(pluginmanager=config.pluginmanager)) + kwargs=dict(pluginmanager=config.pluginmanager)) config.pluginmanager._importconftest(conf) - #print(config.pluginmanager.get_plugins()) + # print(config.pluginmanager.get_plugins()) res = config.hook.pytest_myhook(xyz=10) assert res == [11] @@ -81,46 +85,50 @@ class TestPytestPluginInteractions: def test_configure(self, testdir): config = testdir.parseconfig() - l = [] - class A: + values = [] + + class A(object): def pytest_configure(self, config): - l.append(self) + values.append(self) config.pluginmanager.register(A()) - assert len(l) == 0 + assert len(values) == 0 config._do_configure() - assert len(l) == 1 + assert len(values) == 1 config.pluginmanager.register(A()) # leads to a configured() plugin - assert len(l) == 2 - assert l[0] != l[1] + assert len(values) == 2 + assert values[0] != values[1] config._ensure_unconfigure() config.pluginmanager.register(A()) - assert len(l) == 2 + assert len(values) == 2 def test_hook_tracing(self): pytestpm = get_config().pluginmanager # fully initialized with plugins saveindent = [] - class api1: + + class api1(object): def pytest_plugin_registered(self): saveindent.append(pytestpm.trace.root.indent) - class api2: + + class api2(object): def pytest_plugin_registered(self): saveindent.append(pytestpm.trace.root.indent) raise ValueError() - l = [] - pytestpm.trace.root.setwriter(l.append) + + values = [] + pytestpm.trace.root.setwriter(values.append) undo = pytestpm.enable_tracing() try: indent = pytestpm.trace.root.indent p = api1() pytestpm.register(p) assert pytestpm.trace.root.indent == indent - assert len(l) >= 2 - assert 'pytest_plugin_registered' in l[0] - assert 'finish' in l[1] + assert len(values) >= 2 + assert 'pytest_plugin_registered' in values[0] + assert 'finish' in values[1] - l[:] = [] + values[:] = [] with pytest.raises(ValueError): pytestpm.register(api2()) assert pytestpm.trace.root.indent == indent @@ -128,31 +136,33 @@ class TestPytestPluginInteractions: finally: undo() - def test_warn_on_deprecated_multicall(self, pytestpm): - warnings = [] + def test_hook_proxy(self, testdir): + """Test the gethookproxy function(#2016)""" + config = testdir.parseconfig() + session = Session(config) + testdir.makepyfile(**{ + 'tests/conftest.py': '', + 'tests/subdir/conftest.py': '', + }) - class get_warnings: - def pytest_logwarning(self, message): - warnings.append(message) + conftest1 = testdir.tmpdir.join('tests/conftest.py') + conftest2 = testdir.tmpdir.join('tests/subdir/conftest.py') - class Plugin: - def pytest_configure(self, __multicall__): - pass - - pytestpm.register(get_warnings()) - before = list(warnings) - pytestpm.register(Plugin()) - assert len(warnings) == len(before) + 1 - assert "deprecated" in warnings[-1] + config.pluginmanager._importconftest(conftest1) + ihook_a = session.gethookproxy(testdir.tmpdir.join('tests')) + assert ihook_a is not None + config.pluginmanager._importconftest(conftest2) + ihook_b = session.gethookproxy(testdir.tmpdir.join('tests')) + assert ihook_a is not ihook_b def test_warn_on_deprecated_addhooks(self, pytestpm): warnings = [] - class get_warnings: + class get_warnings(object): def pytest_logwarning(self, code, fslocation, message, nodeid): warnings.append(message) - class Plugin: + class Plugin(object): def pytest_testhook(): pass @@ -171,6 +181,7 @@ def test_namespace_has_default_and_env_plugins(testdir): result = testdir.runpython(p) assert result.ret == 0 + def test_default_markers(testdir): result = testdir.runpytest("--markers") result.stdout.fnmatch_lines([ @@ -179,30 +190,40 @@ def test_default_markers(testdir): ]) -def test_importplugin_issue375(testdir, pytestpm): +def test_importplugin_error_message(testdir, pytestpm): """Don't hide import errors when importing plugins and provide an easy to debug message. + + See #375 and #1998. """ testdir.syspathinsert(testdir.tmpdir) - testdir.makepyfile(qwe="import aaaa") + testdir.makepyfile(qwe=""" + # encoding: UTF-8 + def test_traceback(): + raise ImportError(u'Not possible to import: ☺') + test_traceback() + """) with pytest.raises(ImportError) as excinfo: pytestpm.import_plugin("qwe") - expected = '.*Error importing plugin "qwe": No module named \'?aaaa\'?' - assert py.std.re.match(expected, str(excinfo.value)) + + expected_message = '.*Error importing plugin "qwe": Not possible to import: .' + expected_traceback = ".*in test_traceback" + assert py.std.re.match(expected_message, str(excinfo.value)) + assert py.std.re.match(expected_traceback, str(excinfo.traceback[-1])) -class TestPytestPluginManager: +class TestPytestPluginManager(object): def test_register_imported_modules(self): pm = PytestPluginManager() mod = py.std.types.ModuleType("x.y.pytest_hello") pm.register(mod) assert pm.is_registered(mod) - l = pm.get_plugins() - assert mod in l + values = pm.get_plugins() + assert mod in values pytest.raises(ValueError, "pm.register(mod)") pytest.raises(ValueError, lambda: pm.register(mod)) - #assert not pm.is_registered(mod2) - assert pm.get_plugins() == l + # assert not pm.is_registered(mod2) + assert pm.get_plugins() == values def test_canonical_import(self, monkeypatch): mod = py.std.types.ModuleType("pytest_xyz") @@ -228,7 +249,7 @@ class TestPytestPluginManager: mod.pytest_plugins = "pytest_a" aplugin = testdir.makepyfile(pytest_a="#") reprec = testdir.make_hook_recorder(pytestpm) - #syspath.prepend(aplugin.dirpath()) + # syspath.prepend(aplugin.dirpath()) py.std.sys.path.insert(0, str(aplugin.dirpath())) pytestpm.consider_module(mod) call = reprec.getcall(pytestpm.hook.pytest_plugin_registered.name) @@ -236,8 +257,8 @@ class TestPytestPluginManager: # check that it is not registered twice pytestpm.consider_module(mod) - l = reprec.getcalls("pytest_plugin_registered") - assert len(l) == 1 + values = reprec.getcalls("pytest_plugin_registered") + assert len(values) == 1 def test_consider_env_fails_to_import(self, monkeypatch, pytestpm): monkeypatch.setenv('PYTEST_PLUGINS', 'nonexisting', prepend=",") @@ -254,8 +275,8 @@ class TestPytestPluginManager: result = testdir.runpytest("-rw", "-p", "skipping1", syspathinsert=True) assert result.ret == EXIT_NOTESTSCOLLECTED result.stdout.fnmatch_lines([ - "WI1*skipped plugin*skipping1*hello*", - "WI1*skipped plugin*skipping2*hello*", + "*skipped plugin*skipping1*hello*", + "*skipped plugin*skipping2*hello*", ]) def test_consider_env_plugin_instantiation(self, testdir, monkeypatch, pytestpm): @@ -318,10 +339,10 @@ class TestPytestPluginManager: pytestpm.consider_conftest(mod) -class TestPytestPluginManagerBootstrapming: +class TestPytestPluginManagerBootstrapming(object): def test_preparse_args(self, pytestpm): pytest.raises(ImportError, lambda: - pytestpm.consider_preparse(["xyz", "-p", "hello123"])) + pytestpm.consider_preparse(["xyz", "-p", "hello123"])) def test_plugin_prevent_register(self, pytestpm): pytestpm.consider_preparse(["xyz", "-p", "no:abc"]) diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_pytester.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_pytester.py similarity index 81% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_pytester.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_pytester.py index 65660afdfe3..9508c2954e8 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_pytester.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_pytester.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import, division, print_function import pytest import os from _pytest.pytester import HookRecorder @@ -11,7 +13,8 @@ def test_make_hook_recorder(testdir): assert not recorder.getfailures() pytest.xfail("internal reportrecorder tests need refactoring") - class rep: + + class rep(object): excinfo = None passed = False failed = True @@ -24,7 +27,7 @@ def test_make_hook_recorder(testdir): failures = recorder.getfailures() assert failures == [rep] - class rep: + class rep(object): excinfo = None passed = False failed = False @@ -62,6 +65,7 @@ def test_parseconfig(testdir): assert config2 != config1 assert config1 != pytest.config + def test_testdir_runs_with_plugin(testdir): testdir.makepyfile(""" pytest_plugins = "pytester" @@ -73,17 +77,21 @@ def test_testdir_runs_with_plugin(testdir): def make_holder(): - class apiclass: + class apiclass(object): def pytest_xyz(self, arg): "x" + def pytest_xyz_noarg(self): "x" apimod = type(os)('api') + def pytest_xyz(arg): "x" + def pytest_xyz_noarg(): "x" + apimod.pytest_xyz = pytest_xyz apimod.pytest_xyz_noarg = pytest_xyz_noarg return apiclass, apimod @@ -112,6 +120,17 @@ def test_makepyfile_unicode(testdir): unichr = chr testdir.makepyfile(unichr(0xfffd)) + +def test_makepyfile_utf8(testdir): + """Ensure makepyfile accepts utf-8 bytes as input (#2738)""" + utf8_contents = u""" + def setup_function(function): + mixed_encoding = u'São Paulo' + """.encode('utf-8') + p = testdir.makepyfile(utf8_contents) + assert u"mixed_encoding = u'São Paulo'".encode('utf-8') in p.read('rb') + + def test_inline_run_clean_modules(testdir): test_mod = testdir.makepyfile("def test_foo(): assert True") result = testdir.inline_run(str(test_mod)) @@ -120,3 +139,11 @@ def test_inline_run_clean_modules(testdir): test_mod.write("def test_foo(): assert False") result2 = testdir.inline_run(str(test_mod)) assert result2.ret == EXIT_TESTSFAILED + + +def test_assert_outcomes_after_pytest_erro(testdir): + testdir.makepyfile("def test_foo(): assert True") + + result = testdir.runpytest('--unexpected-argument') + with pytest.raises(ValueError, message="Pytest terminal report not found"): + result.assert_outcomes(passed=0) diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_recwarn.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_recwarn.py similarity index 54% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_recwarn.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_recwarn.py index 87e5846c2b0..31e70460fe4 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_recwarn.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_recwarn.py @@ -1,5 +1,8 @@ +from __future__ import absolute_import, division, print_function import warnings +import re import py + import pytest from _pytest.recwarn import WarningsRecorder @@ -7,25 +10,19 @@ from _pytest.recwarn import WarningsRecorder def test_recwarn_functional(testdir): reprec = testdir.inline_runsource(""" import warnings - oldwarn = warnings.showwarning def test_method(recwarn): - assert warnings.showwarning != oldwarn warnings.warn("hello") warn = recwarn.pop() assert isinstance(warn.message, UserWarning) - def test_finalized(): - assert warnings.showwarning == oldwarn """) res = reprec.countoutcomes() - assert tuple(res) == (2, 0, 0), res + assert tuple(res) == (1, 0, 0), res class TestWarningsRecorderChecker(object): - def test_recording(self, recwarn): - showwarning = py.std.warnings.showwarning + def test_recording(self): rec = WarningsRecorder() with rec: - assert py.std.warnings.showwarning != showwarning assert not rec.list py.std.warnings.warn_explicit("hello", UserWarning, "xyz", 13) assert len(rec.list) == 1 @@ -33,14 +30,12 @@ class TestWarningsRecorderChecker(object): assert len(rec.list) == 2 warn = rec.pop() assert str(warn.message) == "hello" - l = rec.list + values = rec.list rec.clear() assert len(rec.list) == 0 - assert l is rec.list + assert values is rec.list pytest.raises(AssertionError, "rec.pop()") - assert showwarning == py.std.warnings.showwarning - def test_typechecking(self): from _pytest.recwarn import WarningsChecker with pytest.raises(TypeError): @@ -81,7 +76,7 @@ class TestDeprecatedCall(object): def test_deprecated_call_raises(self): with pytest.raises(AssertionError) as excinfo: pytest.deprecated_call(self.dep, 3, 5) - assert str(excinfo).find("did not produce") != -1 + assert 'Did not produce' in str(excinfo) def test_deprecated_call(self): pytest.deprecated_call(self.dep, 0, 5) @@ -110,50 +105,70 @@ class TestDeprecatedCall(object): pytest.deprecated_call(self.dep_explicit, 0) pytest.deprecated_call(self.dep_explicit, 0) - def test_deprecated_call_as_context_manager_no_warning(self): - with pytest.raises(pytest.fail.Exception) as ex: - with pytest.deprecated_call(): - self.dep(1) - assert str(ex.value) == "DID NOT WARN" - - def test_deprecated_call_as_context_manager(self): - with pytest.deprecated_call(): - self.dep(0) - - def test_deprecated_call_pending(self): + @pytest.mark.parametrize('mode', ['context_manager', 'call']) + def test_deprecated_call_no_warning(self, mode): + """Ensure deprecated_call() raises the expected failure when its block/function does + not raise a deprecation warning. + """ def f(): - py.std.warnings.warn(PendingDeprecationWarning("hi")) - pytest.deprecated_call(f) + pass + + msg = 'Did not produce DeprecationWarning or PendingDeprecationWarning' + with pytest.raises(AssertionError, matches=msg): + if mode == 'call': + pytest.deprecated_call(f) + else: + with pytest.deprecated_call(): + f() + + @pytest.mark.parametrize('warning_type', [PendingDeprecationWarning, DeprecationWarning]) + @pytest.mark.parametrize('mode', ['context_manager', 'call']) + @pytest.mark.parametrize('call_f_first', [True, False]) + @pytest.mark.filterwarnings('ignore') + def test_deprecated_call_modes(self, warning_type, mode, call_f_first): + """Ensure deprecated_call() captures a deprecation warning as expected inside its + block/function. + """ + def f(): + warnings.warn(warning_type("hi")) + return 10 + + # ensure deprecated_call() can capture the warning even if it has already been triggered + if call_f_first: + assert f() == 10 + if mode == 'call': + assert pytest.deprecated_call(f) == 10 + else: + with pytest.deprecated_call(): + assert f() == 10 + + @pytest.mark.parametrize('mode', ['context_manager', 'call']) + def test_deprecated_call_exception_is_raised(self, mode): + """If the block of the code being tested by deprecated_call() raises an exception, + it must raise the exception undisturbed. + """ + def f(): + raise ValueError('some exception') + + with pytest.raises(ValueError, match='some exception'): + if mode == 'call': + pytest.deprecated_call(f) + else: + with pytest.deprecated_call(): + f() def test_deprecated_call_specificity(self): other_warnings = [Warning, UserWarning, SyntaxWarning, RuntimeWarning, FutureWarning, ImportWarning, UnicodeWarning] for warning in other_warnings: def f(): - py.std.warnings.warn(warning("hi")) + warnings.warn(warning("hi")) + with pytest.raises(AssertionError): pytest.deprecated_call(f) - - def test_deprecated_function_already_called(self, testdir): - """deprecated_call should be able to catch a call to a deprecated - function even if that function has already been called in the same - module. See #1190. - """ - testdir.makepyfile(""" - import warnings - import pytest - - def deprecated_function(): - warnings.warn("deprecated", DeprecationWarning) - - def test_one(): - deprecated_function() - - def test_two(): - pytest.deprecated_call(deprecated_function) - """) - result = testdir.runpytest() - result.stdout.fnmatch_lines('*=== 2 passed in *===') + with pytest.raises(AssertionError): + with pytest.deprecated_call(): + f() class TestWarns(object): @@ -185,17 +200,38 @@ class TestWarns(object): with pytest.warns(RuntimeWarning): warnings.warn("runtime", RuntimeWarning) - with pytest.raises(pytest.fail.Exception): - with pytest.warns(RuntimeWarning): - warnings.warn("user", UserWarning) - - with pytest.raises(pytest.fail.Exception): - with pytest.warns(UserWarning): - warnings.warn("runtime", RuntimeWarning) - with pytest.warns(UserWarning): warnings.warn("user", UserWarning) + with pytest.raises(pytest.fail.Exception) as excinfo: + with pytest.warns(RuntimeWarning): + warnings.warn("user", UserWarning) + excinfo.match(r"DID NOT WARN. No warnings of type \(.+RuntimeWarning.+,\) was emitted. " + r"The list of emitted warnings is: \[UserWarning\('user',\)\].") + + with pytest.raises(pytest.fail.Exception) as excinfo: + with pytest.warns(UserWarning): + warnings.warn("runtime", RuntimeWarning) + excinfo.match(r"DID NOT WARN. No warnings of type \(.+UserWarning.+,\) was emitted. " + r"The list of emitted warnings is: \[RuntimeWarning\('runtime',\)\].") + + with pytest.raises(pytest.fail.Exception) as excinfo: + with pytest.warns(UserWarning): + pass + excinfo.match(r"DID NOT WARN. No warnings of type \(.+UserWarning.+,\) was emitted. " + r"The list of emitted warnings is: \[\].") + + warning_classes = (UserWarning, FutureWarning) + with pytest.raises(pytest.fail.Exception) as excinfo: + with pytest.warns(warning_classes) as warninfo: + warnings.warn("runtime", RuntimeWarning) + warnings.warn("import", ImportWarning) + + message_template = ("DID NOT WARN. No warnings of type {0} was emitted. " + "The list of emitted warnings is: {1}.") + excinfo.match(re.escape(message_template.format(warning_classes, + [each.message for each in warninfo]))) + def test_record(self): with pytest.warns(UserWarning) as record: warnings.warn("user", UserWarning) @@ -212,6 +248,29 @@ class TestWarns(object): assert str(record[0].message) == "user" assert str(record[1].message) == "runtime" + def test_record_by_subclass(self): + with pytest.warns(Warning) as record: + warnings.warn("user", UserWarning) + warnings.warn("runtime", RuntimeWarning) + + assert len(record) == 2 + assert str(record[0].message) == "user" + assert str(record[1].message) == "runtime" + + class MyUserWarning(UserWarning): + pass + + class MyRuntimeWarning(RuntimeWarning): + pass + + with pytest.warns((UserWarning, RuntimeWarning)) as record: + warnings.warn("user", MyUserWarning) + warnings.warn("runtime", MyRuntimeWarning) + + assert len(record) == 2 + assert str(record[0].message) == "user" + assert str(record[1].message) == "runtime" + def test_double_test(self, testdir): """If a test is run again, the warning should still be raised""" testdir.makepyfile(''' @@ -225,3 +284,27 @@ class TestWarns(object): ''') result = testdir.runpytest() result.stdout.fnmatch_lines(['*2 passed in*']) + + def test_match_regex(self): + with pytest.warns(UserWarning, match=r'must be \d+$'): + warnings.warn("value must be 42", UserWarning) + + with pytest.raises(pytest.fail.Exception): + with pytest.warns(UserWarning, match=r'must be \d+$'): + warnings.warn("this is not here", UserWarning) + + with pytest.raises(pytest.fail.Exception): + with pytest.warns(FutureWarning, match=r'must be \d+$'): + warnings.warn("value must be 42", UserWarning) + + def test_one_from_multiple_warns(self): + with pytest.warns(UserWarning, match=r'aaa'): + warnings.warn("cccccccccc", UserWarning) + warnings.warn("bbbbbbbbbb", UserWarning) + warnings.warn("aaaaaaaaaa", UserWarning) + + def test_none_of_multiple_warns(self): + with pytest.raises(pytest.fail.Exception): + with pytest.warns(UserWarning, match=r'aaa'): + warnings.warn("bbbbbbbbbb", UserWarning) + warnings.warn("cccccccccc", UserWarning) diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_resultlog.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_resultlog.py similarity index 90% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_resultlog.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_resultlog.py index 74d13f64330..b7dd2687cdf 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_resultlog.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_resultlog.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import, division, print_function import os import _pytest._code @@ -5,7 +6,7 @@ import py import pytest from _pytest.main import Node, Item, FSCollector from _pytest.resultlog import generic_path, ResultLog, \ - pytest_configure, pytest_unconfigure + pytest_configure, pytest_unconfigure def test_generic_path(testdir): @@ -13,10 +14,10 @@ def test_generic_path(testdir): config = testdir.parseconfig() session = Session(config) p1 = Node('a', config=config, session=session) - #assert p1.fspath is None + # assert p1.fspath is None p2 = Node('B', parent=p1) - p3 = Node('()', parent = p2) - item = Item('c', parent = p3) + p3 = Node('()', parent=p2) + item = Item('c', parent=p3) res = generic_path(item) assert res == 'a.B().c' @@ -24,13 +25,14 @@ def test_generic_path(testdir): p0 = FSCollector('proj/test', config=config, session=session) p1 = FSCollector('proj/test/a', parent=p0) p2 = Node('B', parent=p1) - p3 = Node('()', parent = p2) + p3 = Node('()', parent=p2) p4 = Node('c', parent=p3) - item = Item('[1]', parent = p4) + item = Item('[1]', parent=p4) res = generic_path(item) assert res == 'test/a:B().c[1]' + def test_write_log_entry(): reslog = ResultLog(None, None) reslog.logfile = py.io.TextIO() @@ -67,10 +69,10 @@ def test_write_log_entry(): entry_lines = entry.splitlines() assert len(entry_lines) == 5 assert entry_lines[0] == 'F name' - assert entry_lines[1:] == [' '+line for line in longrepr.splitlines()] + assert entry_lines[1:] == [' ' + line for line in longrepr.splitlines()] -class TestWithFunctionIntegration: +class TestWithFunctionIntegration(object): # XXX (hpk) i think that the resultlog plugin should # provide a Parser object so that one can remain # ignorant regarding formatting details. @@ -83,19 +85,10 @@ class TestWithFunctionIntegration: def test_collection_report(self, testdir): ok = testdir.makepyfile(test_collection_ok="") - skip = testdir.makepyfile(test_collection_skip= - "import pytest ; pytest.skip('hello')") fail = testdir.makepyfile(test_collection_fail="XXX") lines = self.getresultlog(testdir, ok) assert not lines - lines = self.getresultlog(testdir, skip) - assert len(lines) == 2 - assert lines[0].startswith("S ") - assert lines[0].endswith("test_collection_skip.py") - assert lines[1].startswith(" ") - assert lines[1].endswith("test_collection_skip.py:1: Skipped: hello") - lines = self.getresultlog(testdir, fail) assert lines assert lines[0].startswith("F ") @@ -152,7 +145,7 @@ class TestWithFunctionIntegration: assert entry_lines[0].startswith('! ') if style != "native": - assert os.path.basename(__file__)[:-9] in entry_lines[0] #.pyc/class + assert os.path.basename(__file__)[:-9] in entry_lines[0] # .pyc/class assert entry_lines[-1][0] == ' ' assert 'ValueError' in entry @@ -184,6 +177,7 @@ def test_generic(testdir, LineMatcher): "x *:test_xfail_norun", ]) + def test_makedir_for_resultlog(testdir, LineMatcher): """--resultlog should automatically create directories for the log file""" testdir.plugins.append("resultlog") @@ -231,6 +225,4 @@ def test_failure_issue380(testdir): pass """) result = testdir.runpytest("--resultlog=log") - assert result.ret == 1 - - + assert result.ret == 2 diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_runner.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_runner.py similarity index 70% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_runner.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_runner.py index 4421c5d0d29..c8e2a6463a0 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_runner.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_runner.py @@ -1,23 +1,24 @@ # -*- coding: utf-8 -*- -from __future__ import with_statement +from __future__ import absolute_import, division, print_function import _pytest._code import os import py import pytest import sys -from _pytest import runner, main +from _pytest import runner, main, outcomes -class TestSetupState: + +class TestSetupState(object): def test_setup(self, testdir): ss = runner.SetupState() item = testdir.getitem("def test_func(): pass") - l = [1] + values = [1] ss.prepare(item) - ss.addfinalizer(l.pop, colitem=item) - assert l + ss.addfinalizer(values.pop, colitem=item) + assert values ss._pop_and_teardown() - assert not l + assert not values def test_teardown_exact_stack_empty(self, testdir): item = testdir.getitem("def test_func(): pass") @@ -31,16 +32,23 @@ class TestSetupState: def setup_module(mod): raise ValueError(42) def test_func(): pass - """) # noqa + """) # noqa ss = runner.SetupState() pytest.raises(ValueError, lambda: ss.prepare(item)) pytest.raises(ValueError, lambda: ss.prepare(item)) def test_teardown_multiple_one_fails(self, testdir): r = [] - def fin1(): r.append('fin1') - def fin2(): raise Exception('oops') - def fin3(): r.append('fin3') + + def fin1(): + r.append('fin1') + + def fin2(): + raise Exception('oops') + + def fin3(): + r.append('fin3') + item = testdir.getitem("def test_func(): pass") ss = runner.SetupState() ss.addfinalizer(fin1, item) @@ -54,8 +62,12 @@ class TestSetupState: def test_teardown_multiple_fail(self, testdir): # Ensure the first exception is the one which is re-raised. # Ideally both would be reported however. - def fin1(): raise Exception('oops1') - def fin2(): raise Exception('oops2') + def fin1(): + raise Exception('oops1') + + def fin2(): + raise Exception('oops2') + item = testdir.getitem("def test_func(): pass") ss = runner.SetupState() ss.addfinalizer(fin1, item) @@ -65,7 +77,7 @@ class TestSetupState: assert err.value.args == ('oops2',) -class BaseFunctionalTests: +class BaseFunctionalTests(object): def test_passfunction(self, testdir): reports = testdir.runitem(""" def test_func(): @@ -88,7 +100,7 @@ class BaseFunctionalTests: assert rep.failed assert rep.when == "call" assert rep.outcome == "failed" - #assert isinstance(rep.longrepr, ReprExceptionInfo) + # assert isinstance(rep.longrepr, ReprExceptionInfo) def test_skipfunction(self, testdir): reports = testdir.runitem(""" @@ -101,12 +113,12 @@ class BaseFunctionalTests: assert not rep.passed assert rep.skipped assert rep.outcome == "skipped" - #assert rep.skipped.when == "call" - #assert rep.skipped.when == "call" - #assert rep.skipped == "%sreason == "hello" - #assert rep.skipped.location.lineno == 3 - #assert rep.skipped.location.path - #assert not rep.skipped.failurerepr + # assert rep.skipped.when == "call" + # assert rep.skipped.when == "call" + # assert rep.skipped == "%sreason == "hello" + # assert rep.skipped.location.lineno == 3 + # assert rep.skipped.location.path + # assert not rep.skipped.failurerepr def test_skip_in_setup_function(self, testdir): reports = testdir.runitem(""" @@ -121,11 +133,11 @@ class BaseFunctionalTests: assert not rep.failed assert not rep.passed assert rep.skipped - #assert rep.skipped.reason == "hello" - #assert rep.skipped.location.lineno == 3 - #assert rep.skipped.location.lineno == 3 + # assert rep.skipped.reason == "hello" + # assert rep.skipped.location.lineno == 3 + # assert rep.skipped.location.lineno == 3 assert len(reports) == 2 - assert reports[1].passed # teardown + assert reports[1].passed # teardown def test_failure_in_setup_function(self, testdir): reports = testdir.runitem(""" @@ -157,8 +169,8 @@ class BaseFunctionalTests: assert not rep.passed assert rep.failed assert rep.when == "teardown" - #assert rep.longrepr.reprcrash.lineno == 3 - #assert rep.longrepr.reprtraceback.reprentries + # assert rep.longrepr.reprcrash.lineno == 3 + # assert rep.longrepr.reprtraceback.reprentries def test_custom_failure_repr(self, testdir): testdir.makepyfile(conftest=""" @@ -176,10 +188,10 @@ class BaseFunctionalTests: assert not rep.skipped assert not rep.passed assert rep.failed - #assert rep.outcome.when == "call" - #assert rep.failed.where.lineno == 3 - #assert rep.failed.where.path.basename == "test_func.py" - #assert rep.failed.failurerepr == "hello" + # assert rep.outcome.when == "call" + # assert rep.failed.where.lineno == 3 + # assert rep.failed.where.path.basename == "test_func.py" + # assert rep.failed.failurerepr == "hello" def test_teardown_final_returncode(self, testdir): rec = testdir.inline_runsource(""" @@ -194,7 +206,7 @@ class BaseFunctionalTests: rec = testdir.inline_runsource(""" import pytest - class TestClass: + class TestClass(object): def test_method(self): pass def teardown_class(cls): @@ -214,20 +226,54 @@ class BaseFunctionalTests: raise ValueError(42) """) reps = rec.getreports("pytest_runtest_logreport") - print (reps) + print(reps) for i in range(2): assert reps[i].nodeid.endswith("test_method") assert reps[i].passed assert reps[2].when == "teardown" assert reps[2].failed assert len(reps) == 6 - for i in range(3,5): + for i in range(3, 5): assert reps[i].nodeid.endswith("test_func") assert reps[i].passed assert reps[5].when == "teardown" assert reps[5].nodeid.endswith("test_func") assert reps[5].failed + def test_exact_teardown_issue1206(self, testdir): + """issue shadowing error with wrong number of arguments on teardown_method.""" + rec = testdir.inline_runsource(""" + import pytest + + class TestClass(object): + def teardown_method(self, x, y, z): + pass + + def test_method(self): + assert True + """) + reps = rec.getreports("pytest_runtest_logreport") + print(reps) + assert len(reps) == 3 + # + assert reps[0].nodeid.endswith("test_method") + assert reps[0].passed + assert reps[0].when == 'setup' + # + assert reps[1].nodeid.endswith("test_method") + assert reps[1].passed + assert reps[1].when == 'call' + # + assert reps[2].nodeid.endswith("test_method") + assert reps[2].failed + assert reps[2].when == "teardown" + assert reps[2].longrepr.reprcrash.message in ( + # python3 error + "TypeError: teardown_method() missing 2 required positional arguments: 'y' and 'z'", + # python2 error + 'TypeError: teardown_method() takes exactly 4 arguments (2 given)' + ) + def test_failure_in_setup_function_ignores_custom_repr(self, testdir): testdir.makepyfile(conftest=""" import pytest @@ -247,10 +293,10 @@ class BaseFunctionalTests: assert not rep.skipped assert not rep.passed assert rep.failed - #assert rep.outcome.when == "setup" - #assert rep.outcome.where.lineno == 3 - #assert rep.outcome.where.path.basename == "test_func.py" - #assert instanace(rep.failed.failurerepr, PythonFailureRepr) + # assert rep.outcome.when == "setup" + # assert rep.outcome.where.lineno == 3 + # assert rep.outcome.where.path.basename == "test_func.py" + # assert instanace(rep.failed.failurerepr, PythonFailureRepr) def test_systemexit_does_not_bail_out(self, testdir): try: @@ -276,6 +322,7 @@ class BaseFunctionalTests: else: pytest.fail("did not raise") + class TestExecutionNonForked(BaseFunctionalTests): def getrunner(self): def f(item): @@ -293,6 +340,7 @@ class TestExecutionNonForked(BaseFunctionalTests): else: pytest.fail("did not raise") + class TestExecutionForked(BaseFunctionalTests): pytestmark = pytest.mark.skipif("not hasattr(os, 'fork')") @@ -311,12 +359,13 @@ class TestExecutionForked(BaseFunctionalTests): assert rep.failed assert rep.when == "???" -class TestSessionReports: + +class TestSessionReports(object): def test_collect_result(self, testdir): col = testdir.getmodulecol(""" def test_func1(): pass - class TestClass: + class TestClass(object): pass """) rep = runner.collect_one_node(col) @@ -332,18 +381,6 @@ class TestSessionReports: assert res[0].name == "test_func1" assert res[1].name == "TestClass" - def test_skip_at_module_scope(self, testdir): - col = testdir.getmodulecol(""" - import pytest - pytest.skip("hello") - def test_func(): - pass - """) - rep = main.collect_one_node(col) - assert not rep.failed - assert not rep.passed - assert rep.skipped - reporttypes = [ runner.BaseReport, @@ -352,6 +389,7 @@ reporttypes = [ runner.CollectReport, ] + @pytest.mark.parametrize('reporttype', reporttypes, ids=[x.__name__ for x in reporttypes]) def test_report_extra_parameters(reporttype): if hasattr(py.std.inspect, 'signature'): @@ -362,12 +400,13 @@ def test_report_extra_parameters(reporttype): report = reporttype(newthing=1, **basekw) assert report.newthing == 1 + def test_callinfo(): ci = runner.CallInfo(lambda: 0, '123') assert ci.when == "123" assert ci.result == 0 assert "result" in repr(ci) - ci = runner.CallInfo(lambda: 0/0, '123') + ci = runner.CallInfo(lambda: 0 / 0, '123') assert ci.when == "123" assert not hasattr(ci, 'result') assert ci.excinfo @@ -375,16 +414,20 @@ def test_callinfo(): # design question: do we want general hooks in python files? # then something like the following functional tests makes sense + + @pytest.mark.xfail def test_runtest_in_module_ordering(testdir): p1 = testdir.makepyfile(""" + import pytest def pytest_runtest_setup(item): # runs after class-level! item.function.mylist.append("module") - class TestClass: + class TestClass(object): def pytest_runtest_setup(self, item): assert not hasattr(item.function, 'mylist') item.function.mylist = ['class'] - def pytest_funcarg__mylist(self, request): + @pytest.fixture + def mylist(self, request): return request.function.mylist def pytest_runtest_call(self, item, __multicall__): try: @@ -406,9 +449,18 @@ def test_runtest_in_module_ordering(testdir): def test_outcomeexception_exceptionattributes(): - outcome = runner.OutcomeException('test') + outcome = outcomes.OutcomeException('test') assert outcome.args[0] == outcome.msg + +def test_outcomeexception_passes_except_Exception(): + with pytest.raises(outcomes.OutcomeException): + try: + raise outcomes.OutcomeException('test') + except Exception: + pass + + def test_pytest_exit(): try: pytest.exit("hello") @@ -416,6 +468,7 @@ def test_pytest_exit(): excinfo = _pytest._code.ExceptionInfo() assert excinfo.errisinstance(KeyboardInterrupt) + def test_pytest_fail(): try: pytest.fail("hello") @@ -424,6 +477,20 @@ def test_pytest_fail(): s = excinfo.exconly(tryshort=True) assert s.startswith("Failed") + +def test_pytest_exit_msg(testdir): + testdir.makeconftest(""" + import pytest + + def pytest_configure(config): + pytest.exit('oh noes') + """) + result = testdir.runpytest() + result.stderr.fnmatch_lines([ + "Exit: oh noes", + ]) + + def test_pytest_fail_notrace(testdir): testdir.makepyfile(""" import pytest @@ -471,12 +538,12 @@ def test_pytest_no_tests_collected_exit_status(testdir): assert 1 """) result = testdir.runpytest() - result.stdout.fnmatch_lines('*collected 1 items*') + result.stdout.fnmatch_lines('*collected 1 item*') result.stdout.fnmatch_lines('*1 passed*') assert result.ret == main.EXIT_OK result = testdir.runpytest('-k nonmatch') - result.stdout.fnmatch_lines('*collected 1 items*') + result.stdout.fnmatch_lines('*collected 1 item*') result.stdout.fnmatch_lines('*1 deselected*') assert result.ret == main.EXIT_NOTESTSCOLLECTED @@ -489,15 +556,18 @@ def test_exception_printing_skip(): s = excinfo.exconly(tryshort=True) assert s.startswith("Skipped") + def test_importorskip(monkeypatch): importorskip = pytest.importorskip + def f(): importorskip("asdlkj") + try: sys = importorskip("sys") # noqa assert sys == py.std.sys - #path = pytest.importorskip("os.path") - #assert path == py.std.os.path + # path = pytest.importorskip("os.path") + # assert path == py.std.os.path excinfo = pytest.raises(pytest.skip.Exception, f) path = py.path.local(excinfo.getrepr().reprcrash.path) # check that importorskip reports the actual call @@ -517,10 +587,12 @@ def test_importorskip(monkeypatch): print(_pytest._code.ExceptionInfo()) pytest.fail("spurious skip") + def test_importorskip_imports_last_module_part(): ospath = pytest.importorskip("os.path") assert os.path == ospath + def test_importorskip_dev_module(monkeypatch): try: mod = py.std.types.ModuleType("mockmodule") @@ -535,6 +607,19 @@ def test_importorskip_dev_module(monkeypatch): pytest.fail("spurious skip") +def test_importorskip_module_level(testdir): + """importorskip must be able to skip entire modules when used at module level""" + testdir.makepyfile(''' + import pytest + foobarbaz = pytest.importorskip("foobarbaz") + + def test_foo(): + pass + ''') + result = testdir.runpytest() + result.stdout.fnmatch_lines(['*collected 0 items / 1 skipped*']) + + def test_pytest_cmdline_main(testdir): p = testdir.makepyfile(""" import pytest @@ -552,12 +637,14 @@ def test_pytest_cmdline_main(testdir): def test_unicode_in_longrepr(testdir): testdir.makeconftest(""" - import py - def pytest_runtest_makereport(__multicall__): - rep = __multicall__.execute() + # -*- coding: utf-8 -*- + import pytest + @pytest.hookimpl(hookwrapper=True) + def pytest_runtest_makereport(): + outcome = yield + rep = outcome.get_result() if rep.when == "call": - rep.longrepr = py.builtin._totext("\\xc3\\xa4", "utf8") - return rep + rep.longrepr = u'ä' """) testdir.makepyfile(""" def test_out(): @@ -594,11 +681,13 @@ def test_makereport_getsource_dynamic_code(testdir, monkeypatch): """Test that exception in dynamically generated code doesn't break getting the source line.""" import inspect original_findsource = inspect.findsource + def findsource(obj, *args, **kwargs): # Can be triggered by dynamically created functions if obj.__name__ == 'foo': raise IndexError() return original_findsource(obj, *args, **kwargs) + monkeypatch.setattr(inspect, 'findsource', findsource) testdir.makepyfile(""" @@ -621,7 +710,9 @@ def test_store_except_info_on_eror(): sys.last_traceback and friends. """ # Simulate item that raises a specific exception - class ItemThatRaises: + class ItemThatRaises(object): + nodeid = 'item_that_raises' + def runtest(self): raise IndexError('TEST') try: @@ -632,3 +723,91 @@ def test_store_except_info_on_eror(): assert sys.last_type is IndexError assert sys.last_value.args[0] == 'TEST' assert sys.last_traceback + + +def test_current_test_env_var(testdir, monkeypatch): + pytest_current_test_vars = [] + monkeypatch.setattr(sys, 'pytest_current_test_vars', pytest_current_test_vars, raising=False) + testdir.makepyfile(''' + import pytest + import sys + import os + + @pytest.fixture + def fix(): + sys.pytest_current_test_vars.append(('setup', os.environ['PYTEST_CURRENT_TEST'])) + yield + sys.pytest_current_test_vars.append(('teardown', os.environ['PYTEST_CURRENT_TEST'])) + + def test(fix): + sys.pytest_current_test_vars.append(('call', os.environ['PYTEST_CURRENT_TEST'])) + ''') + result = testdir.runpytest_inprocess() + assert result.ret == 0 + test_id = 'test_current_test_env_var.py::test' + assert pytest_current_test_vars == [ + ('setup', test_id + ' (setup)'), ('call', test_id + ' (call)'), ('teardown', test_id + ' (teardown)')] + assert 'PYTEST_CURRENT_TEST' not in os.environ + + +class TestReportContents(object): + """ + Test user-level API of ``TestReport`` objects. + """ + + def getrunner(self): + return lambda item: runner.runtestprotocol(item, log=False) + + def test_longreprtext_pass(self, testdir): + reports = testdir.runitem(""" + def test_func(): + pass + """) + rep = reports[1] + assert rep.longreprtext == '' + + def test_longreprtext_failure(self, testdir): + reports = testdir.runitem(""" + def test_func(): + x = 1 + assert x == 4 + """) + rep = reports[1] + assert 'assert 1 == 4' in rep.longreprtext + + def test_captured_text(self, testdir): + reports = testdir.runitem(""" + import pytest + import sys + + @pytest.fixture + def fix(): + sys.stdout.write('setup: stdout\\n') + sys.stderr.write('setup: stderr\\n') + yield + sys.stdout.write('teardown: stdout\\n') + sys.stderr.write('teardown: stderr\\n') + assert 0 + + def test_func(fix): + sys.stdout.write('call: stdout\\n') + sys.stderr.write('call: stderr\\n') + assert 0 + """) + setup, call, teardown = reports + assert setup.capstdout == 'setup: stdout\n' + assert call.capstdout == 'setup: stdout\ncall: stdout\n' + assert teardown.capstdout == 'setup: stdout\ncall: stdout\nteardown: stdout\n' + + assert setup.capstderr == 'setup: stderr\n' + assert call.capstderr == 'setup: stderr\ncall: stderr\n' + assert teardown.capstderr == 'setup: stderr\ncall: stderr\nteardown: stderr\n' + + def test_no_captured_text(self, testdir): + reports = testdir.runitem(""" + def test_func(): + pass + """) + rep = reports[1] + assert rep.capstdout == '' + assert rep.capstderr == '' diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_runner_xunit.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_runner_xunit.py similarity index 75% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_runner_xunit.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_runner_xunit.py index f32a1311ba8..fc931f86720 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_runner_xunit.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_runner_xunit.py @@ -1,6 +1,10 @@ -# -# test correct setup/teardowns at -# module, class, and instance level +""" + test correct setup/teardowns at + module, class, and instance level +""" +from __future__ import absolute_import, division, print_function +import pytest + def test_module_and_function_setup(testdir): reprec = testdir.inline_runsource(""" @@ -22,7 +26,7 @@ def test_module_and_function_setup(testdir): assert modlevel[0] == 42 assert test_modlevel.answer == 17 - class TestFromClass: + class TestFromClass(object): def test_module(self): assert modlevel[0] == 42 assert not hasattr(test_modlevel, 'answer') @@ -32,22 +36,24 @@ def test_module_and_function_setup(testdir): rep = reprec.matchreport("test_module") assert rep.passed + def test_module_setup_failure_no_teardown(testdir): reprec = testdir.inline_runsource(""" - l = [] + values = [] def setup_module(module): - l.append(1) + values.append(1) 0/0 def test_nothing(): pass def teardown_module(module): - l.append(2) + values.append(2) """) reprec.assertoutcome(failed=1) calls = reprec.getcalls("pytest_runtest_setup") - assert calls[0].item.module.l == [1] + assert calls[0].item.module.values == [1] + def test_setup_function_failure_no_teardown(testdir): reprec = testdir.inline_runsource(""" @@ -65,9 +71,10 @@ def test_setup_function_failure_no_teardown(testdir): calls = reprec.getcalls("pytest_runtest_setup") assert calls[0].item.module.modlevel == [1] + def test_class_setup(testdir): reprec = testdir.inline_runsource(""" - class TestSimpleClassSetup: + class TestSimpleClassSetup(object): clslevel = [] def setup_class(cls): cls.clslevel.append(23) @@ -86,11 +93,12 @@ def test_class_setup(testdir): assert not TestSimpleClassSetup.clslevel assert not TestInheritedClassSetupStillWorks.clslevel """) - reprec.assertoutcome(passed=1+2+1) + reprec.assertoutcome(passed=1 + 2 + 1) + def test_class_setup_failure_no_teardown(testdir): reprec = testdir.inline_runsource(""" - class TestSimpleClassSetup: + class TestSimpleClassSetup(object): clslevel = [] def setup_class(cls): 0/0 @@ -106,9 +114,10 @@ def test_class_setup_failure_no_teardown(testdir): """) reprec.assertoutcome(failed=1, passed=1) + def test_method_setup(testdir): reprec = testdir.inline_runsource(""" - class TestSetupMethod: + class TestSetupMethod(object): def setup_method(self, meth): self.methsetup = meth def teardown_method(self, meth): @@ -122,9 +131,10 @@ def test_method_setup(testdir): """) reprec.assertoutcome(passed=2) + def test_method_setup_failure_no_teardown(testdir): reprec = testdir.inline_runsource(""" - class TestMethodSetup: + class TestMethodSetup(object): clslevel = [] def setup_method(self, method): self.clslevel.append(1) @@ -141,9 +151,10 @@ def test_method_setup_failure_no_teardown(testdir): """) reprec.assertoutcome(failed=1, passed=1) + def test_method_generator_setup(testdir): reprec = testdir.inline_runsource(""" - class TestSetupTeardownOnInstance: + class TestSetupTeardownOnInstance(object): def setup_class(cls): cls.classsetup = True @@ -163,6 +174,7 @@ def test_method_generator_setup(testdir): """) reprec.assertoutcome(passed=1, failed=1) + def test_func_generator_setup(testdir): reprec = testdir.inline_runsource(""" import sys @@ -191,9 +203,10 @@ def test_func_generator_setup(testdir): rep = reprec.matchreport("test_one", names="pytest_runtest_logreport") assert rep.passed + def test_method_setup_uses_fresh_instances(testdir): reprec = testdir.inline_runsource(""" - class TestSelfState1: + class TestSelfState1(object): memory = [] def test_hello(self): self.memory.append(self) @@ -203,6 +216,7 @@ def test_method_setup_uses_fresh_instances(testdir): """) reprec.assertoutcome(passed=2, failed=0) + def test_setup_that_skips_calledagain(testdir): p = testdir.makepyfile(""" import pytest @@ -216,6 +230,7 @@ def test_setup_that_skips_calledagain(testdir): reprec = testdir.inline_run(p) reprec.assertoutcome(skipped=2) + def test_setup_fails_again_on_all_tests(testdir): p = testdir.makepyfile(""" import pytest @@ -229,12 +244,14 @@ def test_setup_fails_again_on_all_tests(testdir): reprec = testdir.inline_run(p) reprec.assertoutcome(failed=2) + def test_setup_funcarg_setup_when_outer_scope_fails(testdir): p = testdir.makepyfile(""" import pytest def setup_module(mod): raise ValueError(42) - def pytest_funcarg__hello(request): + @pytest.fixture + def hello(request): raise ValueError("xyz43") def test_function1(hello): pass @@ -250,3 +267,53 @@ def test_setup_funcarg_setup_when_outer_scope_fails(testdir): "*2 error*" ]) assert "xyz43" not in result.stdout.str() + + +@pytest.mark.parametrize('arg', ['', 'arg']) +def test_setup_teardown_function_level_with_optional_argument(testdir, monkeypatch, arg): + """parameter to setup/teardown xunit-style functions parameter is now optional (#1728).""" + import sys + trace_setups_teardowns = [] + monkeypatch.setattr(sys, 'trace_setups_teardowns', trace_setups_teardowns, raising=False) + p = testdir.makepyfile(""" + import pytest + import sys + + trace = sys.trace_setups_teardowns.append + + def setup_module({arg}): trace('setup_module') + def teardown_module({arg}): trace('teardown_module') + + def setup_function({arg}): trace('setup_function') + def teardown_function({arg}): trace('teardown_function') + + def test_function_1(): pass + def test_function_2(): pass + + class Test(object): + def setup_method(self, {arg}): trace('setup_method') + def teardown_method(self, {arg}): trace('teardown_method') + + def test_method_1(self): pass + def test_method_2(self): pass + """.format(arg=arg)) + result = testdir.inline_run(p) + result.assertoutcome(passed=4) + + expected = [ + 'setup_module', + + 'setup_function', + 'teardown_function', + 'setup_function', + 'teardown_function', + + 'setup_method', + 'teardown_method', + + 'setup_method', + 'teardown_method', + + 'teardown_module', + ] + assert trace_setups_teardowns == expected diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_session.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_session.py similarity index 82% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_session.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_session.py index 76f804b4f99..9ec13f523e6 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_session.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_session.py @@ -1,8 +1,10 @@ +from __future__ import absolute_import, division, print_function import pytest from _pytest.main import EXIT_NOTESTSCOLLECTED -class SessionTests: + +class SessionTests(object): def test_basic_testitem_events(self, testdir): tfile = testdir.makepyfile(""" def test_one(): @@ -11,7 +13,7 @@ class SessionTests: assert 0 def test_other(): raise ValueError(23) - class TestClass: + class TestClass(object): def test_two(self, someargs): pass """) @@ -20,15 +22,18 @@ class SessionTests: assert len(skipped) == 0 assert len(passed) == 1 assert len(failed) == 3 - end = lambda x: x.nodeid.split("::")[-1] + + def end(x): + return x.nodeid.split("::")[-1] + assert end(failed[0]) == "test_one_one" assert end(failed[1]) == "test_other" itemstarted = reprec.getcalls("pytest_itemcollected") assert len(itemstarted) == 4 # XXX check for failing funcarg setup - #colreports = reprec.getcalls("pytest_collectreport") - #assert len(colreports) == 4 - #assert colreports[1].report.failed + # colreports = reprec.getcalls("pytest_collectreport") + # assert len(colreports) == 4 + # assert colreports[1].report.failed def test_nested_import_error(self, testdir): tfile = testdir.makepyfile(""" @@ -40,9 +45,9 @@ class SessionTests: a = 1 """) reprec = testdir.inline_run(tfile) - l = reprec.getfailedcollections() - assert len(l) == 1 - out = l[0].longrepr.reprcrash.message + values = reprec.getfailedcollections() + assert len(values) == 1 + out = str(values[0].longrepr) assert out.find('does_not_work') != -1 def test_raises_output(self, testdir): @@ -70,9 +75,9 @@ class SessionTests: def test_syntax_error_module(self, testdir): reprec = testdir.inline_runsource("this is really not python") - l = reprec.getfailedcollections() - assert len(l) == 1 - out = str(l[0].longrepr) + values = reprec.getfailedcollections() + assert len(values) == 1 + out = str(values[0].longrepr) assert out.find(str('not python')) != -1 def test_exit_first_problem(self, testdir): @@ -97,12 +102,12 @@ class SessionTests: def test_broken_repr(self, testdir): p = testdir.makepyfile(""" import pytest - class BrokenRepr1: + class BrokenRepr1(object): foo=0 def __repr__(self): raise Exception("Ha Ha fooled you, I'm a broken repr().") - class TestBrokenClass: + class TestBrokenClass(object): def test_explicit_bad_repr(self): t = BrokenRepr1() pytest.raises(Exception, 'repr(t)') @@ -116,7 +121,7 @@ class SessionTests: passed, skipped, failed = reprec.listoutcomes() assert len(failed) == 1 out = failed[0].longrepr.reprcrash.message - assert out.find("""[Exception("Ha Ha fooled you, I'm a broken repr().") raised in repr()]""") != -1 #' + assert out.find("""[Exception("Ha Ha fooled you, I'm a broken repr().") raised in repr()]""") != -1 # ' def test_skip_file_by_conftest(self, testdir): testdir.makepyfile(conftest=""" @@ -134,19 +139,20 @@ class SessionTests: assert len(reports) == 1 assert reports[0].skipped + class TestNewSession(SessionTests): def test_order_of_execution(self, testdir): reprec = testdir.inline_runsource(""" - l = [] + values = [] def test_1(): - l.append(1) + values.append(1) def test_2(): - l.append(2) + values.append(2) def test_3(): - assert l == [1,2] - class Testmygroup: - reslist = l + assert values == [1,2] + class Testmygroup(object): + reslist = values def test_1(self): self.reslist.append(1) def test_2(self): @@ -167,17 +173,13 @@ class TestNewSession(SessionTests): def test_one(): raise ValueError() - class TestX: + class TestX(object): def test_method_one(self): pass class TestY(TestX): pass """, - test_two=""" - import pytest - pytest.skip('xxx') - """, test_three="xxxdsadsadsadsa", __init__="" ) @@ -189,11 +191,9 @@ class TestNewSession(SessionTests): started = reprec.getcalls("pytest_collectstart") finished = reprec.getreports("pytest_collectreport") assert len(started) == len(finished) - assert len(started) == 8 # XXX extra TopCollector + assert len(started) == 7 # XXX extra TopCollector colfail = [x for x in finished if x.failed] - colskipped = [x for x in finished if x.skipped] assert len(colfail) == 1 - assert len(colskipped) == 1 def test_minus_x_import_error(self, testdir): testdir.makepyfile(__init__="") @@ -203,14 +203,23 @@ class TestNewSession(SessionTests): colfail = [x for x in finished if x.failed] assert len(colfail) == 1 + def test_minus_x_overridden_by_maxfail(self, testdir): + testdir.makepyfile(__init__="") + testdir.makepyfile(test_one="xxxx", test_two="yyyy", test_third="zzz") + reprec = testdir.inline_run("-x", "--maxfail=2", testdir.tmpdir) + finished = reprec.getreports("pytest_collectreport") + colfail = [x for x in finished if x.failed] + assert len(colfail) == 2 + def test_plugin_specify(testdir): pytest.raises(ImportError, """ testdir.parseconfig("-p", "nqweotexistent") """) - #pytest.raises(ImportError, + # pytest.raises(ImportError, # "config.do_configure(config)" - #) + # ) + def test_plugin_already_exists(testdir): config = testdir.parseconfig("-p", "terminal") @@ -218,6 +227,7 @@ def test_plugin_already_exists(testdir): config._do_configure() config._ensure_unconfigure() + def test_exclude(testdir): hellodir = testdir.mkdir("hello") hellodir.join("test_hello.py").write("x y syntaxerror") @@ -228,16 +238,17 @@ def test_exclude(testdir): assert result.ret == 0 result.stdout.fnmatch_lines(["*1 passed*"]) + def test_sessionfinish_with_start(testdir): testdir.makeconftest(""" import os - l = [] + values = [] def pytest_sessionstart(): - l.append(os.getcwd()) + values.append(os.getcwd()) os.chdir("..") def pytest_sessionfinish(): - assert l[0] == os.getcwd() + assert values[0] == os.getcwd() """) res = testdir.runpytest("--collect-only") diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_skipping.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_skipping.py similarity index 83% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_skipping.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_skipping.py index 3464974e0c2..978944876f3 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_skipping.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_skipping.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import, division, print_function import pytest import sys @@ -5,7 +6,7 @@ from _pytest.skipping import MarkEvaluator, folded_skips, pytest_runtest_setup from _pytest.runner import runtestprotocol -class TestEvaluator: +class TestEvaluator(object): def test_no_marker(self, testdir): item = testdir.getitem("def test_func(): pass") evalskipif = MarkEvaluator(item, 'skipif') @@ -79,7 +80,7 @@ class TestEvaluator: %s def test_func(): pass - """ % (lines[i], lines[(i+1) %2])) + """ % (lines[i], lines[(i + 1) % 2])) ev = MarkEvaluator(item, 'skipif') assert ev assert ev.istrue() @@ -114,7 +115,7 @@ class TestEvaluator: def test_skipif_class(self, testdir): item, = testdir.getitems(""" import pytest - class TestClass: + class TestClass(object): pytestmark = pytest.mark.skipif("config._hackxyz") def test_func(self): pass @@ -126,7 +127,7 @@ class TestEvaluator: assert expl == "condition: config._hackxyz" -class TestXFail: +class TestXFail(object): @pytest.mark.parametrize('strict', [True, False]) def test_xfail_simple(self, testdir, strict): @@ -145,7 +146,20 @@ class TestXFail: def test_xfail_xpassed(self, testdir): item = testdir.getitem(""" import pytest - @pytest.mark.xfail + @pytest.mark.xfail(reason="this is an xfail") + def test_func(): + assert 1 + """) + reports = runtestprotocol(item, log=False) + assert len(reports) == 3 + callreport = reports[1] + assert callreport.passed + assert callreport.wasxfail == "this is an xfail" + + def test_xfail_xpassed_strict(self, testdir): + item = testdir.getitem(""" + import pytest + @pytest.mark.xfail(strict=True, reason="nope") def test_func(): assert 1 """) @@ -153,7 +167,8 @@ class TestXFail: assert len(reports) == 3 callreport = reports[1] assert callreport.failed - assert callreport.wasxfail == "" + assert callreport.longrepr == "[XPASS(strict)] nope" + assert not hasattr(callreport, "wasxfail") def test_xfail_run_anyway(self, testdir): testdir.makepyfile(""" @@ -192,9 +207,9 @@ class TestXFail: assert 0 """) testdir.runpytest(p, '-v') - #result.stdout.fnmatch_lines([ + # result.stdout.fnmatch_lines([ # "*HINT*use*-r*" - #]) + # ]) def test_xfail_not_run_xfail_reporting(self, testdir): p = testdir.makepyfile(test_one=""" @@ -209,7 +224,7 @@ class TestXFail: def test_this_false(): assert 1 """) - result = testdir.runpytest(p, '--report=xfailed', ) + result = testdir.runpytest(p, '-rx', ) result.stdout.fnmatch_lines([ "*test_one*test_this*", "*NOTRUN*noway", @@ -227,7 +242,7 @@ class TestXFail: def setup_module(mod): raise ValueError(42) """) - result = testdir.runpytest(p, '--report=xfailed', ) + result = testdir.runpytest(p, '-rx', ) result.stdout.fnmatch_lines([ "*test_one*test_this*", "*NOTRUN*hello", @@ -309,7 +324,8 @@ class TestXFail: def test_dynamic_xfail_no_run(self, testdir): p = testdir.makepyfile(""" import pytest - def pytest_funcarg__arg(request): + @pytest.fixture + def arg(request): request.applymarker(pytest.mark.xfail(run=False)) def test_this(arg): assert 0 @@ -323,7 +339,8 @@ class TestXFail: def test_dynamic_xfail_set_during_funcarg_setup(self, testdir): p = testdir.makepyfile(""" import pytest - def pytest_funcarg__arg(request): + @pytest.fixture + def arg(request): request.applymarker(pytest.mark.xfail) def test_this2(arg): assert 0 @@ -333,7 +350,6 @@ class TestXFail: "*1 xfailed*", ]) - @pytest.mark.parametrize('expected, actual, matchline', [('TypeError', 'TypeError', "*1 xfailed*"), ('(AttributeError, TypeError)', 'TypeError', "*1 xfailed*"), @@ -405,6 +421,19 @@ class TestXFail: result.stdout.fnmatch_lines('*1 passed*') assert result.ret == 0 + @pytest.mark.parametrize('strict', [True, False]) + def test_xfail_condition_keyword(self, testdir, strict): + p = testdir.makepyfile(""" + import pytest + + @pytest.mark.xfail(condition=False, reason='unsupported feature', strict=%s) + def test_foo(): + pass + """ % strict) + result = testdir.runpytest(p, '-rxX') + result.stdout.fnmatch_lines('*1 passed*') + assert result.ret == 0 + @pytest.mark.parametrize('strict_val', ['true', 'false']) def test_strict_xfail_default_from_file(self, testdir, strict_val): testdir.makeini(''' @@ -423,7 +452,7 @@ class TestXFail: assert result.ret == (1 if strict else 0) -class TestXFailwithSetupTeardown: +class TestXFailwithSetupTeardown(object): def test_failing_setup_issue9(self, testdir): testdir.makepyfile(""" import pytest @@ -455,7 +484,7 @@ class TestXFailwithSetupTeardown: ]) -class TestSkip: +class TestSkip(object): def test_skip_class(self, testdir): testdir.makepyfile(""" import pytest @@ -539,14 +568,28 @@ class TestSkip: "*1 passed*2 skipped*", ]) -class TestSkipif: + def test_strict_and_skip(self, testdir): + testdir.makepyfile(""" + import pytest + @pytest.mark.skip + def test_hello(): + pass + """) + result = testdir.runpytest("-rs") + result.stdout.fnmatch_lines([ + "*unconditional skip*", + "*1 skipped*", + ]) + + +class TestSkipif(object): def test_skipif_conditional(self, testdir): item = testdir.getitem(""" import pytest @pytest.mark.skipif("hasattr(os, 'sep')") def test_func(): pass - """) # noqa + """) # noqa x = pytest.raises(pytest.skip.Exception, lambda: pytest_runtest_setup(item)) assert x.value.msg == "condition: hasattr(os, 'sep')" @@ -597,7 +640,7 @@ def test_skip_not_report_default(testdir): """) result = testdir.runpytest(p, '-v') result.stdout.fnmatch_lines([ - #"*HINT*use*-r*", + # "*HINT*use*-r*", "*1 skipped*", ]) @@ -606,7 +649,7 @@ def test_skipif_class(testdir): p = testdir.makepyfile(""" import pytest - class TestClass: + class TestClass(object): pytestmark = pytest.mark.skipif("True") def test_that(self): assert 0 @@ -620,12 +663,12 @@ def test_skipif_class(testdir): def test_skip_reasons_folding(): - path = 'xyz' + path = "xyz" lineno = 3 message = "justso" longrepr = (path, lineno, message) - class X: + class X(object): pass ev1 = X() ev1.when = "execute" @@ -633,17 +676,24 @@ def test_skip_reasons_folding(): ev1.longrepr = longrepr ev2 = X() + ev2.when = "execute" ev2.longrepr = longrepr ev2.skipped = True - l = folded_skips([ev1, ev2]) - assert len(l) == 1 - num, fspath, lineno, reason = l[0] - assert num == 2 + # ev3 might be a collection report + ev3 = X() + ev3.longrepr = longrepr + ev3.skipped = True + + values = folded_skips([ev1, ev2, ev3]) + assert len(values) == 1 + num, fspath, lineno, reason = values[0] + assert num == 3 assert fspath == path assert lineno == lineno assert reason == message + def test_skipped_reasons_functional(testdir): testdir.makepyfile( test_one=""" @@ -652,26 +702,44 @@ def test_skipped_reasons_functional(testdir): doskip() def test_func(): pass - class TestClass: + class TestClass(object): def test_method(self): doskip() """, - test_two = """ - from conftest import doskip - doskip() - """, - conftest = """ + conftest=""" import pytest def doskip(): pytest.skip('test') """ ) - result = testdir.runpytest('--report=skipped') + result = testdir.runpytest('-rs') result.stdout.fnmatch_lines([ - "*SKIP*3*conftest.py:3: test", + "*SKIP*2*conftest.py:4: test", ]) assert result.ret == 0 + +def test_skipped_folding(testdir): + testdir.makepyfile( + test_one=""" + import pytest + pytestmark = pytest.mark.skip("Folding") + def setup_function(func): + pass + def test_func(): + pass + class TestClass(object): + def test_method(self): + pass + """, + ) + result = testdir.runpytest('-rs') + result.stdout.fnmatch_lines([ + "*SKIP*2*test_one.py: Folding" + ]) + assert result.ret == 0 + + def test_reportchars(testdir): testdir.makepyfile(""" import pytest @@ -694,6 +762,7 @@ def test_reportchars(testdir): "SKIP*four*", ]) + def test_reportchars_error(testdir): testdir.makepyfile( conftest=""" @@ -709,6 +778,7 @@ def test_reportchars_error(testdir): 'ERROR*test_foo*', ]) + def test_reportchars_all(testdir): testdir.makepyfile(""" import pytest @@ -731,6 +801,7 @@ def test_reportchars_all(testdir): "XPASS*test_3*", ]) + def test_reportchars_all_error(testdir): testdir.makepyfile( conftest=""" @@ -746,6 +817,7 @@ def test_reportchars_all_error(testdir): 'ERROR*test_foo*', ]) + @pytest.mark.xfail("hasattr(sys, 'pypy_version_info')") def test_errors_in_xfail_skip_expressions(testdir): testdir.makepyfile(""" @@ -777,6 +849,7 @@ def test_errors_in_xfail_skip_expressions(testdir): "*1 pass*2 error*", ]) + def test_xfail_skipif_with_globals(testdir): testdir.makepyfile(""" import pytest @@ -795,6 +868,7 @@ def test_xfail_skipif_with_globals(testdir): "*x == 3*", ]) + def test_direct_gives_error(testdir): testdir.makepyfile(""" import pytest @@ -812,9 +886,10 @@ def test_default_markers(testdir): result = testdir.runpytest("--markers") result.stdout.fnmatch_lines([ "*skipif(*condition)*skip*", - "*xfail(*condition, reason=None, run=True, raises=None)*expected failure*", + "*xfail(*condition, reason=None, run=True, raises=None, strict=False)*expected failure*", ]) + def test_xfail_test_setup_exception(testdir): testdir.makeconftest(""" def pytest_runtest_setup(): @@ -831,6 +906,7 @@ def test_xfail_test_setup_exception(testdir): assert 'xfailed' in result.stdout.str() assert 'xpassed' not in result.stdout.str() + def test_imperativeskip_on_xfail_test(testdir): testdir.makepyfile(""" import pytest @@ -854,7 +930,8 @@ def test_imperativeskip_on_xfail_test(testdir): *2 skipped* """) -class TestBooleanCondition: + +class TestBooleanCondition(object): def test_skipif(self, testdir): testdir.makepyfile(""" import pytest @@ -915,3 +992,76 @@ def test_xfail_item(testdir): assert not failed xfailed = [r for r in skipped if hasattr(r, 'wasxfail')] assert xfailed + + +def test_module_level_skip_error(testdir): + """ + Verify that using pytest.skip at module level causes a collection error + """ + testdir.makepyfile(""" + import pytest + @pytest.skip + def test_func(): + assert True + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines( + "*Using pytest.skip outside of a test is not allowed*" + ) + + +def test_module_level_skip_with_allow_module_level(testdir): + """ + Verify that using pytest.skip(allow_module_level=True) is allowed + """ + testdir.makepyfile(""" + import pytest + pytest.skip("skip_module_level", allow_module_level=True) + + def test_func(): + assert 0 + """) + result = testdir.runpytest("-rxs") + result.stdout.fnmatch_lines( + "*SKIP*skip_module_level" + ) + + +def test_invalid_skip_keyword_parameter(testdir): + """ + Verify that using pytest.skip() with unknown parameter raises an error + """ + testdir.makepyfile(""" + import pytest + pytest.skip("skip_module_level", unknown=1) + + def test_func(): + assert 0 + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines( + "*TypeError:*['unknown']*" + ) + + +def test_mark_xfail_item(testdir): + # Ensure pytest.mark.xfail works with non-Python Item + testdir.makeconftest(""" + import pytest + + class MyItem(pytest.Item): + nodeid = 'foo' + def setup(self): + marker = pytest.mark.xfail(True, reason="Expected failure") + self.add_marker(marker) + def runtest(self): + assert False + + def pytest_collect_file(path, parent): + return MyItem("foo", parent) + """) + result = testdir.inline_run() + passed, skipped, failed = result.listoutcomes() + assert not failed + xfailed = [r for r in skipped if hasattr(r, 'wasxfail')] + assert xfailed diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_terminal.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_terminal.py similarity index 77% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_terminal.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_terminal.py index b43d6b37923..97c2f71fb66 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_terminal.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_terminal.py @@ -1,39 +1,36 @@ """ terminal reporting of the full testing process. """ +from __future__ import absolute_import, division, print_function import collections import sys -import _pytest._pluggy as pluggy +import pluggy import _pytest._code import py import pytest -from _pytest import runner from _pytest.main import EXIT_NOTESTSCOLLECTED from _pytest.terminal import TerminalReporter, repr_pythonversion, getreportopt from _pytest.terminal import build_summary_stats_line, _plugin_nameversions -def basic_run_report(item): - runner.call_and_report(item, "setup", log=False) - return runner.call_and_report(item, "call", log=False) - DistInfo = collections.namedtuple('DistInfo', ['project_name', 'version']) -class Option: +class Option(object): def __init__(self, verbose=False, fulltrace=False): self.verbose = verbose self.fulltrace = fulltrace @property def args(self): - l = [] + values = [] if self.verbose: - l.append('-v') + values.append('-v') if self.fulltrace: - l.append('--fulltrace') - return l + values.append('--fulltrace') + return values + def pytest_generate_tests(metafunc): if "option" in metafunc.fixturenames: @@ -42,7 +39,7 @@ def pytest_generate_tests(metafunc): metafunc.addcall(id="verbose", funcargs={'option': Option(verbose=True)}) metafunc.addcall(id="quiet", - funcargs={'option': Option(verbose= -1)}) + funcargs={'option': Option(verbose=-1)}) metafunc.addcall(id="fulltrace", funcargs={'option': Option(fulltrace=True)}) @@ -61,7 +58,7 @@ def test_plugin_nameversion(input, expected): assert result == expected -class TestTerminal: +class TestTerminal(object): def test_pass_skip_fail(self, testdir, option): testdir.makepyfile(""" import pytest @@ -81,8 +78,8 @@ class TestTerminal: ]) else: result.stdout.fnmatch_lines([ - "*test_pass_skip_fail.py .sF" - ]) + "*test_pass_skip_fail.py .sF*" + ]) result.stdout.fnmatch_lines([ " def test_func():", "> assert 0", @@ -114,7 +111,7 @@ class TestTerminal: item.config.pluginmanager.register(tr) location = item.reportinfo() tr.config.hook.pytest_runtest_logstart(nodeid=item.nodeid, - location=location, fspath=str(item.fspath)) + location=location, fspath=str(item.fspath)) linecomp.assert_contains_lines([ "*test_show_runtest_logstart.py*" ]) @@ -132,7 +129,7 @@ class TestTerminal: def test_itemreport_subclasses_show_subclassed_file(self, testdir): testdir.makepyfile(test_p1=""" - class BaseTests: + class BaseTests(object): def test_p1(self): pass class TestClass(BaseTests): @@ -145,18 +142,18 @@ class TestTerminal: """) result = testdir.runpytest(p2) result.stdout.fnmatch_lines([ - "*test_p2.py .", + "*test_p2.py .*", "*1 passed*", ]) result = testdir.runpytest("-v", p2) result.stdout.fnmatch_lines([ - "*test_p2.py::TestMore::test_p1* <- *test_p1.py*PASSED", + "*test_p2.py::TestMore::test_p1* <- *test_p1.py*PASSED*", ]) def test_itemreport_directclasses_not_shown_as_subclasses(self, testdir): a = testdir.mkpydir("a123") a.join("test_hello123.py").write(_pytest._code.Source(""" - class TestClass: + class TestClass(object): def test_method(self): pass """)) @@ -208,8 +205,27 @@ class TestTerminal: assert result.ret == 2 result.stdout.fnmatch_lines(['*KeyboardInterrupt*']) + def test_collect_single_item(self, testdir): + """Use singular 'item' when reporting a single test item""" + testdir.makepyfile(""" + def test_foobar(): + pass + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines(['collected 1 item']) -class TestCollectonly: + def test_rewrite(self, testdir, monkeypatch): + config = testdir.parseconfig() + f = py.io.TextIO() + monkeypatch.setattr(f, 'isatty', lambda *args: True) + tr = TerminalReporter(config, f) + tr._tw.fullwidth = 10 + tr.write('hello') + tr.rewrite('hey', erase=True) + assert f.getvalue() == 'hello' + '\r' + 'hey' + (6 * ' ') + + +class TestCollectonly(object): def test_collectonly_basic(self, testdir): testdir.makepyfile(""" def test_func(): @@ -217,8 +233,8 @@ class TestCollectonly: """) result = testdir.runpytest("--collect-only",) result.stdout.fnmatch_lines([ - "", - " ", + "", + " ", ]) def test_collectonly_skipped_module(self, testdir): @@ -228,8 +244,7 @@ class TestCollectonly: """) result = testdir.runpytest("--collect-only", "-rs") result.stdout.fnmatch_lines([ - "SKIP*hello*", - "*1 skip*", + "*ERROR collecting*", ]) def test_collectonly_failed_module(self, testdir): @@ -255,29 +270,29 @@ class TestCollectonly: p = testdir.makepyfile(""" def test_func1(): pass - class TestClass: + class TestClass(object): def test_method(self): pass """) result = testdir.runpytest("--collect-only", p) - #assert stderr.startswith("inserting into sys.path") + # assert stderr.startswith("inserting into sys.path") assert result.ret == 0 result.stdout.fnmatch_lines([ "*", "* ", "* ", - #"* ", + # "* ", "* ", ]) def test_collectonly_error(self, testdir): p = testdir.makepyfile("import Errlkjqweqwe") result = testdir.runpytest("--collect-only", p) - assert result.ret == 1 + assert result.ret == 2 result.stdout.fnmatch_lines(_pytest._code.Source(""" *ERROR* - *import Errlk* *ImportError* + *No module named *Errlk* *1 error* """).strip()) @@ -314,9 +329,10 @@ def test_repr_python_version(monkeypatch): py.std.sys.version_info = x = (2, 3) assert repr_pythonversion() == str(x) finally: - monkeypatch.undo() # do this early as pytest can get confused + monkeypatch.undo() # do this early as pytest can get confused -class TestFixtureReporting: + +class TestFixtureReporting(object): def test_setup_fixture_error(self, testdir): testdir.makepyfile(""" def setup_function(function): @@ -374,9 +390,35 @@ class TestFixtureReporting: "*def test_fail():", "*failingfunc*", "*1 failed*1 error*", - ]) + ]) -class TestTerminalFunctional: + def test_setup_teardown_output_and_test_failure(self, testdir): + """ Test for issue #442 """ + testdir.makepyfile(""" + def setup_function(function): + print ("setup func") + + def test_fail(): + assert 0, "failingfunc" + + def teardown_function(function): + print ("teardown func") + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + "*test_fail*", + "*def test_fail():", + "*failingfunc*", + "*Captured stdout setup*", + "*setup func*", + "*Captured stdout teardown*", + "*teardown func*", + + "*1 failed*", + ]) + + +class TestTerminalFunctional(object): def test_deselected(self, testdir): testpath = testdir.makepyfile(""" def test_one(): @@ -386,11 +428,11 @@ class TestTerminalFunctional: def test_three(): pass """ - ) + ) result = testdir.runpytest("-k", "test_two:", testpath) result.stdout.fnmatch_lines([ - "*test_deselected.py ..", - "=* 1 test*deselected by*test_two:*=", + "*test_deselected.py ..*", + "=* 1 test*deselected *=", ]) assert result.ret == 0 @@ -412,7 +454,7 @@ class TestTerminalFunctional: p1 = testdir.makepyfile(""" def test_passes(): pass - class TestClass: + class TestClass(object): def test_method(self): pass """) @@ -422,7 +464,7 @@ class TestTerminalFunctional: finally: old.chdir() result.stdout.fnmatch_lines([ - "test_passes.py ..", + "test_passes.py ..*", "* 2 pass*", ]) assert result.ret == 0 @@ -439,7 +481,7 @@ class TestTerminalFunctional: "platform %s -- Python %s*pytest-%s*py-%s*pluggy-%s" % ( py.std.sys.platform, verinfo, pytest.__version__, py.__version__, pluggy.__version__), - "*test_header_trailer_info.py .", + "*test_header_trailer_info.py .*", "=* 1 passed*in *.[0-9][0-9] seconds *=", ]) if pytest.config.pluginmanager.list_plugin_distinfo(): @@ -456,7 +498,7 @@ class TestTerminalFunctional: """) result = testdir.runpytest(p1, '-l') result.stdout.fnmatch_lines([ - #"_ _ * Locals *", + # "_ _ * Locals *", "x* = 3", "y* = 'xxxxxx*" ]) @@ -468,7 +510,7 @@ class TestTerminalFunctional: raise ValueError() def test_pass(): pass - class TestClass: + class TestClass(object): def test_skip(self): pytest.skip("hello") def test_gen(): @@ -512,6 +554,23 @@ class TestTerminalFunctional: assert "===" not in s assert "passed" not in s + def test_report_collectionfinish_hook(self, testdir): + testdir.makeconftest(""" + def pytest_report_collectionfinish(config, startdir, items): + return ['hello from hook: {0} items'.format(len(items))] + """) + testdir.makepyfile(""" + import pytest + @pytest.mark.parametrize('i', range(3)) + def test(i): + pass + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + "collected 3 items", + "hello from hook: 3 items", + ]) + def test_fail_extra_reporting(testdir): testdir.makepyfile("def test_this(): assert 0") @@ -523,11 +582,13 @@ def test_fail_extra_reporting(testdir): "FAIL*test_fail_extra_reporting*", ]) + def test_fail_reporting_on_pass(testdir): testdir.makepyfile("def test_this(): assert 1") result = testdir.runpytest('-rf') assert 'short test summary' not in result.stdout.str() + def test_pass_extra_reporting(testdir): testdir.makepyfile("def test_this(): assert 1") result = testdir.runpytest() @@ -538,11 +599,13 @@ def test_pass_extra_reporting(testdir): "PASS*test_pass_extra_reporting*", ]) + def test_pass_reporting_on_fail(testdir): testdir.makepyfile("def test_this(): assert 0") result = testdir.runpytest('-rp') assert 'short test summary' not in result.stdout.str() + def test_pass_output_reporting(testdir): testdir.makepyfile(""" def test_pass_output(): @@ -555,6 +618,7 @@ def test_pass_output_reporting(testdir): "Four score and seven years ago...", ]) + def test_color_yes(testdir): testdir.makepyfile("def test_this(): assert 1") result = testdir.runpytest('--color=yes') @@ -593,29 +657,33 @@ def test_color_yes_collection_on_non_atty(testdir, verbose): def test_getreportopt(): - class config: - class option: + class config(object): + class option(object): reportchars = "" - config.option.report = "xfailed" - assert getreportopt(config) == "x" + disable_warnings = True - config.option.report = "xfailed,skipped" - assert getreportopt(config) == "xs" - - config.option.report = "skipped,xfailed" - assert getreportopt(config) == "sx" - - config.option.report = "skipped" config.option.reportchars = "sf" assert getreportopt(config) == "sf" - config.option.reportchars = "sfx" + config.option.reportchars = "sfxw" assert getreportopt(config) == "sfx" + config.option.reportchars = "sfx" + config.option.disable_warnings = False + assert getreportopt(config) == "sfxw" + + config.option.reportchars = "sfxw" + config.option.disable_warnings = False + assert getreportopt(config) == "sfxw" + + def test_terminalreporter_reportopt_addopts(testdir): testdir.makeini("[pytest]\naddopts=-rs") testdir.makepyfile(""" - def pytest_funcarg__tr(request): + import pytest + + @pytest.fixture + def tr(request): tr = request.config.pluginmanager.getplugin("terminalreporter") return tr def test_opt(tr): @@ -627,9 +695,13 @@ def test_terminalreporter_reportopt_addopts(testdir): "*1 passed*" ]) + def test_tbstyle_short(testdir): p = testdir.makepyfile(""" - def pytest_funcarg__arg(request): + import pytest + + @pytest.fixture + def arg(request): return 42 def test_opt(arg): x = 0 @@ -640,7 +712,7 @@ def test_tbstyle_short(testdir): assert 'arg = 42' not in s assert 'x = 0' not in s result.stdout.fnmatch_lines([ - "*%s:5*" % p.basename, + "*%s:8*" % p.basename, " assert x", "E assert*", ]) @@ -649,6 +721,7 @@ def test_tbstyle_short(testdir): assert 'x = 0' in s assert 'assert x' in s + def test_traceconfig(testdir, monkeypatch): result = testdir.runpytest("--traceconfig") result.stdout.fnmatch_lines([ @@ -657,16 +730,17 @@ def test_traceconfig(testdir, monkeypatch): assert result.ret == EXIT_NOTESTSCOLLECTED -class TestGenericReporting: +class TestGenericReporting(object): """ this test class can be subclassed with a different option provider to run e.g. distributed tests. """ + def test_collect_fail(self, testdir, option): testdir.makepyfile("import xyz\n") result = testdir.runpytest(*option.args) result.stdout.fnmatch_lines([ - "? import xyz", - "E ImportError: No module named *xyz*", + "ImportError while importing*", + "*No module named *xyz*", "*1 error*", ]) @@ -683,11 +757,9 @@ class TestGenericReporting: result.stdout.fnmatch_lines([ "*def test_1():*", "*def test_2():*", - "*!! Interrupted: stopping after 2 failures*!!*", "*2 failed*", ]) - def test_tb_option(self, testdir, option): testdir.makepyfile(""" import pytest @@ -751,6 +823,7 @@ def pytest_report_header(config, startdir): str(testdir.tmpdir), ]) + @pytest.mark.xfail("not hasattr(os, 'dup')") def test_fdopen_kept_alive_issue124(testdir): testdir.makepyfile(""" @@ -769,6 +842,7 @@ def test_fdopen_kept_alive_issue124(testdir): "*2 passed*" ]) + def test_tbstyle_native_setup_error(testdir): testdir.makepyfile(""" import pytest @@ -781,20 +855,23 @@ def test_tbstyle_native_setup_error(testdir): """) result = testdir.runpytest("--tb=native") result.stdout.fnmatch_lines([ - '*File *test_tbstyle_native_setup_error.py", line *, in setup_error_fixture*' - ]) + '*File *test_tbstyle_native_setup_error.py", line *, in setup_error_fixture*' + ]) + def test_terminal_summary(testdir): testdir.makeconftest(""" - def pytest_terminal_summary(terminalreporter): + def pytest_terminal_summary(terminalreporter, exitstatus): w = terminalreporter w.section("hello") w.line("world") + w.line("exitstatus: {0}".format(exitstatus)) """) result = testdir.runpytest() result.stdout.fnmatch_lines(""" *==== hello ====* world + exitstatus: 5 """) @@ -809,8 +886,8 @@ def test_terminal_summary_warnings_are_displayed(testdir): """) result = testdir.runpytest('-rw') result.stdout.fnmatch_lines([ - '*C1*internal warning', - '*== 1 pytest-warnings in *', + '*internal warning', + '*== 1 warnings in *', ]) @@ -830,11 +907,11 @@ def test_terminal_summary_warnings_are_displayed(testdir): ("yellow", "1 weird", {"weird": (1,)}), ("yellow", "1 passed, 1 weird", {"weird": (1,), "passed": (1,)}), - ("yellow", "1 pytest-warnings", {"warnings": (1,)}), - ("yellow", "1 passed, 1 pytest-warnings", {"warnings": (1,), - "passed": (1,)}), + ("yellow", "1 warnings", {"warnings": (1,)}), + ("yellow", "1 passed, 1 warnings", {"warnings": (1,), + "passed": (1,)}), - ("green", "5 passed", {"passed": (1,2,3,4,5)}), + ("green", "5 passed", {"passed": (1, 2, 3, 4, 5)}), # "Boring" statuses. These have no effect on the color of the summary @@ -863,13 +940,13 @@ def test_terminal_summary_warnings_are_displayed(testdir): # A couple more complex combinations ("red", "1 failed, 2 passed, 3 xfailed", - {"passed": (1,2), "failed": (1,), "xfailed": (1,2,3)}), + {"passed": (1, 2), "failed": (1,), "xfailed": (1, 2, 3)}), ("green", "1 passed, 2 skipped, 3 deselected, 2 xfailed", {"passed": (1,), - "skipped": (1,2), - "deselected": (1,2,3), - "xfailed": (1,2)}), + "skipped": (1, 2), + "deselected": (1, 2, 3), + "xfailed": (1, 2)}), ]) def test_summary_stats(exp_line, exp_color, stats_arg): print("Based on stats: %s" % stats_arg) @@ -878,3 +955,85 @@ def test_summary_stats(exp_line, exp_color, stats_arg): print("Actually got: \"%s\"; with color \"%s\"" % (line, color)) assert line == exp_line assert color == exp_color + + +def test_no_trailing_whitespace_after_inifile_word(testdir): + result = testdir.runpytest('') + assert 'inifile:\n' in result.stdout.str() + + testdir.makeini('[pytest]') + result = testdir.runpytest('') + assert 'inifile: tox.ini\n' in result.stdout.str() + + +class TestProgress: + + @pytest.fixture + def many_tests_file(self, testdir): + testdir.makepyfile( + test_bar=""" + import pytest + @pytest.mark.parametrize('i', range(10)) + def test_bar(i): pass + """, + test_foo=""" + import pytest + @pytest.mark.parametrize('i', range(5)) + def test_foo(i): pass + """, + test_foobar=""" + import pytest + @pytest.mark.parametrize('i', range(5)) + def test_foobar(i): pass + """, + ) + + def test_zero_tests_collected(self, testdir): + """Some plugins (testmon for example) might issue pytest_runtest_logreport without any tests being + actually collected (#2971).""" + testdir.makeconftest(""" + def pytest_collection_modifyitems(items, config): + from _pytest.runner import CollectReport + for node_id in ('nodeid1', 'nodeid2'): + rep = CollectReport(node_id, 'passed', None, None) + rep.when = 'passed' + rep.duration = 0.1 + config.hook.pytest_runtest_logreport(report=rep) + """) + output = testdir.runpytest() + assert 'ZeroDivisionError' not in output.stdout.str() + output.stdout.fnmatch_lines([ + '=* 2 passed in *=', + ]) + + def test_normal(self, many_tests_file, testdir): + output = testdir.runpytest() + output.stdout.re_match_lines([ + r'test_bar.py \.{10} \s+ \[ 50%\]', + r'test_foo.py \.{5} \s+ \[ 75%\]', + r'test_foobar.py \.{5} \s+ \[100%\]', + ]) + + def test_verbose(self, many_tests_file, testdir): + output = testdir.runpytest('-v') + output.stdout.re_match_lines([ + r'test_bar.py::test_bar\[0\] PASSED \s+ \[ 5%\]', + r'test_foo.py::test_foo\[4\] PASSED \s+ \[ 75%\]', + r'test_foobar.py::test_foobar\[4\] PASSED \s+ \[100%\]', + ]) + + def test_xdist_normal(self, many_tests_file, testdir): + pytest.importorskip('xdist') + output = testdir.runpytest('-n2') + output.stdout.re_match_lines([ + r'\.{20} \s+ \[100%\]', + ]) + + def test_xdist_verbose(self, many_tests_file, testdir): + pytest.importorskip('xdist') + output = testdir.runpytest('-n2', '-v') + output.stdout.re_match_lines_random([ + r'\[gw\d\] \[\s*\d+%\] PASSED test_bar.py::test_bar\[1\]', + r'\[gw\d\] \[\s*\d+%\] PASSED test_foo.py::test_foo\[1\]', + r'\[gw\d\] \[\s*\d+%\] PASSED test_foobar.py::test_foobar\[1\]', + ]) diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_tmpdir.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_tmpdir.py similarity index 97% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_tmpdir.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_tmpdir.py index d514e722e1f..467e77252e7 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_tmpdir.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_tmpdir.py @@ -1,9 +1,11 @@ +from __future__ import absolute_import, division, print_function import sys import py import pytest from _pytest.tmpdir import tmpdir + def test_funcarg(testdir): testdir.makepyfile(""" def pytest_generate_tests(metafunc): @@ -28,14 +30,15 @@ def test_funcarg(testdir): bn = p.basename.strip("0123456789") assert bn == "qwe__abc" + def test_ensuretemp(recwarn): - #pytest.deprecated_call(pytest.ensuretemp, 'hello') d1 = pytest.ensuretemp('hello') d2 = pytest.ensuretemp('hello') assert d1 == d2 assert d1.check(dir=1) -class TestTempdirHandler: + +class TestTempdirHandler(object): def test_mktemp(self, testdir): from _pytest.tmpdir import TempdirFactory config = testdir.parseconfig() @@ -49,7 +52,8 @@ class TestTempdirHandler: assert tmp2.relto(t.getbasetemp()).startswith("this") assert tmp2 != tmp -class TestConfigTmpdir: + +class TestConfigTmpdir(object): def test_getbasetemp_custom_removes_old(self, testdir): mytemp = testdir.tmpdir.join("xyz") p = testdir.makepyfile(""" @@ -76,6 +80,7 @@ def test_basetemp(testdir): assert result.ret == 0 assert mytemp.join('hello').check() + @pytest.mark.skipif(not hasattr(py.path.local, 'mksymlinkto'), reason="symlink not available on this platform") def test_tmpdir_always_is_realpath(testdir): diff --git a/tests/wpt/web-platform-tests/tools/pytest/testing/test_unittest.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_unittest.py similarity index 75% rename from tests/wpt/web-platform-tests/tools/pytest/testing/test_unittest.py rename to tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_unittest.py index 144aad79bf4..e197735871f 100644 --- a/tests/wpt/web-platform-tests/tools/pytest/testing/test_unittest.py +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_unittest.py @@ -1,28 +1,32 @@ +from __future__ import absolute_import, division, print_function from _pytest.main import EXIT_NOTESTSCOLLECTED import pytest +import gc + def test_simple_unittest(testdir): testpath = testdir.makepyfile(""" import unittest class MyTestCase(unittest.TestCase): def testpassing(self): - self.assertEquals('foo', 'foo') + self.assertEqual('foo', 'foo') def test_failing(self): - self.assertEquals('foo', 'bar') + self.assertEqual('foo', 'bar') """) reprec = testdir.inline_run(testpath) assert reprec.matchreport("testpassing").passed assert reprec.matchreport("test_failing").failed + def test_runTest_method(testdir): testdir.makepyfile(""" import unittest class MyTestCaseWithRunTest(unittest.TestCase): def runTest(self): - self.assertEquals('foo', 'foo') + self.assertEqual('foo', 'foo') class MyTestCaseWithoutRunTest(unittest.TestCase): def runTest(self): - self.assertEquals('foo', 'foo') + self.assertEqual('foo', 'foo') def test_something(self): pass """) @@ -33,6 +37,7 @@ def test_runTest_method(testdir): *2 passed* """) + def test_isclasscheck_issue53(testdir): testpath = testdir.makepyfile(""" import unittest @@ -44,6 +49,7 @@ def test_isclasscheck_issue53(testdir): result = testdir.runpytest(testpath) assert result.ret == EXIT_NOTESTSCOLLECTED + def test_setup(testdir): testpath = testdir.makepyfile(""" import unittest @@ -53,7 +59,7 @@ def test_setup(testdir): def setup_method(self, method): self.foo2 = 1 def test_both(self): - self.assertEquals(1, self.foo) + self.assertEqual(1, self.foo) assert self.foo2 == 1 def teardown_method(self, method): assert 0, "42" @@ -64,36 +70,38 @@ def test_setup(testdir): rep = reprec.matchreport("test_both", when="teardown") assert rep.failed and '42' in str(rep.longrepr) + def test_setUpModule(testdir): testpath = testdir.makepyfile(""" - l = [] + values = [] def setUpModule(): - l.append(1) + values.append(1) def tearDownModule(): - del l[0] + del values[0] def test_hello(): - assert l == [1] + assert values == [1] def test_world(): - assert l == [1] + assert values == [1] """) result = testdir.runpytest(testpath) result.stdout.fnmatch_lines([ "*2 passed*", ]) + def test_setUpModule_failing_no_teardown(testdir): testpath = testdir.makepyfile(""" - l = [] + values = [] def setUpModule(): 0/0 def tearDownModule(): - l.append(1) + values.append(1) def test_hello(): pass @@ -101,7 +109,8 @@ def test_setUpModule_failing_no_teardown(testdir): reprec = testdir.inline_run(testpath) reprec.assertoutcome(passed=0, failed=1) call = reprec.getcalls("pytest_runtest_setup")[0] - assert not call.item.module.l + assert not call.item.module.values + def test_new_instances(testdir): testpath = testdir.makepyfile(""" @@ -115,18 +124,19 @@ def test_new_instances(testdir): reprec = testdir.inline_run(testpath) reprec.assertoutcome(passed=2) + def test_teardown(testdir): testpath = testdir.makepyfile(""" import unittest class MyTestCase(unittest.TestCase): - l = [] + values = [] def test_one(self): pass def tearDown(self): - self.l.append(None) + self.values.append(None) class Second(unittest.TestCase): def test_check(self): - self.assertEquals(MyTestCase.l, [None]) + self.assertEqual(MyTestCase.values, [None]) """) reprec = testdir.inline_run(testpath) passed, skipped, failed = reprec.countoutcomes() @@ -134,7 +144,30 @@ def test_teardown(testdir): assert passed == 2 assert passed + skipped + failed == 2 -@pytest.mark.skipif("sys.version_info < (2,7)") + +def test_teardown_issue1649(testdir): + """ + Are TestCase objects cleaned up? Often unittest TestCase objects set + attributes that are large and expensive during setUp. + + The TestCase will not be cleaned up if the test fails, because it + would then exist in the stackframe. + """ + testpath = testdir.makepyfile(""" + import unittest + class TestCaseObjectsShouldBeCleanedUp(unittest.TestCase): + def setUp(self): + self.an_expensive_object = 1 + def test_demo(self): + pass + + """) + testdir.inline_run("-s", testpath) + gc.collect() + for obj in gc.get_objects(): + assert type(obj).__name__ != 'TestCaseObjectsShouldBeCleanedUp' + + def test_unittest_skip_issue148(testdir): testpath = testdir.makepyfile(""" import unittest @@ -153,6 +186,7 @@ def test_unittest_skip_issue148(testdir): reprec = testdir.inline_run(testpath) reprec.assertoutcome(skipped=1) + def test_method_and_teardown_failing_reporting(testdir): testdir.makepyfile(""" import unittest, pytest @@ -172,6 +206,7 @@ def test_method_and_teardown_failing_reporting(testdir): "*1 failed*1 error*", ]) + def test_setup_failure_is_shown(testdir): testdir.makepyfile(""" import unittest @@ -192,6 +227,7 @@ def test_setup_failure_is_shown(testdir): ]) assert 'never42' not in result.stdout.str() + def test_setup_setUpClass(testdir): testpath = testdir.makepyfile(""" import unittest @@ -214,6 +250,7 @@ def test_setup_setUpClass(testdir): reprec = testdir.inline_run(testpath) reprec.assertoutcome(passed=3) + def test_setup_class(testdir): testpath = testdir.makepyfile(""" import unittest @@ -255,6 +292,7 @@ def test_testcase_adderrorandfailure_defers(testdir, type): result = testdir.runpytest() assert 'should not raise' not in result.stdout.str() + @pytest.mark.parametrize("type", ['Error', 'Failure']) def test_testcase_custom_exception_info(testdir, type): testdir.makepyfile(""" @@ -265,8 +303,8 @@ def test_testcase_custom_exception_info(testdir, type): def run(self, result): excinfo = pytest.raises(ZeroDivisionError, lambda: 0/0) # we fake an incompatible exception info - from _pytest.monkeypatch import monkeypatch - mp = monkeypatch() + from _pytest.monkeypatch import MonkeyPatch + mp = MonkeyPatch() def t(*args): mp.undo() raise TypeError() @@ -286,6 +324,7 @@ def test_testcase_custom_exception_info(testdir, type): "*1 failed*", ]) + def test_testcase_totally_incompatible_exception_info(testdir): item, = testdir.getitems(""" from unittest import TestCase @@ -297,6 +336,7 @@ def test_testcase_totally_incompatible_exception_info(testdir): excinfo = item._excinfo.pop(0) assert 'ERROR: Unknown Incompatible' in str(excinfo.getrepr()) + def test_module_level_pytestmark(testdir): testpath = testdir.makepyfile(""" import unittest @@ -310,61 +350,12 @@ def test_module_level_pytestmark(testdir): reprec.assertoutcome(skipped=1) -def test_trial_testcase_skip_property(testdir): - pytest.importorskip('twisted.trial.unittest') - testpath = testdir.makepyfile(""" - from twisted.trial import unittest - class MyTestCase(unittest.TestCase): - skip = 'dont run' - def test_func(self): - pass - """) - reprec = testdir.inline_run(testpath, "-s") - reprec.assertoutcome(skipped=1) - - -def test_trial_testfunction_skip_property(testdir): - pytest.importorskip('twisted.trial.unittest') - testpath = testdir.makepyfile(""" - from twisted.trial import unittest - class MyTestCase(unittest.TestCase): - def test_func(self): - pass - test_func.skip = 'dont run' - """) - reprec = testdir.inline_run(testpath, "-s") - reprec.assertoutcome(skipped=1) - - -def test_trial_testcase_todo_property(testdir): - pytest.importorskip('twisted.trial.unittest') - testpath = testdir.makepyfile(""" - from twisted.trial import unittest - class MyTestCase(unittest.TestCase): - todo = 'dont run' - def test_func(self): - assert 0 - """) - reprec = testdir.inline_run(testpath, "-s") - reprec.assertoutcome(skipped=1) - - -def test_trial_testfunction_todo_property(testdir): - pytest.importorskip('twisted.trial.unittest') - testpath = testdir.makepyfile(""" - from twisted.trial import unittest - class MyTestCase(unittest.TestCase): - def test_func(self): - assert 0 - test_func.todo = 'dont run' - """) - reprec = testdir.inline_run(testpath, "-s") - reprec.assertoutcome(skipped=1) - - -class TestTrialUnittest: +class TestTrialUnittest(object): def setup_class(cls): cls.ut = pytest.importorskip("twisted.trial.unittest") + # on windows trial uses a socket for a reactor and apparently doesn't close it properly + # https://twistedmatrix.com/trac/ticket/9227 + cls.ignore_unclosed_socket_warning = ('-W', 'always') def test_trial_testcase_runtest_not_collected(self, testdir): testdir.makepyfile(""" @@ -374,7 +365,7 @@ class TestTrialUnittest: def test_hello(self): pass """) - reprec = testdir.inline_run() + reprec = testdir.inline_run(*self.ignore_unclosed_socket_warning) reprec.assertoutcome(passed=1) testdir.makepyfile(""" from twisted.trial.unittest import TestCase @@ -383,7 +374,7 @@ class TestTrialUnittest: def runTest(self): pass """) - reprec = testdir.inline_run() + reprec = testdir.inline_run(*self.ignore_unclosed_socket_warning) reprec.assertoutcome(passed=1) def test_trial_exceptions_with_skips(self, testdir): @@ -419,8 +410,9 @@ class TestTrialUnittest: def test_method(self): pass """) - result = testdir.runpytest("-rxs") - assert result.ret == 0 + from _pytest.compat import _is_unittest_unexpected_success_a_failure + should_fail = _is_unittest_unexpected_success_a_failure() + result = testdir.runpytest("-rxs", *self.ignore_unclosed_socket_warning) result.stdout.fnmatch_lines_random([ "*XFAIL*test_trial_todo*", "*trialselfskip*", @@ -429,8 +421,9 @@ class TestTrialUnittest: "*i2wanto*", "*sys.version_info*", "*skip_in_method*", - "*4 skipped*3 xfail*1 xpass*", + "*1 failed*4 skipped*3 xfailed*" if should_fail else "*4 skipped*3 xfail*1 xpass*", ]) + assert result.ret == (1 if should_fail else 0) def test_trial_error(self, testdir): testdir.makepyfile(""" @@ -494,6 +487,51 @@ class TestTrialUnittest: child.expect("hellopdb") child.sendeof() + def test_trial_testcase_skip_property(self, testdir): + testpath = testdir.makepyfile(""" + from twisted.trial import unittest + class MyTestCase(unittest.TestCase): + skip = 'dont run' + def test_func(self): + pass + """) + reprec = testdir.inline_run(testpath, "-s") + reprec.assertoutcome(skipped=1) + + def test_trial_testfunction_skip_property(self, testdir): + testpath = testdir.makepyfile(""" + from twisted.trial import unittest + class MyTestCase(unittest.TestCase): + def test_func(self): + pass + test_func.skip = 'dont run' + """) + reprec = testdir.inline_run(testpath, "-s") + reprec.assertoutcome(skipped=1) + + def test_trial_testcase_todo_property(self, testdir): + testpath = testdir.makepyfile(""" + from twisted.trial import unittest + class MyTestCase(unittest.TestCase): + todo = 'dont run' + def test_func(self): + assert 0 + """) + reprec = testdir.inline_run(testpath, "-s") + reprec.assertoutcome(skipped=1) + + def test_trial_testfunction_todo_property(self, testdir): + testpath = testdir.makepyfile(""" + from twisted.trial import unittest + class MyTestCase(unittest.TestCase): + def test_func(self): + assert 0 + test_func.todo = 'dont run' + """) + reprec = testdir.inline_run(testpath, "-s", *self.ignore_unclosed_socket_warning) + reprec.assertoutcome(skipped=1) + + def test_djangolike_testcase(testdir): # contributed from Morten Breekevold testdir.makepyfile(""" @@ -554,11 +592,12 @@ def test_unittest_not_shown_in_traceback(testdir): class t(unittest.TestCase): def test_hello(self): x = 3 - self.assertEquals(x, 4) + self.assertEqual(x, 4) """) res = testdir.runpytest() assert "failUnlessEqual" not in res.stdout.str() + def test_unorderable_types(testdir): testdir.makepyfile(""" import unittest @@ -576,6 +615,7 @@ def test_unorderable_types(testdir): assert "TypeError" not in result.stdout.str() assert result.ret == EXIT_NOTESTSCOLLECTED + def test_unittest_typerror_traceback(testdir): testdir.makepyfile(""" import unittest @@ -587,24 +627,60 @@ def test_unittest_typerror_traceback(testdir): assert "TypeError" in result.stdout.str() assert result.ret == 1 -@pytest.mark.skipif("sys.version_info < (2,7)") -def test_unittest_unexpected_failure(testdir): - testdir.makepyfile(""" + +@pytest.mark.parametrize('runner', ['pytest', 'unittest']) +def test_unittest_expected_failure_for_failing_test_is_xfail(testdir, runner): + script = testdir.makepyfile(""" import unittest class MyTestCase(unittest.TestCase): @unittest.expectedFailure - def test_func1(self): - assert 0 - @unittest.expectedFailure - def test_func2(self): - assert 1 + def test_failing_test_is_xfail(self): + assert False + if __name__ == '__main__': + unittest.main() """) - result = testdir.runpytest("-rxX") - result.stdout.fnmatch_lines([ - "*XFAIL*MyTestCase*test_func1*", - "*XPASS*MyTestCase*test_func2*", - "*1 xfailed*1 xpass*", - ]) + if runner == 'pytest': + result = testdir.runpytest("-rxX") + result.stdout.fnmatch_lines([ + "*XFAIL*MyTestCase*test_failing_test_is_xfail*", + "*1 xfailed*", + ]) + else: + result = testdir.runpython(script) + result.stderr.fnmatch_lines([ + "*1 test in*", + "*OK*(expected failures=1)*", + ]) + assert result.ret == 0 + + +@pytest.mark.parametrize('runner', ['pytest', 'unittest']) +def test_unittest_expected_failure_for_passing_test_is_fail(testdir, runner): + script = testdir.makepyfile(""" + import unittest + class MyTestCase(unittest.TestCase): + @unittest.expectedFailure + def test_passing_test_is_fail(self): + assert True + if __name__ == '__main__': + unittest.main() + """) + from _pytest.compat import _is_unittest_unexpected_success_a_failure + should_fail = _is_unittest_unexpected_success_a_failure() + if runner == 'pytest': + result = testdir.runpytest("-rxX") + result.stdout.fnmatch_lines([ + "*MyTestCase*test_passing_test_is_fail*", + "*1 failed*" if should_fail else "*1 xpassed*", + ]) + else: + result = testdir.runpython(script) + result.stderr.fnmatch_lines([ + "*1 test in*", + "*(unexpected successes=1)*", + ]) + + assert result.ret == (1 if should_fail else 0) @pytest.mark.parametrize('fix_type, stmt', [ @@ -641,7 +717,7 @@ def test_unittest_setup_interaction(testdir, fix_type, stmt): def test_non_unittest_no_setupclass_support(testdir): testpath = testdir.makepyfile(""" - class TestFoo: + class TestFoo(object): x = 0 @classmethod @@ -691,8 +767,10 @@ def test_no_teardown_if_setupclass_failed(testdir): def test_issue333_result_clearing(testdir): testdir.makeconftest(""" - def pytest_runtest_call(__multicall__, item): - __multicall__.execute() + import pytest + @pytest.hookimpl(hookwrapper=True) + def pytest_runtest_call(item): + yield assert 0 """) testdir.makepyfile(""" @@ -705,7 +783,7 @@ def test_issue333_result_clearing(testdir): reprec = testdir.inline_run() reprec.assertoutcome(failed=1) -@pytest.mark.skipif("sys.version_info < (2,7)") + def test_unittest_raise_skip_issue748(testdir): testdir.makepyfile(test_foo=""" import unittest @@ -720,11 +798,11 @@ def test_unittest_raise_skip_issue748(testdir): *1 skipped* """) -@pytest.mark.skipif("sys.version_info < (2,7)") + def test_unittest_skip_issue1169(testdir): testdir.makepyfile(test_foo=""" import unittest - + class MyTestCase(unittest.TestCase): @unittest.skip("skipping due to reasons") def test_skip(self): @@ -735,3 +813,18 @@ def test_unittest_skip_issue1169(testdir): *SKIP*[1]*skipping due to reasons* *1 skipped* """) + + +def test_class_method_containing_test_issue1558(testdir): + testdir.makepyfile(test_foo=""" + import unittest + + class MyTestCase(unittest.TestCase): + def test_should_run(self): + pass + def test_should_not_run(self): + pass + test_should_not_run.__test__ = False + """) + reprec = testdir.inline_run() + reprec.assertoutcome(passed=1) diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_warnings.py b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_warnings.py new file mode 100644 index 00000000000..02400bd1ded --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/testing/test_warnings.py @@ -0,0 +1,258 @@ +# -*- coding: utf8 -*- +from __future__ import unicode_literals + +import sys + +import pytest + + +WARNINGS_SUMMARY_HEADER = 'warnings summary' + + +@pytest.fixture +def pyfile_with_warnings(testdir, request): + """ + Create a test file which calls a function in a module which generates warnings. + """ + testdir.syspathinsert() + test_name = request.function.__name__ + module_name = test_name.lstrip('test_') + '_module' + testdir.makepyfile(**{ + module_name: ''' + import warnings + def foo(): + warnings.warn(UserWarning("user warning")) + warnings.warn(RuntimeWarning("runtime warning")) + return 1 + ''', + test_name: ''' + import {module_name} + def test_func(): + assert {module_name}.foo() == 1 + '''.format(module_name=module_name) + }) + + +@pytest.mark.filterwarnings('always') +def test_normal_flow(testdir, pyfile_with_warnings): + """ + Check that the warnings section is displayed, containing test node ids followed by + all warnings generated by that test node. + """ + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + '*== %s ==*' % WARNINGS_SUMMARY_HEADER, + + '*test_normal_flow.py::test_func', + + '*normal_flow_module.py:3: UserWarning: user warning', + '* warnings.warn(UserWarning("user warning"))', + + '*normal_flow_module.py:4: RuntimeWarning: runtime warning', + '* warnings.warn(RuntimeWarning("runtime warning"))', + '* 1 passed, 2 warnings*', + ]) + assert result.stdout.str().count('test_normal_flow.py::test_func') == 1 + + +@pytest.mark.filterwarnings('always') +def test_setup_teardown_warnings(testdir, pyfile_with_warnings): + testdir.makepyfile(''' + import warnings + import pytest + + @pytest.fixture + def fix(): + warnings.warn(UserWarning("warning during setup")) + yield + warnings.warn(UserWarning("warning during teardown")) + + def test_func(fix): + pass + ''') + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + '*== %s ==*' % WARNINGS_SUMMARY_HEADER, + + '*test_setup_teardown_warnings.py:6: UserWarning: warning during setup', + '*warnings.warn(UserWarning("warning during setup"))', + + '*test_setup_teardown_warnings.py:8: UserWarning: warning during teardown', + '*warnings.warn(UserWarning("warning during teardown"))', + '* 1 passed, 2 warnings*', + ]) + + +@pytest.mark.parametrize('method', ['cmdline', 'ini']) +def test_as_errors(testdir, pyfile_with_warnings, method): + args = ('-W', 'error') if method == 'cmdline' else () + if method == 'ini': + testdir.makeini(''' + [pytest] + filterwarnings= error + ''') + result = testdir.runpytest(*args) + result.stdout.fnmatch_lines([ + 'E UserWarning: user warning', + 'as_errors_module.py:3: UserWarning', + '* 1 failed in *', + ]) + + +@pytest.mark.parametrize('method', ['cmdline', 'ini']) +def test_ignore(testdir, pyfile_with_warnings, method): + args = ('-W', 'ignore') if method == 'cmdline' else () + if method == 'ini': + testdir.makeini(''' + [pytest] + filterwarnings= ignore + ''') + + result = testdir.runpytest(*args) + result.stdout.fnmatch_lines([ + '* 1 passed in *', + ]) + assert WARNINGS_SUMMARY_HEADER not in result.stdout.str() + + +@pytest.mark.skipif(sys.version_info < (3, 0), + reason='warnings message is unicode is ok in python3') +@pytest.mark.filterwarnings('always') +def test_unicode(testdir, pyfile_with_warnings): + testdir.makepyfile(''' + # -*- coding: utf8 -*- + import warnings + import pytest + + + @pytest.fixture + def fix(): + warnings.warn(u"测试") + yield + + def test_func(fix): + pass + ''') + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + '*== %s ==*' % WARNINGS_SUMMARY_HEADER, + '*test_unicode.py:8: UserWarning: \u6d4b\u8bd5*', + '* 1 passed, 1 warnings*', + ]) + + +@pytest.mark.skipif(sys.version_info >= (3, 0), + reason='warnings message is broken as it is not str instance') +def test_py2_unicode(testdir, pyfile_with_warnings): + if getattr(sys, "pypy_version_info", ())[:2] == (5, 9) and sys.platform.startswith('win'): + pytest.xfail("fails with unicode error on PyPy2 5.9 and Windows (#2905)") + testdir.makepyfile(''' + # -*- coding: utf8 -*- + import warnings + import pytest + + + @pytest.fixture + def fix(): + warnings.warn(u"测试") + yield + + @pytest.mark.filterwarnings('always') + def test_func(fix): + pass + ''') + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + '*== %s ==*' % WARNINGS_SUMMARY_HEADER, + + '*test_py2_unicode.py:8: UserWarning: \\u6d4b\\u8bd5', + '*warnings.warn(u"\u6d4b\u8bd5")', + '*warnings.py:*: UnicodeWarning: Warning is using unicode non*', + '* 1 passed, 2 warnings*', + ]) + + +def test_py2_unicode_ascii(testdir): + """Ensure that our warning about 'unicode warnings containing non-ascii messages' + does not trigger with ascii-convertible messages""" + testdir.makeini('[pytest]') + testdir.makepyfile(''' + import pytest + import warnings + + @pytest.mark.filterwarnings('always') + def test_func(): + warnings.warn(u"hello") + ''') + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + '*== %s ==*' % WARNINGS_SUMMARY_HEADER, + '*warnings.warn(u"hello")', + '* 1 passed, 1 warnings in*' + ]) + + +def test_works_with_filterwarnings(testdir): + """Ensure our warnings capture does not mess with pre-installed filters (#2430).""" + testdir.makepyfile(''' + import warnings + + class MyWarning(Warning): + pass + + warnings.filterwarnings("error", category=MyWarning) + + class TestWarnings(object): + def test_my_warning(self): + try: + warnings.warn(MyWarning("warn!")) + assert False + except MyWarning: + assert True + ''') + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + '*== 1 passed in *', + ]) + + +@pytest.mark.parametrize('default_config', ['ini', 'cmdline']) +def test_filterwarnings_mark(testdir, default_config): + """ + Test ``filterwarnings`` mark works and takes precedence over command line and ini options. + """ + if default_config == 'ini': + testdir.makeini(""" + [pytest] + filterwarnings = always + """) + testdir.makepyfile(""" + import warnings + import pytest + + @pytest.mark.filterwarnings('ignore::RuntimeWarning') + def test_ignore_runtime_warning(): + warnings.warn(RuntimeWarning()) + + @pytest.mark.filterwarnings('error') + def test_warning_error(): + warnings.warn(RuntimeWarning()) + + def test_show_warning(): + warnings.warn(RuntimeWarning()) + """) + result = testdir.runpytest('-W always' if default_config == 'cmdline' else '') + result.stdout.fnmatch_lines(['*= 1 failed, 2 passed, 1 warnings in *']) + + +def test_non_string_warning_argument(testdir): + """Non-str argument passed to warning breaks pytest (#2956)""" + testdir.makepyfile(""" + import warnings + import pytest + + def test(): + warnings.warn(UserWarning(1, u'foo')) + """) + result = testdir.runpytest('-W', 'always') + result.stdout.fnmatch_lines(['*= 1 passed, 1 warnings in *']) diff --git a/tests/wpt/web-platform-tests/tools/third_party/pytest/tox.ini b/tests/wpt/web-platform-tests/tools/third_party/pytest/tox.ini new file mode 100644 index 00000000000..900b602dc33 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/pytest/tox.ini @@ -0,0 +1,220 @@ +[tox] +minversion = 2.0 +distshare = {homedir}/.tox/distshare +# make sure to update environment list in travis.yml and appveyor.yml +envlist = + linting + py27 + py34 + py35 + py36 + py37 + pypy + {py27,py36}-{pexpect,xdist,trial,numpy,pluggymaster} + py27-nobyte + doctesting + py35-freeze + docs + +[testenv] +commands = pytest --lsof -ra {posargs:testing} +passenv = USER USERNAME +deps = + hypothesis>=3.5.2 + nose + mock + requests + +[testenv:py27-subprocess] +changedir = . +deps = + pytest-xdist>=1.13 + mock + nose +commands = + pytest -n3 -ra --runpytest=subprocess {posargs:testing} + + +[testenv:linting] +skipsdist = True +usedevelop = True +basepython = python2.7 +deps = + flake8 + # pygments required by rst-lint + pygments + restructuredtext_lint +commands = + flake8 pytest.py _pytest testing setup.py pytest.py + {envpython} scripts/check-rst.py + +[testenv:py27-xdist] +deps = + pytest-xdist>=1.13 + mock + nose + hypothesis>=3.5.2 +changedir=testing +commands = + pytest -n1 -ra {posargs:.} + +[testenv:py36-xdist] +deps = {[testenv:py27-xdist]deps} +commands = + pytest -n3 -ra {posargs:testing} + +[testenv:py27-pexpect] +changedir = testing +platform = linux|darwin +deps = pexpect +commands = + pytest -ra test_pdb.py test_terminal.py test_unittest.py + +[testenv:py36-pexpect] +changedir = testing +platform = linux|darwin +deps = {[testenv:py27-pexpect]deps} +commands = + pytest -ra test_pdb.py test_terminal.py test_unittest.py + +[testenv:py27-nobyte] +deps = + pytest-xdist>=1.13 + hypothesis>=3.5.2 +distribute = true +changedir=testing +setenv = + PYTHONDONTWRITEBYTECODE=1 +commands = + pytest -n3 -ra {posargs:.} + +[testenv:py27-trial] +deps = twisted +commands = + pytest -ra {posargs:testing/test_unittest.py} + +[testenv:py36-trial] +deps = {[testenv:py27-trial]deps} +commands = + pytest -ra {posargs:testing/test_unittest.py} + +[testenv:py27-numpy] +deps=numpy +commands= + pytest -ra {posargs:testing/python/approx.py} + +[testenv:py36-numpy] +deps=numpy +commands= + pytest -ra {posargs:testing/python/approx.py} + +[testenv:py27-pluggymaster] +setenv= + _PYTEST_SETUP_SKIP_PLUGGY_DEP=1 +deps = + {[testenv]deps} + git+https://github.com/pytest-dev/pluggy.git@master + +[testenv:py35-pluggymaster] +setenv= + _PYTEST_SETUP_SKIP_PLUGGY_DEP=1 +deps = + {[testenv:py27-pluggymaster]deps} + git+https://github.com/pytest-dev/pluggy.git@master + +[testenv:docs] +skipsdist = True +usedevelop = True +basepython = python +changedir = doc/en +deps = + sphinx + PyYAML + +commands = + sphinx-build -W -b html . _build + +[testenv:doctesting] +basepython = python +usedevelop = True +skipsdist = True +# ensure the given pyargs cant mean anytrhing else +changedir = doc/ +deps = + PyYAML +commands = + pytest -ra en + pytest --doctest-modules --pyargs _pytest + +[testenv:regen] +changedir = doc/en +skipsdist = True +basepython = python3.5 +deps = + sphinx + PyYAML + regendoc>=0.6.1 +whitelist_externals = + rm + make +commands = + rm -rf /tmp/doc-exec* + make regen + +[testenv:fix-lint] +skipsdist = True +usedevelop = True +deps = + autopep8 +commands = + autopep8 --in-place -r --max-line-length=120 --exclude=test_source_multiline_block.py _pytest testing setup.py pytest.py + +[testenv:jython] +changedir = testing +commands = + {envpython} {envbindir}/py.test-jython -ra {posargs} + +[testenv:py35-freeze] +changedir = testing/freeze +deps = pyinstaller +commands = + {envpython} create_executable.py + {envpython} tox_run.py + + +[testenv:coveralls] +passenv = TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH COVERALLS_REPO_TOKEN +usedevelop = True +changedir = . +deps = + {[testenv]deps} + coveralls +commands = + coverage run --source=_pytest -m pytest testing + coverage report -m + coveralls + +[pytest] +minversion = 2.0 +plugins = pytester +#--pyargs --doctest-modules --ignore=.tox +addopts = -ra -p pytester --ignore=testing/cx_freeze +rsyncdirs = tox.ini pytest.py _pytest testing +python_files = test_*.py *_test.py testing/*/*.py +python_classes = Test Acceptance +python_functions = test +norecursedirs = .tox ja .hg cx_freeze_source +xfail_strict=true +filterwarnings = + error + # produced by path.local + ignore:bad escape.*:DeprecationWarning:re + # produced by path.readlines + ignore:.*U.*mode is deprecated:DeprecationWarning + # produced by pytest-xdist + ignore:.*type argument to addoption.*:DeprecationWarning + # produced by python >=3.5 on execnet (pytest-xdist) + ignore:.*inspect.getargspec.*deprecated, use inspect.signature.*:DeprecationWarning + +[flake8] +max-line-length = 120 diff --git a/tests/wpt/web-platform-tests/tools/tox.ini b/tests/wpt/web-platform-tests/tools/tox.ini index 3b97ae4b5f7..b154c471d6f 100644 --- a/tests/wpt/web-platform-tests/tools/tox.ini +++ b/tests/wpt/web-platform-tests/tools/tox.ini @@ -21,4 +21,4 @@ passenv = [flake8] ignore = E128,E129,E221,E226,E231,E251,E265,E302,E303,E305,E402,E901,F401,F821,F841 max-line-length = 141 -exclude = .tox,html5lib,py,pytest,pywebsocket,six,_venv,webencodings,wptserve/docs,wptserve/tests/functional/docroot/,wpt,wptrunner +exclude = .tox,html5lib,third_party/py,third_party/pytest,third_party/funcsigs,third_party/attrs,third_party/pluggy/,pywebsocket,six,_venv,webencodings,wptserve/docs,wptserve/tests/functional/docroot/,wpt,wptrunner diff --git a/tests/wpt/web-platform-tests/tools/webdriver/webdriver/client.py b/tests/wpt/web-platform-tests/tools/webdriver/webdriver/client.py index 26a035da776..ec7d6deccba 100644 --- a/tests/wpt/web-platform-tests/tools/webdriver/webdriver/client.py +++ b/tests/wpt/web-platform-tests/tools/webdriver/webdriver/client.py @@ -42,7 +42,7 @@ class Timeouts(object): def _set(self, key, secs): body = {key: secs * 1000} timeouts = self.session.send_session_command("POST", "timeouts", body) - return timeouts[key] + return None @property def script(self): @@ -370,8 +370,8 @@ class Session(object): self.actions = Actions(self) def __eq__(self, other): - return (self.session_id is not None and isinstance(other, Session) - and self.session_Id == other.session_id) + return (self.session_id is not None and isinstance(other, Session) and + self.session_id == other.session_id) def __enter__(self): self.start() @@ -507,6 +507,11 @@ class Session(object): def title(self): return self.send_session_command("GET", "title") + @property + @command + def source(self): + return self.send_session_command("GET", "source") + @property @command def window_handle(self): @@ -626,8 +631,8 @@ class Element(object): self.session._element_cache[self.id] = self def __eq__(self, other): - return isinstance(other, Element) and self.id == other.id \ - and self.session == other.session + return (isinstance(other, Element) and self.id == other.id and + self.session == other.session) @classmethod def from_json(cls, json, session): diff --git a/tests/wpt/web-platform-tests/tools/webdriver/webdriver/error.py b/tests/wpt/web-platform-tests/tools/webdriver/webdriver/error.py index 01ab31b8af1..ecfe8910c51 100644 --- a/tests/wpt/web-platform-tests/tools/webdriver/webdriver/error.py +++ b/tests/wpt/web-platform-tests/tools/webdriver/webdriver/error.py @@ -8,17 +8,25 @@ class WebDriverException(Exception): def __init__(self, message, stacktrace=None): super(WebDriverException, self) + self.message = message self.stacktrace = stacktrace def __repr__(self): - return "<%s http_status=%d>" % (self.__class__.__name__, self.http_status) + return "<%s http_status=%s>" % (self.__class__.__name__, self.http_status) def __str__(self): - return ("%s (%d)\n" - "\n" + message = "%s (%s): %s\n" % (self.status_code, self.http_status, self.message) + if self.stacktrace: + message += ("\n" "Remote-end stacktrace:\n" "\n" - "%s" % (self.status_code, self.http_status, self.stacktrace)) + "%s" % self.stacktrace) + return message + + +class ElementClickInterceptedException(WebDriverException): + http_status = 400 + status_code = "element click intercepted" class ElementNotSelectableException(WebDriverException): @@ -53,7 +61,7 @@ class InvalidElementCoordinatesException(WebDriverException): class InvalidElementStateException(WebDriverException): http_status = 400 - status_code = "invalid cookie domain" + status_code = "invalid element state" class InvalidSelectorException(WebDriverException): @@ -107,7 +115,7 @@ class SessionNotCreatedException(WebDriverException): class StaleElementReferenceException(WebDriverException): - http_status = 400 + http_status = 404 status_code = "stale element reference" diff --git a/tests/wpt/web-platform-tests/tools/webdriver/webdriver/transport.py b/tests/wpt/web-platform-tests/tools/webdriver/webdriver/transport.py index ef8e59a6f82..b198b194b38 100644 --- a/tests/wpt/web-platform-tests/tools/webdriver/webdriver/transport.py +++ b/tests/wpt/web-platform-tests/tools/webdriver/webdriver/transport.py @@ -19,6 +19,7 @@ class Response(object): self.body = body def __repr__(self): + cls_name = self.__class__.__name__ if self.error: return "<%s status=%s error=%s>" % (cls_name, self.status, repr(self.error)) return "<% status=%s body=%s>" % (cls_name, self.status, json.dumps(self.body)) diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/OWNERS b/tests/wpt/web-platform-tests/tools/wptrunner/OWNERS deleted file mode 100644 index 4bf48ad76e5..00000000000 --- a/tests/wpt/web-platform-tests/tools/wptrunner/OWNERS +++ /dev/null @@ -1 +0,0 @@ -@bobholt diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/docs/conf.py b/tests/wpt/web-platform-tests/tools/wptrunner/docs/conf.py index 39e5cc4f0d2..0c717f56536 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/docs/conf.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/docs/conf.py @@ -264,4 +264,4 @@ texinfo_documents = [ # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'python': ('http://docs.python.org/', None), - 'mozlog': ('http://mozbase.readthedocs.org/en/latest/', None)} + 'mozlog': ('https://firefox-source-docs.mozilla.org/', None)} diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/browsers/firefox.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/browsers/firefox.py index 552cd15b459..b324bccd91e 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/browsers/firefox.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/browsers/firefox.py @@ -51,7 +51,10 @@ def get_timeout_multiplier(test_type, run_info_data, **kwargs): else: return 2 elif run_info_data["debug"] or run_info_data.get("asan"): - return 3 + if run_info_data.get("ccov"): + return 4 + else: + return 3 return 1 diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/browsers/ie.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/browsers/ie.py index c981024f22b..553372f390e 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/browsers/ie.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/browsers/ie.py @@ -31,8 +31,6 @@ def executor_kwargs(test_type, server_config, cache_manager, run_info_data, ieOptions = {} ieOptions["requireWindowFocus"] = True capabilities = {} - capabilities["browserName"] = "internet explorer" - capabilities["platformName"] = "windows" capabilities["se:ieOptions"] = ieOptions executor_kwargs = base_executor_kwargs(test_type, server_config, cache_manager, **kwargs) diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/browsers/servo.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/browsers/servo.py index 3738ce4bddc..17fa59834fd 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/browsers/servo.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/browsers/servo.py @@ -54,7 +54,7 @@ def env_extras(**kwargs): def env_options(): return {"host": "127.0.0.1", "external_host": "web-platform.test", - "bind_hostname": "true", + "bind_hostname": "false", "testharnessreport": "testharnessreport-servo.js", "supports_debugger": True} diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/environment.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/environment.py index e8734405e00..874595cbff3 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/environment.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/environment.py @@ -36,8 +36,6 @@ def do_delayed_imports(logger, test_paths): try: from tools.serve import serve - except ImportError: - from wpt_tools.serve import serve except ImportError: failed.append("serve") @@ -86,7 +84,6 @@ class TestEnvironment(object): self.ssl_env = ssl_env self.server = None self.config = None - self.external_config = None self.pause_after_test = pause_after_test self.test_server_port = options.pop("test_server_port", True) self.debug_info = debug_info @@ -105,9 +102,10 @@ class TestEnvironment(object): cm.__enter__(self.options) self.setup_server_logging() self.config = self.load_config() - serve.set_computed_defaults(self.config) - self.external_config, self.servers = serve.start(self.config, self.ssl_env, - self.get_routes()) + ports = serve.get_ports(self.config, self.ssl_env) + self.config = serve.normalise_config(self.config, ports) + self.servers = serve.start(self.config, self.ssl_env, + self.get_routes()) if self.options.get("supports_debugger") and self.debug_info and self.debug_info.interactive: self.ignore_interrupts() return self @@ -160,6 +158,8 @@ class TestEnvironment(object): config["key_file"] = key_file config["certificate"] = certificate + serve.set_computed_defaults(config) + return config def setup_server_logging(self): diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/executors/base.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/executors/base.py index b33bc428ecb..d87e4ab9924 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/executors/base.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/executors/base.py @@ -113,7 +113,7 @@ class TestExecutor(object): :param browser: ExecutorBrowser instance providing properties of the browser that will be tested. :param server_config: Dictionary of wptserve server configuration of the - form stored in TestEnvironment.external_config + form stored in TestEnvironment.config :param timeout_multiplier: Multiplier relative to base timeout to use when setting test timeout. """ @@ -357,12 +357,10 @@ class WdspecExecutor(TestExecutor): return (test.result_cls(*data), []) def do_wdspec(self, session_config, path, timeout): - harness_result = ("OK", None) - subtest_results = pytestrunner.run(path, - self.server_config, - session_config, - timeout=timeout) - return (harness_result, subtest_results) + return pytestrunner.run(path, + self.server_config, + session_config, + timeout=timeout) def do_delayed_imports(self): global pytestrunner diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/executors/executormarionette.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/executors/executormarionette.py index e2163bb0707..2d0dc914d10 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/executors/executormarionette.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/executors/executormarionette.py @@ -63,30 +63,26 @@ class MarionetteProtocol(Protocol): self.marionette = marionette.Marionette(host='localhost', port=self.marionette_port, socket_timeout=None, - startup_timeout=None) + startup_timeout=startup_timeout) + try: + self.logger.debug("Waiting for Marionette connection") + while True: + try: + self.marionette.raise_for_port() + break + except IOError: + # When running in a debugger wait indefinitely for Firefox to start + if self.executor.debug_info is None: + raise - # XXX Move this timeout somewhere - self.logger.debug("Waiting for Marionette connection") - while True: - success = self.marionette.wait_for_port(startup_timeout) - #When running in a debugger wait indefinitely for firefox to start - if success or self.executor.debug_info is None: - break + self.logger.debug("Starting Marionette session") + self.marionette.start_session() + self.logger.debug("Marionette session started") - session_started = False - if success: - try: - self.logger.debug("Starting Marionette session") - self.marionette.start_session(capabilities=self.capabilities) - except Exception as e: - self.logger.warning("Starting marionette session failed: %s" % e) - else: - self.logger.debug("Marionette session started") - session_started = True - - if not success or not session_started: - self.logger.warning("Failed to connect to Marionette") + except Exception as e: + self.logger.warning("Failed to start a Marionette session: %s" % e) self.executor.runner.send_message("init_failed") + else: try: self.after_connect() @@ -173,9 +169,17 @@ class MarionetteProtocol(Protocol): self.load_runner(protocol) def wait(self): - socket_timeout = self.marionette.client.sock.gettimeout() + try: + socket_timeout = self.marionette.client.socket_timeout + except AttributeError: + # This can happen if there was a crash + return if socket_timeout: - self.marionette.timeout.script = socket_timeout / 2 + try: + self.marionette.timeout.script = socket_timeout / 2 + except (socket.error, IOError): + self.logger.debug("Socket closed") + return self.marionette.switch_to_window(self.runner_handle) while True: @@ -564,7 +568,7 @@ class InternalRefTestImplementation(object): self.executor.protocol.marionette.set_context(self.executor.protocol.marionette.CONTEXT_CONTENT) except Exception as e: # Ignore errors during teardown - self.logger.warning(traceback.traceback.format_exc(e)) + self.logger.warning(traceback.format_exc(e)) diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/executors/pytestrunner/runner.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/executors/pytestrunner/runner.py index 611a4989c39..0870b1232ad 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/executors/pytestrunner/runner.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/executors/pytestrunner/runner.py @@ -1,4 +1,5 @@ -"""Provides interface to deal with pytest. +""" +Provides interface to deal with pytest. Usage:: @@ -24,7 +25,8 @@ def do_delayed_imports(): def run(path, server_config, session_config, timeout=0): - """Run Python test at ``path`` in pytest. The provided ``session`` + """ + Run Python test at ``path`` in pytest. The provided ``session`` is exposed as a fixture available in the scope of the test functions. :param path: Path to the test file. @@ -33,36 +35,51 @@ def run(path, server_config, session_config, timeout=0): :param timeout: Duration before interrupting potentially hanging tests. If 0, there is no timeout. - :returns: List of subtest results, which are tuples of (test id, - status, message, stacktrace). + :returns: (, [, ...]), + where is (test id, status, message, stacktrace). """ - if pytest is None: do_delayed_imports() - recorder = SubtestResultRecorder() - os.environ["WD_HOST"] = session_config["host"] os.environ["WD_PORT"] = str(session_config["port"]) os.environ["WD_CAPABILITIES"] = json.dumps(session_config["capabilities"]) os.environ["WD_SERVER_CONFIG"] = json.dumps(server_config) - plugins = [recorder] - - # TODO(ato): Deal with timeouts + harness = HarnessResultRecorder() + subtests = SubtestResultRecorder() with TemporaryDirectory() as cache: - pytest.main(["--strict", # turn warnings into errors - "--verbose", # show each individual subtest - "--capture", "no", # enable stdout/stderr from tests - "--basetemp", cache, # temporary directory - "--showlocals", # display contents of variables in local scope - "-p", "no:mozlog", # use the WPT result recorder - "-p", "no:cacheprovider", # disable state preservation across invocations - path], - plugins=plugins) + try: + pytest.main(["--strict", # turn warnings into errors + "--verbose", # show each individual subtest + "--capture", "no", # enable stdout/stderr from tests + "--basetemp", cache, # temporary directory + "--showlocals", # display contents of variables in local scope + "-p", "no:mozlog", # use the WPT result recorder + "-p", "no:cacheprovider", # disable state preservation across invocations + path], + plugins=[harness, subtests]) + except Exception as e: + harness.outcome = ("ERROR", str(e)) - return recorder.results + return (harness.outcome, subtests.results) + + +class HarnessResultRecorder(object): + outcomes = { + "failed": "ERROR", + "passed": "OK", + "skipped": "SKIP", + } + + def __init__(self): + # we are ok unless told otherwise + self.outcome = ("OK", None) + + def pytest_collectreport(self, report): + harness_result = self.outcomes[report.outcome] + self.outcome = (harness_result, None) class SubtestResultRecorder(object): @@ -100,7 +117,7 @@ class SubtestResultRecorder(object): def record(self, test, status, message=None, stack=None): if stack is not None: stack = str(stack) - new_result = (test, status, message, stack) + new_result = (test.split("::")[-1], status, message, stack) self.results.append(new_result) diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/stability.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/stability.py index dc1a1d0fed0..6eb060485c2 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/stability.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/stability.py @@ -1,14 +1,14 @@ import copy import functools import imp +import io import os -import sys from collections import OrderedDict, defaultdict from datetime import datetime from mozlog import reader -from mozlog.formatters import JSONFormatter, TbplFormatter -from mozlog.handlers import BaseHandler, LogLevelFilter, StreamHandler +from mozlog.formatters import JSONFormatter +from mozlog.handlers import BaseHandler, StreamHandler, LogLevelFilter here = os.path.dirname(__file__) localpaths = imp.load_source("localpaths", os.path.abspath(os.path.join(here, os.pardir, os.pardir, "localpaths.py"))) @@ -86,6 +86,8 @@ class LogHandler(reader.LogHandler): def is_inconsistent(results_dict, iterations): """Return whether or not a single test is inconsistent.""" + if 'SKIP' in results_dict: + return False return len(results_dict) > 1 or sum(results_dict.values()) != iterations @@ -178,31 +180,29 @@ def run_step(logger, iterations, restart_after_iteration, kwargs_extras, **kwarg kwargs["pause_after_test"] = False kwargs.update(kwargs_extras) - handler = LogActionFilter( - LogLevelFilter( - StreamHandler( - sys.stdout, - TbplFormatter() - ), - "WARNING"), - ["log", "process_output"]) + def wrap_handler(x): + x = LogLevelFilter(x, "WARNING") + if not kwargs["verify_log_full"]: + x = LogActionFilter(x, ["log", "process_output"]) + return x - # There is a public API for this in the next mozlog initial_handlers = logger._state.handlers - logger._state.handlers = [] + logger._state.handlers = [wrap_handler(handler) + for handler in initial_handlers] - with open("raw.log", "wb") as log: - # Setup logging for wptrunner that keeps process output and - # warning+ level logs only - logger.add_handler(handler) - logger.add_handler(StreamHandler(log, JSONFormatter())) + log = io.BytesIO() + # Setup logging for wptrunner that keeps process output and + # warning+ level logs only + logger.add_handler(StreamHandler(log, JSONFormatter())) - wptrunner.run_tests(**kwargs) + wptrunner.run_tests(**kwargs) logger._state.handlers = initial_handlers + logger._state.running_tests = set() + logger._state.suite_started = False - with open("raw.log", "rb") as log: - results, inconsistent = process_results(log, iterations) + log.seek(0) + results, inconsistent = process_results(log, iterations) return results, inconsistent, iterations diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/testdriver-vendor.js b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/testdriver-vendor.js new file mode 100644 index 00000000000..3e884036363 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/testdriver-vendor.js @@ -0,0 +1 @@ +// This file intentionally left blank diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/testloader.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/testloader.py index 71c55232580..0eb78bb884f 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/testloader.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/testloader.py @@ -460,7 +460,8 @@ class TestLoader(object): chunk_type="none", total_chunks=1, chunk_number=1, - include_https=True): + include_https=True, + skip_timeout=False): self.test_types = test_types self.run_info = run_info @@ -472,6 +473,7 @@ class TestLoader(object): self.tests = None self.disabled_tests = None self.include_https = include_https + self.skip_timeout = skip_timeout self.chunk_type = chunk_type self.total_chunks = total_chunks @@ -557,6 +559,8 @@ class TestLoader(object): enabled = not test.disabled() if not self.include_https and test.environment["protocol"] == "https": enabled = False + if self.skip_timeout and test.expected() == "TIMEOUT": + enabled = False key = "enabled" if enabled else "disabled" tests[key][test_type].append(test) diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/testrunner.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/testrunner.py index 64418285e66..75f4825f952 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/testrunner.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/testrunner.py @@ -120,6 +120,13 @@ def start_runner(runner_command_queue, runner_result_queue, executor_browser_cls, executor_browser_kwargs, stop_flag): """Launch a TestRunner in a new process""" + def log(level, msg): + runner_result_queue.put(("log", (level, {"message": msg}))) + + def handle_error(e): + log("critical", traceback.format_exc()) + stop_flag.set() + try: browser = executor_browser_cls(**executor_browser_kwargs) executor = executor_cls(browser, **executor_kwargs) @@ -128,10 +135,10 @@ def start_runner(runner_command_queue, runner_result_queue, runner.run() except KeyboardInterrupt: stop_flag.set() - except Exception: - runner_result_queue.put(("log", ("critical", {"message": traceback.format_exc()}))) - print >> sys.stderr, traceback.format_exc() - stop_flag.set() + except Exception as e: + handle_error(e) + except Exception as e: + handle_error(e) finally: runner_command_queue = None runner_result_queue = None @@ -389,6 +396,7 @@ class TestRunnerManager(threading.Thread): } try: command, data = self.command_queue.get(True, 1) + self.logger.debug("Got command: %r" % command) except IOError: self.logger.error("Got IOError from poll") return RunnerManagerState.restarting(0) @@ -676,7 +684,18 @@ class TestRunnerManager(threading.Thread): self.browser.cleanup() while True: try: - self.logger.warning(" ".join(map(repr, self.command_queue.get_nowait()))) + cmd, data = self.command_queue.get_nowait() + except Empty: + break + else: + if cmd == "log": + self.log(*data) + else: + self.logger.warning("%r: %r" % (cmd, data)) + while True: + try: + cmd, data = self.remote_queue.get_nowait() + self.logger.warning("%r: %r" % (cmd, data)) except Empty: break diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/update/sync.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/update/sync.py index 40bd1d7ebb7..c1bff854349 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/update/sync.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/update/sync.py @@ -81,7 +81,6 @@ def copy_wpt_tree(tree, dest, excludes=None, includes=None): shutil.copy2(source_path, dest_path) for source, destination in [("testharness_runner.html", ""), - ("testharnessreport.js", "resources/"), ("testdriver-vendor.js", "resources/")]: source_path = os.path.join(here, os.pardir, source) dest_path = os.path.join(dest, destination, os.path.split(source)[1]) diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/update/update.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/update/update.py index d9ef40fcda8..c985d3513ac 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/update/update.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/update/update.py @@ -11,10 +11,7 @@ from state import State def setup_paths(sync_path): sys.path.insert(0, os.path.abspath(sync_path)) - try: - from tools import localpaths - except ImportError: - from wpt_tools import localpaths + from tools import localpaths class LoadConfig(Step): """Step for loading configuration from the ini file and kwargs.""" diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptcommandline.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptcommandline.py index b9f7a4c34a5..b232462d915 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptcommandline.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptcommandline.py @@ -79,6 +79,9 @@ scheme host and port.""") mode_group.add_argument("--verify", action="store_true", default=False, help="Run a stability check on the selected tests") + mode_group.add_argument("--verify-log-full", action="store_true", + default=False, + help="Output per-iteration test results when running verify") test_selection_group = parser.add_argument_group("Test Selection") test_selection_group.add_argument("--test-types", action="store", @@ -91,6 +94,8 @@ scheme host and port.""") help="URL prefix to exclude") test_selection_group.add_argument("--include-manifest", type=abs_path, help="Path to manifest listing tests to include") + test_selection_group.add_argument("--skip-timeout", action="store_true", + help="Skip tests that are expected to time out") test_selection_group.add_argument("--tag", action="append", dest="tags", help="Labels applied to tests to include in the run. Labels starting dir: are equivalent to top-level directories.") diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptlogging.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptlogging.py index 4d320617859..26d174c066b 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptlogging.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptlogging.py @@ -1,13 +1,20 @@ import logging import sys import threading +from Queue import Empty from StringIO import StringIO from multiprocessing import Queue -from mozlog import commandline, stdadapter +from mozlog import commandline, stdadapter, set_default_logger +from mozlog.structuredlog import StructuredLogger def setup(args, defaults): - logger = commandline.setup_logging("web-platform-tests", args, defaults) + logger = args.pop('log', None) + if logger: + set_default_logger(logger) + StructuredLogger._logger_states["web-platform-tests"] = logger._state + else: + logger = commandline.setup_logging("web-platform-tests", args, defaults) setup_stdlib_logger() for name in args.keys(): @@ -45,7 +52,6 @@ class LogLevelRewriter(object): return self.inner(data) - class LogThread(threading.Thread): def __init__(self, queue, logger, level): self.queue = queue @@ -120,5 +126,10 @@ class CaptureIO(object): self.logging_queue.put(None) if self.logging_thread is not None: self.logging_thread.join(10) + while not self.logging_queue.empty(): + try: + self.logger.warning("Dropping log message: %r", self.logging_queue.get()) + except Exception: + pass self.logging_queue.close() self.logger.info("queue closed") diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptrunner.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptrunner.py index f34698a6380..637cbe57b6f 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptrunner.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptrunner.py @@ -38,6 +38,7 @@ def setup_logging(*args, **kwargs): global logger logger = wptlogging.setup(*args, **kwargs) + def get_loader(test_paths, product, ssl_env, debug=None, run_info_extras=None, **kwargs): if run_info_extras is None: run_info_extras = {} @@ -67,9 +68,11 @@ def get_loader(test_paths, product, ssl_env, debug=None, run_info_extras=None, * chunk_type=kwargs["chunk_type"], total_chunks=kwargs["total_chunks"], chunk_number=kwargs["this_chunk"], - include_https=ssl_env.ssl_enabled) + include_https=ssl_env.ssl_enabled, + skip_timeout=kwargs["skip_timeout"]) return run_info, test_loader + def list_test_groups(test_paths, product, **kwargs): env.do_delayed_imports(logger, test_paths) @@ -198,7 +201,7 @@ def run_tests(config, test_paths, product, **kwargs): logger.info("Repetition %i / %i" % (repeat_count, repeat)) unexpected_count = 0 - logger.suite_start(test_loader.test_ids, run_info) + logger.suite_start(test_loader.test_ids, name='web-platform-test', run_info=run_info) for test_type in kwargs["test_types"]: logger.info("Running %s tests" % test_type) @@ -217,10 +220,9 @@ def run_tests(config, test_paths, product, **kwargs): ssl_env=ssl_env, **kwargs) - executor_cls = executor_classes.get(test_type) executor_kwargs = get_executor_kwargs(test_type, - test_environment.external_config, + test_environment.config, test_environment.cache_manager, run_info, **kwargs) diff --git a/tests/wpt/web-platform-tests/tools/wptserve/docs/pipes.rst b/tests/wpt/web-platform-tests/tools/wptserve/docs/pipes.rst index c606140d474..39e98ab4f5e 100644 --- a/tests/wpt/web-platform-tests/tools/wptserve/docs/pipes.rst +++ b/tests/wpt/web-platform-tests/tools/wptserve/docs/pipes.rst @@ -11,6 +11,10 @@ functions are applied to the response from left to right. For example:: This would serve bytes 1 to 199, inclusive, of foo.txt with the HTTP status code 404. +.. note:: + Pipes are only applied to static files, and will not work if applied to + other types of handlers, such as Python File Handlers. + There are several built-in pipe functions, and it is possible to add more using the `@pipe` decorator on a function, if required. diff --git a/tests/wpt/web-platform-tests/tools/wptserve/tests/functional/test_pipes.py b/tests/wpt/web-platform-tests/tools/wptserve/tests/functional/test_pipes.py index 95da70faea9..bd38f2ef18f 100644 --- a/tests/wpt/web-platform-tests/tools/wptserve/tests/functional/test_pipes.py +++ b/tests/wpt/web-platform-tests/tools/wptserve/tests/functional/test_pipes.py @@ -76,5 +76,11 @@ class TestTrickle(TestUsingServer): self.assertEqual(resp.read(), expected) self.assertGreater(6, t1-t0) + def test_headers(self): + resp = self.request("/document.txt", query="pipe=trickle(d0.01)") + self.assertEqual(resp.info()["Cache-Control"], "no-cache, no-store, must-revalidate") + self.assertEqual(resp.info()["Pragma"], "no-cache") + self.assertEqual(resp.info()["Expires"], "0") + if __name__ == '__main__': unittest.main() diff --git a/tests/wpt/web-platform-tests/tools/wptserve/wptserve/pipes.py b/tests/wpt/web-platform-tests/tools/wptserve/wptserve/pipes.py index 95108ba7e93..7203815b70c 100644 --- a/tests/wpt/web-platform-tests/tools/wptserve/wptserve/pipes.py +++ b/tests/wpt/web-platform-tests/tools/wptserve/wptserve/pipes.py @@ -231,6 +231,13 @@ def trickle(request, response, delays): content = resolve_content(response) offset = [0] + if not ("Cache-Control" in response.headers or + "Pragma" in response.headers or + "Expires" in response.headers): + response.headers.set("Cache-Control", "no-cache, no-store, must-revalidate") + response.headers.set("Pragma", "no-cache") + response.headers.set("Expires", "0") + def add_content(delays, repeat=False): for i, (item_type, value) in enumerate(delays): if item_type == "bytes": diff --git a/tests/wpt/web-platform-tests/tools/wptserve/wptserve/server.py b/tests/wpt/web-platform-tests/tools/wptserve/wptserve/server.py index 0ab512cb2a5..2a83bd8097e 100644 --- a/tests/wpt/web-platform-tests/tools/wptserve/wptserve/server.py +++ b/tests/wpt/web-platform-tests/tools/wptserve/wptserve/server.py @@ -418,7 +418,8 @@ class WebTestHttpd(object): _host, self.port = self.httpd.socket.getsockname() except Exception: - self.logger.error('Init failed! You may need to modify your hosts file. Refer to README.md.') + self.logger.error("Failed to start HTTP server. " + "You may need to edit /etc/hosts or similar, see README.md.") raise def start(self, block=False): diff --git a/tests/wpt/web-platform-tests/touch-events/multi-touch-interactions-manual.html b/tests/wpt/web-platform-tests/touch-events/multi-touch-interactions-manual.html index e9835d9c90b..45e53af0ee9 100644 --- a/tests/wpt/web-platform-tests/touch-events/multi-touch-interactions-manual.html +++ b/tests/wpt/web-platform-tests/touch-events/multi-touch-interactions-manual.html @@ -1,7 +1,7 @@ + @@ -11,10 +13,10 @@ @@ -9,21 +9,21 @@ diff --git a/tests/wpt/web-platform-tests/web-animations/animation-model/keyframe-effects/effect-value-context.html b/tests/wpt/web-platform-tests/web-animations/animation-model/keyframe-effects/effect-value-context.html index 07fb6097c9f..3730a02098a 100644 --- a/tests/wpt/web-platform-tests/web-animations/animation-model/keyframe-effects/effect-value-context.html +++ b/tests/wpt/web-platform-tests/web-animations/animation-model/keyframe-effects/effect-value-context.html @@ -1,19 +1,21 @@ -Tests that property values respond to changes to their context - +The effect value of a keyframe effect: Property values that depend on + their context (target element) +
    + + +
    + diff --git a/tests/wpt/web-platform-tests/web-animations/animation-model/keyframe-effects/effect-value-overlapping-keyframes.html b/tests/wpt/web-platform-tests/web-animations/animation-model/keyframe-effects/effect-value-overlapping-keyframes.html index 99b4f3df6fe..2a41f04c05a 100644 --- a/tests/wpt/web-platform-tests/web-animations/animation-model/keyframe-effects/effect-value-overlapping-keyframes.html +++ b/tests/wpt/web-platform-tests/web-animations/animation-model/keyframe-effects/effect-value-overlapping-keyframes.html @@ -1,7 +1,7 @@ -Effect value computation tests when keyframes overlap - +The effect value of a keyframe effect: Overlapping keyframes + @@ -11,16 +11,16 @@ @@ -13,8 +14,8 @@ // Test that applying easing to keyframes is applied as expected -gEasingTests.forEach(params => { - test(function(t) { +for (const params of gEasingTests) { + test(t => { const target = createDiv(t); const anim = target.animate([ { width: '0px' }, // We put the easing on the second keyframe @@ -25,7 +26,7 @@ gEasingTests.forEach(params => { { duration: 2000, fill: 'forwards' }); - [ 0, 999, 1000, 1100, 1500, 2000 ].forEach(sampleTime => { + for (const sampleTime of [0, 999, 1000, 1100, 1500, 2000]) { anim.currentTime = sampleTime; const portion = (sampleTime - 1000) / 1000; @@ -37,18 +38,18 @@ gEasingTests.forEach(params => { 0.01, 'The width should be approximately ' + `${expectedWidth} at ${sampleTime}ms`); - }); + } }, `A ${params.desc} on a keyframe affects the resulting style`); -}); +} // Test that a linear-equivalent cubic-bezier easing applied to a keyframe does // not alter (including clamping) the result. -gEasingTests.forEach(params => { +for (const params of gEasingTests) { const linearEquivalentEasings = [ 'cubic-bezier(0, 0, 0, 0)', 'cubic-bezier(1, 1, 1, 1)' ]; - test(function(t) { - linearEquivalentEasings.forEach(linearEquivalentEasing => { + test(t => { + for (const linearEquivalentEasing of linearEquivalentEasings) { const timing = { duration: 1000, fill: 'forwards', easing: params.easing }; @@ -65,7 +66,7 @@ gEasingTests.forEach(params => { { width: '100px' } ], timing); - [ 0, 250, 500, 750, 1000 ].forEach(sampleTime => { + for (const sampleTime of [0, 250, 500, 750, 1000]) { linearAnim.currentTime = sampleTime; equivalentAnim.currentTime = sampleTime; @@ -73,11 +74,11 @@ gEasingTests.forEach(params => { getComputedStyle(equivalentTarget).width, `The 'width' of the animated elements should be equal ` + `at ${sampleTime}ms`); - }); - }); + } + } }, 'Linear-equivalent cubic-bezier keyframe easing applied to an effect ' + `with a ${params.desc} does not alter the result`); -}); +} diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/Animatable/animate-no-browsing-context.html b/tests/wpt/web-platform-tests/web-animations/interfaces/Animatable/animate-no-browsing-context.html index 10371959d33..61a7502a988 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/Animatable/animate-no-browsing-context.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/Animatable/animate-no-browsing-context.html @@ -1,8 +1,8 @@ -Animatable.animate tests in combination with elements in documents +<title>Animatable.animate in combination with elements in documents without a browsing context - + @@ -76,16 +76,15 @@ promise_test(t => { const div = xhrdoc.getElementById('test'); anim = div.animate(null); anim.timeline = document.timeline; - assert_equals(anim.playState, 'pending', - 'The animation should be initially pending'); + assert_true(anim.pending, 'The animation should be initially pending'); return waitForAnimationFrames(2); }).then(() => { // Because the element is in a document without a browsing context, it will // not be rendered and hence the user agent will never deem it ready to // animate. - assert_equals(anim.playState, 'pending', - 'The animation should still be pending after replacing' - + ' the document timeline'); + assert_true(anim.pending, + 'The animation should still be pending after replacing' + + ' the document timeline'); }); }, 'Replacing the timeline of an animation targetting an element in a' + ' document without a browsing context leaves it in the pending state'); diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/Animatable/animate.html b/tests/wpt/web-platform-tests/web-animations/interfaces/Animatable/animate.html index a07103ccc7b..36c4ee148e8 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/Animatable/animate.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/Animatable/animate.html @@ -1,7 +1,7 @@ -Animatable.animate tests - +Animatable.animate + @@ -16,16 +16,16 @@ // Tests on Element -test(function(t) { - var div = createDiv(t); - var anim = div.animate(null); +test(t => { + const div = createDiv(t); + const anim = div.animate(null); assert_class_string(anim, 'Animation', 'Returned object is an Animation'); }, 'Element.animate() creates an Animation object'); -test(function(t) { - var iframe = window.frames[0]; - var div = createDiv(t, iframe.document); - var anim = Element.prototype.animate.call(div, null); +test(t => { + const iframe = window.frames[0]; + const div = createDiv(t, iframe.document); + const anim = Element.prototype.animate.call(div, null); assert_equals(Object.getPrototypeOf(anim), iframe.Animation.prototype, 'The prototype of the created Animation is that defined on' + ' the relevant global for the target element'); @@ -35,17 +35,17 @@ test(function(t) { }, 'Element.animate() creates an Animation object in the relevant realm of' + ' the target element'); -test(function(t) { - var div = createDiv(t); - var anim = Element.prototype.animate.call(div, null); +test(t => { + const div = createDiv(t); + const anim = Element.prototype.animate.call(div, null); assert_class_string(anim.effect, 'KeyframeEffect', 'Returned Animation has a KeyframeEffect'); }, 'Element.animate() creates an Animation object with a KeyframeEffect'); -test(function(t) { - var iframe = window.frames[0]; - var div = createDiv(t, iframe.document); - var anim = Element.prototype.animate.call(div, null); +test(t => { + const iframe = window.frames[0]; + const div = createDiv(t, iframe.document); + const anim = Element.prototype.animate.call(div, null); assert_equals(Object.getPrototypeOf(anim.effect), iframe.KeyframeEffect.prototype, 'The prototype of the created KeyframeEffect is that defined on' @@ -57,10 +57,10 @@ test(function(t) { }, 'Element.animate() creates an Animation object with a KeyframeEffect' + ' that is created in the relevant realm of the target element'); -test(function(t) { - var iframe = window.frames[0]; - var div = createDiv(t, iframe.document); - var anim = div.animate(null); +test(t => { + const iframe = window.frames[0]; + const div = createDiv(t, iframe.document); + const anim = div.animate(null); assert_equals(Object.getPrototypeOf(anim.effect.timing), iframe.AnimationEffectTiming.prototype, 'The prototype of the created AnimationEffectTiming is that' @@ -73,91 +73,91 @@ test(function(t) { + ' whose AnimationEffectTiming object is created in the relevant realm' + ' of the target element'); -gEmptyKeyframeListTests.forEach(function(subTest) { - test(function(t) { - var div = createDiv(t); - var anim = div.animate(subTest, 2000); +for (const subtest of gEmptyKeyframeListTests) { + test(t => { + const div = createDiv(t); + const anim = div.animate(subtest, 2000); assert_not_equals(anim, null); }, 'Element.animate() accepts empty keyframe lists ' + - `(input: ${JSON.stringify(subTest)})`); -}); + `(input: ${JSON.stringify(subtest)})`); +} -gKeyframesTests.forEach(function(subtest) { - test(function(t) { - var div = createDiv(t); - var anim = div.animate(subtest.input, 2000); +for (const subtest of gKeyframesTests) { + test(t => { + const div = createDiv(t); + const anim = div.animate(subtest.input, 2000); assert_frame_lists_equal(anim.effect.getKeyframes(), subtest.output); - }, 'Element.animate() accepts ' + subtest.desc); -}); + }, `Element.animate() accepts ${subtest.desc}`); +} -gInvalidKeyframesTests.forEach(function(subtest) { - test(function(t) { - var div = createDiv(t); - assert_throws(new TypeError, function() { +for (const subtest of gInvalidKeyframesTests) { + test(t => { + const div = createDiv(t); + assert_throws(new TypeError, () => { div.animate(subtest.input, 2000); }); - }, 'Element.animate() does not accept ' + subtest.desc); -}); + }, `Element.animate() does not accept ${subtest.desc}`); +} -gInvalidEasings.forEach(invalidEasing => { - test(function(t) { - var div = createDiv(t); +for (const invalidEasing of gInvalidEasings) { + test(t => { + const div = createDiv(t); assert_throws(new TypeError, () => { div.animate({ easing: invalidEasing }, 2000); }); }, `Element.animate() does not accept invalid easing: '${invalidEasing}'`); -}); +} -test(function(t) { - var div = createDiv(t); - var anim = div.animate({ opacity: [ 0, 1 ] }, 2000); +test(t => { + const div = createDiv(t); + const anim = div.animate({ opacity: [ 0, 1 ] }, 2000); assert_equals(anim.effect.timing.duration, 2000); // Also check that unspecified parameters receive their default values assert_equals(anim.effect.timing.fill, 'auto'); }, 'Element.animate() accepts a double as an options argument'); -test(function(t) { - var div = createDiv(t); - var anim = div.animate({ opacity: [ 0, 1 ] }, - { duration: Infinity, fill: 'forwards' }); +test(t => { + const div = createDiv(t); + const anim = div.animate({ opacity: [ 0, 1 ] }, + { duration: Infinity, fill: 'forwards' }); assert_equals(anim.effect.timing.duration, Infinity); assert_equals(anim.effect.timing.fill, 'forwards'); // Also check that unspecified parameters receive their default values assert_equals(anim.effect.timing.direction, 'normal'); }, 'Element.animate() accepts a KeyframeAnimationOptions argument'); -test(function(t) { - var div = createDiv(t); - var anim = div.animate({ opacity: [ 0, 1 ] }); +test(t => { + const div = createDiv(t); + const anim = div.animate({ opacity: [ 0, 1 ] }); assert_equals(anim.effect.timing.duration, 'auto'); }, 'Element.animate() accepts an absent options argument'); -test(function(t) { - var div = createDiv(t); - var anim = div.animate({ opacity: [ 0, 1 ] }, 2000); +test(t => { + const div = createDiv(t); + const anim = div.animate({ opacity: [ 0, 1 ] }, 2000); assert_equals(anim.id, ''); }, 'Element.animate() correctly sets the id attribute when no id is specified'); -test(function(t) { - var div = createDiv(t); - var anim = div.animate({ opacity: [ 0, 1 ] }, { id: 'test' }); +test(t => { + const div = createDiv(t); + const anim = div.animate({ opacity: [ 0, 1 ] }, { id: 'test' }); assert_equals(anim.id, 'test'); }, 'Element.animate() correctly sets the id attribute'); -test(function(t) { - var div = createDiv(t); - var anim = div.animate({ opacity: [ 0, 1 ] }, 2000); +test(t => { + const div = createDiv(t); + const anim = div.animate({ opacity: [ 0, 1 ] }, 2000); assert_equals(anim.timeline, document.timeline); }, 'Element.animate() correctly sets the Animation\'s timeline'); -async_test(function(t) { - var iframe = document.createElement('iframe'); +async_test(t => { + const iframe = document.createElement('iframe'); iframe.width = 10; iframe.height = 10; - iframe.addEventListener('load', t.step_func(function() { - var div = createDiv(t, iframe.contentDocument); - var anim = div.animate({ opacity: [ 0, 1 ] }, 2000); + iframe.addEventListener('load', t.step_func(() => { + const div = createDiv(t, iframe.contentDocument); + const anim = div.animate({ opacity: [ 0, 1 ] }, 2000); assert_equals(anim.timeline, iframe.contentDocument.timeline); iframe.remove(); t.done(); @@ -167,23 +167,23 @@ async_test(function(t) { }, 'Element.animate() correctly sets the Animation\'s timeline when ' + 'triggered on an element in a different document'); -test(function(t) { - var div = createDiv(t); - var anim = div.animate({ opacity: [ 0, 1 ] }, 2000); - assert_equals(anim.playState, 'pending'); +test(t => { + const div = createDiv(t); + const anim = div.animate({ opacity: [ 0, 1 ] }, 2000); + assert_equals(anim.playState, 'running'); }, 'Element.animate() calls play on the Animation'); // Tests on CSSPseudoElement -test(function(t) { - var pseudoTarget = createPseudo(t, 'before'); - var anim = pseudoTarget.animate(null); +test(t => { + const pseudoTarget = createPseudo(t, 'before'); + const anim = pseudoTarget.animate(null); assert_class_string(anim, 'Animation', 'The returned object is an Animation'); }, 'CSSPseudoElement.animate() creates an Animation object'); -test(function(t) { - var pseudoTarget = createPseudo(t, 'before'); - var anim = pseudoTarget.animate(null); +test(t => { + const pseudoTarget = createPseudo(t, 'before'); + const anim = pseudoTarget.animate(null); assert_equals(anim.effect.target, pseudoTarget, 'The returned Animation targets to the correct object'); }, 'CSSPseudoElement.animate() creates an Animation object targeting ' + diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/Animatable/getAnimations.html b/tests/wpt/web-platform-tests/web-animations/interfaces/Animatable/getAnimations.html index 49551a8ef2b..d05e2aa50b9 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/Animatable/getAnimations.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/Animatable/getAnimations.html @@ -1,7 +1,7 @@ -Animatable.getAnimations tests - +Animatable.getAnimations + @@ -9,62 +9,148 @@ diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/Animation/cancel.html b/tests/wpt/web-platform-tests/web-animations/interfaces/Animation/cancel.html index f8f174abd91..be1bb5d7847 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/Animation/cancel.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/Animation/cancel.html @@ -1,7 +1,7 @@ -Animation.cancel() - +Animation.cancel + @@ -10,11 +10,13 @@ @@ -10,9 +9,9 @@
    diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/Animation/effect.html b/tests/wpt/web-platform-tests/web-animations/interfaces/Animation/effect.html index 3c9c4f079c0..175fc31341b 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/Animation/effect.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/Animation/effect.html @@ -1,29 +1,29 @@ -Animation.effect tests - +Animation.effect +
    @@ -10,32 +10,32 @@
    @@ -20,6 +20,7 @@ interface Animation : EventTarget { attribute double? currentTime; attribute double playbackRate; readonly attribute AnimationPlayState playState; + readonly attribute boolean pending; readonly attribute Promise ready; readonly attribute Promise finished; attribute EventHandler onfinish; diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/Animation/oncancel.html b/tests/wpt/web-platform-tests/web-animations/interfaces/Animation/oncancel.html index b8d9ced61ec..3e918a40d0d 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/Animation/oncancel.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/Animation/oncancel.html @@ -1,24 +1,24 @@ Animation.oncancel - +
    + + + +
    + + diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/Animation/play.html b/tests/wpt/web-platform-tests/web-animations/interfaces/Animation/play.html index 767d8df1707..3e8f923d544 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/Animation/play.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/Animation/play.html @@ -1,7 +1,7 @@ -Animation.play() - +Animation.play + @@ -10,19 +10,19 @@ - - - -
    - - diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/Animation/playbackRate.html b/tests/wpt/web-platform-tests/web-animations/interfaces/Animation/playbackRate.html index c923df6b4ba..9a3b76240f0 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/Animation/playbackRate.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/Animation/playbackRate.html @@ -1,23 +1,23 @@ Animation.playbackRate - +
    @@ -11,41 +11,41 @@ href="https://w3c.github.io/web-animations/#dom-animation-starttime"> @@ -11,69 +10,69 @@ diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/direction.html b/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/direction.html index 95718120245..7bc315da967 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/direction.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/direction.html @@ -1,8 +1,7 @@ -direction tests - - +AnimationEffectTiming.direction + @@ -11,22 +10,99 @@ diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/duration.html b/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/duration.html index c8154d53970..9caa0e36e05 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/duration.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/duration.html @@ -1,8 +1,7 @@ -duration tests - - +AnimationEffectTiming.duration + @@ -11,148 +10,150 @@ diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/easing.html b/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/easing.html index 11173fc8644..ec2b239fe52 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/easing.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/easing.html @@ -1,7 +1,7 @@ -easing tests - +AnimationEffectTiming.easing + @@ -11,68 +11,68 @@ diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/endDelay.html b/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/endDelay.html index c6c2e88cc2d..b6793edaed5 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/endDelay.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/endDelay.html @@ -1,8 +1,7 @@ -endDelay tests - - +AnimationEffectTiming.endDelay + @@ -11,79 +10,80 @@ diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/fill.html b/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/fill.html index 89f6a467938..01739478f47 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/fill.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/fill.html @@ -1,7 +1,7 @@ -fill tests - +AnimationEffectTiming.fill + @@ -10,20 +10,21 @@ diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/getAnimations.html b/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/getAnimations.html deleted file mode 100644 index d96192c9d01..00000000000 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/getAnimations.html +++ /dev/null @@ -1,91 +0,0 @@ - - -Element.getAnimations tests - - - - - - -
    - - diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/getComputedStyle.html b/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/getComputedStyle.html deleted file mode 100644 index cfc233f0e98..00000000000 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/getComputedStyle.html +++ /dev/null @@ -1,172 +0,0 @@ - - -getComputedStyle tests - - - - - - -
    - - diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/getComputedTiming.html b/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/getComputedTiming.html new file mode 100644 index 00000000000..9a92880a606 --- /dev/null +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/getComputedTiming.html @@ -0,0 +1,201 @@ + + +AnimationEffectTiming.getComputedTiming + + + + + +
    + + diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/idlharness.html b/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/idlharness.html index 866d5bf8ee5..7e537d1dd83 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/idlharness.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/idlharness.html @@ -2,9 +2,9 @@ AnimationEffectTiming and AnimationEffectTimingReadOnly IDL + href="https://drafts.csswg.org/web-animations/#animationeffecttiming"> + href="https://drafts.csswg.org/web-animations/#animationeffecttimingreadonly"> diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/iterationStart.html b/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/iterationStart.html index ed2d0e097ac..5521f1e8594 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/iterationStart.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/iterationStart.html @@ -1,8 +1,7 @@ -iterationStart tests - - +AnimationEffectTiming.iterationStart + @@ -11,66 +10,63 @@ diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/iterations.html b/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/iterations.html index 8dfe1695643..32390626463 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/iterations.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/iterations.html @@ -1,7 +1,7 @@ -iterations tests - +AnimationEffectTiming.iterations + @@ -10,52 +10,85 @@ diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationPlaybackEvent/constructor.html b/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationPlaybackEvent/constructor.html index ca6dc6eec0c..1c40a3fb211 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationPlaybackEvent/constructor.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/AnimationPlaybackEvent/constructor.html @@ -2,21 +2,21 @@ AnimationPlaybackEvent constructor + href="https://drafts.csswg.org/web-animations/#dom-animationplaybackevent-animationplaybackevent">
    diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/Document/getAnimations.html b/tests/wpt/web-platform-tests/web-animations/interfaces/Document/getAnimations.html index e87751c04b2..165626decc9 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/Document/getAnimations.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/Document/getAnimations.html @@ -1,7 +1,7 @@ -document.getAnimations tests - +Document.getAnimations + @@ -9,20 +9,20 @@
    @@ -10,7 +10,7 @@
    diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/composite.html b/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/composite.html index 1825b71db09..745f66bc711 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/composite.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/composite.html @@ -1,8 +1,8 @@ -KeyframeEffect.composite tests +KeyframeEffect.composite + href="https://drafts.csswg.org/web-animations/#dom-keyframeeffect-composite"> @@ -11,34 +11,34 @@ @@ -19,16 +19,16 @@ const target = document.getElementById('target'); -test(function(t) { - gEmptyKeyframeListTests.forEach(function(frames) { +test(t => { + for (const frames of gEmptyKeyframeListTests) { assert_equals(new KeyframeEffectReadOnly(target, frames) .getKeyframes().length, - 0, 'number of frames for ' + JSON.stringify(frames)); - }); + 0, `number of frames for ${JSON.stringify(frames)}`); + } }, 'A KeyframeEffectReadOnly can be constructed with no frames'); -test(function(t) { - gEasingParsingTests.forEach(function(subtest) { +test(t => { + for (const subtest of gEasingParsingTests) { const easing = subtest[0]; const expected = subtest[1]; const effect = new KeyframeEffectReadOnly(target, { @@ -36,98 +36,96 @@ test(function(t) { }, { easing: easing }); assert_equals(effect.timing.easing, expected, `resulting easing for '${easing}'`); - }); + } }, 'easing values are parsed correctly when passed to the ' + 'KeyframeEffectReadOnly constructor in KeyframeEffectOptions'); -test(function(t) { - gInvalidEasings.forEach(invalidEasing => { +test(t => { + for (const invalidEasing of gInvalidEasings) { assert_throws(new TypeError, () => { new KeyframeEffectReadOnly(target, null, { easing: invalidEasing }); }, `TypeError is thrown for easing '${invalidEasing}'`); - }); + } }, 'Invalid easing values are correctly rejected when passed to the ' + 'KeyframeEffectReadOnly constructor in KeyframeEffectOptions'); -test(function(t) { - const getKeyframe = function(composite) { - return { left: [ '10px', '20px' ], composite: composite }; - }; - gGoodKeyframeCompositeValueTests.forEach(function(composite) { +test(t => { + const getKeyframe = + composite => ({ left: [ '10px', '20px' ], composite: composite }); + for (const composite of gGoodKeyframeCompositeValueTests) { const effect = new KeyframeEffectReadOnly(target, getKeyframe(composite)); assert_equals(effect.getKeyframes()[0].composite, composite, `resulting composite for '${composite}'`); - }); - gBadCompositeValueTests.forEach(function(composite) { - assert_throws(new TypeError, function() { + } + for (const composite of gBadCompositeValueTests) { + assert_throws(new TypeError, () => { new KeyframeEffectReadOnly(target, getKeyframe(composite)); }); - }); + } }, 'composite values are parsed correctly when passed to the ' + 'KeyframeEffectReadOnly constructor in property-indexed keyframes'); -test(function(t) { - const getKeyframes = function(composite) { - return [ +test(t => { + const getKeyframes = composite => + [ { offset: 0, left: '10px', composite: composite }, { offset: 1, left: '20px' } ]; - }; - gGoodKeyframeCompositeValueTests.forEach(function(composite) { + for (const composite of gGoodKeyframeCompositeValueTests) { const effect = new KeyframeEffectReadOnly(target, getKeyframes(composite)); assert_equals(effect.getKeyframes()[0].composite, composite, `resulting composite for '${composite}'`); - }); - gBadCompositeValueTests.forEach(function(composite) { - assert_throws(new TypeError, function() { + } + for (const composite of gBadCompositeValueTests) { + assert_throws(new TypeError, () => { new KeyframeEffectReadOnly(target, getKeyframes(composite)); }); - }); + } }, 'composite values are parsed correctly when passed to the ' + 'KeyframeEffectReadOnly constructor in regular keyframes'); -test(function(t) { - gGoodOptionsCompositeValueTests.forEach(function(composite) { +test(t => { + for (const composite of gGoodOptionsCompositeValueTests) { const effect = new KeyframeEffectReadOnly(target, { left: ['10px', '20px'] }, { composite: composite }); assert_equals(effect.getKeyframes()[0].composite, undefined, `resulting composite for '${composite}'`); - }); - gBadCompositeValueTests.forEach(function(composite) { - assert_throws(new TypeError, function() { + } + for (const composite of gBadCompositeValueTests) { + assert_throws(new TypeError, () => { new KeyframeEffectReadOnly(target, { left: ['10px', '20px'] }, { composite: composite }); }); - }); + } }, 'composite value is absent if the composite operation specified on the ' + 'keyframe effect is being used'); -gKeyframesTests.forEach(function(subtest) { - test(function(t) { +for (const subtest of gKeyframesTests) { + test(t => { const effect = new KeyframeEffectReadOnly(target, subtest.input); assert_frame_lists_equal(effect.getKeyframes(), subtest.output); }, `A KeyframeEffectReadOnly can be constructed with ${subtest.desc}`); - test(function(t) { + test(t => { const effect = new KeyframeEffectReadOnly(target, subtest.input); const secondEffect = new KeyframeEffectReadOnly(target, effect.getKeyframes()); assert_frame_lists_equal(secondEffect.getKeyframes(), effect.getKeyframes()); }, `A KeyframeEffectReadOnly constructed with ${subtest.desc} roundtrips`); -}); +} -gInvalidKeyframesTests.forEach(function(subtest) { - test(function(t) { - assert_throws(new TypeError, function() { +for (const subtest of gInvalidKeyframesTests) { + test(t => { + assert_throws(new TypeError, () => { new KeyframeEffectReadOnly(target, subtest.input); }); }, `KeyframeEffectReadOnly constructor throws with ${subtest.desc}`); -}); +} -test(function(t) { +test(t => { const effect = new KeyframeEffectReadOnly(target, { left: ['10px', '20px'] }); @@ -147,8 +145,8 @@ test(function(t) { }, 'A KeyframeEffectReadOnly constructed without any ' + 'KeyframeEffectOptions object'); -gKeyframeEffectOptionTests.forEach(function(subtest) { - test(function(t) { +for (const subtest of gKeyframeEffectOptionTests) { + test(t => { const effect = new KeyframeEffectReadOnly(target, { left: ['10px', '20px'] }, subtest.input); @@ -172,19 +170,19 @@ gKeyframeEffectOptionTests.forEach(function(subtest) { 'timing direction'); }, `A KeyframeEffectReadOnly constructed by ${subtest.desc}`); -}); +} -gInvalidKeyframeEffectOptionTests.forEach(function(subtest) { - test(function(t) { - assert_throws(new TypeError, function() { +for (const subtest of gInvalidKeyframeEffectOptionTests) { + test(t => { + assert_throws(new TypeError, () => { new KeyframeEffectReadOnly(target, { left: ['10px', '20px'] }, subtest.input); }); }, `Invalid KeyframeEffectReadOnly option by ${subtest.desc}`); -}); +} -test(function(t) { +test(t => { const effect = new KeyframeEffectReadOnly(null, { left: ['10px', '20px'] }, { duration: 100 * MS_PER_SEC, @@ -193,10 +191,10 @@ test(function(t) { 'Effect created with null target has correct target'); }, 'A KeyframeEffectReadOnly constructed with null target'); -test(function(t) { +test(t => { const test_error = { name: 'test' }; - assert_throws(test_error, function() { + assert_throws(test_error, () => { new KeyframeEffect(target, { get left() { throw test_error }}) }); }, 'KeyframeEffect constructor propagates exceptions generated by accessing' diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/copy-constructor.html b/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/copy-constructor.html index a6b413231e2..c4e8a8ec37c 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/copy-constructor.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/copy-constructor.html @@ -2,9 +2,9 @@ KeyframeEffect and KeyframeEffectReadOnly copy constructor + href="https://drafts.csswg.org/web-animations/#dom-keyframeeffect-keyframeeffect-source"> + href="https://drafts.csswg.org/web-animations/#dom-keyframeeffectreadonly-keyframeeffectreadonly-source"> @@ -13,13 +13,13 @@ - - - -
    -
    - - diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/idlharness.html b/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/idlharness.html index c3972349271..5056a875e43 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/idlharness.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/idlharness.html @@ -1,9 +1,9 @@ KeyframeEffect IDL - + + href="https://drafts.csswg.org/web-animations/#keyframeeffectreadonly"> diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/iterationComposite.html b/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/iterationComposite.html index 7719fa9c1c5..de2afa7c2b8 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/iterationComposite.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/iterationComposite.html @@ -1,7 +1,7 @@ -KeyframeEffect.iterationComposite tests - +KeyframeEffect.iterationComposite + @@ -9,792 +9,13 @@ diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-001.html b/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-001.html index b20f5193c84..e6c5c2af851 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-001.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-001.html @@ -1,7 +1,7 @@ -Tests for processing a keyframes argument (property access) - +Processing a keyframes argument (property access) + @@ -201,7 +201,7 @@ test(() => { { offset: null, computedOffset: 0.5, easing: 'linear', left: '300px' }, { offset: null, computedOffset: 1, easing: 'linear', left: '200px' }, ]); -}, "'easing' and 'offset' are ignored on iterable objects"); +}, '\'easing\' and \'offset\' are ignored on iterable objects'); test(() => { const effect = new KeyframeEffect(null, createIterable([ diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-002.html b/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-002.html index c44de912925..8233dc07c5d 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-002.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-002.html @@ -1,7 +1,7 @@ -Tests for processing a keyframes argument (easing) - +Processing a keyframes argument (easing) + diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/setKeyframes.html b/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/setKeyframes.html index 079e896e69f..90ab89d5761 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/setKeyframes.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/setKeyframes.html @@ -1,7 +1,7 @@ -KeyframeEffect setKeyframes() tests - +KeyframeEffect.setKeyframes + @@ -13,31 +13,31 @@ diff --git a/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/setTarget.html b/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/target.html similarity index 77% rename from tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/setTarget.html rename to tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/target.html index 49ef8402d90..b8fc05b81d4 100644 --- a/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/setTarget.html +++ b/tests/wpt/web-platform-tests/web-animations/interfaces/KeyframeEffect/target.html @@ -1,24 +1,24 @@ -Writable effect.target tests +KeyframeEffect.target + href="https://drafts.csswg.org/web-animations/#dom-keyframeeffect-target">
    @@ -10,110 +10,109 @@ @@ -38,11 +38,11 @@ function runTests(tests, description) { } } -async_test(function(t) { - var div = createDiv(t); - var anim = div.animate({ opacity: [ 0, 1 ] }, { delay: 1 }); +async_test(t => { + const div = createDiv(t); + const anim = div.animate({ opacity: [ 0, 1 ] }, { delay: 1 }); assert_equals(anim.effect.getComputedTiming().currentIteration, null); - anim.finished.then(t.step_func(function() { + anim.finished.then(t.step_func(() => { assert_equals(anim.effect.getComputedTiming().currentIteration, null); t.done(); })); diff --git a/tests/wpt/web-platform-tests/web-animations/timing-model/animation-effects/local-time.html b/tests/wpt/web-platform-tests/web-animations/timing-model/animation-effects/local-time.html index 91c1ed401c9..79437d9f542 100644 --- a/tests/wpt/web-platform-tests/web-animations/timing-model/animation-effects/local-time.html +++ b/tests/wpt/web-platform-tests/web-animations/timing-model/animation-effects/local-time.html @@ -1,7 +1,7 @@ -AnimationEffect local time tests - +Local time + @@ -9,16 +9,19 @@ @@ -25,7 +25,7 @@ function assert_phase_at_time(animation, phase, currentTime) { animation.effect.timing.fill = 'none'; assert_not_equals(animation.effect.getComputedTiming().progress, null, 'Animation effect is in active phase when current time' - + ' is ' + currentTime + 'ms'); + + ` is ${currentTime}ms`); } else { // The easiest way to distinguish between the 'before' phase and the 'after' // phase is to toggle the fill mode. For example, if the progress is null @@ -33,157 +33,146 @@ function assert_phase_at_time(animation, phase, currentTime) { // 'backwards' then we are in the before phase. animation.effect.timing.fill = 'none'; assert_equals(animation.effect.getComputedTiming().progress, null, - 'Animation effect is in ' + phase + ' phase when current time' - + ' is ' + currentTime + 'ms' + `Animation effect is in ${phase} phase when current time` + + ` is ${currentTime}ms` + ' (progress is null with \'none\' fill mode)'); animation.effect.timing.fill = phase === 'before' ? 'backwards' : 'forwards'; assert_not_equals(animation.effect.getComputedTiming().progress, null, - 'Animation effect is in ' + phase + ' phase when current' - + ' time is ' + currentTime + 'ms' + `Animation effect is in ${phase} phase when current time` + + ` is ${currentTime}ms` + ' (progress is non-null with appropriate fill mode)'); } } -test(function(t) { - var animation = createDiv(t).animate(null, 1); +test(t => { + const animation = createDiv(t).animate(null, 1); - [ { currentTime: -1, phase: 'before' }, - { currentTime: 0, phase: 'active' }, - { currentTime: 1, phase: 'after' } ] - .forEach(function(test) { + for (const test of [{ currentTime: -1, phase: 'before' }, + { currentTime: 0, phase: 'active' }, + { currentTime: 1, phase: 'after' }]) { assert_phase_at_time(animation, test.phase, test.currentTime); - }); + } }, 'Phase calculation for a simple animation effect'); -test(function(t) { - var animation = createDiv(t).animate(null, { duration: 1, delay: 1 }); +test(t => { + const animation = createDiv(t).animate(null, { duration: 1, delay: 1 }); - [ { currentTime: 0, phase: 'before' }, - { currentTime: 1, phase: 'active' }, - { currentTime: 2, phase: 'after' } ] - .forEach(function(test) { + for (const test of [{ currentTime: 0, phase: 'before' }, + { currentTime: 1, phase: 'active' }, + { currentTime: 2, phase: 'after' }]) { assert_phase_at_time(animation, test.phase, test.currentTime); - }); + } }, 'Phase calculation for an animation effect with a positive start delay'); -test(function(t) { - var animation = createDiv(t).animate(null, { duration: 1, delay: -1 }); +test(t => { + const animation = createDiv(t).animate(null, { duration: 1, delay: -1 }); - [ { currentTime: -2, phase: 'before' }, - { currentTime: -1, phase: 'before' }, - { currentTime: 0, phase: 'after' } ] - .forEach(function(test) { + for (const test of [{ currentTime: -2, phase: 'before' }, + { currentTime: -1, phase: 'before' }, + { currentTime: 0, phase: 'after' }]) { assert_phase_at_time(animation, test.phase, test.currentTime); - }); + } }, 'Phase calculation for an animation effect with a negative start delay'); -test(function(t) { - var animation = createDiv(t).animate(null, { duration: 1, endDelay: 1 }); +test(t => { + const animation = createDiv(t).animate(null, { duration: 1, endDelay: 1 }); - [ { currentTime: -1, phase: 'before' }, - { currentTime: 0, phase: 'active' }, - { currentTime: 1, phase: 'after' }, - { currentTime: 2, phase: 'after' } ] - .forEach(function(test) { + for (const test of [{ currentTime: -1, phase: 'before' }, + { currentTime: 0, phase: 'active' }, + { currentTime: 1, phase: 'after' }, + { currentTime: 2, phase: 'after' }]) { assert_phase_at_time(animation, test.phase, test.currentTime); - }); + } }, 'Phase calculation for an animation effect with a positive end delay'); -test(function(t) { - var animation = createDiv(t).animate(null, { duration: 2, endDelay: -1 }); +test(t => { + const animation = createDiv(t).animate(null, { duration: 2, endDelay: -1 }); - [ { currentTime: -1, phase: 'before' }, - { currentTime: 0, phase: 'active' }, - { currentTime: 0.9, phase: 'active' }, - { currentTime: 1, phase: 'after' } ] - .forEach(function(test) { + for (const test of [{ currentTime: -1, phase: 'before' }, + { currentTime: 0, phase: 'active' }, + { currentTime: 0.9, phase: 'active' }, + { currentTime: 1, phase: 'after' }]) { assert_phase_at_time(animation, test.phase, test.currentTime); - }); + } }, 'Phase calculation for an animation effect with a negative end delay lesser' + ' in magnitude than the active duration'); -test(function(t) { - var animation = createDiv(t).animate(null, { duration: 1, endDelay: -1 }); +test(t => { + const animation = createDiv(t).animate(null, { duration: 1, endDelay: -1 }); - [ { currentTime: -1, phase: 'before' }, - { currentTime: 0, phase: 'after' }, - { currentTime: 1, phase: 'after' } ] - .forEach(function(test) { + for (const test of [{ currentTime: -1, phase: 'before' }, + { currentTime: 0, phase: 'after' }, + { currentTime: 1, phase: 'after' }]) { assert_phase_at_time(animation, test.phase, test.currentTime); - }); + } }, 'Phase calculation for an animation effect with a negative end delay equal' + ' in magnitude to the active duration'); -test(function(t) { - var animation = createDiv(t).animate(null, { duration: 1, endDelay: -2 }); +test(t => { + const animation = createDiv(t).animate(null, { duration: 1, endDelay: -2 }); - [ { currentTime: -2, phase: 'before' }, - { currentTime: -1, phase: 'before' }, - { currentTime: 0, phase: 'after' } ] - .forEach(function(test) { + for (const test of [{ currentTime: -2, phase: 'before' }, + { currentTime: -1, phase: 'before' }, + { currentTime: 0, phase: 'after' }]) { assert_phase_at_time(animation, test.phase, test.currentTime); - }); + } }, 'Phase calculation for an animation effect with a negative end delay' + ' greater in magnitude than the active duration'); -test(function(t) { - var animation = createDiv(t).animate(null, { duration: 2, - delay: 1, - endDelay: -1 }); +test(t => { + const animation = createDiv(t).animate(null, { duration: 2, + delay: 1, + endDelay: -1 }); - [ { currentTime: 0, phase: 'before' }, - { currentTime: 1, phase: 'active' }, - { currentTime: 2, phase: 'after' } ] - .forEach(function(test) { + for (const test of [{ currentTime: 0, phase: 'before' }, + { currentTime: 1, phase: 'active' }, + { currentTime: 2, phase: 'after' }]) { assert_phase_at_time(animation, test.phase, test.currentTime); - }); + } }, 'Phase calculation for an animation effect with a positive start delay' + ' and a negative end delay lesser in magnitude than the active duration'); -test(function(t) { - var animation = createDiv(t).animate(null, { duration: 1, - delay: -1, - endDelay: -1 }); +test(t => { + const animation = createDiv(t).animate(null, { duration: 1, + delay: -1, + endDelay: -1 }); - [ { currentTime: -2, phase: 'before' }, - { currentTime: -1, phase: 'before' }, - { currentTime: 0, phase: 'after' } ] - .forEach(function(test) { + for (const test of [{ currentTime: -2, phase: 'before' }, + { currentTime: -1, phase: 'before' }, + { currentTime: 0, phase: 'after' }]) { assert_phase_at_time(animation, test.phase, test.currentTime); - }); + } }, 'Phase calculation for an animation effect with a negative start delay' + ' and a negative end delay equal in magnitude to the active duration'); -test(function(t) { - var animation = createDiv(t).animate(null, { duration: 1, - delay: -1, - endDelay: -2 }); +test(t => { + const animation = createDiv(t).animate(null, { duration: 1, + delay: -1, + endDelay: -2 }); - [ { currentTime: -3, phase: 'before' }, - { currentTime: -2, phase: 'before' }, - { currentTime: -1, phase: 'before' }, - { currentTime: 0, phase: 'after' } ] - .forEach(function(test) { + for (const test of [{ currentTime: -3, phase: 'before' }, + { currentTime: -2, phase: 'before' }, + { currentTime: -1, phase: 'before' }, + { currentTime: 0, phase: 'after' }]) { assert_phase_at_time(animation, test.phase, test.currentTime); - }); + } }, 'Phase calculation for an animation effect with a negative start delay' + ' and a negative end delay equal greater in magnitude than the active' + ' duration'); -test(function(t) { - var animation = createDiv(t).animate(null, 1); +test(t => { + const animation = createDiv(t).animate(null, 1); animation.playbackRate = -1; - [ { currentTime: -1, phase: 'before' }, - { currentTime: 0, phase: 'before' }, - { currentTime: 1, phase: 'active' }, - { currentTime: 2, phase: 'after' } ] - .forEach(function(test) { + for (const test of [{ currentTime: -1, phase: 'before' }, + { currentTime: 0, phase: 'before' }, + { currentTime: 1, phase: 'active' }, + { currentTime: 2, phase: 'after' }]) { assert_phase_at_time(animation, test.phase, test.currentTime); - }); + } }, 'Phase calculation for a simple animation effect with negative playback' + ' rate'); diff --git a/tests/wpt/web-platform-tests/web-animations/timing-model/animation-effects/simple-iteration-progress.html b/tests/wpt/web-platform-tests/web-animations/timing-model/animation-effects/simple-iteration-progress.html index e4253a0bd35..3c42f79a710 100644 --- a/tests/wpt/web-platform-tests/web-animations/timing-model/animation-effects/simple-iteration-progress.html +++ b/tests/wpt/web-platform-tests/web-animations/timing-model/animation-effects/simple-iteration-progress.html @@ -1,8 +1,8 @@ -Simple iteration progress tests +Simple iteration progress + href="https://drafts.csswg.org/web-animations/#simple-iteration-progress"> diff --git a/tests/wpt/web-platform-tests/web-animations/timing-model/animations/canceling-an-animation.html b/tests/wpt/web-platform-tests/web-animations/timing-model/animations/canceling-an-animation.html index 5aa7de2bb87..69644319a63 100644 --- a/tests/wpt/web-platform-tests/web-animations/timing-model/animations/canceling-an-animation.html +++ b/tests/wpt/web-platform-tests/web-animations/timing-model/animations/canceling-an-animation.html @@ -2,16 +2,16 @@ Canceling an animation + href="https://drafts.csswg.org/web-animations/#canceling-an-animation-section">
    diff --git a/tests/wpt/web-platform-tests/web-animations/timing-model/animations/current-time.html b/tests/wpt/web-platform-tests/web-animations/timing-model/animations/current-time.html index 7500175435c..d2f5075d1b2 100644 --- a/tests/wpt/web-platform-tests/web-animations/timing-model/animations/current-time.html +++ b/tests/wpt/web-platform-tests/web-animations/timing-model/animations/current-time.html @@ -1,7 +1,7 @@ -Tests for current time - +Current time + @@ -10,8 +10,8 @@ @@ -11,7 +11,7 @@ @@ -11,14 +11,14 @@ + + + +
    + + diff --git a/tests/wpt/web-platform-tests/web-animations/timing-model/animations/playing-an-animation.html b/tests/wpt/web-platform-tests/web-animations/timing-model/animations/playing-an-animation.html index 1cf109deb15..2beed475e7e 100644 --- a/tests/wpt/web-platform-tests/web-animations/timing-model/animations/playing-an-animation.html +++ b/tests/wpt/web-platform-tests/web-animations/timing-model/animations/playing-an-animation.html @@ -2,7 +2,7 @@ Playing an animation + href="https://drafts.csswg.org/web-animations/#playing-an-animation-section"> @@ -11,24 +11,24 @@
    @@ -10,12 +10,11 @@ @@ -10,63 +10,67 @@ @@ -16,8 +16,8 @@ // // --------------------------------------------------------------------- -test(function(t) { - var animation = +test(t => { + const animation = new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), null); animation.currentTime = 50 * MS_PER_SEC; @@ -29,8 +29,8 @@ test(function(t) { assert_times_equal(animation.currentTime, 50 * MS_PER_SEC); }, 'After setting timeline on paused animation it is still paused'); -test(function(t) { - var animation = +test(t => { + const animation = new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), null); animation.currentTime = 200 * MS_PER_SEC; @@ -43,8 +43,8 @@ test(function(t) { }, 'After setting timeline on animation paused outside active interval' + ' it is still paused'); -test(function(t) { - var animation = +test(t => { + const animation = new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), null); assert_equals(animation.playState, 'idle'); @@ -55,8 +55,8 @@ test(function(t) { }, 'After setting timeline on an idle animation without a start time' + ' it is still idle'); -test(function(t) { - var animation = +test(t => { + const animation = new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), null); animation.startTime = document.timeline.currentTime; @@ -68,8 +68,8 @@ test(function(t) { }, 'After setting timeline on an idle animation with a start time' + ' it is running'); -test(function(t) { - var animation = +test(t => { + const animation = new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), null); animation.startTime = document.timeline.currentTime - 200 * MS_PER_SEC; @@ -81,60 +81,44 @@ test(function(t) { }, 'After setting timeline on an idle animation with a sufficiently ancient' + ' start time it is finished'); -test(function(t) { - var animation = +promise_test(t => { + const animation = new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), null); animation.play(); - assert_equals(animation.playState, 'pending'); + assert_true(animation.pending && animation.playState === 'running', + 'Animation is initially play-pending'); animation.timeline = document.timeline; - assert_equals(animation.playState, 'pending'); -}, 'After setting timeline on a play-pending animation it is still pending'); + assert_true(animation.pending && animation.playState === 'running', + 'Animation is still play-pending after setting timeline'); -promise_test(function(t) { - var animation = - new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), - null); - animation.play(); - assert_equals(animation.playState, 'pending'); - - animation.timeline = document.timeline; - - return animation.ready.then(function() { - assert_equals(animation.playState, 'running'); + return animation.ready.then(() => { + assert_true(!animation.pending && animation.playState === 'running', + 'Animation plays after it finishes pending'); }); }, 'After setting timeline on a play-pending animation it begins playing' + ' after pending'); -test(function(t) { - var animation = +promise_test(t => { + const animation = new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), null); animation.startTime = document.timeline.currentTime; animation.pause(); animation.timeline = null; - assert_equals(animation.playState, 'pending'); + assert_true(animation.pending && animation.playState === 'paused', + 'Animation is initially pause-pending'); animation.timeline = document.timeline; - assert_equals(animation.playState, 'pending'); -}, 'After setting timeline on a pause-pending animation it is still pending'); + assert_true(animation.pending && animation.playState === 'paused', + 'Animation is still pause-pending after setting timeline'); -promise_test(function(t) { - var animation = - new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), - null); - animation.startTime = document.timeline.currentTime; - animation.pause(); - animation.timeline = null; - assert_equals(animation.playState, 'pending'); - - animation.timeline = document.timeline; - - return animation.ready.then(function() { - assert_equals(animation.playState, 'paused'); + return animation.ready.then(() => { + assert_true(!animation.pending && animation.playState === 'paused', + 'Animation pauses after it finishes pending'); }); }, 'After setting timeline on a pause-pending animation it becomes paused' + ' after pending'); @@ -145,24 +129,26 @@ promise_test(function(t) { // // --------------------------------------------------------------------- -test(function(t) { - var animation = +test(t => { + const animation = new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), document.timeline); animation.currentTime = 50 * MS_PER_SEC; + assert_false(animation.pending); assert_equals(animation.playState, 'paused'); animation.timeline = null; + assert_false(animation.pending); assert_equals(animation.playState, 'paused'); assert_times_equal(animation.currentTime, 50 * MS_PER_SEC); }, 'After clearing timeline on paused animation it is still paused'); -test(function(t) { - var animation = +test(t => { + const animation = new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), document.timeline); - var initialStartTime = document.timeline.currentTime - 200 * MS_PER_SEC; + const initialStartTime = document.timeline.currentTime - 200 * MS_PER_SEC; animation.startTime = initialStartTime; assert_equals(animation.playState, 'finished'); @@ -172,11 +158,11 @@ test(function(t) { assert_times_equal(animation.startTime, initialStartTime); }, 'After clearing timeline on finished animation it is idle'); -test(function(t) { - var animation = +test(t => { + const animation = new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), document.timeline); - var initialStartTime = document.timeline.currentTime - 50 * MS_PER_SEC; + const initialStartTime = document.timeline.currentTime - 50 * MS_PER_SEC; animation.startTime = initialStartTime; assert_equals(animation.playState, 'running'); @@ -186,8 +172,8 @@ test(function(t) { assert_times_equal(animation.startTime, initialStartTime); }, 'After clearing timeline on running animation it is idle'); -test(function(t) { - var animation = +test(t => { + const animation = new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), document.timeline); assert_equals(animation.playState, 'idle'); @@ -198,75 +184,73 @@ test(function(t) { assert_equals(animation.startTime, null); }, 'After clearing timeline on idle animation it is still idle'); -test(function(t) { - var animation = createDiv(t).animate(null, 100 * MS_PER_SEC); - assert_equals(animation.playState, 'pending'); +test(t => { + const animation = createDiv(t).animate(null, 100 * MS_PER_SEC); + assert_true(animation.pending && animation.playState === 'running'); animation.timeline = null; - assert_equals(animation.playState, 'pending'); + assert_true(animation.pending && animation.playState === 'running'); }, 'After clearing timeline on play-pending animation it is still pending'); -promise_test(function(t) { - var animation = createDiv(t).animate(null, 100 * MS_PER_SEC); - assert_equals(animation.playState, 'pending'); +promise_test(t => { + const animation = createDiv(t).animate(null, 100 * MS_PER_SEC); + assert_true(animation.pending && animation.playState === 'running'); animation.timeline = null; animation.timeline = document.timeline; - assert_equals(animation.playState, 'pending'); - return animation.ready.then(function() { - assert_equals(animation.playState, 'running'); + assert_true(animation.pending && animation.playState === 'running'); + return animation.ready.then(() => { + assert_true(!animation.pending && animation.playState === 'running'); }); }, 'After clearing and re-setting timeline on play-pending animation it' + ' begins to play'); -test(function(t) { - var animation = +test(t => { + const animation = new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), document.timeline); animation.startTime = document.timeline.currentTime; animation.pause(); - assert_equals(animation.playState, 'pending'); + assert_true(animation.pending && animation.playState === 'paused'); animation.timeline = null; - assert_equals(animation.playState, 'pending'); + assert_true(animation.pending && animation.playState === 'paused'); }, 'After clearing timeline on a pause-pending animation it is still pending'); -promise_test(function(t) { - var animation = +promise_test(t => { + const animation = new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), document.timeline); animation.startTime = document.timeline.currentTime; animation.pause(); - assert_equals(animation.playState, 'pending'); + assert_true(animation.pending && animation.playState === 'paused'); animation.timeline = null; animation.timeline = document.timeline; - assert_equals(animation.playState, 'pending'); - return animation.ready.then(function() { - assert_equals(animation.playState, 'paused'); + assert_true(animation.pending && animation.playState === 'paused'); + return animation.ready.then(() => { + assert_true(!animation.pending && animation.playState === 'paused'); }); }, 'After clearing and re-setting timeline on a pause-pending animation it' - + ' becomes paused'); + + ' completes pausing'); -promise_test(function(t) { - var animation = +promise_test(t => { + const animation = new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), document.timeline); - var initialStartTime = document.timeline.currentTime - 50 * MS_PER_SEC; + const initialStartTime = document.timeline.currentTime - 50 * MS_PER_SEC; animation.startTime = initialStartTime; animation.pause(); animation.play(); animation.timeline = null; animation.timeline = document.timeline; - assert_equals(animation.playState, 'pending'); - return animation.ready.then(function() { - assert_equals(animation.playState, 'running'); + return animation.ready.then(() => { assert_times_equal(animation.startTime, initialStartTime); }); }, 'After clearing and re-setting timeline on an animation in the middle of' diff --git a/tests/wpt/web-platform-tests/web-animations/timing-model/animations/updating-the-finished-state.html b/tests/wpt/web-platform-tests/web-animations/timing-model/animations/updating-the-finished-state.html index 7b9efedbf63..034cd6ee683 100644 --- a/tests/wpt/web-platform-tests/web-animations/timing-model/animations/updating-the-finished-state.html +++ b/tests/wpt/web-platform-tests/web-animations/timing-model/animations/updating-the-finished-state.html @@ -1,7 +1,7 @@ -Tests for updating the finished state of an animation - +Updating the finished state + @@ -20,29 +20,29 @@ // (Also the start time is resolved and there is pending task) // Did seek = false -promise_test(function(t) { - var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); +promise_test(t => { + const anim = createDiv(t).animate(null, 100 * MS_PER_SEC); // Here and in the following tests we wait until ready resolves as // otherwise we don't have a resolved start time. We test the case // where the start time is unresolved in a subsequent test. - return anim.ready.then(function() { + return anim.ready.then(() => { // Seek to 1ms before the target end and then wait 1ms anim.currentTime = 100 * MS_PER_SEC - 1; return waitForAnimationFramesWithDelay(1); - }).then(function() { + }).then(() => { assert_equals(anim.currentTime, 100 * MS_PER_SEC, 'Hold time is set to target end clamping current time'); }); }, 'Updating the finished state when playing past end'); // Did seek = true -promise_test(function(t) { - var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); - return anim.ready.then(function() { +promise_test(t => { + const anim = createDiv(t).animate(null, 100 * MS_PER_SEC); + return anim.ready.then(() => { anim.currentTime = 200 * MS_PER_SEC; - return waitForAnimationFrames(1); - }).then(function() { + return waitForNextFrame(); + }).then(() => { assert_equals(anim.currentTime, 200 * MS_PER_SEC, 'Hold time is set so current time should NOT change'); }); @@ -59,12 +59,12 @@ promise_test(function(t) { // (on the subsequent tick the hold time will be set to the same value anyway). // Did seek = true -promise_test(function(t) { - var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); - return anim.ready.then(function() { +promise_test(t => { + const anim = createDiv(t).animate(null, 100 * MS_PER_SEC); + return anim.ready.then(() => { anim.currentTime = 100 * MS_PER_SEC; - return waitForAnimationFrames(1); - }).then(function() { + return waitForNextFrame(); + }).then(() => { assert_equals(anim.currentTime, 100 * MS_PER_SEC, 'Hold time is set so current time should NOT change'); }); @@ -75,29 +75,29 @@ promise_test(function(t) { // (Also the start time is resolved and there is pending task) // Did seek = false -promise_test(function(t) { - var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); +promise_test(t => { + const anim = createDiv(t).animate(null, 100 * MS_PER_SEC); anim.playbackRate = -1; anim.play(); // Make sure animation is not initially finished - return anim.ready.then(function() { + return anim.ready.then(() => { // Seek to 1ms before 0 and then wait 1ms anim.currentTime = 1; return waitForAnimationFramesWithDelay(1); - }).then(function() { + }).then(() => { assert_equals(anim.currentTime, 0 * MS_PER_SEC, 'Hold time is set to zero clamping current time'); }); }, 'Updating the finished state when playing in reverse past zero'); // Did seek = true -promise_test(function(t) { - var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); +promise_test(t => { + const anim = createDiv(t).animate(null, 100 * MS_PER_SEC); anim.playbackRate = -1; anim.play(); - return anim.ready.then(function() { + return anim.ready.then(() => { anim.currentTime = -100 * MS_PER_SEC; - return waitForAnimationFrames(1); - }).then(function() { + return waitForNextFrame(); + }).then(() => { assert_equals(anim.currentTime, -100 * MS_PER_SEC, 'Hold time is set so current time should NOT change'); }); @@ -107,14 +107,14 @@ promise_test(function(t) { // it doesn't really matter. // Did seek = true -promise_test(function(t) { - var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); +promise_test(t => { + const anim = createDiv(t).animate(null, 100 * MS_PER_SEC); anim.playbackRate = -1; anim.play(); - return anim.ready.then(function() { + return anim.ready.then(() => { anim.currentTime = 0; - return waitForAnimationFrames(1); - }).then(function() { + return waitForNextFrame(); + }).then(() => { assert_equals(anim.currentTime, 0 * MS_PER_SEC, 'Hold time is set so current time should NOT change'); }); @@ -126,38 +126,38 @@ promise_test(function(t) { // (Also the start time is resolved and there is pending task) // Did seek = false; playback rate > 0 -promise_test(function(t) { - var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); +promise_test(t => { + const anim = createDiv(t).animate(null, 100 * MS_PER_SEC); // We want to test that the hold time is cleared so first we need to // put the animation in a state where the hold time is set. anim.finish(); - return anim.ready.then(function() { + return anim.ready.then(() => { assert_equals(anim.currentTime, 100 * MS_PER_SEC, 'Hold time is initially set'); // Then extend the duration so that the hold time is cleared and on // the next tick the current time will increase. anim.effect.timing.duration *= 2; - return waitForAnimationFrames(1); - }).then(function() { + return waitForNextFrame(); + }).then(() => { assert_greater_than(anim.currentTime, 100 * MS_PER_SEC, 'Hold time is not set so current time should increase'); }); }, 'Updating the finished state when playing before end'); // Did seek = true; playback rate > 0 -promise_test(function(t) { - var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); +promise_test(t => { + const anim = createDiv(t).animate(null, 100 * MS_PER_SEC); anim.finish(); - return anim.ready.then(function() { + return anim.ready.then(() => { anim.currentTime = 50 * MS_PER_SEC; // When did seek = true, updating the finished state: (i) updates // the animation's start time and (ii) clears the hold time. // We can test both by checking that the currentTime is initially // updated and then increases. assert_equals(anim.currentTime, 50 * MS_PER_SEC, 'Start time is updated'); - return waitForAnimationFrames(1); - }).then(function() { + return waitForNextFrame(); + }).then(() => { assert_greater_than(anim.currentTime, 50 * MS_PER_SEC, 'Hold time is not set so current time should increase'); }); @@ -177,14 +177,14 @@ promise_test(function(t) { // will set did seek = true). // Did seek = true; playback rate < 0 -promise_test(function(t) { - var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); +promise_test(t => { + const anim = createDiv(t).animate(null, 100 * MS_PER_SEC); anim.playbackRate = -1; - return anim.ready.then(function() { + return anim.ready.then(() => { anim.currentTime = 50 * MS_PER_SEC; assert_equals(anim.currentTime, 50 * MS_PER_SEC, 'Start time is updated'); - return waitForAnimationFrames(1); - }).then(function() { + return waitForNextFrame(); + }).then(() => { assert_less_than(anim.currentTime, 50 * MS_PER_SEC, 'Hold time is not set so current time should decrease'); }); @@ -193,13 +193,13 @@ promise_test(function(t) { // CASE 4: playback rate == 0 // current time < 0 -promise_test(function(t) { - var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); +promise_test(t => { + const anim = createDiv(t).animate(null, 100 * MS_PER_SEC); anim.playbackRate = 0; - return anim.ready.then(function() { + return anim.ready.then(() => { anim.currentTime = -100 * MS_PER_SEC; - return waitForAnimationFrames(1); - }).then(function() { + return waitForNextFrame(); + }).then(() => { assert_equals(anim.currentTime, -100 * MS_PER_SEC, 'Hold time should not be cleared so current time should' + ' NOT change'); @@ -208,13 +208,13 @@ promise_test(function(t) { + ' current time is less than zero'); // current time < target end -promise_test(function(t) { - var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); +promise_test(t => { + const anim = createDiv(t).animate(null, 100 * MS_PER_SEC); anim.playbackRate = 0; - return anim.ready.then(function() { + return anim.ready.then(() => { anim.currentTime = 50 * MS_PER_SEC; - return waitForAnimationFrames(1); - }).then(function() { + return waitForNextFrame(); + }).then(() => { assert_equals(anim.currentTime, 50 * MS_PER_SEC, 'Hold time should not be cleared so current time should' + ' NOT change'); @@ -223,13 +223,13 @@ promise_test(function(t) { + ' current time is less than end'); // current time > target end -promise_test(function(t) { - var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); +promise_test(t => { + const anim = createDiv(t).animate(null, 100 * MS_PER_SEC); anim.playbackRate = 0; - return anim.ready.then(function() { + return anim.ready.then(() => { anim.currentTime = 200 * MS_PER_SEC; - return waitForAnimationFrames(1); - }).then(function() { + return waitForNextFrame(); + }).then(() => { assert_equals(anim.currentTime, 200 * MS_PER_SEC, 'Hold time should not be cleared so current time should' + ' NOT change'); @@ -239,8 +239,8 @@ promise_test(function(t) { // CASE 5: current time unresolved -promise_test(function(t) { - var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); +promise_test(t => { + const anim = createDiv(t).animate(null, 100 * MS_PER_SEC); anim.cancel(); // Trigger a change that will cause the "update the finished state" // procedure to run. @@ -251,7 +251,7 @@ promise_test(function(t) { // change to timing, but just in case an implementation defers that, let's // wait a frame and check that the hold time / start time has still not been // updated. - return waitForAnimationFrames(1).then(function() { + return waitForAnimationFrames(1).then(() => { assert_equals(anim.currentTime, null, 'The animation hold time / start time should not be updated'); }); @@ -259,8 +259,8 @@ promise_test(function(t) { // CASE 6: has a pending task -test(function(t) { - var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); +test(t => { + const anim = createDiv(t).animate(null, 100 * MS_PER_SEC); anim.cancel(); anim.currentTime = 75 * MS_PER_SEC; anim.play(); @@ -278,8 +278,8 @@ test(function(t) { // CASE 7: start time unresolved // Did seek = false -promise_test(function(t) { - var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); +promise_test(t => { + const anim = createDiv(t).animate(null, 100 * MS_PER_SEC); anim.cancel(); // Make it so that only the start time is unresolved (to avoid overlapping // with the test case where current time is unresolved) @@ -287,7 +287,7 @@ promise_test(function(t) { // Trigger a change that will cause the "update the finished state" // procedure to run (did seek = false). anim.effect.timing.duration = 200 * MS_PER_SEC; - return waitForAnimationFrames(1).then(function() { + return waitForAnimationFrames(1).then(() => { assert_equals(anim.currentTime, 150 * MS_PER_SEC, 'The animation hold time should not be updated'); assert_equals(anim.startTime, null, @@ -297,8 +297,8 @@ promise_test(function(t) { + ' did seek = false'); // Did seek = true -test(function(t) { - var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); +test(t => { + const anim = createDiv(t).animate(null, 100 * MS_PER_SEC); anim.cancel(); anim.currentTime = 150 * MS_PER_SEC; // Trigger a change that will cause the "update the finished state" @@ -318,14 +318,14 @@ test(function(t) { // -------------------------------------------------------------------- function waitForFinishEventAndPromise(animation) { - var eventPromise = new Promise(function(resolve) { - animation.onfinish = function() { resolve(); } + const eventPromise = new Promise(resolve => { + animation.onfinish = resolve; }); return Promise.all([eventPromise, animation.finished]); } -promise_test(function(t) { - var animation = createDiv(t).animate(null, 1); +promise_test(t => { + const animation = createDiv(t).animate(null, 1); animation.onfinish = t.unreached_func('Seeking to finish should not fire finish event'); animation.finished.then( @@ -337,27 +337,27 @@ promise_test(function(t) { }, 'Finish notification steps don\'t run when the animation seeks to finish' + ' and then seeks back again'); -promise_test(function(t) { - var animation = createDiv(t).animate(null, 1); - return animation.ready.then(function() { +promise_test(t => { + const animation = createDiv(t).animate(null, 1); + return animation.ready.then(() => { return waitForFinishEventAndPromise(animation); }); }, 'Finish notification steps run when the animation completes normally'); -promise_test(function(t) { - var animation = createDiv(t).animate(null, 1); - return animation.ready.then(function() { +promise_test(t => { + const animation = createDiv(t).animate(null, 1); + return animation.ready.then(() => { animation.currentTime = 10; return waitForFinishEventAndPromise(animation); }); }, 'Finish notification steps run when the animation seeks past finish'); -promise_test(function(t) { - var animation = createDiv(t).animate(null, 1); - return animation.ready.then(function() { +promise_test(t => { + const animation = createDiv(t).animate(null, 1); + return animation.ready.then(() => { // Register for notifications now since once we seek away from being // finished the 'finished' promise will be replaced. - var finishNotificationSteps = waitForFinishEventAndPromise(animation); + const finishNotificationSteps = waitForFinishEventAndPromise(animation); animation.finish(); animation.currentTime = 0; animation.pause(); @@ -366,41 +366,41 @@ promise_test(function(t) { }, 'Finish notification steps run when the animation completes with .finish(),' + ' even if we then seek away'); -promise_test(function(t) { - var animation = createDiv(t).animate(null, 1); - var initialFinishedPromise = animation.finished; +promise_test(t => { + const animation = createDiv(t).animate(null, 1); + const initialFinishedPromise = animation.finished; - return animation.finished.then(function(target) { + return animation.finished.then(target => { animation.currentTime = 0; assert_not_equals(initialFinishedPromise, animation.finished); }); }, 'Animation finished promise is replaced after seeking back to start'); -promise_test(function(t) { - var animation = createDiv(t).animate(null, 1); - var initialFinishedPromise = animation.finished; +promise_test(t => { + const animation = createDiv(t).animate(null, 1); + const initialFinishedPromise = animation.finished; - return animation.finished.then(function(target) { + return animation.finished.then(target => { animation.play(); assert_not_equals(initialFinishedPromise, animation.finished); }); }, 'Animation finished promise is replaced after replaying from start'); -async_test(function(t) { - var animation = createDiv(t).animate(null, 1); - animation.onfinish = function(event) { +async_test(t => { + const animation = createDiv(t).animate(null, 1); + animation.onfinish = event => { animation.currentTime = 0; - animation.onfinish = function(event) { + animation.onfinish = event => { t.done(); }; }; }, 'Animation finish event is fired again after seeking back to start'); -async_test(function(t) { - var animation = createDiv(t).animate(null, 1); - animation.onfinish = function(event) { +async_test(t => { + const animation = createDiv(t).animate(null, 1); + animation.onfinish = event => { animation.play(); - animation.onfinish = function(event) { + animation.onfinish = event => { t.done(); }; }; diff --git a/tests/wpt/web-platform-tests/web-animations/timing-model/time-transformations/transformed-progress.html b/tests/wpt/web-platform-tests/web-animations/timing-model/time-transformations/transformed-progress.html index 6ca27cf5af8..839ebe1093e 100644 --- a/tests/wpt/web-platform-tests/web-animations/timing-model/time-transformations/transformed-progress.html +++ b/tests/wpt/web-platform-tests/web-animations/timing-model/time-transformations/transformed-progress.html @@ -1,7 +1,7 @@ -Tests for the transformed progress - +Transformed progress + @@ -12,14 +12,14 @@ diff --git a/tests/wpt/web-platform-tests/web-animations/timing-model/timelines/document-timelines.html b/tests/wpt/web-platform-tests/web-animations/timing-model/timelines/document-timelines.html index 7b863888aaa..bc3edff112e 100644 --- a/tests/wpt/web-platform-tests/web-animations/timing-model/timelines/document-timelines.html +++ b/tests/wpt/web-platform-tests/web-animations/timing-model/timelines/document-timelines.html @@ -1,7 +1,7 @@ Document timelines - + @@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@ diff --git a/tests/wpt/web-platform-tests/webaudio/resources/audit.js b/tests/wpt/web-platform-tests/webaudio/resources/audit.js index e3ccd470e4e..4f4c6b7aed8 100644 --- a/tests/wpt/web-platform-tests/webaudio/resources/audit.js +++ b/tests/wpt/web-platform-tests/webaudio/resources/audit.js @@ -118,6 +118,8 @@ window.Audit = (function() { this._expectedDescription = null; this._detail = ''; + // If true and the test failed, print the actual value at the + // end of the message. this._printActualForFailure = true; this._result = null; @@ -620,7 +622,8 @@ window.Audit = (function() { passDetail = '${actual} contains only the constant ${expected}.'; } else { let counter = 0; - failDetail = 'Expected ${expected} for all values but found ' + + failDetail = + '${actual}: Expected ${expected} for all values but found ' + numberOfErrors + ' unexpected values: '; failDetail += '\n\tIndex\tActual'; for (let errorIndex in errors) { diff --git a/tests/wpt/web-platform-tests/webdriver/OWNERS b/tests/wpt/web-platform-tests/webdriver/OWNERS index 07296e312b3..c004c0467e0 100644 --- a/tests/wpt/web-platform-tests/webdriver/OWNERS +++ b/tests/wpt/web-platform-tests/webdriver/OWNERS @@ -4,3 +4,4 @@ @lukeis @mjzffr @shs96c +@whimboo diff --git a/tests/wpt/web-platform-tests/webdriver/interface/interface.html b/tests/wpt/web-platform-tests/webdriver/interface/interface.html deleted file mode 100644 index e29fa63e933..00000000000 --- a/tests/wpt/web-platform-tests/webdriver/interface/interface.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - diff --git a/tests/wpt/web-platform-tests/webdriver/tests/actions/key_shortcuts.py b/tests/wpt/web-platform-tests/webdriver/tests/actions/key_shortcuts.py new file mode 100644 index 00000000000..ec062f75224 --- /dev/null +++ b/tests/wpt/web-platform-tests/webdriver/tests/actions/key_shortcuts.py @@ -0,0 +1,49 @@ +from tests.actions.support.keys import Keys, MODIFIER_KEY +from tests.actions.support.refine import get_keys + + +def test_mod_a_and_backspace_deletes_all_text(session, key_reporter, key_chain): + key_chain.send_keys("abc d") \ + .key_down(MODIFIER_KEY) \ + .key_down("a") \ + .key_up(MODIFIER_KEY) \ + .key_up("a") \ + .key_down(Keys.BACKSPACE) \ + .perform() + assert get_keys(key_reporter) == "" + + +def test_mod_a_mod_c_right_mod_v_pastes_text(session, key_reporter, key_chain): + initial = "abc d" + key_chain.send_keys(initial) \ + .key_down(MODIFIER_KEY) \ + .key_down("a") \ + .key_up(MODIFIER_KEY) \ + .key_up("a") \ + .key_down(MODIFIER_KEY) \ + .key_down("c") \ + .key_up(MODIFIER_KEY) \ + .key_up("c") \ + .send_keys([Keys.RIGHT]) \ + .key_down(MODIFIER_KEY) \ + .key_down("v") \ + .key_up(MODIFIER_KEY) \ + .key_up("v") \ + .perform() + assert get_keys(key_reporter) == initial * 2 + + +def test_mod_a_mod_x_deletes_all_text(session, key_reporter, key_chain): + key_chain.send_keys("abc d") \ + .key_down(MODIFIER_KEY) \ + .key_down("a") \ + .key_up(MODIFIER_KEY) \ + .key_up("a") \ + .key_down(MODIFIER_KEY) \ + .key_down("x") \ + .key_up(MODIFIER_KEY) \ + .key_up("x") \ + .perform() + assert get_keys(key_reporter) == "" + + diff --git a/tests/wpt/web-platform-tests/webdriver/tests/actions/modifier_click.py b/tests/wpt/web-platform-tests/webdriver/tests/actions/modifier_click.py index 73de161119d..fdd43e2ebcb 100644 --- a/tests/wpt/web-platform-tests/webdriver/tests/actions/modifier_click.py +++ b/tests/wpt/web-platform-tests/webdriver/tests/actions/modifier_click.py @@ -6,30 +6,55 @@ from tests.actions.support.refine import filter_dict, get_events from tests.actions.support.keys import Keys +# Using local fixtures because we want to start a new session between +# each test, otherwise the clicks in each test interfere with each other. +@pytest.fixture(autouse=True) +def release_actions(mod_click_session, request): + request.addfinalizer(mod_click_session.actions.release) + + +@pytest.fixture +def mod_click_session(new_session, url, add_browser_capabilites): + _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({})}}) + session.url = url("/webdriver/tests/actions/support/test_actions_wdspec.html") + + return session + + +@pytest.fixture +def key_chain(mod_click_session): + return mod_click_session.actions.sequence("key", "keyboard_id") + + +@pytest.fixture +def mouse_chain(mod_click_session): + return mod_click_session.actions.sequence( + "pointer", + "pointer_id", + {"pointerType": "mouse"}) + + @pytest.mark.parametrize("modifier, prop", [ - (Keys.CONTROL, "ctrlKey"), - (Keys.ALT, "altKey"), - (Keys.META, "metaKey"), - (Keys.SHIFT, "shiftKey"), - (Keys.R_CONTROL, "ctrlKey"), - (Keys.R_ALT, "altKey"), - (Keys.R_META, "metaKey"), - (Keys.R_SHIFT, "shiftKey"), + (Keys.ALT, "altKey"), + (Keys.R_ALT, "altKey"), + (Keys.META, "metaKey"), + (Keys.R_META, "metaKey"), + (Keys.SHIFT, "shiftKey"), + (Keys.R_SHIFT, "shiftKey"), ]) -def test_modifier_click(session, - test_actions_page, +def test_modifier_click(mod_click_session, key_chain, mouse_chain, modifier, prop): key_chain \ - .pause(0) \ + .pause(200) \ .key_down(modifier) \ .pause(200) \ .key_up(modifier) - outer = session.find.css("#outer", all=False) + outer = mod_click_session.find.css("#outer", all=False) mouse_chain.click(element=outer) - session.actions.perform([key_chain.dict, mouse_chain.dict]) + mod_click_session.actions.perform([key_chain.dict, mouse_chain.dict]) expected = [ {"type": "mousemove"}, {"type": "mousedown"}, @@ -46,29 +71,47 @@ def test_modifier_click(session, e.update(defaults) if e["type"] != "mousemove": e[prop] = True - filtered_events = [filter_dict(e, expected[0]) for e in get_events(session)] + filtered_events = [filter_dict(e, expected[0]) for e in get_events(mod_click_session)] assert expected == filtered_events -def test_release_control_click(session, key_reporter, key_chain, mouse_chain): +def test_many_modifiers_click(mod_click_session, key_chain, mouse_chain): + outer = mod_click_session.find.css("#outer", all=False) key_chain \ .pause(0) \ - .key_down(Keys.CONTROL) + .key_down(Keys.CONTROL) \ + .key_down(Keys.SHIFT) \ + .pause(0) \ + .key_up(Keys.CONTROL) \ + .key_up(Keys.SHIFT) mouse_chain \ - .pointer_move(0, 0, origin=key_reporter) \ + .pointer_move(0, 0, origin=outer) \ + .pause(0) \ + .pointer_down() \ + .pointer_up() \ + .pause(0) \ + .pause(0) \ .pointer_down() - session.actions.perform([key_chain.dict, mouse_chain.dict]) - session.execute_script(""" - var keyReporter = document.getElementById("keys"); - ["mousedown", "mouseup"].forEach((e) => { - keyReporter.addEventListener(e, recordPointerEvent); - }); - resetEvents(); - """) - session.actions.release() + mod_click_session.actions.perform([key_chain.dict, mouse_chain.dict]) expected = [ + {"type": "mousemove"}, + # shift and ctrl presses + {"type": "mousedown"}, {"type": "mouseup"}, - {"type": "keyup"}, + {"type": "click"}, + # no modifiers pressed + {"type": "mousedown"}, ] - events = [filter_dict(e, expected[0]) for e in get_events(session)] + defaults = { + "altKey": False, + "metaKey": False, + "shiftKey": False, + "ctrlKey": False + } + for e in expected: + e.update(defaults) + for e in expected[1:4]: + e["shiftKey"] = True + e["ctrlKey"] = True + events = [filter_dict(e, expected[0]) for e in get_events(mod_click_session)] assert events == expected diff --git a/tests/wpt/web-platform-tests/webdriver/tests/actions/mouse.py b/tests/wpt/web-platform-tests/webdriver/tests/actions/mouse.py index 07f7809e918..95d284c4b72 100644 --- a/tests/wpt/web-platform-tests/webdriver/tests/actions/mouse.py +++ b/tests/wpt/web-platform-tests/webdriver/tests/actions/mouse.py @@ -1,7 +1,8 @@ import pytest -from tests.support.inline import inline +from tests.actions.support.mouse import assert_move_to_coordinates, get_center from tests.actions.support.refine import get_events, filter_dict +from tests.support.inline import inline from tests.support.wait import wait @@ -10,13 +11,6 @@ def link_doc(dest): return inline(content) -def get_center(rect): - return { - "x": rect["width"] / 2 + rect["x"], - "y": rect["height"] / 2 + rect["y"], - } - - # TODO use pytest.approx once we upgrade to pytest > 3.0 def approx(n, m, tolerance=1): return abs(n - m) <= tolerance @@ -33,11 +27,8 @@ def test_click_at_coordinates(session, test_actions_page, mouse_chain): .perform() events = get_events(session) assert len(events) == 4 + assert_move_to_coordinates(div_point, "outer", events) for e in events: - if e["type"] != "mousemove": - assert e["pageX"] == div_point["x"] - assert e["pageY"] == div_point["y"] - assert e["target"] == "outer" if e["type"] != "mousedown": assert e["buttons"] == 0 assert e["button"] == 0 @@ -89,7 +80,7 @@ def test_click_element_center(session, test_actions_page, mouse_chain): assert e["target"] == "outer" -def test_click_navigation(session, url): +def test_click_navigation(session, url, release_actions): destination = url("/webdriver/tests/actions/support/test_actions_wdspec.html") start = link_doc(destination) @@ -112,7 +103,12 @@ def test_click_navigation(session, url): @pytest.mark.parametrize("drag_duration", [0, 300, 800]) @pytest.mark.parametrize("dx, dy", [(20, 0), (0, 15), (10, 15), (-20, 0), (10, -15), (-10, -15)]) -def test_drag_and_drop(session, test_actions_page, mouse_chain, dx, dy, drag_duration): +def test_drag_and_drop(session, + test_actions_page, + mouse_chain, + dx, + dy, + drag_duration): drag_target = session.find.css("#dragTarget", all=False) initial_rect = drag_target.rect initial_center = get_center(initial_rect) diff --git a/tests/wpt/web-platform-tests/webdriver/tests/actions/mouse_dblclick.py b/tests/wpt/web-platform-tests/webdriver/tests/actions/mouse_dblclick.py new file mode 100644 index 00000000000..f73f780a7a7 --- /dev/null +++ b/tests/wpt/web-platform-tests/webdriver/tests/actions/mouse_dblclick.py @@ -0,0 +1,108 @@ +import pytest + +from tests.actions.support.mouse import assert_move_to_coordinates, get_center +from tests.actions.support.refine import get_events, filter_dict + + +_DBLCLICK_INTERVAL = 640 + + +# Using local fixtures because we want to start a new session between +# each test, otherwise the clicks in each test interfere with each other. +@pytest.fixture(autouse=True) +def release_actions(dblclick_session, request): + # release all actions after each test + # equivalent to a teardown_function, but with access to session fixture + request.addfinalizer(dblclick_session.actions.release) + + +@pytest.fixture +def dblclick_session(new_session, url, add_browser_capabilites): + _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({})}}) + session.url = url("/webdriver/tests/actions/support/test_actions_wdspec.html") + + return session + + +@pytest.fixture +def mouse_chain(dblclick_session): + return dblclick_session.actions.sequence( + "pointer", + "pointer_id", + {"pointerType": "mouse"}) + + +@pytest.mark.parametrize("click_pause", [0, 200]) +def test_dblclick_at_coordinates(dblclick_session, mouse_chain, click_pause): + div_point = { + "x": 82, + "y": 187, + } + mouse_chain \ + .pointer_move(div_point["x"], div_point["y"]) \ + .click() \ + .pause(click_pause) \ + .click() \ + .perform() + events = get_events(dblclick_session) + assert_move_to_coordinates(div_point, "outer", events) + expected = [ + {"type": "mousedown", "button": 0}, + {"type": "mouseup", "button": 0}, + {"type": "click", "button": 0}, + {"type": "mousedown", "button": 0}, + {"type": "mouseup", "button": 0}, + {"type": "click", "button": 0}, + {"type": "dblclick", "button": 0}, + ] + assert len(events) == 8 + filtered_events = [filter_dict(e, expected[0]) for e in events] + assert expected == filtered_events[1:] + + +def test_dblclick_with_pause_after_second_pointerdown(dblclick_session, mouse_chain): + outer = dblclick_session.find.css("#outer", all=False) + center = get_center(outer.rect) + mouse_chain \ + .pointer_move(int(center["x"]), int(center["y"])) \ + .click() \ + .pointer_down() \ + .pause(_DBLCLICK_INTERVAL + 10) \ + .pointer_up() \ + .perform() + events = get_events(dblclick_session) + expected = [ + {"type": "mousedown", "button": 0}, + {"type": "mouseup", "button": 0}, + {"type": "click", "button": 0}, + {"type": "mousedown", "button": 0}, + {"type": "mouseup", "button": 0}, + {"type": "click", "button": 0}, + {"type": "dblclick", "button": 0}, + ] + assert len(events) == 8 + filtered_events = [filter_dict(e, expected[0]) for e in events] + assert expected == filtered_events[1:] + + +def test_no_dblclick(dblclick_session, mouse_chain): + outer = dblclick_session.find.css("#outer", all=False) + center = get_center(outer.rect) + mouse_chain \ + .pointer_move(int(center["x"]), int(center["y"])) \ + .click() \ + .pause(_DBLCLICK_INTERVAL + 10) \ + .click() \ + .perform() + events = get_events(dblclick_session) + expected = [ + {"type": "mousedown", "button": 0}, + {"type": "mouseup", "button": 0}, + {"type": "click", "button": 0}, + {"type": "mousedown", "button": 0}, + {"type": "mouseup", "button": 0}, + {"type": "click", "button": 0}, + ] + assert len(events) == 7 + filtered_events = [filter_dict(e, expected[0]) for e in events] + assert expected == filtered_events[1:] diff --git a/tests/wpt/web-platform-tests/webdriver/tests/actions/sequence.py b/tests/wpt/web-platform-tests/webdriver/tests/actions/sequence.py index 3092034c46f..426dbe82f48 100644 --- a/tests/wpt/web-platform-tests/webdriver/tests/actions/sequence.py +++ b/tests/wpt/web-platform-tests/webdriver/tests/actions/sequence.py @@ -37,45 +37,3 @@ def test_release_no_actions_sends_no_events(session, key_reporter): session.actions.release() assert len(get_keys(key_reporter)) == 0 assert len(get_events(session)) == 0 - - -def test_many_modifiers_click(session, test_actions_page, key_chain, mouse_chain): - outer = session.find.css("#outer", all=False) - key_chain \ - .pause(0) \ - .key_down(Keys.CONTROL) \ - .key_down(Keys.SHIFT) \ - .pause(0) \ - .key_up(Keys.CONTROL) \ - .key_up(Keys.SHIFT) - mouse_chain \ - .pointer_move(0, 0, origin=outer) \ - .pause(0) \ - .pointer_down() \ - .pointer_up() \ - .pause(0) \ - .pause(0) \ - .pointer_down() - session.actions.perform([key_chain.dict, mouse_chain.dict]) - expected = [ - {"type": "mousemove"}, - # shift and ctrl presses - {"type": "mousedown"}, - {"type": "mouseup"}, - {"type": "click"}, - # no modifiers pressed - {"type": "mousedown"}, - ] - defaults = { - "altKey": False, - "metaKey": False, - "shiftKey": False, - "ctrlKey": False - } - for e in expected: - e.update(defaults) - for e in expected[1:4]: - e["shiftKey"] = True - e["ctrlKey"] = True - events = [filter_dict(e, expected[0]) for e in get_events(session)] - assert events == expected diff --git a/tests/wpt/web-platform-tests/webdriver/tests/actions/support/keys.py b/tests/wpt/web-platform-tests/webdriver/tests/actions/support/keys.py index 85517916678..7c71a87bc69 100644 --- a/tests/wpt/web-platform-tests/webdriver/tests/actions/support/keys.py +++ b/tests/wpt/web-platform-tests/webdriver/tests/actions/support/keys.py @@ -20,6 +20,7 @@ The Keys implementation. """ from inspect import getmembers +import sys class Keys(object): @@ -740,3 +741,8 @@ ALL_EVENTS = { "value": u"\ue040", } } + +if sys.platform == 'darwin': + MODIFIER_KEY = Keys.META +else: + MODIFIER_KEY = Keys.CONTROL diff --git a/tests/wpt/web-platform-tests/webdriver/tests/actions/support/mouse.py b/tests/wpt/web-platform-tests/webdriver/tests/actions/support/mouse.py new file mode 100644 index 00000000000..63a771d9487 --- /dev/null +++ b/tests/wpt/web-platform-tests/webdriver/tests/actions/support/mouse.py @@ -0,0 +1,13 @@ +def assert_move_to_coordinates(point, target, events): + for e in events: + if e["type"] != "mousemove": + assert e["pageX"] == point["x"] + assert e["pageY"] == point["y"] + assert e["target"] == target + + +def get_center(rect): + return { + "x": rect["width"] / 2 + rect["x"], + "y": rect["height"] / 2 + rect["y"], + } diff --git a/tests/wpt/web-platform-tests/webdriver/tests/cookies/add_cookie.py b/tests/wpt/web-platform-tests/webdriver/tests/cookies/add_cookie.py index df45722b100..1ebbcb41de7 100644 --- a/tests/wpt/web-platform-tests/webdriver/tests/cookies/add_cookie.py +++ b/tests/wpt/web-platform-tests/webdriver/tests/cookies/add_cookie.py @@ -1,14 +1,14 @@ from tests.support.fixtures import clear_all_cookies -from tests.support.fixtures import server_config +from datetime import datetime, timedelta -def test_add_domain_cookie(session, url): +def test_add_domain_cookie(session, url, server_config): session.url = url("/common/blank.html") clear_all_cookies(session) create_cookie_request = { "cookie": { "name": "hello", "value": "world", - "domain": "web-platform.test", + "domain": server_config["domains"][""], "path": "/", "httpOnly": False, "secure": False @@ -36,16 +36,16 @@ def test_add_domain_cookie(session, url): assert cookie["name"] == "hello" assert cookie["value"] == "world" - assert cookie["domain"] == ".web-platform.test" + assert cookie["domain"] == ".%s" % server_config["domains"][""] -def test_add_cookie_for_ip(session, url, server_config): +def test_add_cookie_for_ip(session, url, server_config, configuration): session.url = "http://127.0.0.1:%s/404" % (server_config["ports"]["http"][0]) clear_all_cookies(session) create_cookie_request = { "cookie": { "name": "hello", "value": "world", - "domain": "127.0.0.1", + "domain": configuration["host"], "path": "/", "httpOnly": False, "secure": False @@ -74,3 +74,104 @@ def test_add_cookie_for_ip(session, url, server_config): assert cookie["name"] == "hello" assert cookie["value"] == "world" assert cookie["domain"] == "127.0.0.1" + +def test_add_non_session_cookie(session, url): + session.url = url("/common/blank.html") + clear_all_cookies(session) + a_year_from_now = int((datetime.utcnow() + timedelta(days=365)).strftime("%s")) + create_cookie_request = { + "cookie": { + "name": "hello", + "value": "world", + "expiry": a_year_from_now + } + } + result = session.transport.send("POST", "session/%s/cookie" % session.session_id, create_cookie_request) + assert result.status == 200 + assert "value" in result.body + assert isinstance(result.body["value"], dict) + + result = session.transport.send("GET", "session/%s/cookie" % session.session_id) + assert result.status == 200 + assert "value" in result.body + assert isinstance(result.body["value"], list) + assert len(result.body["value"]) == 1 + assert isinstance(result.body["value"][0], dict) + + cookie = result.body["value"][0] + assert "name" in cookie + assert isinstance(cookie["name"], basestring) + assert "value" in cookie + assert isinstance(cookie["value"], basestring) + assert "expiry" in cookie + assert isinstance(cookie["expiry"], int) + + assert cookie["name"] == "hello" + assert cookie["value"] == "world" + assert cookie["expiry"] == a_year_from_now + +def test_add_session_cookie(session, url): + session.url = url("/common/blank.html") + clear_all_cookies(session) + create_cookie_request = { + "cookie": { + "name": "hello", + "value": "world" + } + } + result = session.transport.send("POST", "session/%s/cookie" % session.session_id, create_cookie_request) + assert result.status == 200 + assert "value" in result.body + assert isinstance(result.body["value"], dict) + + result = session.transport.send("GET", "session/%s/cookie" % session.session_id) + assert result.status == 200 + assert "value" in result.body + assert isinstance(result.body["value"], list) + assert len(result.body["value"]) == 1 + assert isinstance(result.body["value"][0], dict) + + cookie = result.body["value"][0] + assert "name" in cookie + assert isinstance(cookie["name"], basestring) + assert "value" in cookie + assert isinstance(cookie["value"], basestring) + assert "expiry" in cookie + assert cookie.get("expiry") is None + + assert cookie["name"] == "hello" + assert cookie["value"] == "world" + +def test_add_session_cookie_with_leading_dot_character_in_domain(session, url, server_config): + session.url = url("/common/blank.html") + clear_all_cookies(session) + create_cookie_request = { + "cookie": { + "name": "hello", + "value": "world", + "domain": ".%s" % server_config["domains"][""] + } + } + result = session.transport.send("POST", "session/%s/cookie" % session.session_id, create_cookie_request) + assert result.status == 200 + assert "value" in result.body + assert isinstance(result.body["value"], dict) + + result = session.transport.send("GET", "session/%s/cookie" % session.session_id) + assert result.status == 200 + assert "value" in result.body + assert isinstance(result.body["value"], list) + assert len(result.body["value"]) == 1 + assert isinstance(result.body["value"][0], dict) + + cookie = result.body["value"][0] + assert "name" in cookie + assert isinstance(cookie["name"], basestring) + assert "value" in cookie + assert isinstance(cookie["value"], basestring) + assert "domain" in cookie + assert isinstance(cookie["domain"], basestring) + + assert cookie["name"] == "hello" + assert cookie["value"] == "world" + assert cookie["domain"] == ".%s" % server_config["domains"][""] diff --git a/tests/wpt/web-platform-tests/webdriver/tests/cookies/get_named_cookie.py b/tests/wpt/web-platform-tests/webdriver/tests/cookies/get_named_cookie.py index 027859dd7f9..f367eccf947 100644 --- a/tests/wpt/web-platform-tests/webdriver/tests/cookies/get_named_cookie.py +++ b/tests/wpt/web-platform-tests/webdriver/tests/cookies/get_named_cookie.py @@ -61,14 +61,14 @@ def test_get_named_cookie(session, url): # convert from seconds since epoch assert datetime.utcfromtimestamp(cookie["expiry"]).strftime(utc_string_format) == a_year_from_now -def test_duplicated_cookie(session, url): +def test_duplicated_cookie(session, url, server_config): session.url = url("/common/blank.html") clear_all_cookies(session) create_cookie_request = { "cookie": { "name": "hello", "value": "world", - "domain": "web-platform.test", + "domain": server_config["domains"][""], "path": "/", "httpOnly": False, "secure": False @@ -79,7 +79,7 @@ def test_duplicated_cookie(session, url): assert "value" in result.body assert isinstance(result.body["value"], dict) - session.url = inline("") + session.url = inline("" % server_config["domains"][""]) result = session.transport.send("GET", "session/%s/cookie" % session.session_id) assert result.status == 200 assert "value" in result.body diff --git a/tests/wpt/web-platform-tests/webdriver/tests/document_handling/page_source.py b/tests/wpt/web-platform-tests/webdriver/tests/document_handling/page_source.py new file mode 100644 index 00000000000..04eae6f83be --- /dev/null +++ b/tests/wpt/web-platform-tests/webdriver/tests/document_handling/page_source.py @@ -0,0 +1,14 @@ +import pytest + +from tests.support.inline import inline + + +# 15.1.3 "Let source be the result returned from the outerHTML IDL attribute +# of the document element" +def test_source_matches_outer_html(session): + session.url = inline("CheesePeas") + expected_source = session.execute_script( + "return document.documentElement.outerHTML") + + assert session.source == expected_source + diff --git a/tests/wpt/web-platform-tests/webdriver/tests/element_click/bubbling.py b/tests/wpt/web-platform-tests/webdriver/tests/element_click/bubbling.py new file mode 100644 index 00000000000..1cfb2efa2f5 --- /dev/null +++ b/tests/wpt/web-platform-tests/webdriver/tests/element_click/bubbling.py @@ -0,0 +1,152 @@ +from tests.support.asserts import assert_success +from tests.support.inline import inline + + +def click(session, element): + return session.transport.send( + "POST", "/session/{session_id}/element/{element_id}/click".format( + session_id=session.session_id, + element_id=element.id)) + + +def test_click_event_bubbles_to_parents(session): + session.url = inline(""" + + +
    THREE +
    TWO +
    ONE
    +
    +
    + + + """) + three, two, one = session.find.css("div") + one.click() + + clicks = session.execute_script("return window.clicks") + assert one in clicks + assert two in clicks + assert three in clicks + + +def test_spin_event_loop(session): + """ + Wait until the user agent event loop has spun enough times to + process the DOM events generated by clicking. + """ + session.url = inline(""" + + +
    THREE +
    TWO +
    ONE
    +
    +
    + + + """) + three, two, one = session.find.css("div") + one.click() + + delayed_clicks = session.execute_script("return window.delayedClicks") + assert one in delayed_clicks + assert two in delayed_clicks + assert three in delayed_clicks + + +def test_element_disappears_during_click(session): + """ + When an element in the event bubbling order disappears (its CSS + display style is set to "none") during a click, Gecko and Blink + exhibit different behaviour. Whilst Chrome fires a "click" + DOM event on , Firefox does not. + + A WebDriver implementation may choose to wait for this event to let + the event loops spin enough times to let click events propagate, + so this is a corner case test that Firefox does not hang indefinitely. + """ + session.url = inline(""" + + + +
    +
    + +
    + + + + """) + over = session.find.css("#over", all=False) + + # should not time out + response = click(session, over) + assert_success(response) diff --git a/tests/wpt/web-platform-tests/webdriver/tests/element_click/stale.py b/tests/wpt/web-platform-tests/webdriver/tests/element_click/stale.py new file mode 100644 index 00000000000..d39e3a3ecb7 --- /dev/null +++ b/tests/wpt/web-platform-tests/webdriver/tests/element_click/stale.py @@ -0,0 +1,22 @@ +import pytest +import webdriver + +from tests.support.asserts import assert_error +from tests.support.inline import inline + + +def click_element(session, element): + return session.transport.send( + "POST", "/session/{session_id}/element/{element_id}/click".format(**{ + "session_id": session.session_id, + "element_id": element.id, + })) + + +def test_is_stale(session): + session.url = inline("") + button = session.find.css("button", all=False) + session.url = inline("") + + response = click_element(session, button) + assert_error(response, "stale element reference") diff --git a/tests/wpt/web-platform-tests/webdriver/tests/element_retrieval/__init__.py b/tests/wpt/web-platform-tests/webdriver/tests/element_retrieval/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/wpt/web-platform-tests/webdriver/tests/retrieval/find_element.py b/tests/wpt/web-platform-tests/webdriver/tests/element_retrieval/find_element.py similarity index 88% rename from tests/wpt/web-platform-tests/webdriver/tests/retrieval/find_element.py rename to tests/wpt/web-platform-tests/webdriver/tests/element_retrieval/find_element.py index a0047eb9f08..454e3c38bdc 100644 --- a/tests/wpt/web-platform-tests/webdriver/tests/retrieval/find_element.py +++ b/tests/wpt/web-platform-tests/webdriver/tests/element_retrieval/find_element.py @@ -71,3 +71,13 @@ def test_xhtml_namespace(session, using, value): response = find_element(session, using, value) value = assert_success(response) assert_same_element(session, value, expected) + + +@pytest.mark.parametrize("using,value", + [("css selector", ":root"), + ("tag name", "html"), + ("xpath", "/html")]) +def test_htmldocument(session, using, value): + session.url = inline("") + response = find_element(session, using, value) + assert_success(response) diff --git a/tests/wpt/web-platform-tests/webdriver/tests/retrieval/find_element_from_element.py b/tests/wpt/web-platform-tests/webdriver/tests/element_retrieval/find_element_from_element.py similarity index 92% rename from tests/wpt/web-platform-tests/webdriver/tests/retrieval/find_element_from_element.py rename to tests/wpt/web-platform-tests/webdriver/tests/element_retrieval/find_element_from_element.py index 3bf1d860bd4..d79d512a13c 100644 --- a/tests/wpt/web-platform-tests/webdriver/tests/retrieval/find_element_from_element.py +++ b/tests/wpt/web-platform-tests/webdriver/tests/element_retrieval/find_element_from_element.py @@ -72,3 +72,11 @@ def test_xhtml_namespace(session, using, value): response = find_element(session, from_element.id, using, value) value = assert_success(response) assert_same_element(session, value, expected) + + +def test_parent_htmldocument(session): + session.url = inline("") + from_element = session.execute_script("return document.documentElement") + + response = find_element(session, from_element.id, "xpath", "..") + assert_success(response) diff --git a/tests/wpt/web-platform-tests/webdriver/tests/retrieval/find_elements.py b/tests/wpt/web-platform-tests/webdriver/tests/element_retrieval/find_elements.py similarity index 87% rename from tests/wpt/web-platform-tests/webdriver/tests/retrieval/find_elements.py rename to tests/wpt/web-platform-tests/webdriver/tests/element_retrieval/find_elements.py index 8bc2113a84a..a00ae2358c2 100644 --- a/tests/wpt/web-platform-tests/webdriver/tests/retrieval/find_elements.py +++ b/tests/wpt/web-platform-tests/webdriver/tests/element_retrieval/find_elements.py @@ -77,3 +77,15 @@ def test_xhtml_namespace(session, using, value): found_element = value[0] assert_same_element(session, found_element, expected) + + +@pytest.mark.parametrize("using,value", + [("css selector", ":root"), + ("tag name", "html"), + ("xpath", "/html")]) +def test_htmldocument(session, using, value): + session.url = inline("") + response = find_elements(session, using, value) + value = assert_success(response) + assert isinstance(value, list) + assert len(value) == 1 diff --git a/tests/wpt/web-platform-tests/webdriver/tests/retrieval/find_element_from_elements.py b/tests/wpt/web-platform-tests/webdriver/tests/element_retrieval/find_elements_from_element.py similarity index 90% rename from tests/wpt/web-platform-tests/webdriver/tests/retrieval/find_element_from_elements.py rename to tests/wpt/web-platform-tests/webdriver/tests/element_retrieval/find_elements_from_element.py index 933d69d1e60..486d7cb7aee 100644 --- a/tests/wpt/web-platform-tests/webdriver/tests/retrieval/find_element_from_elements.py +++ b/tests/wpt/web-platform-tests/webdriver/tests/element_retrieval/find_elements_from_element.py @@ -75,3 +75,13 @@ def test_xhtml_namespace(session, using, value): found_element = value[0] assert_same_element(session, found_element, expected) + + +def test_parent_htmldocument(session): + session.url = inline("") + from_element = session.execute_script("return document.documentElement") + + response = find_elements(session, from_element.id, "xpath", "..") + value = assert_success(response) + assert isinstance(value, list) + assert len(value) == 1 diff --git a/tests/wpt/web-platform-tests/webdriver/tests/element_retrieval/get_active_element.py b/tests/wpt/web-platform-tests/webdriver/tests/element_retrieval/get_active_element.py index 9bc6f732768..af3e1257a17 100644 --- a/tests/wpt/web-platform-tests/webdriver/tests/element_retrieval/get_active_element.py +++ b/tests/wpt/web-platform-tests/webdriver/tests/element_retrieval/get_active_element.py @@ -2,9 +2,11 @@ from tests.support.asserts import assert_error, assert_dialog_handled, assert_sa from tests.support.fixtures import create_dialog from tests.support.inline import inline + def read_global(session, name): return session.execute_script("return %s;" % name) + def get_active_element(session): return session.transport.send("GET", "session/%s/element/active" % session.session_id) @@ -67,7 +69,7 @@ def test_handle_prompt_dismiss(new_session, add_browser_capabilites): response = get_active_element(session) assert_is_active_element(session, response) assert_dialog_handled(session, "dismiss #2") - assert read_global(session, "dismiss2") is None + assert read_global(session, "dismiss2") is False create_dialog(session)("prompt", text="dismiss #3", result_var="dismiss3") @@ -244,7 +246,7 @@ def test_success_iframe_content(session): assert_is_active_element(session, response) -def test_sucess_without_body(session): +def test_missing_document_element(session): session.url = inline("") session.execute_script(""" if (document.body.remove) { @@ -254,4 +256,4 @@ def test_sucess_without_body(session): }""") response = get_active_element(session) - assert_is_active_element(session, response) + assert_error(response, "no such element") diff --git a/tests/wpt/web-platform-tests/webdriver/tests/element_send_keys/__init__.py b/tests/wpt/web-platform-tests/webdriver/tests/element_send_keys/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/wpt/web-platform-tests/webdriver/tests/element_send_keys/interactability.py b/tests/wpt/web-platform-tests/webdriver/tests/element_send_keys/interactability.py new file mode 100644 index 00000000000..5812f2b305f --- /dev/null +++ b/tests/wpt/web-platform-tests/webdriver/tests/element_send_keys/interactability.py @@ -0,0 +1,136 @@ +from tests.support.asserts import assert_error, assert_same_element, assert_success +from tests.support.inline import iframe, inline + + +def send_keys_to_element(session, element, text): + return session.transport.send( + "POST", + "/session/{session_id}/element/{element_id}/value".format( + session_id=session.session_id, + element_id=element.id), + {"text": text}) + + +def test_body_is_interactable(session): + session.url = inline(""" + + + + """) + + element = session.find.css("body", all=False) + result = session.find.css("input", all=False) + + # By default body is the active element + assert_same_element(session, element, session.active_element) + + response = send_keys_to_element(session, element, "foo") + assert_success(response) + assert_same_element(session, element, session.active_element) + assert result.property("value") == "foo" + + +def test_document_element_is_interactable(session): + session.url = inline(""" + + + + """) + + body = session.find.css("body", all=False) + element = session.find.css(":root", all=False) + result = session.find.css("input", all=False) + + # By default body is the active element + assert_same_element(session, body, session.active_element) + + response = send_keys_to_element(session, element, "foo") + assert_success(response) + assert_same_element(session, element, session.active_element) + assert result.property("value") == "foo" + + +def test_iframe_is_interactable(session): + session.url = inline(iframe(""" + + + + """)) + + body = session.find.css("body", all=False) + frame = session.find.css("iframe", all=False) + + # By default the body has the focus + assert_same_element(session, body, session.active_element) + + response = send_keys_to_element(session, frame, "foo") + assert_success(response) + assert_same_element(session, frame, session.active_element) + + # Any key events are immediately routed to the nested + # browsing context's active document. + session.switch_frame(frame) + result = session.find.css("input", all=False) + assert result.property("value") == "foo" + + +def test_transparent_element(session): + session.url = inline("") + element = session.find.css("input", all=False) + + response = send_keys_to_element(session, element, "foo") + assert_success(response) + assert element.property("value") == "foo" + + +def test_readonly_element(session): + session.url = inline("") + element = session.find.css("input", all=False) + + response = send_keys_to_element(session, element, "foo") + assert_success(response) + assert element.property("value") == "" + + +def test_obscured_element(session): + session.url = inline(""" + +
    + """) + element = session.find.css("input", all=False) + + response = send_keys_to_element(session, element, "foo") + assert_success(response) + assert element.property("value") == "foo" + + +def test_not_a_focusable_element(session): + session.url = inline("
    foo
    ") + element = session.find.css("div", all=False) + + response = send_keys_to_element(session, element, "foo") + assert_error(response, "element not interactable") + + +def test_not_displayed_element(session): + session.url = inline("") + element = session.find.css("input", all=False) + + response = send_keys_to_element(session, element, "foo") + assert_error(response, "element not interactable") + + +def test_hidden_element(session): + session.url = inline("") + element = session.find.css("input", all=False) + + response = send_keys_to_element(session, element, "foo") + assert_error(response, "element not interactable") + + +def test_disabled_element(session): + session.url = inline("") + element = session.find.css("input", all=False) + + response = send_keys_to_element(session, element, "foo") + assert_error(response, "element not interactable") diff --git a/tests/wpt/web-platform-tests/webdriver/tests/element_send_keys/scroll_into_view.py b/tests/wpt/web-platform-tests/webdriver/tests/element_send_keys/scroll_into_view.py new file mode 100644 index 00000000000..a1d454d1fe2 --- /dev/null +++ b/tests/wpt/web-platform-tests/webdriver/tests/element_send_keys/scroll_into_view.py @@ -0,0 +1,78 @@ +from tests.support.asserts import assert_success +from tests.support.fixtures import is_element_in_viewport +from tests.support.inline import inline + + +def send_keys_to_element(session, element, text): + return session.transport.send( + "POST", + "/session/{session_id}/element/{element_id}/value".format( + session_id=session.session_id, + element_id=element.id), + {"text": text}) + + +def test_element_outside_of_not_scrollable_viewport(session): + session.url = inline("") + element = session.find.css("input", all=False) + + response = send_keys_to_element(session, element, "foo") + assert_success(response) + + assert not is_element_in_viewport(session, element) + + +def test_element_outside_of_scrollable_viewport(session): + session.url = inline("") + element = session.find.css("input", all=False) + + response = send_keys_to_element(session, element, "foo") + assert_success(response) + + assert is_element_in_viewport(session, element) + + +def test_option_select_container_outside_of_scrollable_viewport(session): + session.url = inline(""" + + """) + element = session.find.css("option#bar", all=False) + select = session.find.css("select", all=False) + + response = send_keys_to_element(session, element, "bar") + assert_success(response) + + assert is_element_in_viewport(session, select) + assert is_element_in_viewport(session, element) + + +def test_option_stays_outside_of_scrollable_viewport(session): + session.url = inline(""" + + """) + select = session.find.css("select", all=False) + option_foo = session.find.css("option#foo", all=False) + option_bar = session.find.css("option#bar", all=False) + + response = send_keys_to_element(session, option_bar, "bar") + assert_success(response) + + assert is_element_in_viewport(session, select) + assert is_element_in_viewport(session, option_foo) + assert not is_element_in_viewport(session, option_bar) + + +def test_contenteditable_element_outside_of_scrollable_viewport(session): + session.url = inline("
    ") + element = session.find.css("div", all=False) + + response = send_keys_to_element(session, element, "foo") + assert_success(response) + + assert is_element_in_viewport(session, element) diff --git a/tests/wpt/web-platform-tests/webdriver/tests/execute_async_script/user_prompts.py b/tests/wpt/web-platform-tests/webdriver/tests/execute_async_script/user_prompts.py new file mode 100644 index 00000000000..03e1762d8b0 --- /dev/null +++ b/tests/wpt/web-platform-tests/webdriver/tests/execute_async_script/user_prompts.py @@ -0,0 +1,60 @@ +import pytest + +from webdriver import error + + +# 15.2 Executing Script + +def test_handle_prompt_accept(new_session, add_browser_capabilites): + _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "accept"})}}) + session.execute_async_script("window.alert('Hello');") + with pytest.raises(error.NoSuchAlertException): + session.alert.accept() + + +def test_handle_prompt_dismiss(new_session, add_browser_capabilites): + _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "dismiss"})}}) + session.execute_async_script("window.alert('Hello');") + with pytest.raises(error.NoSuchAlertException): + session.alert.dismiss() + + +def test_handle_prompt_dismiss_and_notify(new_session, add_browser_capabilites): + _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "dismiss and notify"})}}) + with pytest.raises(error.UnexpectedAlertOpenException): + session.execute_async_script("window.alert('Hello');") + with pytest.raises(error.NoSuchAlertException): + session.alert.dismiss() + + +def test_handle_prompt_accept_and_notify(new_session, add_browser_capabilites): + _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "accept and notify"})}}) + with pytest.raises(error.UnexpectedAlertOpenException): + session.execute_async_script("window.alert('Hello');") + with pytest.raises(error.NoSuchAlertException): + session.alert.accept() + + +def test_handle_prompt_ignore(new_session, add_browser_capabilites): + _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "ignore"})}}) + with pytest.raises(error.UnexpectedAlertOpenException): + session.execute_async_script("window.alert('Hello');") + session.alert.dismiss() + + +def test_handle_prompt_default(new_session, add_browser_capabilites): + _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({})}}) + with pytest.raises(error.UnexpectedAlertOpenException): + session.execute_async_script("window.alert('Hello');") + with pytest.raises(error.NoSuchAlertException): + session.alert.dismiss() + + +def test_handle_prompt_twice(new_session, add_browser_capabilites): + _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "accept"})}}) + session.execute_async_script("window.alert('Hello');window.alert('Bye');") + # The first alert has been accepted by the user prompt handler, the second one remains. + # FIXME: this is how browsers currently work, but the spec should clarify if this is the + # expected behavior, see https://github.com/w3c/webdriver/issues/1153. + assert session.alert.text == "Bye" + session.alert.dismiss() diff --git a/tests/wpt/web-platform-tests/webdriver/tests/execute_script/cyclic.py b/tests/wpt/web-platform-tests/webdriver/tests/execute_script/cyclic.py new file mode 100644 index 00000000000..ae9d2f5775c --- /dev/null +++ b/tests/wpt/web-platform-tests/webdriver/tests/execute_script/cyclic.py @@ -0,0 +1,48 @@ +from tests.support.asserts import assert_error + + +def execute_script(session, script, args=None): + if args is None: + args = [] + body = {"script": script, "args": args} + return session.transport.send( + "POST", + "/session/{session_id}/execute/sync".format( + session_id=session.session_id), + body) + + +def test_array(session): + response = execute_script(session, """ + let arr = []; + arr.push(arr); + return arr; + """) + assert_error(response, "javascript error") + + +def test_object(session): + response = execute_script(session, """ + let obj = {}; + obj.reference = obj; + return obj; + """) + assert_error(response, "javascript error") + + +def test_array_in_object(session): + response = execute_script(session, """ + let arr = []; + arr.push(arr); + return {arr}; + """) + assert_error(response, "javascript error") + + +def test_object_in_array(session): + response = execute_script(session, """ + let obj = {}; + obj.reference = obj; + return [obj]; + """) + assert_error(response, "javascript error") diff --git a/tests/wpt/web-platform-tests/webdriver/tests/execute_script/user_prompts.py b/tests/wpt/web-platform-tests/webdriver/tests/execute_script/user_prompts.py new file mode 100644 index 00000000000..8d91bdd8f9f --- /dev/null +++ b/tests/wpt/web-platform-tests/webdriver/tests/execute_script/user_prompts.py @@ -0,0 +1,60 @@ +import pytest + +from webdriver import error + + +# 15.2 Executing Script + +def test_handle_prompt_accept(new_session, add_browser_capabilites): + _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "accept"})}}) + session.execute_script("window.alert('Hello');") + with pytest.raises(error.NoSuchAlertException): + session.alert.accept() + + +def test_handle_prompt_dismiss(new_session, add_browser_capabilites): + _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "dismiss"})}}) + session.execute_script("window.alert('Hello');") + with pytest.raises(error.NoSuchAlertException): + session.alert.dismiss() + + +def test_handle_prompt_dismiss_and_notify(new_session, add_browser_capabilites): + _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "dismiss and notify"})}}) + with pytest.raises(error.UnexpectedAlertOpenException): + session.execute_script("window.alert('Hello');") + with pytest.raises(error.NoSuchAlertException): + session.alert.dismiss() + + +def test_handle_prompt_accept_and_notify(new_session, add_browser_capabilites): + _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "accept and notify"})}}) + with pytest.raises(error.UnexpectedAlertOpenException): + session.execute_script("window.alert('Hello');") + with pytest.raises(error.NoSuchAlertException): + session.alert.accept() + + +def test_handle_prompt_ignore(new_session, add_browser_capabilites): + _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "ignore"})}}) + with pytest.raises(error.UnexpectedAlertOpenException): + session.execute_script("window.alert('Hello');") + session.alert.dismiss() + + +def test_handle_prompt_default(new_session, add_browser_capabilites): + _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({})}}) + with pytest.raises(error.UnexpectedAlertOpenException): + session.execute_script("window.alert('Hello');") + with pytest.raises(error.NoSuchAlertException): + session.alert.dismiss() + + +def test_handle_prompt_twice(new_session, add_browser_capabilites): + _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "accept"})}}) + session.execute_script("window.alert('Hello');window.alert('Bye');") + # The first alert has been accepted by the user prompt handler, the second one remains. + # FIXME: this is how browsers currently work, but the spec should clarify if this is the + # expected behavior, see https://github.com/w3c/webdriver/issues/1153. + assert session.alert.text == "Bye" + session.alert.dismiss() diff --git a/tests/wpt/web-platform-tests/webdriver/tests/get_window_rect.py b/tests/wpt/web-platform-tests/webdriver/tests/get_window_rect.py index b25ca28692f..cb3398ecccc 100644 --- a/tests/wpt/web-platform-tests/webdriver/tests/get_window_rect.py +++ b/tests/wpt/web-platform-tests/webdriver/tests/get_window_rect.py @@ -151,11 +151,10 @@ def test_payload(session): assert response.status == 200 assert isinstance(response.body["value"], dict) value = response.body["value"] - assert "width" in value - assert "height" in value - assert "x" in value - assert "y" in value - assert isinstance(value["width"], int) - assert isinstance(value["height"], int) - assert isinstance(value["x"], int) - assert isinstance(value["y"], int) + expected = session.execute_script("""return { + x: window.screenX, + y: window.screenY, + width: window.outerWidth, + height: window.outerHeight + }""") + assert expected == value diff --git a/tests/wpt/web-platform-tests/webdriver/tests/interaction/element_clear.py b/tests/wpt/web-platform-tests/webdriver/tests/interaction/element_clear.py index 07122906ac1..f9755f784e5 100644 --- a/tests/wpt/web-platform-tests/webdriver/tests/interaction/element_clear.py +++ b/tests/wpt/web-platform-tests/webdriver/tests/interaction/element_clear.py @@ -147,9 +147,9 @@ def test_clear_content_editable_resettable_element(session, element): url = element[1] + """ - + + + + - - + + diff --git a/tests/wpt/web-platform-tests/webdriver/tests/navigation/current_url.py b/tests/wpt/web-platform-tests/webdriver/tests/navigation/current_url.py index 45e462fb8e1..b3dfe1ffbd7 100644 --- a/tests/wpt/web-platform-tests/webdriver/tests/navigation/current_url.py +++ b/tests/wpt/web-platform-tests/webdriver/tests/navigation/current_url.py @@ -4,6 +4,7 @@ import types from tests.support.inline import inline from tests.support.asserts import assert_error, assert_success +from tests.support.wait import wait alert_doc = inline("") frame_doc = inline("

    frame") @@ -75,8 +76,11 @@ def test_set_malformed_url(session): assert_error(result, "invalid argument") def test_get_current_url_after_modified_location(session): + start = session.transport.send("GET", "session/%s/url" % session.session_id) session.execute_script("window.location.href = 'about:blank#wd_test_modification'") - + wait(session, + lambda s: s.transport.send("GET", "session/%s/url" % session.session_id) != start.body["value"], + "URL did not change") result = session.transport.send("GET", "session/%s/url" % session.session_id) assert_success(result, "about:blank#wd_test_modification") diff --git a/tests/wpt/web-platform-tests/webdriver/tests/sessions/status.py b/tests/wpt/web-platform-tests/webdriver/tests/sessions/status.py new file mode 100644 index 00000000000..892ce927145 --- /dev/null +++ b/tests/wpt/web-platform-tests/webdriver/tests/sessions/status.py @@ -0,0 +1,45 @@ +import pytest +import json + + +def test_get_status_no_session(http): + with http.get("/status") as response: + # GET /status should never return an error + assert response.status == 200 + + # parse JSON response and unwrap 'value' property + parsed_obj = json.loads(response.read().decode('utf-8')) + value = parsed_obj["value"] + + # Let body be a new JSON Object with the following properties: + # "ready" + # The remote end's readiness state. + assert value["ready"] in [True, False] + # "message" + # An implementation-defined string explaining the remote end's + # readiness state. + assert isinstance(value["message"], basestring) + + +def test_status_with_session_running_on_endpoint_node(new_session, add_browser_capabilites): + # For an endpoint node, the maximum number of active + # sessions is 1: https://www.w3.org/TR/webdriver/#dfn-maximum-active-sessions + # A session is open, so we expect `ready` to be False + # 8.3 step 1. + + _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({})}}) + value = session.send_command("GET", "status") + + assert value["ready"] == False + assert "message" in value + + session.end() + + # Active session count is 0, meaning that the + # readiness state of the server should be True + # 8.3 step 1. Again + value = session.send_command("GET", "status") + + assert value["ready"] == True + assert "message" in value + diff --git a/tests/wpt/web-platform-tests/webdriver/tests/status.py b/tests/wpt/web-platform-tests/webdriver/tests/status.py deleted file mode 100644 index 9472f8a80bb..00000000000 --- a/tests/wpt/web-platform-tests/webdriver/tests/status.py +++ /dev/null @@ -1,21 +0,0 @@ -import pytest -import json - - -def test_get_status_no_session(http): - with http.get("/status") as response: - # GET /status should never return an error - assert response.status == 200 - - # parse JSON response and unwrap 'value' property - parsed_obj = json.loads(response.read().decode('utf-8')) - value = parsed_obj["value"] - - # Let body be a new JSON Object with the following properties: - # "ready" - # The remote end's readiness state. - assert value["ready"] in [True, False] - # "message" - # An implementation-defined string explaining the remote end's - # readiness state. - assert isinstance(value["message"], basestring) diff --git a/tests/wpt/web-platform-tests/webdriver/tests/support/asserts.py b/tests/wpt/web-platform-tests/webdriver/tests/support/asserts.py index c68883a631e..95859ac3d2b 100644 --- a/tests/wpt/web-platform-tests/webdriver/tests/support/asserts.py +++ b/tests/wpt/web-platform-tests/webdriver/tests/support/asserts.py @@ -1,5 +1,6 @@ from webdriver import Element, WebDriverException + # WebDriver specification ID: dfn-error-response-data errors = { "element click intercepted": 400, @@ -21,7 +22,7 @@ errors = { "no such window": 404, "script timeout": 408, "session not created": 500, - "stale element reference": 400, + "stale element reference": 404, "timeout": 408, "unable to set cookie": 500, "unable to capture screen": 500, @@ -32,6 +33,7 @@ errors = { "unsupported operation": 500, } + # WebDriver specification ID: dfn-send-an-error # # > When required to send an error, with error code, a remote end must run the @@ -54,12 +56,13 @@ errors = { # > # > 5. Send a response with status and data as arguments. def assert_error(response, error_code): - """Verify that the provided wdclient.Response instance described a valid - error response as defined by `dfn-send-an-error` and the provided error - code. + """ + Verify that the provided webdriver.Response instance described + a valid error response as defined by `dfn-send-an-error` and + the provided error code. - :param response: wdclient.Response instance - :param error_code: string value of the expected "error code" + :param response: ``webdriver.Response`` instance. + :param error_code: String value of the expected error code """ assert response.status == errors[error_code] assert "value" in response.body @@ -69,13 +72,13 @@ def assert_error(response, error_code): def assert_success(response, value=None): - """Verify that the provided wdclient.Response instance described a valid - error response as defined by `dfn-send-an-error` and the provided error - code. + """ + Verify that the provided webdriver.Response instance described + a valid error response as defined by `dfn-send-an-error` and + the provided error code. - :param response: wdclient.Response instance. + :param response: ``webdriver.Response`` instance. :param value: Expected value of the response body, if any. - """ assert response.status == 200, str(response.error) @@ -97,7 +100,7 @@ def assert_dialog_handled(session, expected_text): except: assert (result.status == 200 and result.body["value"] != expected_text), ( - "Dialog with text '%s' was not handled." % expected_text) + "Dialog with text '%s' was not handled." % expected_text) def assert_same_element(session, a, b): @@ -122,7 +125,7 @@ def assert_same_element(session, a, b): return message = ("Expected element references to describe the same element, " + - "but they did not.") + "but they did not.") # Attempt to provide more information, accounting for possible errors such # as stale element references or not visible elements. diff --git a/tests/wpt/web-platform-tests/webdriver/tests/support/fixtures.py b/tests/wpt/web-platform-tests/webdriver/tests/support/fixtures.py index 778acd314c6..844ae039e57 100644 --- a/tests/wpt/web-platform-tests/webdriver/tests/support/fixtures.py +++ b/tests/wpt/web-platform-tests/webdriver/tests/support/fixtures.py @@ -8,6 +8,7 @@ import mozlog from tests.support.asserts import assert_error from tests.support.http_request import HTTPRequest +from tests.support.wait import wait from tests.support import merge_dictionaries default_host = "http://127.0.0.1" @@ -254,10 +255,31 @@ def create_dialog(session): session.send_session_command("POST", "execute/async", {"script": spawn, "args": []}) + wait(session, + lambda s: s.send_session_command("GET", "alert/text") == text, + "modal has not appeared", + timeout=15, + ignored_exceptions=webdriver.NoSuchAlertException) return create_dialog + def clear_all_cookies(session): """Removes all cookies associated with the current active document""" session.transport.send("DELETE", "session/%s/cookie" % session.session_id) + +def is_element_in_viewport(session, element): + """Check if element is outside of the viewport""" + return session.execute_script(""" + let el = arguments[0]; + + let rect = el.getBoundingClientRect(); + let viewport = { + height: window.innerHeight || document.documentElement.clientHeight, + width: window.innerWidth || document.documentElement.clientWidth, + }; + + return !(rect.right < 0 || rect.bottom < 0 || + rect.left > viewport.width || rect.top > viewport.height) + """, args=(element,)) diff --git a/tests/wpt/web-platform-tests/webdriver/tests/support/wait.py b/tests/wpt/web-platform-tests/webdriver/tests/support/wait.py index f645abe7367..6f439ec61a3 100644 --- a/tests/wpt/web-platform-tests/webdriver/tests/support/wait.py +++ b/tests/wpt/web-platform-tests/webdriver/tests/support/wait.py @@ -1,10 +1,13 @@ +import sys import time + class TimeoutException(Exception): pass -def wait(session, condition, message, interval=0.1, timeout=5): +def wait(session, condition, message, + interval=0.1, timeout=5, ignored_exceptions=Exception): """ Poll a condition until it's true or the timeout ellapses. :param session: WebDriver session to use with `condition` @@ -12,6 +15,8 @@ def wait(session, condition, message, interval=0.1, timeout=5): :param message: failure description to display in case the timeout is reached :param interval: seconds between each call to `condition`. Default: 0.1 :param timeout: seconds until we stop polling. Default: 5 + :param ignored_exceptions: Exceptions that are expected and can be ignored. + Default: Exception """ start = time.time() @@ -19,10 +24,15 @@ def wait(session, condition, message, interval=0.1, timeout=5): while not (time.time() >= end): next_step = time.time() + interval - success = condition(session) + try: + success = condition(session) + except ignored_exceptions: + last_exc = sys.exc_info()[0] + success = False next_interval = max(next_step - time.time(), 0) if not success: time.sleep(next_interval) continue return success + raise TimeoutException("Timed out after %d seconds: %s" % (timeout, message)) diff --git a/tests/wpt/web-platform-tests/webdriver/tests/user_prompts/accept_alert.py b/tests/wpt/web-platform-tests/webdriver/tests/user_prompts/accept_alert.py index d97aa73739a..d47ed1c8627 100644 --- a/tests/wpt/web-platform-tests/webdriver/tests/user_prompts/accept_alert.py +++ b/tests/wpt/web-platform-tests/webdriver/tests/user_prompts/accept_alert.py @@ -1,4 +1,5 @@ from tests.support.asserts import assert_error, assert_success +from tests.support.inline import inline def accept_alert(session): @@ -25,14 +26,14 @@ def test_no_user_prompt(session): def test_accept_alert(session): # 18.2 step 3 - session.execute_script("window.alert(\"Hello\");") + session.url = inline("") response = accept_alert(session) assert_success(response) def test_accept_confirm(session): # 18.2 step 3 - session.execute_script("window.result = window.confirm(\"Hello\");") + session.url = inline("") response = accept_alert(session) assert_success(response) assert session.execute_script("return window.result") is True @@ -40,7 +41,7 @@ def test_accept_confirm(session): def test_accept_prompt(session): # 18.2 step 3 - session.execute_script("window.result = window.prompt(\"Enter Your Name: \", \"Federer\");") + session.url = inline("") response = accept_alert(session) assert_success(response) assert session.execute_script("return window.result") == "Federer" diff --git a/tests/wpt/web-platform-tests/webdriver/tests/user_prompts/dismiss_alert.py b/tests/wpt/web-platform-tests/webdriver/tests/user_prompts/dismiss_alert.py index 73f9822fc57..6a2049684a6 100644 --- a/tests/wpt/web-platform-tests/webdriver/tests/user_prompts/dismiss_alert.py +++ b/tests/wpt/web-platform-tests/webdriver/tests/user_prompts/dismiss_alert.py @@ -1,4 +1,5 @@ from tests.support.asserts import assert_error, assert_success +from tests.support.inline import inline def dismiss_alert(session): @@ -25,14 +26,14 @@ def test_no_user_prompt(session): def test_dismiss_alert(session): # 18.1 step 3 - session.execute_script("window.alert(\"Hello\");") + session.url = inline("") response = dismiss_alert(session) assert_success(response) def test_dismiss_confirm(session): # 18.1 step 3 - session.execute_script("window.result = window.confirm(\"Hello\");") + session.url = inline("") response = dismiss_alert(session) assert_success(response) assert session.execute_script("return window.result;") is False @@ -40,7 +41,7 @@ def test_dismiss_confirm(session): def test_dismiss_prompt(session): # 18.1 step 3 - session.execute_script("window.result = window.prompt(\"Enter Your Name: \", \"Federer\");") + session.url = inline("") response = dismiss_alert(session) assert_success(response) assert session.execute_script("return window.result") is None diff --git a/tests/wpt/web-platform-tests/webdriver/tests/user_prompts/get_alert_text.py b/tests/wpt/web-platform-tests/webdriver/tests/user_prompts/get_alert_text.py index 85506eea4f2..7b71f7f4fd1 100644 --- a/tests/wpt/web-platform-tests/webdriver/tests/user_prompts/get_alert_text.py +++ b/tests/wpt/web-platform-tests/webdriver/tests/user_prompts/get_alert_text.py @@ -1,4 +1,5 @@ from tests.support.asserts import assert_error, assert_success +from tests.support.inline import inline def get_dialog_text(session): @@ -25,7 +26,7 @@ def test_no_user_prompt(session): def test_get_alert_text(session): # 18.3 step 3 - session.execute_script("window.alert(\"Hello\");") + session.url = inline("") response = get_dialog_text(session) assert_success(response) assert isinstance(response.body, dict) @@ -37,7 +38,7 @@ def test_get_alert_text(session): def test_get_confirm_text(session): # 18.3 step 3 - session.execute_script("window.confirm(\"Hello\");") + session.url = inline("") response = get_dialog_text(session) assert_success(response) assert isinstance(response.body, dict) @@ -49,7 +50,7 @@ def test_get_confirm_text(session): def test_get_prompt_text(session): # 18.3 step 3 - session.execute_script("window.prompt(\"Enter Your Name: \", \"Federer\");") + session.url = inline("") response = get_dialog_text(session) assert_success(response) assert isinstance(response.body, dict) diff --git a/tests/wpt/web-platform-tests/webdriver/tests/user_prompts/send_alert_text.py b/tests/wpt/web-platform-tests/webdriver/tests/user_prompts/send_alert_text.py index 8e07b8561d0..6769b556f1a 100644 --- a/tests/wpt/web-platform-tests/webdriver/tests/user_prompts/send_alert_text.py +++ b/tests/wpt/web-platform-tests/webdriver/tests/user_prompts/send_alert_text.py @@ -1,6 +1,7 @@ import pytest from tests.support.asserts import assert_error, assert_success +from tests.support.inline import inline def send_alert_text(session, body=None): return session.transport.send("POST", "session/{session_id}/alert/text" @@ -12,7 +13,7 @@ def send_alert_text(session, body=None): @pytest.mark.parametrize("text", [None, {}, [], 42, True]) def test_invalid_input(session, text): # 18.4 step 2 - session.execute_script("window.result = window.prompt(\"Enter Your Name: \", \"Name\");") + session.url = inline("") response = send_alert_text(session, {"text": text}) assert_error(response, "invalid argument") @@ -35,7 +36,7 @@ def test_no_user_prompt(session): def test_alert_element_not_interactable(session): # 18.4 step 5 - session.execute_script("window.alert(\"Hello\");") + session.url = inline("") body = {"text": "Federer"} response = send_alert_text(session, body) assert_error(response, "element not interactable") @@ -43,7 +44,7 @@ def test_alert_element_not_interactable(session): def test_confirm_element_not_interactable(session): # 18.4 step 5 - session.execute_script("window.confirm(\"Hello\");") + session.url = inline("") body = {"text": "Federer"} response = send_alert_text(session, body) assert_error(response, "element not interactable") @@ -51,7 +52,7 @@ def test_confirm_element_not_interactable(session): def test_send_alert_text(session): # 18.4 step 6 - session.execute_script("window.result = window.prompt(\"Enter Your Name: \", \"Name\");") + session.url = inline("") body = {"text": "Federer"} send_response = send_alert_text(session, body) assert_success(send_response) @@ -63,7 +64,7 @@ def test_send_alert_text(session): def test_send_alert_text_with_whitespace(session): # 18.4 step 6 - session.execute_script("window.result = window.prompt(\"Enter Your Name: \", \"Name\");") + session.url = inline("") body = {"text": " Fed erer "} send_response = send_alert_text(session, body) assert_success(send_response) diff --git a/tests/wpt/web-platform-tests/webmessaging/event.origin.sub.htm b/tests/wpt/web-platform-tests/webmessaging/event.origin.sub.htm index ce944ae3443..ea3c9e40eb6 100644 --- a/tests/wpt/web-platform-tests/webmessaging/event.origin.sub.htm +++ b/tests/wpt/web-platform-tests/webmessaging/event.origin.sub.htm @@ -9,7 +9,7 @@

    - +
    @@ -23,7 +23,7 @@ var PORT = location.port !== "" ? ":" + location.port : ""; var TARGET1 = document.querySelectorAll("iframe")[0]; var TARGET2 = document.querySelectorAll("iframe")[1]; - var XORIGIN = "{{location[scheme]}}://{{domains[www]}}" + PORT; + var XORIGIN = "{{location[scheme]}}://{{domains[天気の良い日]}}" + PORT; var SORIGIN = "{{location[scheme]}}://{{host}}" + PORT; var ExpectedResult = ["#1", XORIGIN, "#2", SORIGIN]; var ActualResult = []; diff --git a/tests/wpt/web-platform-tests/webrtc/OWNERS b/tests/wpt/web-platform-tests/webrtc/OWNERS index f2d66bf5c08..378bf87a106 100644 --- a/tests/wpt/web-platform-tests/webrtc/OWNERS +++ b/tests/wpt/web-platform-tests/webrtc/OWNERS @@ -1,3 +1,4 @@ +@snuggs @agouaillard @alvestrand @dontcallmedom diff --git a/tests/wpt/web-platform-tests/webrtc/RTCCertificate.html b/tests/wpt/web-platform-tests/webrtc/RTCCertificate.html index f5eccabf91b..e5f1749eb5b 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCCertificate.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCCertificate.html @@ -172,8 +172,9 @@ assert_equals(typeof fingerprint, 'object', 'Expect fingerprint to be an object (dictionary)'); - // Can only do simple test as the allowed values may be extended - assert_true(/^[a-zA-Z\-]+$/.test(fingerprint.algorithm), + // https://www.iana.org/assignments/hash-function-text-names/hash-function-text-names.xml + const algorithms = ['md2', 'md5', 'sha-1', 'sha-224', 'sha-256', 'sha-384', 'sha-512']; + assert_in_array(fingerprint.algorithm, algorithms, 'Expect fingerprint.algorithm to be string of algorithm identifier'); assert_true(/^([0-9a-f]{2}\:)+[0-9a-f]{2}$/.test(fingerprint.value), diff --git a/tests/wpt/web-platform-tests/webrtc/RTCConfiguration-iceTransportPolicy.html b/tests/wpt/web-platform-tests/webrtc/RTCConfiguration-iceTransportPolicy.html index 7387c5424cd..74e8b4b2ae7 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCConfiguration-iceTransportPolicy.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCConfiguration-iceTransportPolicy.html @@ -64,7 +64,7 @@ assert_equals(pc.getConfiguration().iceTransportPolicy, 'all'); pc.setConfiguration({ iceTransportPolicy: 'relay' }); - assert_equals(pc.getConfiguration(), iceTransportPolicy, 'relay'); + assert_equals(pc.getConfiguration().iceTransportPolicy, 'relay'); }, `setConfiguration({ iceTransportPolicy: 'relay' }) with initial iceTransportPolicy all should succeed`); test(() => { @@ -72,7 +72,7 @@ assert_equals(pc.getConfiguration().iceTransportPolicy, 'relay'); pc.setConfiguration({ iceTransportPolicy: 'all' }); - assert_equals(pc.getConfiguration(), iceTransportPolicy, 'all'); + assert_equals(pc.getConfiguration().iceTransportPolicy, 'all'); }, `setConfiguration({ iceTransportPolicy: 'all' }) with initial iceTransportPolicy relay should succeed`); test(() => { @@ -81,7 +81,7 @@ // default value for iceTransportPolicy is all pc.setConfiguration({}); - assert_equals(pc.getConfiguration(), iceTransportPolicy, 'all'); + assert_equals(pc.getConfiguration().iceTransportPolicy, 'all'); }, `setConfiguration({}) with initial iceTransportPolicy relay should set new value to all`); config_test(makePc => { diff --git a/tests/wpt/web-platform-tests/webrtc/RTCDTMFSender-helper.js b/tests/wpt/web-platform-tests/webrtc/RTCDTMFSender-helper.js index b66c4aedbda..97bb6f93479 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCDTMFSender-helper.js +++ b/tests/wpt/web-platform-tests/webrtc/RTCDTMFSender-helper.js @@ -76,8 +76,8 @@ function test_tone_change_events(testFunc, toneChanges, desc) { const now = Date.now(); const duration = now - lastEventTime; - assert_approx_equals(duration, expectedDuration, 150, - `Expect tonechange event for "${tone}" to be fired approximately after ${expectedDuration} seconds`); + assert_approx_equals(duration, expectedDuration, 250, + `Expect tonechange event for "${tone}" to be fired approximately after ${expectedDuration} milliseconds`); lastEventTime = now; diff --git a/tests/wpt/web-platform-tests/webrtc/RTCDtlsTransport-getRemoteCertificates.html b/tests/wpt/web-platform-tests/webrtc/RTCDtlsTransport-getRemoteCertificates.html index 0fd5340006b..80d1bfae46d 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCDtlsTransport-getRemoteCertificates.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCDtlsTransport-getRemoteCertificates.html @@ -76,7 +76,7 @@ testedTransports.add(dtlsTransport); // End the test if both dtlsTransports are tested. - if(testedTransports.has(dtlsTransport1) && testedTransports.has(dtslTransport2)) { + if(testedTransports.has(dtlsTransport1) && testedTransports.has(dtlsTransport2)) { t.done(); } }) diff --git a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-addTransceiver.html b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-addTransceiver.html index ce1c2827aac..97205714f07 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-addTransceiver.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-addTransceiver.html @@ -80,6 +80,8 @@ */ test(t => { const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + assert_idl_attribute(pc, 'addTransceiver'); assert_throws(new TypeError(), () => pc.addTransceiver('invalid')); }, 'addTransceiver() with string argument as invalid kind should throw TypeError'); @@ -125,6 +127,7 @@ */ test(t => { const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); assert_idl_attribute(pc, 'addTransceiver'); @@ -170,6 +173,7 @@ test(t => { const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); assert_idl_attribute(pc, 'addTransceiver'); @@ -214,18 +218,24 @@ test(t => { const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + const transceiver = pc.addTransceiver('audio', { direction: 'sendonly' }); assert_equals(transceiver.direction, 'sendonly'); }, `addTransceiver() with direction sendonly should have result transceiver.direction be the same`); test(t => { const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + const transceiver = pc.addTransceiver('audio', { direction: 'inactive' }); assert_equals(transceiver.direction, 'inactive'); }, `addTransceiver() with direction inactive should have result transceiver.direction be the same`); test(t => { const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + assert_idl_attribute(pc, 'addTransceiver'); assert_throws(new TypeError(), () => pc.addTransceiver('audio', { direction: 'invalid' })); @@ -238,8 +248,9 @@ */ test(t => { const pc = new RTCPeerConnection(); - const track = generateMediaStreamTrack('audio'); + t.add_cleanup(() => pc.close()); + const track = generateMediaStreamTrack('audio'); const transceiver = pc.addTransceiver(track); const { sender, receiver } = transceiver; @@ -276,8 +287,9 @@ test(t => { const pc = new RTCPeerConnection(); - const track = generateMediaStreamTrack('audio'); + t.add_cleanup(() => pc.close()); + const track = generateMediaStreamTrack('audio'); const transceiver1 = pc.addTransceiver(track); const transceiver2 = pc.addTransceiver(track); @@ -302,7 +314,6 @@ }, 'addTransceiver(track) multiple times should create multiple transceivers'); - /* 5.1. addTransceiver 6. Verify that each rid value in sendEncodings is composed only of @@ -310,8 +321,9 @@ of 16 characters. If one of the RIDs does not meet these requirements, throw a TypeError. */ - test(() => { + test(t => { const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); assert_idl_attribute(pc, 'addTransceiver'); assert_throws(new TypeError(), () => @@ -322,8 +334,9 @@ })); }, 'addTransceiver() with rid containing invalid non-alphanumeric characters should throw TypeError'); - test(() => { + test(t => { const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); assert_idl_attribute(pc, 'addTransceiver'); assert_throws(new TypeError(), () => @@ -334,8 +347,9 @@ })); }, 'addTransceiver() with rid longer than 16 characters should throw TypeError'); - test(() => { + test(t => { const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); pc.addTransceiver('audio', { sendEncodings: [{ rid: 'foo' @@ -353,8 +367,9 @@ Aside from rid , all read-only parameters in the RTCRtpEncodingParameters dictionaries, such as ssrc, must be left unset, or an error will be thrown. */ - test(() => { + test(t => { const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); assert_throws('InvalidAccessError', () => pc.addTransceiver('audio', { @@ -364,8 +379,9 @@ })); }, `addTransceiver() with readonly ssrc set should throw InvalidAccessError`); - test(() => { + test(t => { const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); assert_throws('InvalidAccessError', () => pc.addTransceiver('audio', { @@ -377,8 +393,9 @@ })); }, `addTransceiver() with readonly rtx set should throw InvalidAccessError`); - test(() => { + test(t => { const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); assert_throws('InvalidAccessError', () => pc.addTransceiver('audio', { @@ -390,8 +407,10 @@ })); }, `addTransceiver() with readonly fec set should throw InvalidAccessError`); - test(() => { + test(t => { const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + pc.addTransceiver('audio', { sendEncodings: [{ dtx: 'enabled', diff --git a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-constructor.html b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-constructor.html index 331eefe458d..e00d9870908 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-constructor.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-constructor.html @@ -73,7 +73,7 @@ for (const attr in initialState) { if (!window.pc) { window.pc = new RTCPeerConnection; } - assert_equals(pc[attr], initialState[attr]); + assert_equals(window.pc[attr], initialState[attr]); }, attr + ' initial value'); } diff --git a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-createDataChannel.html b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-createDataChannel.html index a446280eaaa..35e22f934f0 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-createDataChannel.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-createDataChannel.html @@ -375,7 +375,7 @@ promise_test(t => { assert_not_equals(channel1.id, null, 'Expect channel1.id to be assigned'); - assert_greater_than_equals(channel1.id, 0, + assert_greater_than_equal(channel1.id, 0, 'Expect channel1.id to be set to valid unsigned short'); assert_less_than(channel1.id, 65535, @@ -386,7 +386,7 @@ promise_test(t => { assert_not_equals(channel2.id, null, 'Expect channel2.id to be assigned'); - assert_greater_than_equals(channel2.id, 0, + assert_greater_than_equal(channel2.id, 0, 'Expect channel2.id to be set to valid unsigned short'); assert_less_than(channel2.id, 65535, diff --git a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-createOffer-offerToReceive.html b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-createOffer-offerToReceive.html new file mode 100644 index 00000000000..c599b1c0d07 --- /dev/null +++ b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-createOffer-offerToReceive.html @@ -0,0 +1,169 @@ + + +Test legacy offerToReceiveAudio/Video options + + + + + diff --git a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-getStats.https.html b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-getStats.https.html index a4df5630a3a..73138507d4f 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-getStats.https.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-getStats.https.html @@ -10,8 +10,8 @@ 'use strict'; // Test is based on the following editor draft: - // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html - // https://w3c.github.io/webrtc-stats/archives/20170614/webrtc-stats.html + // webrtc-pc 20171130 + // webrtc-stats 20171122 // The following helper function is called from RTCPeerConnection-helper.js // getTrackFromUserMedia @@ -20,39 +20,25 @@ // validateStatsReport // assert_stats_report_has_stats + // The following helper function is called from RTCPeerConnection-helper.js + // exchangeIceCandidates + // doSignalingHandshake + /* - 8.2. RTCPeerConnection Interface Extensions - partial interface RTCPeerConnection { - Promise getStats(optional MediaStreamTrack? selector = null); - }; - - 8.3. RTCStatsReport Object - interface RTCStatsReport { - readonly maplike; - }; - - 8.4. RTCStats Dictionary - dictionary RTCStats { - DOMHighResTimeStamp timestamp; - RTCStatsType type; - DOMString id; - }; - - id - Two RTCStats objects, extracted from two different RTCStatsReport objects, MUST - have the same id if they were produced by inspecting the same underlying object. - 8.2. getStats 1. Let selectorArg be the method's first argument. 2. Let connection be the RTCPeerConnection object on which the method was invoked. - 3. If selectorArg is neither null nor a valid MediaStreamTrack, return a promise - rejected with a newly created TypeError. + 3. If selectorArg is null, let selector be null. + 4. If selectorArg is a MediaStreamTrack let selector be an RTCRtpSender + or RTCRtpReceiver on connection which track member matches selectorArg. + If no such sender or receiver exists, or if more than one sender or + receiver fit this criteria, return a promise rejected with a newly + created InvalidAccessError. 5. Let p be a new promise. 6. Run the following steps in parallel: 1. Gather the stats indicated by selector according to the stats selection algorithm. 2. Resolve p with the resulting RTCStatsReport object, containing the gathered stats. */ - promise_test(() => { const pc = new RTCPeerConnection(); return pc.getStats(); @@ -65,9 +51,11 @@ /* 8.2. getStats - 4. Let selector be a RTCRtpSender or RTCRtpReceiver on connection which track - member matches selectorArg. If no such sender or receiver exists, return a promise - rejected with a newly created InvalidAccessError. + 4. If selectorArg is a MediaStreamTrack let selector be an RTCRtpSender + or RTCRtpReceiver on connection which track member matches selectorArg. + If no such sender or receiver exists, or if more than one sender or + receiver fit this criteria, return a promise rejected with a newly + created InvalidAccessError. */ promise_test(t => { const pc = new RTCPeerConnection(); @@ -94,12 +82,6 @@ return pc.getStats(track); }, 'getStats() with track added via addTransceiver should succeed'); - /* - 8.2. getStats - 4. Let selector be a RTCRtpSender or RTCRtpReceiver on connection which track - member matches selectorArg. If more than one sender or receiver fit this criteria, - return a promise rejected with a newly created InvalidAccessError. - */ promise_test(t => { const pc = new RTCPeerConnection(); return getTrackFromUserMedia('audio') @@ -140,7 +122,35 @@ validateStatsReport(statsReport); assert_stats_report_has_stats(statsReport, ['peer-connection']); }); - }, 'getStats() with no argument should return stats report containing peer-connection stats'); + }, 'getStats() with no argument should return stats report containing peer-connection stats on an empty PC'); + + promise_test(t => { + const pc = new RTCPeerConnection(); + return getTrackFromUserMedia('audio') + .then(([track, mediaStream]) => { + pc.addTrack(track, mediaStream); + return pc.getStats(); + }) + .then(statsReport => { + validateStatsReport(statsReport); + assert_stats_report_has_stats(statsReport, ['peer-connection']); + assert_stats_report_has_stats(statsReport, ['outbound-rtp']); + }); + }, 'getStats() with no argument should return stats report containing peer-connection stats and outbound-track-stats'); + + promise_test(t => { + const pc = new RTCPeerConnection(); + return getTrackFromUserMedia('audio') + .then(([track, mediaStream]) => { + pc.addTrack(track); + return pc.getStats(); + }) + .then(statsReport => { + validateStatsReport(statsReport); + assert_stats_report_has_stats(statsReport, ['peer-connection']); + assert_stats_report_has_stats(statsReport, ['outbound-rtp']); + }); + }, 'getStats() with no argument should return stats for no-stream tracks'); /* 8.5. The stats selection algorithm @@ -184,4 +194,150 @@ }); }, `getStats() on track associated with RtpReceiver should return stats report containing inbound-rtp stats`); + /* + 8.6 Mandatory To Implement Stats + An implementation MUST support generating statistics of the following types + when the corresponding objects exist on a PeerConnection, with the attributes + that are listed when they are valid for that object. + */ + + const mandatoryStats = [ + "codec", + "inbound-rtp", + "outbound-rtp", + "remote-inbound-rtp", + "remote-outbound-rtp", + "peer-connection", + "data-channel", + "stream", + "track", + "transport", + "candidate-pair", + "local-candidate", + "remote-candidate", + "certificate" + ]; + + async_test(t => { + const pc1 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + const pc2 = new RTCPeerConnection(); + t.add_cleanup(() => pc2.close()); + + const dataChannel = pc1.createDataChannel('test-channel'); + + return navigator.mediaDevices.getUserMedia({ + audio: true, + video: true + }) + .then(t.step_func(mediaStream => { + const tracks = mediaStream.getTracks(); + assert_equals(tracks.length, 2, + 'Expect media stream to have one audio and one video track'); + + let audioTrack; + let videoTrack; + + for (const track of tracks) { + t.add_cleanup(() => track.stop()); + + pc1.addTrack(track, mediaStream); + + if (track.kind === 'audio') { + audioTrack = track; + } else if (track.kind === 'video') { + videoTrack = track; + } + } + + if (!audioTrack || ! videoTrack) { + assert_unreached('Expect mediaStream to have both audio and video streams'); + } + + const testStatsReport = (pc, statsReport) => { + validateStatsReport(statsReport); + assert_stats_report_has_stats(statsReport, mandatoryStats); + + const dataChannelStats = findStatsFromReport(statsReport, + stats => { + return stats.type === 'data-channel' && + stats.dataChannelIdentifier === dataChannel.id; + }, + 'Expect data channel stats to be found'); + + assert_equals(dataChannelStats.label, 'test-channel'); + + const audioTrackStats = findStatsFromReport(statsReport, + stats => { + return stats.type === 'track' && + stats.trackIdentifier === audioTrack.id; + }, + 'Expect audio track stats to be found'); + + assert_equals(audioTrackStats.kind, 'audio'); + + const videoTrackStats = findStatsFromReport(statsReport, + stats => { + return stats.type === 'track' && + stats.trackIdentifier === videoTrack.id; + }, + 'Expect video track stats to be found'); + + assert_equals(videoTrackStats.kind, 'video'); + + const mediaStreamStats = findStatsFromReport(statsReport, + stats => { + return stats.type === 'stream' && + stats.streamIdentifier === mediaStream.id; + }, + 'Expect media stream stats to be found'); + + assert_true(mediaStreamStats.trackIds.include(audioTrackStats.id)); + assert_true(mediaStreamStats.trackIds.include(videoTrackStats.id)); + } + + const onConnected = t.step_func(() => { + // Wait a while for the peer connections to collect stats + t.step_timeout(() => { + Promise.all([ + pc1.getStats() + .then(statsReport => testStatsReport(pc1, statsReport)), + + pc2.getStats() + .then(statsReport => testStatsReport(pc2, statsReport)) + ]) + .then(t.step_func_done()) + .catch(t.step_func(err => { + assert_unreached(`test failed with error: ${err}`); + })); + }, 200) + }) + + let onTrackCount = 0 + let onDataChannelCalled = false + + pc2.addEventListener('track', t.step_func(() => { + onTrackCount++; + if (onTrackCount === 2 && onDataChannelCalled) { + onConnected(); + } + })); + + pc2.addEventListener('datachannel', t.step_func(() => { + onDataChannelCalled = true; + if (onTrackCount === 2) { + onConnected(); + } + })); + + + exchangeIceCandidates(pc1, pc2); + doSignalingHandshake(pc1, pc2); + })) + .catch(t.step_func(err => { + assert_unreached(`test failed with error: ${err}`); + })); + + }, `getStats() with connected peer connections having tracks and data channel should return all mandatory to implement stats`); + diff --git a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-idl.html b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-idl.html deleted file mode 100644 index 58a153f2946..00000000000 --- a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-idl.html +++ /dev/null @@ -1,108 +0,0 @@ - - - - -IDL check of RTCPeerConnection - - - - - -

    Description

    -

    This test verifies the availability of the RTCPeerConnection interface.

    -
    - - - - - - - - - - diff --git a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-peerIdentity.html b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-peerIdentity.html index 845c55dc6d2..d5f9db9d5d0 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-peerIdentity.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-peerIdentity.html @@ -284,7 +284,7 @@ pc2.setRemoteDescription(offer)) .then(() => assert_rtcerror_rejection('idp-execution-failure', - peerIdentityPromise, + peerIdentityPromise1, `Expect first peerIdentity promise to be rejected with RTCError('idp-execution-failure')`)) .then(() => { const peerIdentityPromise2 = pc2.peerIdentity; diff --git a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html index f530e94cfe0..d4663e5373b 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html @@ -24,11 +24,11 @@ const callee = new RTCPeerConnection(); return getUserMediaTracksAndStreams(1) .then(t.step_func(([tracks, streams]) => { - let localTrack = tracks[0]; + const localTrack = tracks[0]; caller.addTrack(localTrack); - let offerPromise = performOffer(caller, callee); + const offerPromise = performOffer(caller, callee); callee.ontrack = t.step_func(trackEvent => { - let remoteTrack = trackEvent.track; + const remoteTrack = trackEvent.track; assert_equals(remoteTrack.id, localTrack.id, 'Expected local and remote track IDs to match.'); assert_equals(trackEvent.streams.length, 0, @@ -47,15 +47,15 @@ const callee = new RTCPeerConnection(); return getUserMediaTracksAndStreams(1) .then(t.step_func(([tracks, streams]) => { - let localTrack = tracks[0]; - let localStream = streams[0]; + const localTrack = tracks[0]; + const localStream = streams[0]; caller.addTrack(localTrack, localStream); - let offerPromise = performOffer(caller, callee); + const offerPromise = performOffer(caller, callee); callee.ontrack = t.step_func(trackEvent => { assert_equals(trackEvent.streams.length, 1, 'Expected track event to fire with a single stream.'); - let remoteTrack = trackEvent.track; - let remoteStream = trackEvent.streams[0]; + const remoteTrack = trackEvent.track; + const remoteStream = trackEvent.streams[0]; assert_equals(remoteTrack.id, localTrack.id, 'Expected local and remote track IDs to match.'); assert_equals(remoteStream.id, localStream.id, @@ -71,22 +71,50 @@ })); }, 'addTrack() with a track and a stream makes ontrack fire with a track and a stream.'); + async_test(t => { + const caller = new RTCPeerConnection(); + const callee = new RTCPeerConnection(); + let eventSequence = ''; + return getUserMediaTracksAndStreams(1) + .then(t.step_func(([tracks, streams]) => { + const ontrackResolver = new Resolver(); + callee.ontrack = () => { + eventSequence += 'ontrack;'; + ontrackResolver.resolve(); + } + caller.addTrack(tracks[0]); + return Promise.all([ + ontrackResolver.promise, + performOffer(caller, callee).then(() => { + eventSequence += 'setRemoteDescription;'; + }) + ]); + })) + .then(t.step_func(() => { + assert_equals(eventSequence, 'ontrack;setRemoteDescription;'); + t.done(); + })) + .catch(t.step_func(reason => { + assert_unreached(reason); + })); + }, 'ontrack fires before setRemoteDescription resolves.'); + async_test(t => { const caller = new RTCPeerConnection(); const callee = new RTCPeerConnection(); return getUserMediaTracksAndStreams(2) .then(t.step_func(([tracks, streams]) => { - let localTrack1 = tracks[0]; - let localTrack2 = tracks[1]; - let localStream = streams[0]; + const localTrack1 = tracks[0]; + const localTrack2 = tracks[1]; + const localStream = streams[0]; caller.addTrack(localTrack1, localStream); caller.addTrack(localTrack2, localStream); - let offerPromise = performOffer(caller, callee); + const offerPromise = performOffer(caller, callee); callee.ontrack = t.step_func(trackEvent => { assert_equals(trackEvent.streams.length, 1, 'Expected track event to fire with a single stream.'); - let remoteTrack1 = trackEvent.track; - let remoteStream = trackEvent.streams[0]; + const remoteTrack1 = trackEvent.track; + const remoteStream = trackEvent.streams[0]; assert_equals(remoteTrack1.id, localTrack1.id, 'Expected first remote track ID to match first local track ID.'); assert_equals(remoteStream.getTracks().length, 2, @@ -94,7 +122,7 @@ callee.ontrack = t.step_func(trackEvent => { assert_equals(trackEvent.streams.length, 1, 'Expected track event to fire with a single stream.'); - let remoteTrack2 = trackEvent.track; + const remoteTrack2 = trackEvent.track; assert_equals(trackEvent.streams[0], remoteStream, 'Expected both track events to fire with the same remote stream.'); assert_equals(remoteTrack2.id, localTrack2.id, @@ -151,17 +179,53 @@ async_test(t => { const caller = new RTCPeerConnection(); const callee = new RTCPeerConnection(); + let eventSequence = ''; return getUserMediaTracksAndStreams(2) .then(t.step_func(([tracks, streams]) => { - let localTrack = tracks[0]; - let localStreams = streams; + const localTracks = tracks; + const localStream = streams[0]; + caller.addTrack(localTracks[0], localStream); + const offerPromise = performOffer(caller, callee); + callee.ontrack = t.step_func(trackEvent => { + callee.ontrack = null; + const remoteStream = trackEvent.streams[0]; + const onaddtrackResolver = new Resolver(); + remoteStream.onaddtrack = () => { + eventSequence += 'stream.onaddtrack;'; + onaddtrackResolver.resolve(); + } + caller.addTrack(localTracks[1], localStream); + Promise.all([ + onaddtrackResolver.promise, + performOffer(caller, callee).then(() => { + eventSequence += 'setRemoteDescription;'; + }) + ]).then(t.step_func(() => { + assert_equals(eventSequence, 'stream.onaddtrack;setRemoteDescription;'); + t.done(); + })); + }); + return offerPromise; + })) + .catch(t.step_func(reason => { + assert_unreached(reason); + })); + }, 'stream.onaddtrack fires before setRemoteDescription resolves.'); + + async_test(t => { + const caller = new RTCPeerConnection(); + const callee = new RTCPeerConnection(); + return getUserMediaTracksAndStreams(2) + .then(t.step_func(([tracks, streams]) => { + const localTrack = tracks[0]; + const localStreams = streams; caller.addTrack(localTrack, localStreams[0], localStreams[1]); - let performOffer = performOffer(caller, callee); + const performOffer = performOffer(caller, callee); callee.ontrack = t.step_func(trackEvent => { assert_equals(trackEvent.streams.length, 2, 'Expected the track event to fire with two streams.'); - let remoteTrack = trackEvent.track; - let remoteStreams = trackEvent.streams; + const remoteTrack = trackEvent.track; + const remoteStreams = trackEvent.streams; assert_equals(remoteTrack.id, localTrack.id, 'Expected local and remote track IDs to match.'); assert_equals(remoteStreams[0].id, localStreams[0].id, @@ -184,38 +248,10 @@ async_test(t => { const caller = new RTCPeerConnection(); const callee = new RTCPeerConnection(); - let eventSequence = ''; return getUserMediaTracksAndStreams(1) .then(t.step_func(([tracks, streams]) => { caller.addTrack(tracks[0]); - let ontrackResolver = new Resolver(); - callee.ontrack = () => { - eventSequence += 'ontrack;'; - ontrackResolver.resolve(); - } - return Promise.all([ - ontrackResolver.promise, - performOffer(caller, callee).then(() => { - eventSequence += 'setRemoteDescription;'; - }) - ]); - })) - .then(t.step_func(() => { - assert_equals(eventSequence, 'ontrack;setRemoteDescription;'); - t.done(); - })) - .catch(t.step_func(reason => { - assert_unreached(reason); - })); - }, 'ontrack fires before setRemoteDescription resolves.'); - - async_test(t => { - const caller = new RTCPeerConnection(); - const callee = new RTCPeerConnection(); - return getUserMediaTracksAndStreams(1) - .then(t.step_func(([tracks, streams]) => { - caller.addTrack(tracks[0]); - let offerPromise = performOffer(caller, callee); + const offerPromise = performOffer(caller, callee); callee.ontrack = t.step_func(trackEvent => { assert_array_equals(callee.getReceivers(), [trackEvent.receiver]); t.done(); @@ -232,11 +268,11 @@ const callee = new RTCPeerConnection(); return getUserMediaTracksAndStreams(1) .then(t.step_func(([tracks, streams]) => { - let sender = caller.addTrack(tracks[0]); - assert_true(sender != null); - let offerPromise = performOffer(caller, callee); + const sender = caller.addTrack(tracks[0]); + assert_not_equals(sender, null); + const offerPromise = performOffer(caller, callee); callee.ontrack = t.step_func(trackEvent => { - let receivers = callee.getReceivers(); + const receivers = callee.getReceivers(); assert_equals(receivers.length, 1, 'Expected getReceivers() to be the track event\'s receiver.'); caller.removeTrack(sender); @@ -259,9 +295,9 @@ const callee = new RTCPeerConnection(); return getUserMediaTracksAndStreams(1) .then(t.step_func(([tracks, streams]) => { - let sender = caller.addTrack(tracks[0], streams[0]); - assert_true(sender != null); - let offerPromise = performOffer(caller, callee); + const sender = caller.addTrack(tracks[0], streams[0]); + assert_not_equals(sender, null); + const offerPromise = performOffer(caller, callee); callee.ontrack = t.step_func(trackEvent => { assert_not_equals(trackEvent.track, null); assert_equals(trackEvent.streams.length, 1); @@ -279,21 +315,55 @@ .catch(t.step_func(reason => { assert_unreached(reason); })); - }, 'removeTrack() causes onremovetrack and the track to be removed from the stream.'); + }, 'removeTrack() makes stream.onremovetrack fire and the track to be removed from the stream.'); + + async_test(t => { + const caller = new RTCPeerConnection(); + const callee = new RTCPeerConnection(); + let eventSequence = ''; + return getUserMediaTracksAndStreams(1) + .then(t.step_func(([tracks, streams]) => { + const sender = caller.addTrack(tracks[0], streams[0]); + assert_not_equals(sender, null); + const offerPromise = performOffer(caller, callee); + callee.ontrack = t.step_func(trackEvent => { + const remoteStream = trackEvent.streams[0]; + const onremovetrackResolver = new Resolver(); + remoteStream.onremovetrack = t.step_func(removeEvent => { + eventSequence += 'stream.onremovetrack;'; + onremovetrackResolver.resolve(); + }); + caller.removeTrack(sender); + return Promise.all([ + onremovetrackResolver.promise, + performOffer(caller, callee).then(() => { + eventSequence += 'setRemoteDescription;'; + }) + ]).then(t.step_func(() => { + assert_equals(eventSequence, 'stream.onremovetrack;setRemoteDescription;'); + t.done(); + })); + }); + return offerPromise; + })) + .catch(t.step_func(reason => { + assert_unreached(reason); + })); + }, 'stream.onremovetrack fires before setRemoteDescription resolves.'); async_test(t => { const caller = new RTCPeerConnection(); const callee = new RTCPeerConnection(); return getUserMediaTracksAndStreams(1) .then(t.step_func(([tracks, streams]) => { - let sender = caller.addTrack(tracks[0]); - assert_true(sender != null); - let offerPromise = performOffer(caller, callee); + const sender = caller.addTrack(tracks[0]); + assert_not_equals(sender, null); + const offerPromise = performOffer(caller, callee); callee.ontrack = t.step_func(trackEvent => { - assert_not_equals(trackEvent.track, null); + const remoteTrack = trackEvent.track; caller.removeTrack(sender); performOffer(caller, callee); - trackEvent.track.onmute = t.step_func(() => { + remoteTrack.onmute = t.step_func(() => { assert_true(trackEvent.track.muted); t.done(); }); @@ -303,6 +373,54 @@ .catch(t.step_func(reason => { assert_unreached(reason); })); - }, 'removeTrack() causes onmute and the track to be muted.'); + }, 'removeTrack() makes track.onmute fire and the track to be muted.'); + async_test(t => { + const caller = new RTCPeerConnection(); + const callee = new RTCPeerConnection(); + let eventSequence = ''; + return getUserMediaTracksAndStreams(1) + .then(t.step_func(([tracks, streams]) => { + const sender = caller.addTrack(tracks[0]); + assert_not_equals(sender, null); + const offerPromise = performOffer(caller, callee); + callee.ontrack = t.step_func(trackEvent => { + const remoteTrack = trackEvent.track; + const onmuteResolver = new Resolver(); + remoteTrack.onmute = t.step_func(() => { + eventSequence += 'track.onmute;'; + onmuteResolver.resolve(); + }); + caller.removeTrack(sender); + return Promise.all([ + onmuteResolver.promise, + performOffer(caller, callee).then(() => { + eventSequence += 'setRemoteDescription;'; + }) + ]).then(t.step_func(() => { + assert_equals(eventSequence, 'track.onmute;setRemoteDescription;'); + t.done(); + })); + }); + return offerPromise; + })) + .catch(t.step_func(reason => { + assert_unreached(reason); + })); + }, 'track.onmute fires before setRemoteDescription resolves.'); + + async_test(t => { + const pc = new RTCPeerConnection(); + return getUserMediaTracksAndStreams(1) + .then(t.step_func(([tracks, streams]) => { + const sender = pc.addTrack(tracks[0]); + assert_not_equals(sender, null); + pc.removeTrack(sender); + pc.removeTrack(sender); + t.done(); + })) + .catch(t.step_func(reason => { + assert_unreached(reason); + })); + }, 'removeTrack() twice is safe.'); diff --git a/tests/wpt/web-platform-tests/webrtc/RTCRtpCapabilities-helper.js b/tests/wpt/web-platform-tests/webrtc/RTCRtpCapabilities-helper.js index 8617e7f4f97..72f544059ff 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCRtpCapabilities-helper.js +++ b/tests/wpt/web-platform-tests/webrtc/RTCRtpCapabilities-helper.js @@ -48,5 +48,5 @@ function validateCodecCapability(codec) { } function validateHeaderExtensionCapability(headerExt) { - assert_optional_string_field(uri); + assert_optional_string_field(headerExt, 'uri'); } diff --git a/tests/wpt/web-platform-tests/webrtc/RTCRtpSender-getStats.html b/tests/wpt/web-platform-tests/webrtc/RTCRtpSender-getStats.https.html similarity index 69% rename from tests/wpt/web-platform-tests/webrtc/RTCRtpSender-getStats.html rename to tests/wpt/web-platform-tests/webrtc/RTCRtpSender-getStats.https.html index 00aa680f53e..e5cb1eb99fa 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCRtpSender-getStats.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCRtpSender-getStats.https.html @@ -9,8 +9,8 @@ 'use strict'; // Test is based on the following editor draft: - // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html - // https://w3c.github.io/webrtc-stats/archives/20170614/webrtc-stats.html + // webrtc-pc 20171130 + // webrtc-stats 20171122 // The following helper function is called from RTCStats-helper.js // validateStatsReport @@ -18,11 +18,6 @@ /* 5.2. RTCRtpSender Interface - interface RTCRtpSender { - Promise getStats(); - ... - }; - getStats 1. Let selector be the RTCRtpSender object on which the method was invoked. 2. Let p be a new promise, and run the following steps in parallel: @@ -49,6 +44,22 @@ validateStatsReport(statsReport); assert_stats_report_has_stats(statsReport, ['outbound-rtp']); }); - }, 'sender.getStats() should return stats report containing outbound-rtp stats'); + }, 'sender.getStats() via addTransceiver should return stats report containing outbound-rtp stats'); + + promise_test(() => { + const pc = new RTCPeerConnection(); + + return navigator.mediaDevices.getUserMedia({ audio: true }) + .then(mediaStream => { + const [track] = mediaStream.getTracks(); + const sender = pc.addTrack(track, mediaStream); + + return sender.getStats() + .then(statsReport => { + validateStatsReport(statsReport); + assert_stats_report_has_stats(statsReport, ['outbound-rtp']); + }); + }) + }, 'sender.getStats() via addTrack should return stats report containing outbound-rtp stats'); diff --git a/tests/wpt/web-platform-tests/webrtc/RTCSctpTransport-maxMessageSize.html b/tests/wpt/web-platform-tests/webrtc/RTCSctpTransport-maxMessageSize.html new file mode 100644 index 00000000000..7d73cc5a3b5 --- /dev/null +++ b/tests/wpt/web-platform-tests/webrtc/RTCSctpTransport-maxMessageSize.html @@ -0,0 +1,181 @@ + + +RTCSctpTransport.prototype.maxMessageSize + + + + + diff --git a/tests/wpt/web-platform-tests/webrtc/RTCStats-helper.js b/tests/wpt/web-platform-tests/webrtc/RTCStats-helper.js index 1ff3ae6711b..c2be1b3124f 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCStats-helper.js +++ b/tests/wpt/web-platform-tests/webrtc/RTCStats-helper.js @@ -1,18 +1,12 @@ 'use strict'; // Test is based on the following editor draft: -// https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html -// https://w3c.github.io/webrtc-stats/archives/20170614/webrtc-stats.html - +// webrtc-pc 20171130 +// webrtc-stats 20171122 // This file depends on dictionary-helper.js which should // be loaded from the main HTML file. -// To improve readability, the WebIDL definitions of the Stats -// dictionaries are modified to annotate with required fields when -// they are required by section 8.6 of webrtc-pc. ID fields are -// also annotated with the stats type that they are linked to. - /* [webrtc-stats] 6.1. RTCStatsType enum @@ -82,6 +76,16 @@ function assert_stats_report_has_stats(statsReport, statsTypes) { } } +function findStatsFromReport(statsReport, predicate, message) { + for (const stats of statsReport.values()) { + if (predicate(stats)) { + return stats; + } + } + + assert_unreached(message || 'none of stats in statsReport satisfy given condition') +} + // Get stats object of type that is expected to be // found in the statsReport function getRequiredStats(statsReport, type) { @@ -132,7 +136,7 @@ function validateOptionalIdField(statsReport, stats, field, type) { }; */ function validateRtcStats(statsReport, stats) { - assert_number_field(stats, 'timeStamp'); + assert_number_field(stats, 'timestamp'); assert_string_field(stats, 'type'); assert_string_field(stats, 'id'); } @@ -141,35 +145,32 @@ function validateRtcStats(statsReport, stats) { [webrtc-stats] 7.1. RTCRTPStreamStats dictionary dictionary RTCRTPStreamStats : RTCStats { - required unsigned long ssrc; - required DOMString mediaType; - - [RTCMediaStreamTrackStats] - required DOMString trackId; - - [RTCTransportStats] - required DOMString transportId; - - [RTCCodecStats] - required DOMString codecId; - - unsigned long firCount; - unsigned long pliCount; - required unsigned long nackCount; - unsigned long sliCount; - unsigned long long qpSum; + unsigned long ssrc; + DOMString mediaType; + DOMString trackId; + DOMString transportId; + DOMString codecId; + unsigned long firCount; + unsigned long pliCount; + unsigned long nackCount; + unsigned long sliCount; + unsigned long long qpSum; }; + mediaType of type DOMString + Either "audio" or "video". + [webrtc-pc] 8.6. Mandatory To Implement Stats - - RTCRTPStreamStats, with attributes ssrc, associateStatsId, isRemote, mediaType, - mediaTrackId, transportId, codecId, nackCount + - RTCRTPStreamStats, with attributes ssrc, mediaType, trackId, + transportId, codecId, nackCount */ function validateRtpStreamStats(statsReport, stats) { validateRtcStats(statsReport, stats); assert_unsigned_int_field(stats, 'ssrc'); assert_string_field(stats, 'mediaType'); + assert_enum_field(stats, 'mediaType', ['audio', 'video']) validateIdField(statsReport, stats, 'trackId', 'track'); validateIdField(statsReport, stats, 'transportId', 'transport'); @@ -186,15 +187,12 @@ function validateRtpStreamStats(statsReport, stats) { [webrtc-stats] 7.2. RTCCodecStats dictionary dictionary RTCCodecStats : RTCStats { - required unsigned long payloadType; - required RTCCodecType codecType; - - [RTCTransportStats] + unsigned long payloadType; + RTCCodecType codecType; DOMString transportId; - DOMString mimeType; - required unsigned long clockRate; - required unsigned long channels; + unsigned long clockRate; + unsigned long channels; DOMString sdpFmtpLine; DOMString implementation; }; @@ -206,7 +204,7 @@ function validateRtpStreamStats(statsReport, stats) { [webrtc-pc] 8.6. Mandatory To Implement Stats - - RTCCodecStats, with attributes payloadType, codec, clockRate, channels, parameters + - RTCCodecStats, with attributes payloadType, codec, clockRate, channels, sdpFmtpLine */ function validateCodecStats(statsReport, stats) { @@ -221,7 +219,7 @@ function validateCodecStats(statsReport, stats) { assert_unsigned_int_field(stats, 'clockRate'); assert_unsigned_int_field(stats, 'channels'); - assert_optional_string_field(stats, 'sdpFmtpLine'); + assert_string_field(stats, 'sdpFmtpLine'); assert_optional_string_field(stats, 'implementation'); } @@ -229,34 +227,42 @@ function validateCodecStats(statsReport, stats) { [webrtc-stats] 7.3. RTCReceivedRTPStreamStats dictionary dictionary RTCReceivedRTPStreamStats : RTCRTPStreamStats { - unsigned long packetsReceived; - unsigned long long bytesReceived; - unsigned long packetsLost; - double jitter; - double fractionLost; - unsigned long packetsDiscarded; - unsigned long packetsRepaired; - unsigned long burstPacketsLost; - unsigned long burstPacketsDiscarded; - unsigned long burstLossCount; - unsigned long burstDiscardCount; - double burstLossRate; - double burstDiscardRate; - double gapLossRate; - double gapDiscardRate; + unsigned long packetsReceived; + unsigned long long bytesReceived; + long packetsLost; + double jitter; + double fractionLost; + unsigned long packetsDiscarded; + unsigned long packetsFailedDecryption; + unsigned long packetsRepaired; + unsigned long burstPacketsLost; + unsigned long burstPacketsDiscarded; + unsigned long burstLossCount; + unsigned long burstDiscardCount; + double burstLossRate; + double burstDiscardRate; + double gapLossRate; + double gapDiscardRate; }; + + [webrtc-pc] + 8.6. Mandatory To Implement Stats + - RTCReceivedRTPStreamStats, with all required attributes from its + inherited dictionaries, and also attributes packetsReceived, + bytesReceived, packetsLost, jitter, packetsDiscarded */ function validateReceivedRtpStreamStats(statsReport, stats) { validateRtpStreamStats(statsReport, stats); - assert_optional_unsigned_int_field(stats, 'packetsReceived'); - assert_optional_unsigned_int_field(stats, 'bytesReceived'); - assert_optional_unsigned_int_field(stats, 'packetsLost'); + assert_unsigned_int_field(stats, 'packetsReceived'); + assert_unsigned_int_field(stats, 'bytesReceived'); + assert_unsigned_int_field(stats, 'packetsLost'); - assert_optional_number_field(stats, 'jitter'); + assert_number_field(stats, 'jitter'); assert_optional_number_field(stats, 'fractionLost'); - assert_optional_unsigned_int_field(stats, 'packetsDiscarded'); + assert_unsigned_int_field(stats, 'packetsDiscarded'); + assert_optional_unsigned_int_field(stats, 'packetsFailedDecryption'); assert_optional_unsigned_int_field(stats, 'packetsRepaired'); assert_optional_unsigned_int_field(stats, 'burstPacketsLost'); assert_optional_unsigned_int_field(stats, 'burstPacketsDiscarded'); @@ -273,37 +279,21 @@ function validateReceivedRtpStreamStats(statsReport, stats) { [webrtc-stats] 7.4. RTCInboundRTPStreamStats dictionary dictionary RTCInboundRTPStreamStats : RTCReceivedRTPStreamStats { - required unsigned long packetsReceived; - required unsigned long long bytesReceived; - required unsigned long packetsLost; - required double jitter; - required unsigned long packetsDiscarded; - - [RTCRemoteOutboundRTPStreamStats] DOMString remoteId; - unsigned long framesDecoded; DOMHighResTimeStamp lastPacketReceivedTimestamp; }; [webrtc-pc] 8.6. Mandatory To Implement Stats - - RTCInboundRTPStreamStats, with all required attributes from RTCRTPStreamStats, - and also attributes packetsReceived, bytesReceived, packetsLost, jitter, - packetsDiscarded + - RTCInboundRTPStreamStats, with all required attributes from its inherited + dictionaries, and also attributes remoteId, framesDecoded */ function validateInboundRtpStreamStats(statsReport, stats) { validateReceivedRtpStreamStats(statsReport, stats); - assert_unsigned_int_field(stats, 'packetsReceived'); - assert_unsigned_int_field(stats, 'bytesReceived'); - assert_unsigned_int_field(stats, 'packetsLost'); - assert_number_field(stats, 'jitter'); - assert_unsigned_int_field(stats, 'packetsDiscarded'); - - validateOptionalIdField(statsReport, stats, 'remoteId', 'remote-outbound-rtp'); - - assert_optional_unsigned_int_field(stats, 'framesDecoded'); + validateIdField(statsReport, stats, 'remoteId', 'remote-outbound-rtp'); + assert_unsigned_int_field(stats, 'framesDecoded'); assert_optional_number_field(stats, 'lastPacketReceivedTimeStamp'); } @@ -311,18 +301,20 @@ function validateInboundRtpStreamStats(statsReport, stats) { [webrtc-stats] 7.5. RTCRemoteInboundRTPStreamStats dictionary dictionary RTCRemoteInboundRTPStreamStats : RTCReceivedRTPStreamStats { - [RTCOutboundRTPStreamStats] - DOMString localId; - - double roundTripTime; + DOMString localId; + double roundTripTime; }; - */ + [webrtc-pc] + 8.6. Mandatory To Implement Stats + - RTCRemoteInboundRTPStreamStats, with all required attributes from its + inherited dictionaries, and also attributes localId, roundTripTime + */ function validateRemoteInboundRtpStreamStats(statsReport, stats) { validateReceivedRtpStreamStats(statsReport, stats); - validateOptionalIdField(statsReport, stats, 'localId', 'outbound-rtp'); - assert_optional_number_field(stats, 'roundTripTime'); + validateIdField(statsReport, stats, 'localId', 'outbound-rtp'); + assert_number_field(stats, 'roundTripTime'); } /* @@ -334,13 +326,18 @@ function validateRemoteInboundRtpStreamStats(statsReport, stats) { unsigned long long bytesSent; unsigned long long bytesDiscardedOnSend; }; + + [webrtc-pc] + 8.6. Mandatory To Implement Stats + - RTCSentRTPStreamStats, with all required attributes from its inherited + dictionaries, and also attributes packetsSent, bytesSent */ function validateSentRtpStreamStats(statsReport, stats) { validateRtpStreamStats(statsReport, stats); - assert_optional_unsigned_int_field(stats, 'packetsSent'); + assert_unsigned_int_field(stats, 'packetsSent'); assert_optional_unsigned_int_field(stats, 'packetsDiscardedOnSend'); - assert_optional_unsigned_int_field(stats, 'bytesSent'); + assert_unsigned_int_field(stats, 'bytesSent'); assert_optional_unsigned_int_field(stats, 'bytesDiscardedOnSend'); } @@ -348,12 +345,7 @@ function validateSentRtpStreamStats(statsReport, stats) { [webrtc-stats] 7.7. RTCOutboundRTPStreamStats dictionary dictionary RTCOutboundRTPStreamStats : RTCSentRTPStreamStats { - required unsigned long packetsSent; - required unsigned long long bytesSent; - - [RTCRemoteInboundRTPStreamStats] DOMString remoteId; - DOMHighResTimeStamp lastPacketSentTimestamp; double targetBitrate; unsigned long framesEncoded; @@ -361,20 +353,19 @@ function validateSentRtpStreamStats(statsReport, stats) { double averageRTCPInterval; }; - [webrtc-pc] - 8.6. Mandatory To Implement Stats - - RTCOutboundRTPStreamStats, with all required attributes from RTCRTPStreamStats, - and also attributes packetsSent, bytesSent, roundTripTime + [webrtc-pc] + 8.6. Mandatory To Implement Stats + - RTCOutboundRTPStreamStats, with all required attributes from its + inherited dictionaries, and also attributes remoteId, framesEncoded */ function validateOutboundRtpStreamStats(statsReport, stats) { - validateOptionalIdField(statsReport, stats, 'remoteId', 'remote-inbound-rtp'); + validateSentRtpStreamStats(statsReport, stats) - assert_unsigned_int_field(stats, 'packetsSent'); - assert_unsigned_int_field(stats, 'bytesSent'); + validateIdField(statsReport, stats, 'remoteId', 'remote-inbound-rtp'); assert_optional_number_field(stats, 'lastPacketSentTimestamp'); assert_optional_number_field(stats, 'targetBitrate'); - assert_optional_unsigned_int_field(stats, 'framesEncoded'); + assert_unsigned_int_field(stats, 'framesEncoded'); assert_optional_number_field(stats, 'totalEncodeTime'); assert_optional_number_field(stats, 'averageRTCPInterval'); } @@ -383,17 +374,20 @@ function validateOutboundRtpStreamStats(statsReport, stats) { [webrtc-stats] 7.8. RTCRemoteOutboundRTPStreamStats dictionary dictionary RTCRemoteOutboundRTPStreamStats : RTCSentRTPStreamStats { - [RTCInboundRTPStreamStats] DOMString localId; - DOMHighResTimeStamp remoteTimestamp; }; + + [webrtc-pc] + 8.6. Mandatory To Implement Stats + - RTCRemoteOutboundRTPStreamStats, with all required attributes from its + inherited dictionaries, and also attributes localId, remoteTimestamp */ function validateRemoteOutboundRtpStreamStats(statsReport, stats) { validateSentRtpStreamStats(statsReport, stats); - validateOptionalIdField(statsReport, stats, 'localId', 'inbound-rtp'); - assert_optional_number_field(stats, 'remoteTimeStamp'); + validateIdField(statsReport, stats, 'localId', 'inbound-rtp'); + assert_number_field(stats, 'remoteTimeStamp'); } /* @@ -401,10 +395,7 @@ function validateRemoteOutboundRtpStreamStats(statsReport, stats) { 7.9. RTCRTPContributingSourceStats dictionary RTCRTPContributingSourceStats : RTCStats { unsigned long contributorSsrc; - - [RTCInboundRTPStreamStats] DOMString inboundRtpStreamId; - unsigned long packetsContributedTo; double audioLevel; }; @@ -423,10 +414,10 @@ function validateContributingSourceStats(statsReport, stats) { [webrtc-stats] 7.10. RTCPeerConnectionStats dictionary dictionary RTCPeerConnectionStats : RTCStats { - required unsigned long dataChannelsOpened; - required unsigned long dataChannelsClosed; - unsigned long dataChannelsRequested; - unsigned long dataChannelsAccepted; + unsigned long dataChannelsOpened; + unsigned long dataChannelsClosed; + unsigned long dataChannelsRequested; + unsigned long dataChannelsAccepted; }; [webrtc-pc] @@ -446,10 +437,8 @@ function validatePeerConnectionStats(statsReport, stats) { [webrtc-stats] 7.11. RTCMediaStreamStats dictionary dictionary RTCMediaStreamStats : RTCStats { - required DOMString streamIdentifier; - - [RTCMediaStreamTrackStats] - required sequence trackIds; + DOMString streamIdentifier; + sequence trackIds; }; [webrtc-pc] @@ -479,35 +468,37 @@ function validateMediaStreamStats(statsReport, stats) { [webrtc-stats] 7.12. RTCMediaStreamTrackStats dictionary dictionary RTCMediaStreamTrackStats : RTCStats { - required DOMString trackIdentifier; - required boolean remoteSource; - required boolean ended; - required boolean detached; - DOMString kind; - DOMHighResTimeStamp estimatedPlayoutTimestamp; - required unsigned long frameWidth; - required unsigned long frameHeight; - required double framesPerSecond; - unsigned long framesCaptured; - required unsigned long framesSent; - required unsigned long framesReceived; - required unsigned long framesDecoded; - required unsigned long framesDropped; - required unsigned long framesCorrupted; - unsigned long partialFramesLost; - unsigned long fullFramesLost; - required double audioLevel; - double totalAudioEnergy; - boolean voiceActivityFlag; - double echoReturnLoss; - double echoReturnLossEnhancement; - unsigned long long totalSamplesSent; - unsigned long long totalSamplesReceived; - double totalSamplesDuration; - unsigned long long concealedSamples; - unsigned long long concealmentEvents; - double jitterBufferDelay; - RTCPriorityType priority; + DOMString trackIdentifier; + boolean remoteSource; + boolean ended; + boolean detached; + DOMString kind; + DOMHighResTimeStamp estimatedPlayoutTimestamp; + unsigned long frameWidth; + unsigned long frameHeight; + double framesPerSecond; + unsigned long framesCaptured; + unsigned long framesSent; + unsigned long keyFramesSent; + unsigned long framesReceived; + unsigned long keyFramesReceived; + unsigned long framesDecoded; + unsigned long framesDropped; + unsigned long framesCorrupted; + unsigned long partialFramesLost; + unsigned long fullFramesLost; + double audioLevel; + double totalAudioEnergy; + boolean voiceActivityFlag; + double echoReturnLoss; + double echoReturnLossEnhancement; + unsigned long long totalSamplesSent; + unsigned long long totalSamplesReceived; + double totalSamplesDuration; + unsigned long long concealedSamples; + unsigned long long concealmentEvents; + double jitterBufferDelay; + RTCPriorityType priority; }; [webrtc-pc] @@ -520,48 +511,50 @@ function validateMediaStreamStats(statsReport, stats) { }; 8.6. Mandatory To Implement Stats - - RTCMediaStreamTrackStats, with attributes trackIdentifier, remoteSource, ended, - detached, ssrcIds, frameWidth, frameHeight, framesPerSecond, framesSent, + - RTCMediaStreamTrackStats, with attributes trackIdentifier, remoteSource, + ended, detached, frameWidth, frameHeight, framesPerSecond, framesSent, framesReceived, framesDecoded, framesDropped, framesCorrupted, audioLevel */ -function validateMediaStreamTrackStats(stats, stat) { +function validateMediaStreamTrackStats(statsReport, stats) { validateRtcStats(statsReport, stats); - assert_string_field(stat, 'trackIdentifier'); - assert_boolean_field(stat, 'remoteSource'); - assert_boolean_field(stat, 'ended'); - assert_boolean_field(stat, 'detached'); + assert_string_field(stats, 'trackIdentifier'); + assert_boolean_field(stats, 'remoteSource'); + assert_boolean_field(stats, 'ended'); + assert_boolean_field(stats, 'detached'); - assert_optional_string_field(stat, 'kind'); - assert_optional_number_field(stat, 'estimatedPlayoutTimestamp'); + assert_optional_enum_field(stats, 'kind', ['audio', 'video']); + assert_optional_number_field(stats, 'estimatedPlayoutTimestamp'); - assert_unsigned_int_field(stat, 'frameWidth'); - assert_unsigned_int_field(stat, 'frameHeight'); - assert_number_field(stat, 'framesPerSecond'); + assert_unsigned_int_field(stats, 'frameWidth'); + assert_unsigned_int_field(stats, 'frameHeight'); + assert_number_field(stats, 'framesPerSecond'); - assert_optional_unsigned_int_field(stat, 'framesCaptured'); - assert_unsigned_int_field(stat, 'frameSent'); - assert_unsigned_int_field(stat, 'frameReceived'); - assert_unsigned_int_field(stat, 'frameDecoded'); - assert_unsigned_int_field(stat, 'frameDropped'); - assert_unsigned_int_field(stat, 'frameCorrupted'); + assert_optional_unsigned_int_field(stats, 'framesCaptured'); + assert_unsigned_int_field(stats, 'framesSent'); + assert_optional_unsigned_int_field(stats, 'keyFramesSent'); + assert_unsigned_int_field(stats, 'framesReceived'); + assert_optional_unsigned_int_field(stats, 'keyFramesReceived'); + assert_unsigned_int_field(stats, 'framesDecoded'); + assert_unsigned_int_field(stats, 'framesDropped'); + assert_unsigned_int_field(stats, 'framesCorrupted'); - assert_optional_unsigned_int_field(stat, 'partialFramesLost'); - assert_optional_unsigned_int_field(stat, 'fullFramesLost'); + assert_optional_unsigned_int_field(stats, 'partialFramesLost'); + assert_optional_unsigned_int_field(stats, 'fullFramesLost'); - assert_number_field(stat, 'audioLevel'); - assert_optional_number_field(stat, 'totalAudioEnergy'); - assert_optional_boolean_field(stat, 'voiceActivityFlag'); - assert_optional_number_field(stat, 'echoReturnLoss'); - assert_optional_number_field(stat, 'echoReturnLossEnhancement'); + assert_number_field(stats, 'audioLevel'); + assert_optional_number_field(stats, 'totalAudioEnergy'); + assert_optional_boolean_field(stats, 'voiceActivityFlag'); + assert_optional_number_field(stats, 'echoReturnLoss'); + assert_optional_number_field(stats, 'echoReturnLossEnhancement'); - assert_optional_unsigned_int_field(stat, 'totalSamplesSent'); - assert_optional_unsigned_int_field(stat, 'totalSamplesReceived'); - assert_optional_number_field(stat, 'totalSamplesDuration'); - assert_optional_unsigned_int_field(stat, 'concealedSamples'); - assert_optional_unsigned_int_field(stat, 'concealmentEvents'); - assert_optional_number_field(stat, 'jitterBufferDelay'); + assert_optional_unsigned_int_field(stats, 'totalSamplesSent'); + assert_optional_unsigned_int_field(stats, 'totalSamplesReceived'); + assert_optional_number_field(stats, 'totalSamplesDuration'); + assert_optional_unsigned_int_field(stats, 'concealedSamples'); + assert_optional_unsigned_int_field(stats, 'concealmentEvents'); + assert_optional_number_field(stats, 'jitterBufferDelay'); assert_optional_enum_field(stats, 'priority', ['very-low', 'low', 'medium', 'high']); @@ -571,18 +564,15 @@ function validateMediaStreamTrackStats(stats, stat) { [webrtc-stats] 7.13. RTCDataChannelStats dictionary dictionary RTCDataChannelStats : RTCStats { - required DOMString label; - required DOMString protocol; - required long datachannelid; - - [RTCTransportStats] - DOMString transportId; - - required RTCDataChannelState state; - required unsigned long messagesSent; - required unsigned long long bytesSent; - required unsigned long messagesReceived; - required unsigned long long bytesReceived; + DOMString label; + DOMString protocol; + long dataChannelIdentifier; + DOMString transportId; + RTCDataChannelState state; + unsigned long messagesSent; + unsigned long long bytesSent; + unsigned long messagesReceived; + unsigned long long bytesReceived; }; [webrtc-pc] @@ -598,22 +588,19 @@ function validateMediaStreamTrackStats(stats, stat) { - RTCDataChannelStats, with attributes label, protocol, datachannelId, state, messagesSent, bytesSent, messagesReceived, bytesReceived */ - function validateDataChannelStats(statsReport, stats) { validateRtcStats(statsReport, stats); assert_string_field(stats, 'label'); assert_string_field(stats, 'protocol'); - assert_int_field(stats, 'datachannelid'); + assert_int_field(stats, 'dataChannelIdentifier'); validateOptionalIdField(statsReport, stats, 'transportId', 'transport'); assert_enum_field(stats, 'state', ['connecting', 'open', 'closing', 'closed']); - assert_unsigned_int_field(stats, 'messageSent'); - - assert_unsigned_int_field(stats, 'messageSent'); + assert_unsigned_int_field(stats, 'messagesSent'); assert_unsigned_int_field(stats, 'bytesSent'); assert_unsigned_int_field(stats, 'messagesReceived'); assert_unsigned_int_field(stats, 'bytesReceived'); @@ -623,25 +610,16 @@ function validateDataChannelStats(statsReport, stats) { [webrtc-stats] 7.14. RTCTransportStats dictionary dictionary RTCTransportStats : RTCStats { - unsigned long packetsSent; - unsigned long packetsReceived; - required unsigned long long bytesSent; - required unsigned long long bytesReceived; - - [RTCTransportStats] - required DOMString rtcpTransportStatsId; - - RTCIceRole iceRole; - RTCDtlsTransportState dtlsState; - - [RTCIceCandidatePairStats] - required DOMString selectedCandidatePairId; - - [RTCCertificateStats] - required DOMString localCertificateId; - - [RTCCertificateStats] - required DOMString remoteCertificateId; + unsigned long packetsSent; + unsigned long packetsReceived; + unsigned long long bytesSent; + unsigned long long bytesReceived; + DOMString rtcpTransportStatsId; + RTCIceRole iceRole; + RTCDtlsTransportState dtlsState; + DOMString selectedCandidatePairId; + DOMString localCertificateId; + DOMString remoteCertificateId; }; [webrtc-pc] @@ -661,10 +639,10 @@ function validateDataChannelStats(statsReport, stats) { }; 8.6. Mandatory To Implement Stats - - RTCTransportStats, with attributes bytesSent, bytesReceived, rtcpTransportStatsId, - activeConnection, selectedCandidatePairId, localCertificateId, remoteCertificateId + - RTCTransportStats, with attributes bytesSent, bytesReceived, + rtcpTransportStatsId, selectedCandidatePairId, localCertificateId, + remoteCertificateId */ - function validateTransportStats(statsReport, stats) { validateRtcStats(statsReport, stats); @@ -682,26 +660,35 @@ function validateTransportStats(statsReport, stats) { ['new', 'connecting', 'connected', 'closed', 'failed']); validateIdField(statsReport, stats, 'selectedCandidatePairId', 'candidate-pair'); - validateIdField(stateReport, stats, 'localCertificateId', 'certificate'); - validateIdField(stateReport, stats, 'remoteCertificateId', 'certificate'); + validateIdField(statsReport, stats, 'localCertificateId', 'certificate'); + validateIdField(statsReport, stats, 'remoteCertificateId', 'certificate'); } /* [webrtc-stats] 7.15. RTCIceCandidateStats dictionary dictionary RTCIceCandidateStats : RTCStats { - [RTCTransportStats] - DOMString transportId; + DOMString transportId; + boolean isRemote; + RTCNetworkType networkType; + DOMString ip; + long port; + DOMString protocol; + RTCIceCandidateType candidateType; + long priority; + DOMString url; + DOMString relayProtocol; + boolean deleted = false; + }; - boolean isRemote; - required DOMString ip; - required long port; - required DOMString protocol; - required RTCIceCandidateType candidateType; - required long priority; - required DOMString url; - DOMString relayProtocol; - boolean deleted = false; + enum RTCNetworkType { + "bluetooth", + "cellular", + "ethernet", + "wifi", + "wimax", + "vpn", + "unknown" }; [webrtc-pc] @@ -714,16 +701,18 @@ function validateTransportStats(statsReport, stats) { }; 8.6. Mandatory To Implement Stats - - RTCIceCandidateStats, with attributes ip, port, protocol, candidateType, priority, - url + - RTCIceCandidateStats, with attributes ip, port, protocol, candidateType, + priority, url */ - function validateIceCandidateStats(statsReport, stats) { validateRtcStats(statsReport, stats); validateOptionalIdField(statsReport, stats, 'transportId', 'transport'); assert_optional_boolean_field(stats, 'isRemote'); + assert_optional_enum_field(stats, 'networkType', + ['bluetooth', 'cellular', 'ethernet', 'wifi', 'wimax', 'vpn', 'unknown']) + assert_string_field(stats, 'ip'); assert_int_field(stats, 'port'); assert_string_field(stats, 'protocol'); @@ -741,40 +730,34 @@ function validateIceCandidateStats(statsReport, stats) { [webrtc-stats] 7.16. RTCIceCandidatePairStats dictionary dictionary RTCIceCandidatePairStats : RTCStats { - [RTCTransportStats] - required DOMString transportId; - - [RTCIceCandidateStats] - required DOMString localCandidateId; - - [RTCIceCandidateStats] - required DOMString remoteCandidateId; - - required RTCStatsIceCandidatePairState state; - required unsigned long long priority; - required boolean nominated; - unsigned long packetsSent; - unsigned long packetsReceived; - required unsigned long long bytesSent; - required unsigned long long bytesReceived; - DOMHighResTimeStamp lastPacketSentTimestamp; - DOMHighResTimeStamp lastPacketReceivedTimestamp; - DOMHighResTimeStamp firstRequestTimestamp; - DOMHighResTimeStamp lastRequestTimestamp; - DOMHighResTimeStamp lastResponseTimestamp; - required double totalRoundTripTime; - required double currentRoundTripTime; - double availableOutgoingBitrate; - double availableIncomingBitrate; - unsigned long circuitBreakerTriggerCount; - unsigned long long requestsReceived; - unsigned long long requestsSent; - unsigned long long responsesReceived; - unsigned long long responsesSent; - unsigned long long retransmissionsReceived; - unsigned long long retransmissionsSent; - unsigned long long consentRequestsSent; - DOMHighResTimeStamp consentExpiredTimestamp; + DOMString transportId; + DOMString localCandidateId; + DOMString remoteCandidateId; + RTCStatsIceCandidatePairState state; + unsigned long long priority; + boolean nominated; + unsigned long packetsSent; + unsigned long packetsReceived; + unsigned long long bytesSent; + unsigned long long bytesReceived; + DOMHighResTimeStamp lastPacketSentTimestamp; + DOMHighResTimeStamp lastPacketReceivedTimestamp; + DOMHighResTimeStamp firstRequestTimestamp; + DOMHighResTimeStamp lastRequestTimestamp; + DOMHighResTimeStamp lastResponseTimestamp; + double totalRoundTripTime; + double currentRoundTripTime; + double availableOutgoingBitrate; + double availableIncomingBitrate; + unsigned long circuitBreakerTriggerCount; + unsigned long long requestsReceived; + unsigned long long requestsSent; + unsigned long long responsesReceived; + unsigned long long responsesSent; + unsigned long long retransmissionsReceived; + unsigned long long retransmissionsSent; + unsigned long long consentRequestsSent; + DOMHighResTimeStamp consentExpiredTimestamp; }; enum RTCStatsIceCandidatePairState { @@ -788,8 +771,7 @@ function validateIceCandidateStats(statsReport, stats) { [webrtc-pc] 8.6. Mandatory To Implement Stats - RTCIceCandidatePairStats, with attributes transportId, localCandidateId, - remoteCandidateId, state, priority, nominated, writable, readable, bytesSent, - bytesReceived, totalRtt, currentRtt + remoteCandidateId, state, priority, nominated, bytesSent, bytesReceived, totalRoundTripTime, currentRoundTripTime */ function validateIceCandidatePairStats(statsReport, stats) { validateRtcStats(statsReport, stats); @@ -835,10 +817,10 @@ function validateIceCandidatePairStats(statsReport, stats) { [webrtc-stats] 7.17. RTCCertificateStats dictionary dictionary RTCCertificateStats : RTCStats { - required DOMString fingerprint; - required DOMString fingerprintAlgorithm; - required DOMString base64Certificate; - required DOMString issuerCertificateId; + DOMString fingerprint; + DOMString fingerprintAlgorithm; + DOMString base64Certificate; + DOMString issuerCertificateId; }; [webrtc-pc] @@ -846,7 +828,6 @@ function validateIceCandidatePairStats(statsReport, stats) { - RTCCertificateStats, with attributes fingerprint, fingerprintAlgorithm, base64Certificate, issuerCertificateId */ - function validateCertificateStats(statsReport, stats) { validateRtcStats(statsReport, stats); diff --git a/tests/wpt/web-platform-tests/webrtc/RTCTrackEvent-constructor.html b/tests/wpt/web-platform-tests/webrtc/RTCTrackEvent-constructor.html index d5c5f621f80..9579dd4d4f8 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCTrackEvent-constructor.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCTrackEvent-constructor.html @@ -41,6 +41,7 @@ assert_equals(trackEvent.receiver, receiver); assert_equals(trackEvent.track, track); assert_array_equals(trackEvent.streams, []); + assert_equals(trackEvent.streams, trackEvent.streams); // [SameObject] assert_equals(trackEvent.transceiver, transceiver); assert_equals(trackEvent.type, 'track'); diff --git a/tests/wpt/web-platform-tests/webrtc/datachannel-idlharness.html b/tests/wpt/web-platform-tests/webrtc/datachannel-idlharness.html deleted file mode 100644 index ea2dd2a3df9..00000000000 --- a/tests/wpt/web-platform-tests/webrtc/datachannel-idlharness.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - RTCPeerConnection Data Channel Empty String Test - - - - -
    - - - - - - - - - - - diff --git a/tests/wpt/web-platform-tests/webrtc/tools/.eslintrc.js b/tests/wpt/web-platform-tests/webrtc/tools/.eslintrc.js new file mode 100644 index 00000000000..47bbb5dc024 --- /dev/null +++ b/tests/wpt/web-platform-tests/webrtc/tools/.eslintrc.js @@ -0,0 +1,156 @@ +module.exports = { + rules: { + 'no-undef': 1, + 'no-unused-vars': 0 + }, + plugins: [ + 'html' + ], + env: { + browser: true, + es6: true + }, + globals: { + // testharness globals + test: true, + async_test: true, + promise_test: true, + promise_rejects: true, + IdlArray: true, + assert_true: true, + assert_false: true, + assert_equals: true, + assert_not_equals: true, + assert_array_equals: true, + assert_in_array: true, + assert_unreached: true, + assert_throws: true, + assert_idl_attribute: true, + assert_exists: true, + assert_greater_than: true, + assert_less_than: true, + assert_greater_than_equal: true, + assert_less_than_equal: true, + assert_approx_equals: true, + + + // WebRTC globals + RTCPeerConnection: true, + RTCRtpSender: true, + RTCRtpReceiver: true, + RTCRtpTransceiver: true, + RTCIceTransport: true, + RTCDtlsTransport: true, + RTCSctpTransport: true, + RTCDataChannel: true, + RTCCertificate: true, + RTCDTMFSender: true, + RTCError: true, + RTCTrackEvent: true, + RTCPeerConnectionIceEvent: true, + RTCDTMFToneChangeEvent: true, + RTCDataChannelEvent: true, + RTCRtpContributingSource: true, + RTCRtpSynchronizationSource: true, + + // dictionary-helper.js + assert_unsigned_int_field: true, + assert_int_field: true, + assert_string_field: true, + assert_number_field: true, + assert_boolean_field: true, + assert_array_field: true, + assert_dict_field: true, + assert_enum_field: true, + + assert_optional_unsigned_int_field: true, + assert_optional_int_field: true, + assert_optional_string_field: true, + assert_optional_number_field: true, + assert_optional_boolean_field: true, + assert_optional_array_field: true, + assert_optional_dict_field: true, + assert_optional_enum_field: true, + + // identity-helper.js + parseAssertionResult: true, + getIdpDomains: true, + assert_rtcerror_rejection: true, + hostString: true, + + // RTCConfiguration-helper.js + config_test: true, + + // RTCDTMFSender-helper.js + createDtmfSender: true, + test_tone_change_events: true, + getTransceiver: true, + + // RTCPeerConnection-helper.js + countLine: true, + countAudioLine: true, + countVideoLine: true, + countApplicationLine: true, + similarMediaDescriptions: true, + assert_is_session_description: true, + isSimilarSessionDescription: true, + assert_session_desc_equals: true, + assert_session_desc_not_equals: true, + generateOffer: true, + generateAnswer: true, + test_state_change_event: true, + test_never_resolve: true, + exchangeIceCandidates: true, + doSignalingHandshake: true, + createDataChannelPair: true, + awaitMessage: true, + blobToArrayBuffer: true, + assert_equals_array_buffer: true, + generateMediaStreamTrack: true, + getTrackFromUserMedia: true, + getUserMediaTracksAndStreams: true, + performOffer: true, + Resolver: true, + + // RTCRtpCapabilities-helper.js + validateRtpCapabilities: true, + validateCodecCapability: true, + validateHeaderExtensionCapability: true, + + // RTCRtpParameters-helper.js + validateSenderRtpParameters: true, + validateReceiverRtpParameters: true, + validateRtpParameters: true, + validateEncodingParameters: true, + validateRtcpParameters: true, + validateHeaderExtensionParameters: true, + validateCodecParameters: true, + + // RTCStats-helper.js + validateStatsReport: true, + assert_stats_report_has_stats: true, + findStatsFromReport: true, + getRequiredStats: true, + getStatsById: true, + validateIdField: true, + validateOptionalIdField: true, + validateRtcStats: true, + validateRtpStreamStats: true, + validateCodecStats: true, + validateReceivedRtpStreamStats: true, + validateInboundRtpStreamStats: true, + validateRemoteInboundRtpStreamStats: true, + validateSentRtpStreamStats: true, + validateOutboundRtpStreamStats: true, + validateRemoteOutboundRtpStreamStats: true, + validateContributingSourceStats: true, + validatePeerConnectionStats: true, + validateMediaStreamStats: true, + validateMediaStreamTrackStats: true, + validateDataChannelStats: true, + validateTransportStats: true, + validateIceCandidateStats: true, + validateIceCandidatePairStats: true, + validateCertificateStats: true, + } +} diff --git a/tests/wpt/web-platform-tests/webrtc/tools/README.md b/tests/wpt/web-platform-tests/webrtc/tools/README.md new file mode 100644 index 00000000000..68bc284fdfa --- /dev/null +++ b/tests/wpt/web-platform-tests/webrtc/tools/README.md @@ -0,0 +1,14 @@ +WebRTC Tools +============ + +This directory contains a simple Node.js project to aid the development of +WebRTC tests. + +## Lint + +```bash +npm run lint +``` + +Does basic linting of the JavaScript code. Mainly for catching usage of +undefined variables. diff --git a/tests/wpt/web-platform-tests/webrtc/tools/package-lock.json b/tests/wpt/web-platform-tests/webrtc/tools/package-lock.json new file mode 100644 index 00000000000..79e603949cf --- /dev/null +++ b/tests/wpt/web-platform-tests/webrtc/tools/package-lock.json @@ -0,0 +1,1213 @@ +{ + "name": "webrtc-testing-tools", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "acorn": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.2.1.tgz", + "integrity": "sha512-jG0u7c4Ly+3QkkW18V+NRDN+4bWHdln30NL1ZL2AvFZZmQe/BfopYCtghCKKVBUSetZ4QKcyA0pY6/4Gw8Pv8w==", + "dev": true + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "requires": { + "acorn": "3.3.0" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true + } + } + }, + "ajv": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.3.0.tgz", + "integrity": "sha1-RBT/dKUIecII7l/cgm4ywwNUnto=", + "dev": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.0.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "ajv-keywords": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", + "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", + "dev": true + }, + "ansi-escapes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.0.0.tgz", + "integrity": "sha512-O/klc27mWNUigtv0F8NJWbLF00OcegQalkqKURWdosW08YZKi4m6CnSUSvIZG1otNJbTWhN01Hhz389DW7mvDQ==", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "argparse": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "dev": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "1.0.3" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + } + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dev": true, + "requires": { + "callsites": "0.2.0" + } + }, + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true + }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "chardet": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.0.tgz", + "integrity": "sha1-C74TVaxE16PtSpJXB8TvcPgZD2w=", + "dev": true + }, + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "dev": true + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "color-convert": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", + "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", + "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "typedarray": "0.0.6" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "4.1.1", + "shebang-command": "1.2.0", + "which": "1.3.0" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "requires": { + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.0", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.2" + } + }, + "doctrine": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.0.tgz", + "integrity": "sha1-xz2NKQnSIpHhoAejlYBNqLZl/mM=", + "dev": true, + "requires": { + "esutils": "2.0.2", + "isarray": "1.0.0" + } + }, + "dom-serializer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", + "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", + "dev": true, + "requires": { + "domelementtype": "1.1.3", + "entities": "1.1.1" + }, + "dependencies": { + "domelementtype": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", + "dev": true + } + } + }, + "domelementtype": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", + "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", + "dev": true + }, + "domhandler": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.1.tgz", + "integrity": "sha1-iS5HAAqZvlW783dP/qBWHYh5wlk=", + "dev": true, + "requires": { + "domelementtype": "1.3.0" + } + }, + "domutils": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.6.2.tgz", + "integrity": "sha1-GVjMC0yUJuntNn+xyOhUiRsPo/8=", + "dev": true, + "requires": { + "dom-serializer": "0.1.0", + "domelementtype": "1.3.0" + } + }, + "entities": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.11.0.tgz", + "integrity": "sha512-UWbhQpaKlm8h5x/VLwm0S1kheMrDj8jPwhnBMjr/Dlo3qqT7MvcN/UfKAR3E1N4lr4YNtOvS4m3hwsrVc/ky7g==", + "dev": true, + "requires": { + "ajv": "5.3.0", + "babel-code-frame": "6.26.0", + "chalk": "2.3.0", + "concat-stream": "1.6.0", + "cross-spawn": "5.1.0", + "debug": "3.1.0", + "doctrine": "2.0.0", + "eslint-scope": "3.7.1", + "espree": "3.5.2", + "esquery": "1.0.0", + "estraverse": "4.2.0", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "functional-red-black-tree": "1.0.1", + "glob": "7.1.2", + "globals": "9.18.0", + "ignore": "3.3.7", + "imurmurhash": "0.1.4", + "inquirer": "3.3.0", + "is-resolvable": "1.0.0", + "js-yaml": "3.10.0", + "json-stable-stringify-without-jsonify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.4", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "7.0.0", + "progress": "2.0.0", + "require-uncached": "1.0.3", + "semver": "5.4.1", + "strip-ansi": "4.0.0", + "strip-json-comments": "2.0.1", + "table": "4.0.2", + "text-table": "0.2.0" + } + }, + "eslint-plugin-html": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-4.0.0.tgz", + "integrity": "sha512-xK/909qOTq5JVzuO2jo4a24nQcWhkOBz9dOIkORvB7RxC75a4b6B9wFpBXAl8WDhwJGFDj5gBDRN+/L3kK/ghw==", + "dev": true, + "requires": { + "htmlparser2": "3.9.2" + } + }, + "eslint-scope": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", + "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", + "dev": true, + "requires": { + "esrecurse": "4.2.0", + "estraverse": "4.2.0" + } + }, + "espree": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.2.tgz", + "integrity": "sha512-sadKeYwaR/aJ3stC2CdvgXu1T16TdYN+qwCpcWbMnGJ8s0zNWemzrvb2GbD4OhmJ/fwpJjudThAlLobGbWZbCQ==", + "dev": true, + "requires": { + "acorn": "5.2.1", + "acorn-jsx": "3.0.1" + } + }, + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", + "dev": true + }, + "esquery": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz", + "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", + "dev": true, + "requires": { + "estraverse": "4.2.0" + } + }, + "esrecurse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz", + "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", + "dev": true, + "requires": { + "estraverse": "4.2.0", + "object-assign": "4.1.1" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "external-editor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.1.0.tgz", + "integrity": "sha512-E44iT5QVOUJBKij4IIV3uvxuNlbKS38Tw1HiupxEIHPv9qtC2PrDYohbXV5U+1jnfIXttny8gUhj+oZvflFlzA==", + "dev": true, + "requires": { + "chardet": "0.4.0", + "iconv-lite": "0.4.19", + "tmp": "0.0.33" + } + }, + "fast-deep-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", + "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "requires": { + "flat-cache": "1.3.0", + "object-assign": "4.1.1" + } + }, + "flat-cache": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", + "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", + "dev": true, + "requires": { + "circular-json": "0.3.3", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "htmlparser2": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz", + "integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=", + "dev": true, + "requires": { + "domelementtype": "1.3.0", + "domhandler": "2.4.1", + "domutils": "1.6.2", + "entities": "1.1.1", + "inherits": "2.0.3", + "readable-stream": "2.3.3" + } + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", + "dev": true + }, + "ignore": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.7.tgz", + "integrity": "sha512-YGG3ejvBNHRqu0559EOxxNFihD0AjpvHlC/pdGKd3X3ofe+CoJkYazwNJYTNebqpPKN+VVQbh4ZFn1DivMNuHA==", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "dev": true, + "requires": { + "ansi-escapes": "3.0.0", + "chalk": "2.3.0", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.1.0", + "figures": "2.0.0", + "lodash": "4.17.4", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rx-lite": "4.0.8", + "rx-lite-aggregates": "4.0.8", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", + "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", + "dev": true, + "requires": { + "is-path-inside": "1.0.0" + } + }, + "is-path-inside": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", + "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", + "dev": true, + "requires": { + "path-is-inside": "1.0.2" + } + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-resolvable": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz", + "integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=", + "dev": true, + "requires": { + "tryit": "1.0.3" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", + "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", + "dev": true, + "requires": { + "argparse": "1.0.9", + "esprima": "4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + }, + "lru-cache": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", + "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", + "dev": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "mimic-fn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", + "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "1.1.0" + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "progress": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", + "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dev": true, + "requires": { + "caller-path": "0.1.0", + "resolve-from": "1.0.1" + } + }, + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "2.0.1", + "signal-exit": "3.0.2" + } + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "dev": true, + "requires": { + "glob": "7.1.2" + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "2.1.0" + } + }, + "rx-lite": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", + "dev": true + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "dev": true, + "requires": { + "rx-lite": "4.0.8" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "semver": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", + "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + } + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "table": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", + "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", + "dev": true, + "requires": { + "ajv": "5.3.0", + "ajv-keywords": "2.1.1", + "chalk": "2.3.0", + "lodash": "4.17.4", + "slice-ansi": "1.0.0", + "string-width": "2.1.1" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "1.0.2" + } + }, + "tryit": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz", + "integrity": "sha1-OTvnMKlEb9Hq1tpZoBQwjzbCics=", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "which": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", + "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "dev": true, + "requires": { + "isexe": "2.0.0" + } + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "requires": { + "mkdirp": "0.5.1" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } +} diff --git a/tests/wpt/web-platform-tests/webrtc/tools/package.json b/tests/wpt/web-platform-tests/webrtc/tools/package.json new file mode 100644 index 00000000000..70515d8b715 --- /dev/null +++ b/tests/wpt/web-platform-tests/webrtc/tools/package.json @@ -0,0 +1,14 @@ +{ + "name": "webrtc-testing-tools", + "version": "1.0.0", + "description": "Tools for WebRTC testing", + "scripts": { + "lint": "eslint -c .eslintrc.js ../*.html ../*.js" + }, + "devDependencies": { + "eslint": "^4.11.0", + "eslint-plugin-html": "^4.0.0" + }, + "license": "BSD", + "private": true +} diff --git a/tests/wpt/web-platform-tests/websockets/constants.js b/tests/wpt/web-platform-tests/websockets/constants.js index 8312cd253fe..cb17767f48c 100644 --- a/tests/wpt/web-platform-tests/websockets/constants.js +++ b/tests/wpt/web-platform-tests/websockets/constants.js @@ -1,8 +1,7 @@ //This file requires server-side substitutions and must be included as constants.js?pipe=sub var PORT = "{{ports[ws][0]}}"; -//FIXME: Add support for wss -var PORT_SSL = "{{ports[ws][0]}}"; +var PORT_SSL = "{{ports[wss][0]}}"; var SCHEME_DOMAIN_PORT; if (location.search == '?wss') { diff --git a/tests/wpt/web-platform-tests/websockets/handlers/referrer_wsh.py b/tests/wpt/web-platform-tests/websockets/handlers/referrer_wsh.py new file mode 100644 index 00000000000..3418ceb0c80 --- /dev/null +++ b/tests/wpt/web-platform-tests/websockets/handlers/referrer_wsh.py @@ -0,0 +1,12 @@ +#!/usr/bin/python + +from mod_pywebsocket import msgutil + +def web_socket_do_extra_handshake(request): + pass + +def web_socket_transfer_data(request): + referrer = request.headers_in.get("Referer") + if referrer is None: + referrer = "MISSING AS PER FETCH" + msgutil.send_message(request, referrer) diff --git a/tests/wpt/web-platform-tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-defineProperty-getter.html b/tests/wpt/web-platform-tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-defineProperty-getter.html index a6bd53015c6..b564da23967 100644 --- a/tests/wpt/web-platform-tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-defineProperty-getter.html +++ b/tests/wpt/web-platform-tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-defineProperty-getter.html @@ -3,7 +3,7 @@ WebSockets: defineProperty getter for bufferedAmount - +
    diff --git a/tests/wpt/web-platform-tests/websockets/referrer.any.js b/tests/wpt/web-platform-tests/websockets/referrer.any.js new file mode 100644 index 00000000000..914af77e678 --- /dev/null +++ b/tests/wpt/web-platform-tests/websockets/referrer.any.js @@ -0,0 +1,13 @@ +// META: script=constants.js?pipe=sub + +async_test(t => { + const ws = new WebSocket(SCHEME_DOMAIN_PORT + "/referrer"); + ws.onmessage = t.step_func_done(e => { + assert_equals(e.data, "MISSING AS PER FETCH"); + ws.close(); + }); + + // Avoid timeouts in case of failure + ws.onclose = t.unreached_func("close"); + ws.onerror = t.unreached_func("error"); +}, "Ensure no Referer header is included"); diff --git a/tests/wpt/web-platform-tests/webstorage/idlharness.html b/tests/wpt/web-platform-tests/webstorage/idlharness.html index 454e441d6f9..cd880a33f03 100644 --- a/tests/wpt/web-platform-tests/webstorage/idlharness.html +++ b/tests/wpt/web-platform-tests/webstorage/idlharness.html @@ -15,7 +15,7 @@