mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Update web-platform-tests to revision 00fa50687cab43b660296389acad6cc48717f1d1
This commit is contained in:
parent
07d53e32c4
commit
28bbe1473c
58 changed files with 2119 additions and 360 deletions
|
@ -113293,6 +113293,18 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"css/css-display/display-none-inline-img.html": [
|
||||
[
|
||||
"/css/css-display/display-none-inline-img.html",
|
||||
[
|
||||
[
|
||||
"/css/css-display/display-none-inline-img-ref.html",
|
||||
"=="
|
||||
]
|
||||
],
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/css-display/run-in/counter-increment-applies-to-011.xht": [
|
||||
[
|
||||
"/css/css-display/run-in/counter-increment-applies-to-011.xht",
|
||||
|
@ -158593,6 +158605,18 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"css/css-values/viewport-unit-011.html": [
|
||||
[
|
||||
"/css/css-values/viewport-unit-011.html",
|
||||
[
|
||||
[
|
||||
"/css/css-values/reference/viewport-unit-011-ref.html",
|
||||
"=="
|
||||
]
|
||||
],
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/css-variables/css-vars-custom-property-case-sensitive-001.html": [
|
||||
[
|
||||
"/css/css-variables/css-vars-custom-property-case-sensitive-001.html",
|
||||
|
@ -255237,6 +255261,11 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"css/css-display/display-none-inline-img-ref.html": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/css-display/run-in/META.yml": [
|
||||
[
|
||||
{}
|
||||
|
@ -275947,6 +275976,11 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"css/css-values/reference/viewport-unit-011-ref.html": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/css-values/support/1x1-green.png": [
|
||||
[
|
||||
{}
|
||||
|
@ -313917,6 +313951,11 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"tools/docker/retry.py": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"tools/docker/start.sh": [
|
||||
[
|
||||
{}
|
||||
|
@ -322147,6 +322186,11 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"webaudio/the-audio-api/the-audiobuffersourcenode-interface/resources/sub-sample-scheduling.html": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"webaudio/the-audio-api/the-audiocontext-interface/.gitkeep": [
|
||||
[
|
||||
{}
|
||||
|
@ -342248,6 +342292,12 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"css/css-device-adapt/documentElement-clientWidth-on-minimum-scale-size.tentative.html": [
|
||||
[
|
||||
"/css/css-device-adapt/documentElement-clientWidth-on-minimum-scale-size.tentative.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/css-device-adapt/idlharness.html": [
|
||||
[
|
||||
"/css/css-device-adapt/idlharness.html",
|
||||
|
@ -346060,6 +346110,12 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"css/css-position/position-absolute-replaced-minmax.html": [
|
||||
[
|
||||
"/css/css-position/position-absolute-replaced-minmax.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/css-position/position-sticky-bottom.html": [
|
||||
[
|
||||
"/css/css-position/position-sticky-bottom.html",
|
||||
|
@ -347860,6 +347916,12 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"css/css-tables/no-overflow-with-table-cell-margins.html": [
|
||||
[
|
||||
"/css/css-tables/no-overflow-with-table-cell-margins.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/css-tables/parsing/border-collapse-computed.html": [
|
||||
[
|
||||
"/css/css-tables/parsing/border-collapse-computed.html",
|
||||
|
@ -352338,6 +352400,12 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"css/css-values/calc-letter-spacing.html": [
|
||||
[
|
||||
"/css/css-values/calc-letter-spacing.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/css-values/calc-rounding-001.html": [
|
||||
[
|
||||
"/css/css-values/calc-rounding-001.html",
|
||||
|
@ -418702,6 +418770,12 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"webaudio/the-audio-api/the-pannernode-interface/panner-azimuth.html": [
|
||||
[
|
||||
"/webaudio/the-audio-api/the-pannernode-interface/panner-azimuth.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping.html": [
|
||||
[
|
||||
"/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping.html",
|
||||
|
@ -447430,7 +447504,7 @@
|
|||
"support"
|
||||
],
|
||||
".taskcluster.yml": [
|
||||
"ae99c0960acc56ca0970d9a03538e20c42179811",
|
||||
"1045e07c8df889205d8a719585e3dd3c388f77cc",
|
||||
"support"
|
||||
],
|
||||
".travis.yml": [
|
||||
|
@ -548801,6 +548875,10 @@
|
|||
"f04eba57ce450541e9283f62718dd3ed71f3631c",
|
||||
"support"
|
||||
],
|
||||
"css/css-device-adapt/documentElement-clientWidth-on-minimum-scale-size.tentative.html": [
|
||||
"74e2172510f8496bda64bb2ae3600b0e165347fd",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-device-adapt/idlharness.html": [
|
||||
"b9cca1bb7ee2fbee354ec90a3afc5e8e33609bc8",
|
||||
"testharness"
|
||||
|
@ -549185,6 +549263,14 @@
|
|||
"f8d6e85cee2325f3ae51a950a276430d26c04189",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-display/display-none-inline-img-ref.html": [
|
||||
"a3e7369afbae5c35cabbda9aa1a0fe8ab4521af4",
|
||||
"support"
|
||||
],
|
||||
"css/css-display/display-none-inline-img.html": [
|
||||
"f97ca7bbd3519453b362405c542a065a25c43368",
|
||||
"reftest"
|
||||
],
|
||||
"css/css-display/inheritance.html": [
|
||||
"bfd072651cb6ec82cca7d9be5b6768afbc39fca0",
|
||||
"testharness"
|
||||
|
@ -568677,6 +568763,10 @@
|
|||
"5d36710b6fe694b256d9841b3e7a0fff4535c85b",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-position/position-absolute-replaced-minmax.html": [
|
||||
"644b147a227e100c500de2de9e4f8e8449a4a21e",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-position/position-relative-table-left-ref.html": [
|
||||
"7c1193b80007d8e7f89b35400a6d2ea2266cb3ac",
|
||||
"support"
|
||||
|
@ -573926,7 +574016,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"css/css-syntax/escaped-eof.html": [
|
||||
"66ac8e9442e22c8d5b445d556c667f769c0939e2",
|
||||
"5d47c34ac512fab7eb9c37e64b0c677d09a8e3d3",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-syntax/ident-three-code-points.html": [
|
||||
|
@ -574153,6 +574243,10 @@
|
|||
"a8745487b6702b8b8e8ac85bd843014dc296b717",
|
||||
"reftest"
|
||||
],
|
||||
"css/css-tables/no-overflow-with-table-cell-margins.html": [
|
||||
"9657da9c262cede13451978446508ff8917b53bd",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-tables/parsing/border-collapse-computed.html": [
|
||||
"1ad0b6d701a7bbc1b49a9f3d3a34270dbd64ed29",
|
||||
"testharness"
|
||||
|
@ -590057,6 +590151,10 @@
|
|||
"a88416a2c2da6532084dc77ded1d3d5ac15e120e",
|
||||
"reftest"
|
||||
],
|
||||
"css/css-values/calc-letter-spacing.html": [
|
||||
"444785ba14c21faefe56c22de0c23766ddb26c95",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-values/calc-parenthesis-stack.html": [
|
||||
"1d9033d7eecd14066ee9e4f9c52bf1a39e6ddd1b",
|
||||
"reftest"
|
||||
|
@ -590213,6 +590311,10 @@
|
|||
"5e35f6261e266be2981ae79038e464ac354cc8ef",
|
||||
"support"
|
||||
],
|
||||
"css/css-values/reference/viewport-unit-011-ref.html": [
|
||||
"e56c6ec8451370e86fb16f76c50acd627bd5be78",
|
||||
"support"
|
||||
],
|
||||
"css/css-values/support/1x1-green.png": [
|
||||
"b98ca0ba0a03c580ac339e4a3653539cfa8edc71",
|
||||
"support"
|
||||
|
@ -590473,6 +590575,10 @@
|
|||
"dba2af8fa07b07d2ab7c6ca9f657b6e170cd9a41",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-values/viewport-unit-011.html": [
|
||||
"055f3d1fd2d716a68d857738493815c8772bef06",
|
||||
"reftest"
|
||||
],
|
||||
"css/css-values/viewport-units-css2-001.html": [
|
||||
"c51237dd8a07546d31eef6f6f9b3c84b6ac2b65b",
|
||||
"testharness"
|
||||
|
@ -611970,7 +612076,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"dom/events/EventListener-handleEvent.html": [
|
||||
"b33b030a641dd0d2a4e1319f366e3db975e9dc3f",
|
||||
"6630f273fff4b450d1fcc425828b5f1f53357e54",
|
||||
"testharness"
|
||||
],
|
||||
"dom/events/EventListener-incumbent-global-1.sub.html": [
|
||||
|
@ -638326,7 +638432,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"html/webappapis/scripting/events/event-handler-attributes-frameset-window.html": [
|
||||
"ecfe90e88ea404604dfaeb649b8067c15fc03d5a",
|
||||
"b583eca52da2b9b5e58fb25e73b3766452b7c472",
|
||||
"testharness"
|
||||
],
|
||||
"html/webappapis/scripting/events/event-handler-attributes-windowless-body.html": [
|
||||
|
@ -640034,7 +640140,7 @@
|
|||
"support"
|
||||
],
|
||||
"interfaces/webxr.idl": [
|
||||
"3054500f5903f72214b4bd8984488a186b2a5d8a",
|
||||
"63643a11b6b0cb7ecf7aabc19b03edf1d47a6642",
|
||||
"support"
|
||||
],
|
||||
"interfaces/worklets.idl": [
|
||||
|
@ -653050,7 +653156,7 @@
|
|||
"support"
|
||||
],
|
||||
"preload/link-header-preload-nonce.html": [
|
||||
"51b2224864d5a47c9642ded613efcfc702eb0f9d",
|
||||
"240d6f11dd5979457ed8a4d6ab3c97e9d1ce9f9c",
|
||||
"testharness"
|
||||
],
|
||||
"preload/link-header-preload-nonce.html.headers": [
|
||||
|
@ -653058,7 +653164,7 @@
|
|||
"support"
|
||||
],
|
||||
"preload/link-header-preload-srcset.tentative.html": [
|
||||
"9eb8ac4e00d20b9eb48ffd3a981b33b7604246f8",
|
||||
"024da965796fb5960bc43cdf4de1806fbef74ffe",
|
||||
"testharness"
|
||||
],
|
||||
"preload/link-header-preload-srcset.tentative.html.headers": [
|
||||
|
@ -653174,7 +653280,7 @@
|
|||
"support"
|
||||
],
|
||||
"preload/resources/preload_helper.js": [
|
||||
"5a23be74b8df48e56ac335a90a97bf79a75511b3",
|
||||
"b2cf8323db0145fa4876fb40d0d1ed3ff1c6413b",
|
||||
"support"
|
||||
],
|
||||
"preload/resources/sound_5.oga": [
|
||||
|
@ -673458,7 +673564,7 @@
|
|||
"support"
|
||||
],
|
||||
"tools/ci/taskcluster-run.py": [
|
||||
"f443903786e9ee9a8cb2f3ab20e1cf4bb11faf68",
|
||||
"2b3270c17aaacd053bdff516fa1f1ee666011858",
|
||||
"support"
|
||||
],
|
||||
"tools/ci/tcdownload.py": [
|
||||
|
@ -673478,11 +673584,15 @@
|
|||
"support"
|
||||
],
|
||||
"tools/docker/Dockerfile": [
|
||||
"53564ac135c909d19138bee24780c28ddba04a03",
|
||||
"0cb2352e5fdf6117d51c9f745d18bbf453c48a1c",
|
||||
"support"
|
||||
],
|
||||
"tools/docker/retry.py": [
|
||||
"6126b781bfadd15e82b8a3a3b9494050939eab6c",
|
||||
"support"
|
||||
],
|
||||
"tools/docker/start.sh": [
|
||||
"52a5127892ca0455c57de1e3b26e26ea6a3f8db2",
|
||||
"bfc7e9960abf595c8319c1865a2ad3c4d1c51087",
|
||||
"support"
|
||||
],
|
||||
"tools/gitignore/__init__.py": [
|
||||
|
@ -678486,7 +678596,7 @@
|
|||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/browsers/firefox.py": [
|
||||
"67d5b6ec2f5e97046c020947c8449d5205a713bf",
|
||||
"ec317b8bed2ce515661bc056a37039ea44801299",
|
||||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/browsers/ie.py": [
|
||||
|
@ -678554,7 +678664,7 @@
|
|||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/executors/executormarionette.py": [
|
||||
"d69e998e2c302f1983bd43541054ba84b745bbe3",
|
||||
"d5692af77d39771d02af9bbaba9c04a54572bbb6",
|
||||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/executors/executoropera.py": [
|
||||
|
@ -678634,11 +678744,11 @@
|
|||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/formatters.py": [
|
||||
"0a54624b7b447ba16c1fc80a3b9efc39487892a0",
|
||||
"284868522eaf52b5132d46c223ad70e42aa6c81a",
|
||||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/manifestexpected.py": [
|
||||
"7ecef4b0b24ee062fb35f31fee776dd7c59d0c8f",
|
||||
"f4fddc7a2a14d3170ea7afc72c5a1ef949ffa772",
|
||||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/manifestinclude.py": [
|
||||
|
@ -678646,11 +678756,11 @@
|
|||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/manifestupdate.py": [
|
||||
"1f8ba77e8f9e0de32fa497d56ecc999ea722f452",
|
||||
"90bcd593edec91d506d41aef2467859ba5d95c77",
|
||||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/metadata.py": [
|
||||
"b170fc663165af2c20061184ebea8a0a93cf3b01",
|
||||
"26dc71e64e4187b9595eb5f5d1729884763b36f2",
|
||||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/products.py": [
|
||||
|
@ -678730,7 +678840,7 @@
|
|||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/tests/test_update.py": [
|
||||
"36facdc9520f944899908f0eed0cd4c9914eaaec",
|
||||
"032ac82dff6e6fddd65e329550b1d314cb89371b",
|
||||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/tests/test_wpttest.py": [
|
||||
|
@ -678774,7 +678884,7 @@
|
|||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/wptcommandline.py": [
|
||||
"0a3a8c2b6f7ea626b715b23b03b3765ef0c12808",
|
||||
"1d6909daaca68e78083327915c0c30e2f9d1c34e",
|
||||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/wptlogging.py": [
|
||||
|
@ -678838,7 +678948,7 @@
|
|||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/wpttest.py": [
|
||||
"767a25de8c1b9411a15b255c3ecc0dd74caa5a89",
|
||||
"7fa39be4de13aea1e3454d3c44dee86c5245546c",
|
||||
"support"
|
||||
],
|
||||
"tools/wptserve/.gitignore": [
|
||||
|
@ -681646,11 +681756,11 @@
|
|||
"testharness"
|
||||
],
|
||||
"wasm/jsapi/wasm-constants.js": [
|
||||
"18748e6cf540db200a83de6d151dc8d77d1b25e1",
|
||||
"e3846386b8dccada9c24da194950627f4c39836f",
|
||||
"support"
|
||||
],
|
||||
"wasm/jsapi/wasm-module-builder.js": [
|
||||
"c01b71733d667b8d299971f99c3133be9bf08d8b",
|
||||
"e13f4157873baf0896f42b9fd340588f4453a14a",
|
||||
"support"
|
||||
],
|
||||
"wasm/resources/load_wasm.js": [
|
||||
|
@ -682506,7 +682616,7 @@
|
|||
"support"
|
||||
],
|
||||
"webaudio/resources/biquad-testing.js": [
|
||||
"7a0b6e6c1f8a3d616620425731603f0b43c5ff84",
|
||||
"7f90a1f72bec6be2cfc3a1256a40132958632ca9",
|
||||
"support"
|
||||
],
|
||||
"webaudio/resources/convolution-testing.js": [
|
||||
|
@ -682518,7 +682628,7 @@
|
|||
"support"
|
||||
],
|
||||
"webaudio/resources/distance-model-testing.js": [
|
||||
"1b9adde403e37933100a7ef13369aa3e40d5515b",
|
||||
"f8a6cf940a96f197461f605f1bf527175f63670a",
|
||||
"support"
|
||||
],
|
||||
"webaudio/resources/merger-testing.js": [
|
||||
|
@ -682534,7 +682644,7 @@
|
|||
"support"
|
||||
],
|
||||
"webaudio/resources/note-grain-on-testing.js": [
|
||||
"1e941897161228f043d9acd128bd3b44b693b7d1",
|
||||
"ad0631670df932c63c5029ea1f267de5032c9fa9",
|
||||
"support"
|
||||
],
|
||||
"webaudio/resources/panner-formulas.js": [
|
||||
|
@ -682542,7 +682652,7 @@
|
|||
"support"
|
||||
],
|
||||
"webaudio/resources/panner-model-testing.js": [
|
||||
"662fb1d68c5361464b21e8a08c5e23de1a558515",
|
||||
"4df3e178134210d9bb55da1100dd98880aa86801",
|
||||
"support"
|
||||
],
|
||||
"webaudio/resources/sin_440Hz_-6dBFS_1s.wav": [
|
||||
|
@ -682554,7 +682664,7 @@
|
|||
"support"
|
||||
],
|
||||
"webaudio/resources/stereopanner-testing.js": [
|
||||
"d6238a9cd367b00137027735fd0ff7d3c3aae3b7",
|
||||
"2778493e3b6c12d4c00c77bd975e845063621522",
|
||||
"support"
|
||||
],
|
||||
"webaudio/the-audio-api/the-analysernode-interface/.gitkeep": [
|
||||
|
@ -682650,7 +682760,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-playbackrate-zero.html": [
|
||||
"58ee49e42d279e5a28d78aa32c34e0e511850df2",
|
||||
"5624054e3289a18d48fab3b4942f3bb16b9d1c03",
|
||||
"testharness"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-start.html": [
|
||||
|
@ -682685,6 +682795,10 @@
|
|||
"ab9d5fe5a9dbd736a079f0cfd7966d5e064ed7ef",
|
||||
"support"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audiobuffersourcenode-interface/resources/sub-sample-scheduling.html": [
|
||||
"27ac0984a79ef276f6f6e32dc9814131487de31a",
|
||||
"support"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audiobuffersourcenode-interface/sample-accurate-scheduling.html": [
|
||||
"5fafd024eef9b476f4d97b2ebaa2190a4ca520d5",
|
||||
"testharness"
|
||||
|
@ -682718,7 +682832,7 @@
|
|||
"support"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audionode-interface/audionode-channel-rules.html": [
|
||||
"a1c3273cc3fef597eff30e13c6074bd99ddb7acf",
|
||||
"9067e6869bcf682e4f3f945d567a2d8a300d9f4b",
|
||||
"testharness"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audionode-interface/audionode-connect-method-chaining.html": [
|
||||
|
@ -682838,7 +682952,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioparam-interface/k-rate-panner.html": [
|
||||
"ea2a4d1364595865d4c77e3b38449f5ffe3d5da5",
|
||||
"60200b24712c29a92d73b6215b85f734999b8209",
|
||||
"testharness"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioparam-interface/k-rate-stereo-panner.html": [
|
||||
|
@ -683026,7 +683140,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"webaudio/the-audio-api/the-biquadfilternode-interface/biquad-lowpass.html": [
|
||||
"d20786e36b16d7ba36841dd5fcfb30c081113fb2",
|
||||
"69dc85a2e2be61da92d8d48f34472e3da8d35fb1",
|
||||
"testharness"
|
||||
],
|
||||
"webaudio/the-audio-api/the-biquadfilternode-interface/biquad-lowshelf.html": [
|
||||
|
@ -683222,7 +683336,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"webaudio/the-audio-api/the-gainnode-interface/gain.html": [
|
||||
"cff609de4b795a9d6ab0c465af3b959563d45cce",
|
||||
"c1ee0240cb9f87bc05fb4f5fb076d01b2de45899",
|
||||
"testharness"
|
||||
],
|
||||
"webaudio/the-audio-api/the-gainnode-interface/no-dezippering.html": [
|
||||
|
@ -683329,6 +683443,10 @@
|
|||
"8e09e869acb4b5a0e5dd94e2401494c690954208",
|
||||
"testharness"
|
||||
],
|
||||
"webaudio/the-audio-api/the-pannernode-interface/panner-azimuth.html": [
|
||||
"d09f2ec352f052e987178a7ea0cb8a2b83283ccf",
|
||||
"testharness"
|
||||
],
|
||||
"webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping.html": [
|
||||
"96b99a2373bccdab74ebdfd409f0f8adb4acc94d",
|
||||
"testharness"
|
||||
|
@ -684306,7 +684424,7 @@
|
|||
"support"
|
||||
],
|
||||
"webdriver/tests/set_window_rect/set.py": [
|
||||
"4017bc198e41ea618e73c2d71cfcb68312b0c4d0",
|
||||
"81432f293770d0fd0b5da66dc4bca19c1043f9a0",
|
||||
"wdspec"
|
||||
],
|
||||
"webdriver/tests/set_window_rect/user_prompts.py": [
|
||||
|
@ -684330,11 +684448,11 @@
|
|||
"support"
|
||||
],
|
||||
"webdriver/tests/support/defaults.py": [
|
||||
"c2020527a6f38a628b2c1a4199caaff46cf0c36b",
|
||||
"8dd171aa64c71fa031e0e14ef4344f4335e368cc",
|
||||
"support"
|
||||
],
|
||||
"webdriver/tests/support/fixtures.py": [
|
||||
"f662040e4066f14afa6a5f8c40778db23ccab29a",
|
||||
"bd2381d2069ac64788446252d173ae1c052d5b71",
|
||||
"support"
|
||||
],
|
||||
"webdriver/tests/support/helpers.py": [
|
||||
|
|
|
@ -6,6 +6,3 @@
|
|||
[Instant scrolling while doing history navigation.]
|
||||
expected: FAIL
|
||||
|
||||
[Smooth scrolling while doing history navigation.]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -2,3 +2,9 @@
|
|||
[EventListener::handleEvent()]
|
||||
expected: FAIL
|
||||
|
||||
[throws if `handleEvent` is not callable]
|
||||
expected: FAIL
|
||||
|
||||
[calls `handleEvent` method of `EventListener`]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
[javascript-url-abort-return-value-string.tentative.html]
|
||||
[Aborting fetch for javascript:string navigation]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
[non-active-document.html]
|
||||
[DOMParser]
|
||||
expected: FAIL
|
||||
|
||||
[createHTMLDocument]
|
||||
expected: FAIL
|
||||
|
||||
[<template>]
|
||||
expected: FAIL
|
||||
|
|
@ -12,3 +12,6 @@
|
|||
[Verifies the resolution of entry.startTime is at least 5 microseconds.]
|
||||
expected: TIMEOUT
|
||||
|
||||
[Verifies the resolution of performance.now() is at least 5 microseconds.]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
[No imports]
|
||||
expected: FAIL
|
||||
|
||||
[exports and imports]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[constructor.any.worker.html]
|
||||
[exports]
|
||||
|
@ -13,3 +16,6 @@
|
|||
[No imports]
|
||||
expected: FAIL
|
||||
|
||||
[exports and imports]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
[get-set.any.worker.html]
|
||||
expected: ERROR
|
||||
[Setting out-of-range argument: NaN]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -74,8 +75,12 @@
|
|||
[Setting non-function]
|
||||
expected: FAIL
|
||||
|
||||
[Stray argument]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[get-set.any.html]
|
||||
expected: ERROR
|
||||
[Setting out-of-range argument: NaN]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -151,3 +156,6 @@
|
|||
[Setting non-function]
|
||||
expected: FAIL
|
||||
|
||||
[Stray argument]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -8,3 +8,15 @@
|
|||
[# AUDIT TASK RUNNER FINISHED: 1 out of 1 tasks were failed.]
|
||||
expected: FAIL
|
||||
|
||||
[# AUDIT TASK RUNNER FINISHED: 2 out of 2 tasks were failed.]
|
||||
expected: FAIL
|
||||
|
||||
[< [subsample start with playback rate 0\] 2 out of 2 assertions were failed.]
|
||||
expected: FAIL
|
||||
|
||||
[X output[0:27\]: Expected 0 for all values but found 1 unexpected values: \n\tIndex\tActual\n\t[27\]\t5]
|
||||
expected: FAIL
|
||||
|
||||
[X output[28:\]: Expected 5 for all values but found 8164 unexpected values: \n\tIndex\tActual\n\t[0\]\t6\n\t[1\]\t7\n\t[2\]\t8\n\t[3\]\t9\n\t...and 8160 more errors.]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -11,3 +11,9 @@
|
|||
[< [test\] 2 out of 4 assertions were failed.]
|
||||
expected: FAIL
|
||||
|
||||
[X Right SNR (in dB) is not greater than or equal to 148.71. Got NaN.]
|
||||
expected: FAIL
|
||||
|
||||
[X Left SNR (in dB) is not greater than or equal to 148.71. Got NaN.]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
[panner-azimuth.html]
|
||||
expected: ERROR
|
|
@ -1,4 +1,5 @@
|
|||
[005.html]
|
||||
expected: ERROR
|
||||
[dedicated worker in shared worker in dedicated worker]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ tasks:
|
|||
owner: ${event.pusher.email}
|
||||
source: ${event.repository.url}
|
||||
payload:
|
||||
image: harjgam/web-platform-tests:0.26
|
||||
image: harjgam/web-platform-tests:0.29
|
||||
maxRunTime: 7200
|
||||
artifacts:
|
||||
public/results:
|
||||
|
@ -136,7 +136,7 @@ tasks:
|
|||
owner: ${event.pull_request.user.login}@users.noreply.github.com
|
||||
source: ${event.repository.url}
|
||||
payload:
|
||||
image: harjgam/web-platform-tests:0.26
|
||||
image: harjgam/web-platform-tests:0.29
|
||||
maxRunTime: 7200
|
||||
artifacts:
|
||||
public/results:
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<meta name="viewport" content="width=device-width minimum-scale=0.5">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-device-adapt/">
|
||||
<style>
|
||||
html {
|
||||
overflow: hidden;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
div {
|
||||
height: 200%;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
<title></title>
|
||||
<div style="width: 200%;"></div>
|
||||
<div id="reference" style="width: 100%;"></div>
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
<script>
|
||||
'use strict';
|
||||
test(() => {
|
||||
assert_equals(document.documentElement.clientWidth, reference.clientWidth,
|
||||
'documentElement clientWidth should be 100%');
|
||||
}, 'documentElement clientWidth should be equal to device-width even if ' +
|
||||
'overflow:hidden region is visible');
|
||||
</script>
|
|
@ -0,0 +1,46 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Test Reference</title>
|
||||
<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
|
||||
<style>
|
||||
.carousel {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.scroller {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.slides {
|
||||
width: 200%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.slide {
|
||||
flex: 0 0 50%;
|
||||
contain: paint;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 300px;
|
||||
height: 250px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="carousel">
|
||||
<div class="scroller">
|
||||
<div class="slides">
|
||||
<div class="slide">
|
||||
<img id="image" src="/images/green-256x256.png">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Test: display: none then inline on img</title>
|
||||
<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-display-3/#valdef-display-inline">
|
||||
<link rel="match" href="display-none-inline-img-ref.html">
|
||||
<html class="reftest-wait">
|
||||
<style>
|
||||
.carousel {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.scroller {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.slides {
|
||||
width: 200%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.slide {
|
||||
flex: 0 0 50%;
|
||||
contain: paint;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 300px;
|
||||
height: 250px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="carousel">
|
||||
<div class="scroller">
|
||||
<div class="slides">
|
||||
<div class="slide">
|
||||
<img id="image" src="/images/green-256x256.png">
|
||||
</div>
|
||||
<div class="slide">
|
||||
<img>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
function toggleDisplay() {
|
||||
var img = document.getElementById("image");
|
||||
img.style.display = img.style.display == 'none' ? 'inline' : 'none';
|
||||
}
|
||||
|
||||
window.onload = () => {
|
||||
requestAnimationFrame(() => {
|
||||
toggleDisplay();
|
||||
requestAnimationFrame(() => {
|
||||
toggleDisplay();
|
||||
document.documentElement.classList.remove("reftest-wait");
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</html>
|
|
@ -0,0 +1,328 @@
|
|||
<!DOCTYPE html>
|
||||
<title>CSS Position: absolute position, replaced elements, and minmax</title>
|
||||
<link rel="author" title="mailto:atotic@google.com">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<link rel="help" href="https://www.w3.org/TR/CSS2/visudet.html#min-max-widths">
|
||||
<meta name="assert" content="Min/max width and height interact properly with abspos replaced elements">
|
||||
<style>
|
||||
.container {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 400px;
|
||||
height: 200px;
|
||||
border: 1px solid black;
|
||||
}
|
||||
.target {
|
||||
position: absolute;
|
||||
padding: 10px;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
border-width: 3px 7px 9px 11px;
|
||||
border-color: yellow;
|
||||
border-style: solid;
|
||||
}
|
||||
</style>
|
||||
<!-- test all combinations of minmax from section 10.4 table at
|
||||
https://www.w3.org/TR/CSS2/visudet.html#min-max-widths -->
|
||||
|
||||
<!-- IFRAME tests -->
|
||||
<!-- iframe: intrinsic size is 300x150, no aspect ratio -->
|
||||
<div class="container">
|
||||
<iframe class="target"
|
||||
data-expected-width="338" data-expected-height="182" data-offset-y="18" data-offset-x="62"
|
||||
>
|
||||
</iframe>
|
||||
</div>
|
||||
<!-- spec 1: w > max-width -->
|
||||
<div class="container">
|
||||
<iframe class="target" style="max-width:100px"
|
||||
data-expected-width="138" data-expected-height="182" data-offset-y="18" data-offset-x="262"
|
||||
>
|
||||
</iframe>
|
||||
</div>
|
||||
<!-- spec 2: w < min-width -->
|
||||
<div class="container">
|
||||
<iframe class="target" style="min-width: 350px"
|
||||
data-expected-width="388" data-expected-height="182" data-offset-y="18" data-offset-x="12"
|
||||
>
|
||||
</iframe>
|
||||
</div>
|
||||
<!-- spec 3: h > max-height -->
|
||||
<div class="container">
|
||||
<iframe class="target" style="max-height: 150px"
|
||||
data-expected-width="338" data-expected-height="182" data-offset-y="18" data-offset-x="62"
|
||||
>
|
||||
</iframe>
|
||||
</div>
|
||||
<!-- spec 4: h < min-height -->
|
||||
<div class="container">
|
||||
<iframe class="target" style="min-height: 165px"
|
||||
data-expected-width="338" data-expected-height="197" data-offset-y="3" data-offset-x="62"
|
||||
>
|
||||
</iframe>
|
||||
</div>
|
||||
<!-- spec 5: (w > max-width) and (h > max-height), where (max-width/w ≤ max-height/h) -->
|
||||
<div class="container">
|
||||
<iframe class="target" style="max-width: 240px; max-height: 135px"
|
||||
data-expected-width="278" data-expected-height="167" data-offset-y="33" data-offset-x="122"
|
||||
>
|
||||
</iframe>
|
||||
</div>
|
||||
<!-- spec 6: (w > max-width) and (h > max-height), where (max-width/w > max-height/h) -->
|
||||
<div class="container">
|
||||
<iframe class="target" style="max-width: 270px; max-height: 120px"
|
||||
data-expected-width="308" data-expected-height="152" data-offset-y="48" data-offset-x="92"
|
||||
>
|
||||
</iframe>
|
||||
</div>
|
||||
<!-- spec 7: (w < min-width) and (h < min-height), where (min-width/w ≤ min-height/h) -->
|
||||
<div class="container">
|
||||
<iframe class="target" style="min-width: 360px; min-height: 165px"
|
||||
data-expected-width="398" data-expected-height="197" data-offset-y="3" data-offset-x="2"
|
||||
>
|
||||
</iframe>
|
||||
</div>
|
||||
<!-- spec 8: (w < min-width) and (h < min-height), where (min-width/w > min-height/h) -->
|
||||
<div class="container">
|
||||
<iframe class="target" style="min-width: 330px; min-height: 180px"
|
||||
data-expected-width="368" data-expected-height="212" data-offset-y="-12" data-offset-x="32"
|
||||
>
|
||||
</iframe>
|
||||
</div>
|
||||
<!-- spec 9: (w < min-width) and (h > max-height) -->
|
||||
<div class="container">
|
||||
<iframe class="target" style="min-width: 330px; max-height: 135px"
|
||||
data-expected-width="368" data-expected-height="167" data-offset-y="33" data-offset-x="32"
|
||||
>
|
||||
</iframe>
|
||||
</div>
|
||||
<!-- spec 10: (w > max-width) and (h < min-height) -->
|
||||
<div class="container">
|
||||
<iframe class="target" style="max-width: 240px; min-height: 165px"
|
||||
data-expected-width="278" data-expected-height="197" data-offset-y="3" data-offset-x="122"
|
||||
>
|
||||
</iframe>
|
||||
</div>
|
||||
|
||||
<!-- IMG png tests -->
|
||||
<!-- image dimensions: 200x150. images has intrinic size and aspect ratio -->
|
||||
<div class="container">
|
||||
<img class="target png"
|
||||
data-expected-width="238" data-expected-height="182" data-offset-y="18" data-offset-x="162"
|
||||
>
|
||||
</div>
|
||||
<!-- spec 1: w > max-width -->
|
||||
<div class="container">
|
||||
<img class="target png" style="max-width: 180px"
|
||||
data-expected-width="218" data-expected-height="167" data-offset-y="33" data-offset-x="182"
|
||||
>
|
||||
</div>
|
||||
<!-- spec 2: w < min-width -->
|
||||
<div class="container">
|
||||
<img class="target png" style="min-width: 220px"
|
||||
data-expected-width="258" data-expected-height="197" data-offset-y="3" data-offset-x="142"
|
||||
>
|
||||
</div>
|
||||
|
||||
<!-- spec 3: h > max-height -->
|
||||
<div class="container">
|
||||
<img class="target png" style="max-height: 135px"
|
||||
data-expected-width="218" data-expected-height="167" data-offset-y="33" data-offset-x="182"
|
||||
>
|
||||
</div>
|
||||
<!-- spec 4: h < min-height -->
|
||||
<div class="container">
|
||||
<img class="target png" style="min-height: 165px"
|
||||
data-expected-width="258" data-expected-height="197" data-offset-y="3" data-offset-x="142"
|
||||
>
|
||||
</div>
|
||||
<!-- spec 5: (w > max-width) and (h > max-height), where (max-width/w ≤ max-height/h) -->
|
||||
<div class="container">
|
||||
<img class="target png" style="max-width: 160px; max-height: 135px"
|
||||
data-expected-width="198" data-expected-height="152" data-offset-y="48" data-offset-x="202"
|
||||
>
|
||||
</div>
|
||||
<!-- spec 6: (w > max-width) and (h > max-height), where (max-width/w > max-height/h) -->
|
||||
<div class="container">
|
||||
<img class="target png" style="max-width: 180px; max-height: 120px"
|
||||
data-expected-width="198" data-expected-height="152" data-offset-y="48" data-offset-x="202"
|
||||
>
|
||||
</div>
|
||||
<!-- spec 7: (w < min-width) and (h < min-height), where (min-width/w ≤ min-height/h) -->
|
||||
<div class="container">
|
||||
<img class="target png" style="min-width: 240px;min-height: 165px"
|
||||
data-expected-width="278" data-expected-height="212" data-offset-y="-12" data-offset-x="122"
|
||||
>
|
||||
</div>
|
||||
<!-- spec 8: (w < min-width) and (h < min-height), where (min-width/w > min-height/h) -->
|
||||
<div class="container">
|
||||
<img class="target png" style="min-width: 220px;min-height: 180px"
|
||||
data-expected-width="278" data-expected-height="212" data-offset-y="-12" data-offset-x="122"
|
||||
>
|
||||
</div>
|
||||
<!-- spec 9: (w < min-width) and (h > max-height) -->
|
||||
<div class="container">
|
||||
<img class="target png" style="min-width: 220px; max-height: 130px"
|
||||
data-expected-width="258" data-expected-height="162" data-offset-y="38" data-offset-x="142"
|
||||
>
|
||||
</div>
|
||||
<!-- spec 10: (w > max-width) and (h < min-height) -->
|
||||
<div class="container">
|
||||
<img class="target png" style="max-width: 180px; min-height: 165px"
|
||||
data-expected-width="218" data-expected-height="197" data-offset-y="3" data-offset-x="182"
|
||||
>
|
||||
</div>
|
||||
<!-- IMG SVG tests -->
|
||||
<!-- image dimensions: 200x150. images has no intrinic size and no aspect ratio -->
|
||||
<div class="container">
|
||||
<img class="target svg"
|
||||
data-expected-width="338" data-expected-height="182" data-offset-y="18" data-offset-x="62"
|
||||
>
|
||||
</div>
|
||||
<!-- spec 1: w > max-width -->
|
||||
<div class="container">
|
||||
<img class="target svg" style="max-width: 180px"
|
||||
data-expected-width="218" data-expected-height="182" data-offset-y="18" data-offset-x="182"
|
||||
>
|
||||
</div>
|
||||
<!-- spec 2: w < min-width -->
|
||||
<div class="container">
|
||||
<img class="target svg" style="min-width: 220px"
|
||||
data-expected-width="338" data-expected-height="182" data-offset-y="18" data-offset-x="62"
|
||||
>
|
||||
</div>
|
||||
|
||||
<!-- spec 3: h > max-height -->
|
||||
<div class="container">
|
||||
<img class="target svg" style="max-height: 135px"
|
||||
data-expected-width="338" data-expected-height="167" data-offset-y="33" data-offset-x="62"
|
||||
>
|
||||
</div>
|
||||
<!-- spec 4: h < min-height -->
|
||||
<div class="container">
|
||||
<img class="target svg" style="min-height: 165px"
|
||||
data-expected-width="338" data-expected-height="197" data-offset-y="3" data-offset-x="62"
|
||||
>
|
||||
</div>
|
||||
<!-- spec 5: (w > max-width) and (h > max-height), where (max-width/w ≤ max-height/h) -->
|
||||
<div class="container">
|
||||
<img class="target svg" style="max-width: 160px; max-height: 135px"
|
||||
data-expected-width="198" data-expected-height="167" data-offset-y="33" data-offset-x="202"
|
||||
>
|
||||
</div>
|
||||
<!-- spec 6: (w > max-width) and (h > max-height), where (max-width/w > max-height/h) -->
|
||||
<div class="container">
|
||||
<img class="target svg" style="max-width: 180px; max-height: 120px"
|
||||
data-expected-width="218" data-expected-height="152" data-offset-y="48" data-offset-x="182"
|
||||
>
|
||||
</div>
|
||||
<!-- spec 7: (w < min-width) and (h < min-height), where (min-width/w ≤ min-height/h) -->
|
||||
<div class="container">
|
||||
<img class="target svg" style="min-width: 240px;min-height: 165px"
|
||||
data-expected-width="338" data-expected-height="197" data-offset-y="3" data-offset-x="62"
|
||||
>
|
||||
</div>
|
||||
<!-- spec 8: (w < min-width) and (h < min-height), where (min-width/w > min-height/h) -->
|
||||
<div class="container">
|
||||
<img class="target svg" style="min-width: 220px;min-height: 180px"
|
||||
data-expected-width="338" data-expected-height="212" data-offset-y="-12" data-offset-x="62"
|
||||
>
|
||||
</div>
|
||||
<!-- spec 9: (w < min-width) and (h > max-height) -->
|
||||
<div class="container">
|
||||
<img class="target svg" style="min-width: 220px; max-height: 130px"
|
||||
data-expected-width="338" data-expected-height="162" data-offset-y="38" data-offset-x="62"
|
||||
>
|
||||
</div>
|
||||
<!-- spec 10: (w > max-width) and (h < min-height) -->
|
||||
<div class="container">
|
||||
<img class="target svg" style="max-width: 180px; min-height: 165px"
|
||||
data-expected-width="218" data-expected-height="197" data-offset-y="3" data-offset-x="182"
|
||||
>
|
||||
</div>
|
||||
<!-- SVG tests -->
|
||||
<!-- SVGs are special: any combination of intrinsic_size and aspect_ratio
|
||||
can happen. -->
|
||||
<!-- Just viewbox. Has intrinsic aspect ratio, but no width/height -->
|
||||
<div class="container">
|
||||
<img class="target" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' %3E%3Crect width='100%' height='100%' style='fill:rgb(0,255,0);'/%3E%3C/svg%3E" style=""
|
||||
data-expected-width="338" data-expected-height="182" data-offset-y="18" data-offset-x="62"
|
||||
>
|
||||
</div>
|
||||
<!-- Just viewbox. Has aspect_ration, but no intrinsic size
|
||||
inline_width defaults to container width -->
|
||||
<div class="container">
|
||||
<img class="target" src="data:image/svg+xml,%3Csvg viewBox='0 0 100 10' xmlns='http://www.w3.org/2000/svg' %3E%3Crect width='100%' height='100%' style='fill:rgb(0,255,0);'/%3E%3C/svg%3E"
|
||||
data-expected-width="400" data-expected-height="68" data-offset-y="132" data-offset-x="0"
|
||||
>
|
||||
</div>
|
||||
<!-- Viewbox + svg width. Has aspect_ratio and width. Height is scaled -->
|
||||
<div class="container">
|
||||
<img class="target" src="data:image/svg+xml,%3Csvg viewBox='0 0 100 10' width='100px' xmlns='http://www.w3.org/2000/svg' %3E%3Crect width='100%' height='100%' style='fill:rgb(0,255,0);'/%3E%3C/svg%3E"
|
||||
data-expected-width="138" data-expected-height="42" data-offset-y="158" data-offset-x="262"
|
||||
>
|
||||
</div>
|
||||
<!-- Viewbox + svg height. Has aspect_ratio and height. Width is scaled -->
|
||||
<div class="container">
|
||||
<img class="target" src="data:image/svg+xml,%3Csvg viewBox='0 0 100 10' height='20px' xmlns='http://www.w3.org/2000/svg' %3E%3Crect width='100%' height='100%' style='fill:rgb(0,255,0);'/%3E%3C/svg%3E"
|
||||
data-expected-width="238" data-expected-height="52" data-offset-y="148" data-offset-x="162"
|
||||
>
|
||||
</div>
|
||||
<script>
|
||||
// initialize png images with 200x150 green png
|
||||
let pngSrc="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACWAQMAAAChElVaAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABlBMVEUAgAD///8UPy9PAAAAAWJLR0QB/wIt3gAAAAd0SU1FB+MBDwkdA1Cz/EMAAAAbSURBVEjH7cGBAAAAAMOg+VPf4ARVAQAAAM8ADzwAAeM8wQsAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTktMDEtMTVUMTc6Mjk6MDMtMDg6MDCYDy9IAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE5LTAxLTE1VDE3OjI5OjAzLTA4OjAw6VKX9AAAAABJRU5ErkJggg=="
|
||||
;
|
||||
let images = document.querySelectorAll("img.png");
|
||||
for (let i=0; i<images.length; ++i) {
|
||||
images[i].src = pngSrc;
|
||||
}
|
||||
|
||||
// SVG with no intrinsic width/height
|
||||
let svgSrc="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' %3E%3Crect width='100%' height='100%' style='fill:rgb(0,255,0);'/%3E%3C/svg%3E ";
|
||||
images = document.querySelectorAll("img.svg");
|
||||
for (let i=0; i<images.length; ++i) {
|
||||
images[i].src = svgSrc;
|
||||
}
|
||||
|
||||
function makeTest(el) {
|
||||
return function() {
|
||||
if (!el.getAttribute("data-expected-width")) {
|
||||
// This code is used to generate reference data for the tests.
|
||||
let text = `data-expected-width="${el.offsetWidth}" data-expected-height="${el.offsetHeight}" data-offset-y="${el.offsetTop}" data-offset-x="${el.offsetLeft}"`;
|
||||
el.parentElement.innerText = text;
|
||||
return;
|
||||
}
|
||||
assert_equals(el.offsetWidth + "", el.getAttribute("data-expected-width"), "incorrect offsetWidth");
|
||||
assert_equals(el.offsetHeight + "", el.getAttribute("data-expected-height"), "incorrect offsetHeight");
|
||||
assert_equals(el.offsetTop + "", el.getAttribute("data-offset-y"), "incorrect offsetTop");
|
||||
assert_equals(el.offsetLeft + "", el.getAttribute("data-offset-x"), "incorrect offsetLeft");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
let testNameIndex = 1;
|
||||
function getTestName(el) {
|
||||
let svg = el.classList.contains("svg") ? " svg" : "";
|
||||
return "minmax replaced " + el.nodeName + svg + " " + testNameIndex++;
|
||||
};
|
||||
|
||||
function testAfterImageLoads(img, test) {
|
||||
let asyncTest = async_test(getTestName(img));
|
||||
img.addEventListener("load", _ => {
|
||||
asyncTest.step(test);
|
||||
asyncTest.done();
|
||||
});
|
||||
};
|
||||
|
||||
let testElements = document.querySelectorAll(".target");
|
||||
|
||||
for (let i=0; i<testElements.length; ++i) {
|
||||
let myTest = makeTest(testElements[i]);
|
||||
if (testElements[i].nodeName == "IMG" && !testElements[i].complete) {
|
||||
testAfterImageLoads(testElements[i], myTest);
|
||||
} else {
|
||||
test(myTest, getTestName(testElements[i]));
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
<script>
|
||||
test(()=>{
|
||||
assert_throws(new SyntaxError, ()=>{document.querySelector("#123");}, "numeric hash token is invalid in a selector");
|
||||
assert_throws("SyntaxError", ()=>{document.querySelector("#123");}, "numeric hash token is invalid in a selector");
|
||||
document.querySelector("#foo\\"); // escaped-EOF in a hash token is valid in a selector
|
||||
}, "Escaped EOF turns into a U+FFFD in a hash token, makes it 'ID' type.");
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-tables-3/">
|
||||
<meta name="assert" content="Table cell margins do not contribute to layout overflow.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<style>
|
||||
html {
|
||||
display: table;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
display: table-cell;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
<body></body>
|
||||
<script>
|
||||
test(() => {
|
||||
const scroller = document.scrollingElement;
|
||||
|
||||
// There shouldn't be any layout overflow on the root scrollable element.
|
||||
assert_equals(scroller.clientHeight, scroller.scrollHeight);
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,75 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<meta charset="UTF-8">
|
||||
|
||||
<title>CSS Values and Units Test: computed value of 'letter-spacing' when specified with calc() function</title>
|
||||
|
||||
<!--
|
||||
|
||||
Original test is:
|
||||
|
||||
https://chromium.googlesource.com/chromium/src/+/c825d655f6aaf73484f9d56e9012793f5b9668cc/third_party/WebKit/LayoutTests/css3/calc/letter-spacing.html
|
||||
|
||||
-->
|
||||
|
||||
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
|
||||
<link rel="help" href="https://www.w3.org/TR/css3-values/#calc-computed-value">
|
||||
|
||||
<meta name="flags" content="invalid">
|
||||
<meta content="This test verifies how 6 calc() functions are computed for 'letter-spacing'." name="assert">
|
||||
|
||||
<script src="/resources/testharness.js"></script>
|
||||
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<div id="target"></div>
|
||||
|
||||
<script>
|
||||
function startTesting()
|
||||
{
|
||||
|
||||
function verifyComputedStyle(property_name, initial_value, specified_value, expected_value, description)
|
||||
{
|
||||
|
||||
var elemTarget = document.getElementById("target");
|
||||
|
||||
test(function()
|
||||
{
|
||||
|
||||
elemTarget.style.setProperty(property_name, initial_value);
|
||||
|
||||
/*
|
||||
In exactly 5 out of the 6 sub-tests, the initial_value will
|
||||
act as a fallback value because the calc() function in the
|
||||
specified value generates an invalid value. Since we are
|
||||
running 6 consecutive tests on the same element, then
|
||||
it is necessary to 'reset' its property to an initial
|
||||
value.
|
||||
*/
|
||||
|
||||
elemTarget.style.setProperty(property_name, specified_value);
|
||||
|
||||
assert_equals(getComputedStyle(elemTarget)[property_name], expected_value, specified_value + ' should compute to ' + expected_value);
|
||||
|
||||
}, description);
|
||||
}
|
||||
|
||||
/* verifyComputedStyle(property_name, initial_value, specified_value, expected_value, description) */
|
||||
|
||||
verifyComputedStyle("letter-spacing", "20px", "calc(1 + 1px)", "20px", "testing letter-spacing: calc(1 + 1px)");
|
||||
|
||||
verifyComputedStyle("letter-spacing", "20px", "calc(1 + 100%)", "20px", "testing letter-spacing: calc(1 + 100%)");
|
||||
|
||||
verifyComputedStyle("letter-spacing", "20px", "calc(100%)", "20px", "testing letter-spacing: calc(100%)");
|
||||
|
||||
verifyComputedStyle("letter-spacing", "20px", "calc(10px) bla", "20px", "testing letter-spacing: calc(10px) bla");
|
||||
|
||||
verifyComputedStyle("letter-spacing", "20px", "calc(bla) 10px", "20px", "testing letter-spacing: calc(bla) 10px");
|
||||
|
||||
verifyComputedStyle("letter-spacing", "initial", "calc(10px)", "10px", "testing letter-spacing: calc(10px)");
|
||||
|
||||
}
|
||||
|
||||
startTesting();
|
||||
|
||||
</script>
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<meta charset="UTF-8">
|
||||
|
||||
<title>CSS Values and Units Test Reference File</title>
|
||||
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100vh;
|
||||
}
|
||||
div {
|
||||
width: 60%;
|
||||
height: 60%;
|
||||
background-color: green;
|
||||
}
|
||||
</style>
|
||||
<div>
|
||||
</div>
|
|
@ -0,0 +1,29 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<meta charset="UTF-8">
|
||||
|
||||
<title>CSS Values and Units Test: vh unit and vw unit (basic)</title>
|
||||
|
||||
<!--
|
||||
Original test is:
|
||||
|
||||
https://chromium.googlesource.com/chromium/src/+/c825d655f6aaf73484f9d56e9012793f5b9668cc/third_party/WebKit/LayoutTests/css3/calc/viewport-unit.html
|
||||
-->
|
||||
|
||||
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
|
||||
<link rel="help" href="https://www.w3.org/TR/css3-values/#viewport-relative-lengths">
|
||||
<link rel="match" href="reference/viewport-unit-011-ref.html">
|
||||
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100vh;
|
||||
}
|
||||
div {
|
||||
width: calc(50vw + 10%);
|
||||
height: calc(50vh + 10%);
|
||||
background-color: green;
|
||||
}
|
||||
</style>
|
||||
<div>
|
||||
</div>
|
|
@ -3,40 +3,83 @@
|
|||
<title>EventListener::handleEvent()</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<link rel="help" href="https://dom.spec.whatwg.org/#callbackdef-eventlistener">
|
||||
<div id=log></div>
|
||||
<table id="table" border="1" style="display: none">
|
||||
<tbody id="table-body">
|
||||
<tr id="table-row">
|
||||
<td id="table-cell">Shady Grove</td>
|
||||
<td>Aeolian</td>
|
||||
</tr>
|
||||
<tr id="parent">
|
||||
<td id="target">Over the river, Charlie</td>
|
||||
<td>Dorian</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div id=target></div>
|
||||
<script>
|
||||
test(function(t) {
|
||||
var event = "foo";
|
||||
var target = document.getElementById("target");
|
||||
setup({ allow_uncaught_exception: true });
|
||||
|
||||
var event_listener = {
|
||||
"handleEvent": function(evt) {
|
||||
test(function(t) {
|
||||
var type = "foo";
|
||||
var target = document.getElementById("target");
|
||||
var eventListener = {
|
||||
handleEvent: function(evt) {
|
||||
var that = this;
|
||||
t.step(function() {
|
||||
assert_equals(evt.type, event);
|
||||
assert_equals(evt.type, type);
|
||||
assert_equals(evt.target, target);
|
||||
assert_equals(evt.srcElement, target);
|
||||
assert_equals(that, event_listener);
|
||||
assert_equals(that, eventListener);
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
var evt = document.createEvent("Event");
|
||||
evt.initEvent(event, true, true);
|
||||
target.addEventListener(type, eventListener);
|
||||
target.dispatchEvent(new Event(type));
|
||||
}, "calls `handleEvent` method of `EventListener`");
|
||||
|
||||
target.addEventListener(event, event_listener, true);
|
||||
target.dispatchEvent(evt);
|
||||
test(function(t) {
|
||||
var type = "foo";
|
||||
var target = document.getElementById("target");
|
||||
var thrownError = new Error();
|
||||
var uncaughtError;
|
||||
|
||||
window.addEventListener("error", function(event) {
|
||||
uncaughtError = event.error;
|
||||
});
|
||||
|
||||
target.addEventListener(type, {
|
||||
get handleEvent() {
|
||||
throw thrownError;
|
||||
},
|
||||
});
|
||||
|
||||
target.dispatchEvent(new Event(type));
|
||||
assert_equals(thrownError, uncaughtError);
|
||||
}, "rethrows errors when getting `handleEvent`");
|
||||
|
||||
test(function(t) {
|
||||
var type = "foo";
|
||||
var target = document.getElementById("target");
|
||||
var calls = 0;
|
||||
|
||||
target.addEventListener(type, {
|
||||
get handleEvent() {
|
||||
calls++;
|
||||
return function() {};
|
||||
},
|
||||
});
|
||||
|
||||
assert_equals(calls, 0);
|
||||
target.dispatchEvent(new Event(type));
|
||||
target.dispatchEvent(new Event(type));
|
||||
assert_equals(calls, 2);
|
||||
}, "performs `Get` every time event is dispatched");
|
||||
|
||||
test(function(t) {
|
||||
var type = "foo";
|
||||
var target = document.getElementById("target");
|
||||
var uncaughtError;
|
||||
|
||||
window.addEventListener("error", function(event) {
|
||||
uncaughtError = event.error;
|
||||
});
|
||||
|
||||
target.addEventListener(type, {
|
||||
handleEvent: null,
|
||||
});
|
||||
|
||||
target.dispatchEvent(new Event(type));
|
||||
assert_true(uncaughtError instanceof TypeError);
|
||||
}, "throws if `handleEvent` is not callable");
|
||||
</script>
|
||||
|
|
|
@ -17,7 +17,9 @@ handlersListPromise.then(({ shadowedHandlers, notShadowedHandlers }) => {
|
|||
add_completion_callback(() => {
|
||||
const log_elem = document.getElementById("log");
|
||||
const frame_elem = document.querySelector("frame");
|
||||
if (log_elem) {
|
||||
frame_elem.contentDocument.body.innerHTML = log_elem.innerHTML;
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
|
|
|
@ -28,12 +28,10 @@ enum XREnvironmentBlendMode {
|
|||
readonly attribute XRSessionMode mode;
|
||||
readonly attribute XRPresentationContext? outputContext;
|
||||
readonly attribute XREnvironmentBlendMode environmentBlendMode;
|
||||
|
||||
attribute double depthNear;
|
||||
attribute double depthFar;
|
||||
attribute XRLayer? baseLayer;
|
||||
readonly attribute XRRenderState renderState;
|
||||
|
||||
// Methods
|
||||
void updateRenderState(optional XRRenderStateInit state);
|
||||
Promise<XRReferenceSpace> requestReferenceSpace(XRReferenceSpaceOptions options);
|
||||
|
||||
FrozenArray<XRInputSource> getInputSources();
|
||||
|
@ -64,6 +62,18 @@ dictionary XRSessionCreationOptions {
|
|||
XRPresentationContext? outputContext = null;
|
||||
};
|
||||
|
||||
dictionary XRRenderStateInit {
|
||||
double depthNear;
|
||||
double depthFar;
|
||||
XRLayer? baseLayer;
|
||||
};
|
||||
|
||||
[SecureContext, Exposed=Window] interface XRRenderState {
|
||||
readonly attribute double depthNear;
|
||||
readonly attribute double depthFar;
|
||||
readonly attribute XRLayer? baseLayer;
|
||||
};
|
||||
|
||||
callback XRFrameRequestCallback = void (DOMHighResTimeStamp time, XRFrame frame);
|
||||
|
||||
[SecureContext, Exposed=Window] interface XRFrame {
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
<script nonce="abc">
|
||||
window.addEventListener('load', t.step_func(function() {
|
||||
verifyPreloadAndRTSupport();
|
||||
verifyNumberOfDownloads("resources/dummy.js?from-header&without-nonce", 0);
|
||||
verifyNumberOfDownloads("resources/dummy.js?from-header&with-nonce", 1);
|
||||
verifyNumberOfResourceTimingEntries("resources/dummy.js?from-header&without-nonce", 0);
|
||||
verifyNumberOfResourceTimingEntries("resources/dummy.js?from-header&with-nonce", 1);
|
||||
t.done();
|
||||
}));
|
||||
</script>
|
||||
|
|
|
@ -11,16 +11,16 @@
|
|||
<script>
|
||||
window.addEventListener("load", t.step_func(function() {
|
||||
verifyPreloadAndRTSupport();
|
||||
verifyNumberOfDownloads('resources/square.png?from-header&1x', 1);
|
||||
verifyNumberOfDownloads('resources/square.png?from-header&2x', 0);
|
||||
verifyNumberOfDownloads('resources/square.png?from-header&3x', 0);
|
||||
verifyNumberOfDownloads('resources/square.png?from-header&base', 0);
|
||||
verifyNumberOfDownloads('resources/square.png?from-header&200', 0);
|
||||
verifyNumberOfDownloads('resources/square.png?from-header&400', 1);
|
||||
verifyNumberOfDownloads('resources/square.png?from-header&800', 0);
|
||||
verifyNumberOfDownloads('resources/square.png?from-header&150', 0);
|
||||
verifyNumberOfDownloads('resources/square.png?from-header&300', 1);
|
||||
verifyNumberOfDownloads('resources/square.png?from-header&600', 0);
|
||||
verifyNumberOfResourceTimingEntries('resources/square.png?from-header&1x', 1);
|
||||
verifyNumberOfResourceTimingEntries('resources/square.png?from-header&2x', 0);
|
||||
verifyNumberOfResourceTimingEntries('resources/square.png?from-header&3x', 0);
|
||||
verifyNumberOfResourceTimingEntries('resources/square.png?from-header&base', 0);
|
||||
verifyNumberOfResourceTimingEntries('resources/square.png?from-header&200', 0);
|
||||
verifyNumberOfResourceTimingEntries('resources/square.png?from-header&400', 1);
|
||||
verifyNumberOfResourceTimingEntries('resources/square.png?from-header&800', 0);
|
||||
verifyNumberOfResourceTimingEntries('resources/square.png?from-header&150', 0);
|
||||
verifyNumberOfResourceTimingEntries('resources/square.png?from-header&300', 1);
|
||||
verifyNumberOfResourceTimingEntries('resources/square.png?from-header&600', 0);
|
||||
t.done();
|
||||
}));
|
||||
</script>
|
||||
|
|
|
@ -20,3 +20,9 @@ function verifyNumberOfDownloads(url, number)
|
|||
});
|
||||
assert_equals(numDownloads, number, url);
|
||||
}
|
||||
|
||||
function verifyNumberOfResourceTimingEntries(url, number)
|
||||
{
|
||||
var numEntries = performance.getEntriesByName(getAbsoluteURL(url)).length;
|
||||
assert_equals(numEntries, number, url);
|
||||
}
|
||||
|
|
|
@ -56,7 +56,8 @@ def main(product, commit_range, wpt_args):
|
|||
"--no-pause",
|
||||
"--no-restart-on-unexpected",
|
||||
"--install-fonts",
|
||||
"--no-headless"
|
||||
"--no-headless",
|
||||
"--verify-log-full"
|
||||
]
|
||||
wpt_args += browser_specific_args.get(product, [])
|
||||
|
||||
|
|
|
@ -66,9 +66,13 @@ WORKDIR /home/test
|
|||
RUN sudo echo ""
|
||||
|
||||
RUN mkdir -p /home/test/artifacts
|
||||
RUN mkdir -p /home/test/bin
|
||||
|
||||
ENV PATH="/home/test/bin:${PATH}"
|
||||
|
||||
WORKDIR /home/test/
|
||||
|
||||
COPY .bashrc /home/test/.bashrc
|
||||
|
||||
COPY start.sh /home/test/start.sh
|
||||
COPY retry.py /home/test/bin/retry
|
||||
|
|
58
tests/wpt/web-platform-tests/tools/docker/retry.py
Executable file
58
tests/wpt/web-platform-tests/tools/docker/retry.py
Executable file
|
@ -0,0 +1,58 @@
|
|||
#! /usr/bin/env python
|
||||
import argparse
|
||||
import subprocess
|
||||
import time
|
||||
import sys
|
||||
|
||||
|
||||
def get_args():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--delay", action="store", type=float, default=3, help="Initial delay before retry, in seconds")
|
||||
parser.add_argument("--count", action="store", type=int, default=5, help="Total number of tries")
|
||||
parser.add_argument("--factor", action="store", type=float, default=2, help="Exponential backoff factor")
|
||||
parser.add_argument("cmd", nargs=argparse.REMAINDER)
|
||||
return parser
|
||||
|
||||
|
||||
def iter_range(n):
|
||||
i = 0
|
||||
while i < n:
|
||||
yield i
|
||||
i += 1
|
||||
|
||||
|
||||
def main():
|
||||
args = get_args().parse_args()
|
||||
|
||||
if not args.cmd:
|
||||
print("No command supplied")
|
||||
sys.exit(1)
|
||||
|
||||
retcode = None
|
||||
|
||||
for n in iter_range(args.count):
|
||||
try:
|
||||
print("Running %s [try %d/%d]" % (" ".join(args.cmd), (n+1), args.count))
|
||||
subprocess.check_call(args.cmd)
|
||||
except subprocess.CalledProcessError as e:
|
||||
retcode = e.returncode
|
||||
else:
|
||||
print("Command succeeded")
|
||||
retcode = 0
|
||||
break
|
||||
|
||||
if args.factor == 0:
|
||||
wait_time = (n+1) * args.delay
|
||||
else:
|
||||
wait_time = args.factor**n * args.delay
|
||||
if n < args.count - 1:
|
||||
print("Command failed, waiting %s seconds to retry" % wait_time)
|
||||
time.sleep(wait_time)
|
||||
else:
|
||||
print("Command failed, out of retries")
|
||||
|
||||
sys.exit(retcode)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -26,13 +26,13 @@ git init
|
|||
git remote add origin ${REMOTE}
|
||||
|
||||
# Initially we just fetch 50 commits in order to save several minutes of fetching
|
||||
git fetch --quiet --depth=50 --tags origin ${REF}
|
||||
retry git fetch --quiet --depth=50 --tags origin ${REF}
|
||||
|
||||
if [[ ! `git rev-parse --verify -q ${REVISION}` ]];
|
||||
then
|
||||
# But if for some reason the commit under test isn't in that range, we give in and
|
||||
# fetch everything
|
||||
git fetch -q --unshallow ${REMOTE}
|
||||
retry git fetch -q --unshallow ${REMOTE}
|
||||
git rev-parse --verify ${REVISION}
|
||||
fi
|
||||
git checkout -b build ${REVISION}
|
||||
|
|
|
@ -82,7 +82,7 @@ def browser_kwargs(test_type, run_info_data, config, **kwargs):
|
|||
"timeout_multiplier": get_timeout_multiplier(test_type,
|
||||
run_info_data,
|
||||
**kwargs),
|
||||
"leak_check": kwargs["leak_check"],
|
||||
"leak_check": run_info_data["debug"] and (kwargs["leak_check"] is not False),
|
||||
"asan": run_info_data.get("asan"),
|
||||
"stylo_threads": kwargs["stylo_threads"],
|
||||
"chaos_mode_flags": kwargs["chaos_mode_flags"],
|
||||
|
@ -214,6 +214,8 @@ class FirefoxBrowser(Browser):
|
|||
self.lsan_dir = lsan_dir
|
||||
self.lsan_allowed = None
|
||||
self.lsan_max_stack_depth = None
|
||||
self.mozleak_allowed = None
|
||||
self.mozleak_thresholds = None
|
||||
self.leak_check = leak_check
|
||||
self.leak_report_file = None
|
||||
self.lsan_handler = None
|
||||
|
@ -222,21 +224,27 @@ class FirefoxBrowser(Browser):
|
|||
self.headless = headless
|
||||
|
||||
def settings(self, test):
|
||||
self.lsan_allowed = test.lsan_allowed
|
||||
self.lsan_max_stack_depth = test.lsan_max_stack_depth
|
||||
return {"check_leaks": self.leak_check and not test.leaks,
|
||||
"lsan_allowed": test.lsan_allowed}
|
||||
"lsan_allowed": test.lsan_allowed,
|
||||
"lsan_max_stack_depth": test.lsan_max_stack_depth,
|
||||
"mozleak_allowed": self.leak_check and test.mozleak_allowed,
|
||||
"mozleak_thresholds": self.leak_check and test.mozleak_threshold}
|
||||
|
||||
def start(self, group_metadata=None, **kwargs):
|
||||
if group_metadata is None:
|
||||
group_metadata = {}
|
||||
|
||||
self.group_metadata = group_metadata
|
||||
self.lsan_allowed = kwargs.get("lsan_allowed")
|
||||
self.lsan_max_stack_depth = kwargs.get("lsan_max_stack_depth")
|
||||
self.mozleak_allowed = kwargs.get("mozleak_allowed")
|
||||
self.mozleak_thresholds = kwargs.get("mozleak_thresholds")
|
||||
|
||||
if self.marionette_port is None:
|
||||
self.marionette_port = get_free_port(2828, exclude=self.used_ports)
|
||||
self.used_ports.add(self.marionette_port)
|
||||
|
||||
if self.asan:
|
||||
print "Setting up LSAN"
|
||||
self.lsan_handler = mozleak.LSANLeaks(self.logger,
|
||||
scope=group_metadata.get("scope", "/"),
|
||||
allowed=self.lsan_allowed,
|
||||
|
@ -357,21 +365,18 @@ class FirefoxBrowser(Browser):
|
|||
self.logger.debug("stopped")
|
||||
|
||||
def process_leaks(self):
|
||||
self.logger.debug("PROCESS LEAKS %s" % self.leak_report_file)
|
||||
self.logger.info("PROCESS LEAKS %s" % self.leak_report_file)
|
||||
if self.lsan_handler:
|
||||
self.lsan_handler.process()
|
||||
if self.leak_report_file is not None:
|
||||
mozleak.process_leak_log(
|
||||
self.leak_report_file,
|
||||
leak_thresholds={
|
||||
"default": 0,
|
||||
"tab": 10000, # See dependencies of bug 1051230.
|
||||
# GMP rarely gets a log, but when it does, it leaks a little.
|
||||
"geckomediaplugin": 20000,
|
||||
},
|
||||
ignore_missing_leaks=["geckomediaplugin"],
|
||||
leak_thresholds=self.mozleak_thresholds,
|
||||
ignore_missing_leaks=["gmplugin"],
|
||||
log=self.logger,
|
||||
stack_fixer=self.stack_fixer
|
||||
stack_fixer=self.stack_fixer,
|
||||
scope=self.group_metadata.get("scope"),
|
||||
allowed=self.mozleak_allowed
|
||||
)
|
||||
|
||||
def pid(self):
|
||||
|
|
|
@ -595,6 +595,7 @@ class ExecuteAsyncScriptRun(object):
|
|||
if self.protocol.is_alive:
|
||||
self.result = False, ("INTERNAL-ERROR", None)
|
||||
else:
|
||||
self.logger.info("Browser not responding, setting status to CRASH")
|
||||
self.result = False, ("CRASH", None)
|
||||
return self.result
|
||||
|
||||
|
@ -608,15 +609,21 @@ class ExecuteAsyncScriptRun(object):
|
|||
# This can happen on a crash
|
||||
# Also, should check after the test if the firefox process is still running
|
||||
# and otherwise ignore any other result and set it to crash
|
||||
self.logger.info("IOError on command, setting status to CRASH")
|
||||
self.result = False, ("CRASH", None)
|
||||
except errors.NoSuchWindowException:
|
||||
self.logger.info("NoSuchWindowException on command, setting status to CRASH")
|
||||
self.result = False, ("CRASH", None)
|
||||
except Exception as e:
|
||||
if isinstance(e, errors.JavascriptException) and e.message.startswith("Document was unloaded"):
|
||||
message = "Document unloaded; maybe test navigated the top-level-browsing context?"
|
||||
else:
|
||||
message = getattr(e, "message", "")
|
||||
if message:
|
||||
message += "\n"
|
||||
message += traceback.format_exc(e)
|
||||
self.logger.warning(message)
|
||||
self.result = False, ("INTERNAL-ERROR", None)
|
||||
|
||||
self.logger.warning(traceback.format_exc())
|
||||
self.result = False, ("INTERNAL-ERROR", message)
|
||||
finally:
|
||||
self.result_flag.set()
|
||||
|
||||
|
|
|
@ -123,3 +123,32 @@ class WptreportFormatter(BaseFormatter):
|
|||
"min": data["min_expected"],
|
||||
"max": data["max_expected"]
|
||||
}
|
||||
|
||||
def lsan_leak(self, data):
|
||||
if "lsan_leaks" not in self.results:
|
||||
self.results["lsan_leaks"] = []
|
||||
lsan_leaks = self.results["lsan_leaks"]
|
||||
lsan_leaks.append({"frames": data["frames"],
|
||||
"scope": data["scope"],
|
||||
"allowed_match": data.get("allowed_match")})
|
||||
|
||||
def find_or_create_mozleak(self, data):
|
||||
if "mozleak" not in self.results:
|
||||
self.results["mozleak"] = {}
|
||||
scope = data["scope"]
|
||||
if scope not in self.results["mozleak"]:
|
||||
self.results["mozleak"][scope] = {"objects": [], "total": []}
|
||||
return self.results["mozleak"][scope]
|
||||
|
||||
def mozleak_object(self, data):
|
||||
scope_data = self.find_or_create_mozleak(data)
|
||||
scope_data["objects"].append({"process": data["process"],
|
||||
"name": data["name"],
|
||||
"allowed": data.get("allowed", False),
|
||||
"bytes": data["bytes"]})
|
||||
|
||||
def mozleak_total(self, data):
|
||||
scope_data = self.find_or_create_mozleak(data)
|
||||
scope_data["total"].append({"bytes": data["bytes"],
|
||||
"threshold": data.get("threshold", 0),
|
||||
"process": data["process"]})
|
||||
|
|
|
@ -70,9 +70,9 @@ def prefs(node):
|
|||
return rv
|
||||
|
||||
|
||||
def lsan_allowed(node):
|
||||
def set_prop(name, node):
|
||||
try:
|
||||
node_items = node.get("lsan-allowed")
|
||||
node_items = node.get(name)
|
||||
if isinstance(node_items, (str, unicode)):
|
||||
rv = {node_items}
|
||||
else:
|
||||
|
@ -82,6 +82,20 @@ def lsan_allowed(node):
|
|||
return rv
|
||||
|
||||
|
||||
def leak_threshold(node):
|
||||
rv = {}
|
||||
try:
|
||||
node_items = node.get("leak-threshold")
|
||||
if isinstance(node_items, (str, unicode)):
|
||||
node_items = [node_items]
|
||||
for item in node_items:
|
||||
process, value = item.rsplit(":", 1)
|
||||
rv[process.strip()] = int(value.strip())
|
||||
except KeyError:
|
||||
pass
|
||||
return rv
|
||||
|
||||
|
||||
class ExpectedManifest(ManifestItem):
|
||||
def __init__(self, name, test_path, url_base):
|
||||
"""Object representing all the tests in a particular manifest
|
||||
|
@ -154,7 +168,15 @@ class ExpectedManifest(ManifestItem):
|
|||
|
||||
@property
|
||||
def lsan_allowed(self):
|
||||
return lsan_allowed(self)
|
||||
return set_prop("lsan-allowed", self)
|
||||
|
||||
@property
|
||||
def leak_allowed(self):
|
||||
return set_prop("leak-allowed", self)
|
||||
|
||||
@property
|
||||
def leak_threshold(self):
|
||||
return leak_threshold(self)
|
||||
|
||||
@property
|
||||
def lsan_max_stack_depth(self):
|
||||
|
@ -192,7 +214,15 @@ class DirectoryManifest(ManifestItem):
|
|||
|
||||
@property
|
||||
def lsan_allowed(self):
|
||||
return lsan_allowed(self)
|
||||
return set_prop("lsan-allowed", self)
|
||||
|
||||
@property
|
||||
def leak_allowed(self):
|
||||
return set_prop("leak-allowed", self)
|
||||
|
||||
@property
|
||||
def leak_threshold(self):
|
||||
return leak_threshold(self)
|
||||
|
||||
@property
|
||||
def lsan_max_stack_depth(self):
|
||||
|
@ -256,7 +286,15 @@ class TestNode(ManifestItem):
|
|||
|
||||
@property
|
||||
def lsan_allowed(self):
|
||||
return lsan_allowed(self)
|
||||
return set_prop("lsan-allowed", self)
|
||||
|
||||
@property
|
||||
def leak_allowed(self):
|
||||
return set_prop("leak-allowed", self)
|
||||
|
||||
@property
|
||||
def leak_threshold(self):
|
||||
return leak_threshold(self)
|
||||
|
||||
@property
|
||||
def lsan_max_stack_depth(self):
|
||||
|
|
|
@ -2,6 +2,7 @@ import itertools
|
|||
import os
|
||||
import urlparse
|
||||
from collections import namedtuple, defaultdict
|
||||
from math import ceil
|
||||
|
||||
from wptmanifest.node import (DataNode, ConditionalNode, BinaryExpressionNode,
|
||||
BinaryOperatorNode, VariableNode, StringNode, NumberNode,
|
||||
|
@ -81,6 +82,8 @@ class ExpectedManifest(ManifestItem):
|
|||
self.property_order = property_order
|
||||
self.update_properties = {
|
||||
"lsan": LsanUpdate(self),
|
||||
"leak-object": LeakObjectUpdate(self),
|
||||
"leak-threshold": LeakThresholdUpdate(self),
|
||||
}
|
||||
|
||||
def append(self, child):
|
||||
|
@ -122,6 +125,24 @@ class ExpectedManifest(ManifestItem):
|
|||
|
||||
self.update_properties["lsan"].set(run_info, result)
|
||||
|
||||
def set_leak_object(self, run_info, result):
|
||||
"""Set the result of the test in a particular run
|
||||
|
||||
:param run_info: Dictionary of run_info parameters corresponding
|
||||
to this run
|
||||
:param result: Leaked objects deletec"""
|
||||
|
||||
self.update_properties["leak-object"].set(run_info, result)
|
||||
|
||||
def set_leak_threshold(self, run_info, result):
|
||||
"""Set the result of the test in a particular run
|
||||
|
||||
:param run_info: Dictionary of run_info parameters corresponding
|
||||
to this run
|
||||
:param result: Total number of bytes leaked"""
|
||||
|
||||
self.update_properties["leak-threshold"].set(run_info, result)
|
||||
|
||||
def coalesce_properties(self, stability):
|
||||
for prop_update in self.update_properties.itervalues():
|
||||
prop_update.coalesce(stability)
|
||||
|
@ -432,6 +453,10 @@ class ExpectedUpdate(PropertyUpdate):
|
|||
|
||||
|
||||
class MaxAssertsUpdate(PropertyUpdate):
|
||||
"""For asserts we always update the default value and never add new conditionals.
|
||||
The value we set as the default is the maximum the current default or one more than the
|
||||
number of asserts we saw in any configuration."""
|
||||
|
||||
property_name = "max-asserts"
|
||||
cls_default_value = 0
|
||||
value_type = int
|
||||
|
@ -447,9 +472,6 @@ class MaxAssertsUpdate(PropertyUpdate):
|
|||
return old_value
|
||||
|
||||
def update_default(self):
|
||||
"""For asserts we always update the default value and never add new conditionals.
|
||||
The value we set as the default is the maximum the current default or one more than the
|
||||
number of asserts we saw in any configuration."""
|
||||
# Current values
|
||||
values = []
|
||||
current_default = None
|
||||
|
@ -501,20 +523,11 @@ class MinAssertsUpdate(PropertyUpdate):
|
|||
return True, new_value
|
||||
|
||||
|
||||
class LsanUpdate(PropertyUpdate):
|
||||
property_name = "lsan-allowed"
|
||||
class AppendOnlyListUpdate(PropertyUpdate):
|
||||
cls_default_value = None
|
||||
|
||||
def get_value(self, result):
|
||||
# If we have an allowed_match that matched, return None
|
||||
# This value is ignored later (because it matches the default)
|
||||
# We do that because then if we allow a failure in foo/__dir__.ini
|
||||
# we don't want to update foo/bar/__dir__.ini with the same rule
|
||||
if result[1]:
|
||||
return None
|
||||
# Otherwise return the topmost stack frame
|
||||
# TODO: there is probably some improvement to be made by looking for a "better" stack frame
|
||||
return result[0][0]
|
||||
raise NotImplementedError
|
||||
|
||||
def update_value(self, old_value, new_value):
|
||||
if isinstance(new_value, (str, unicode)):
|
||||
|
@ -539,6 +552,96 @@ class LsanUpdate(PropertyUpdate):
|
|||
return True, new_value if new_value else None
|
||||
|
||||
|
||||
class LsanUpdate(AppendOnlyListUpdate):
|
||||
property_name = "lsan-allowed"
|
||||
|
||||
def get_value(self, result):
|
||||
# If we have an allowed_match that matched, return None
|
||||
# This value is ignored later (because it matches the default)
|
||||
# We do that because then if we allow a failure in foo/__dir__.ini
|
||||
# we don't want to update foo/bar/__dir__.ini with the same rule
|
||||
if result[1]:
|
||||
return None
|
||||
# Otherwise return the topmost stack frame
|
||||
# TODO: there is probably some improvement to be made by looking for a "better" stack frame
|
||||
return result[0][0]
|
||||
|
||||
|
||||
class LeakObjectUpdate(AppendOnlyListUpdate):
|
||||
property_name = "leak-allowed"
|
||||
|
||||
def get_value(self, result):
|
||||
# If we have an allowed_match that matched, return None
|
||||
if result[1]:
|
||||
return None
|
||||
# Otherwise return the process/object name
|
||||
return result[0]
|
||||
|
||||
|
||||
class LeakThresholdUpdate(PropertyUpdate):
|
||||
property_name = "leak-threshold"
|
||||
cls_default_value = []
|
||||
|
||||
def __init__(self, node):
|
||||
PropertyUpdate.__init__(self, node)
|
||||
self.thresholds = {}
|
||||
|
||||
def get_value(self, value):
|
||||
threshold = value[2]
|
||||
key = value[0]
|
||||
self.thresholds[key] = threshold
|
||||
return value[:2]
|
||||
|
||||
def value_type(self, data):
|
||||
if all(isinstance(item, tuple) for item in data):
|
||||
return data
|
||||
values = [item.rsplit(":", 1) for item in data]
|
||||
return [(key, int(float(value))) for key, value in values]
|
||||
|
||||
def update_value(self, old_value, new_value, allow_buffer=True):
|
||||
rv = []
|
||||
old_value = dict(old_value)
|
||||
new_value = dict(self.value_type(new_value))
|
||||
for key in set(new_value.keys()) | set(old_value.keys()):
|
||||
old = old_value.get(key, 0)
|
||||
new = new_value.get(key, 0)
|
||||
threshold = self.thresholds.get(key, 0)
|
||||
# If the value is less than the threshold but there isn't
|
||||
# an old value we must have inherited the threshold from
|
||||
# a parent ini file so don't any anything to this one
|
||||
if not old and new < threshold:
|
||||
continue
|
||||
if old >= new:
|
||||
updated = old
|
||||
else:
|
||||
if allow_buffer:
|
||||
# Round up to nearest 50 kb
|
||||
boundary = 50 * 1024
|
||||
updated = int(boundary * ceil(float(new) / boundary))
|
||||
else:
|
||||
updated = new
|
||||
rv.append((key, updated))
|
||||
return ["%s:%s" % item for item in sorted(rv)]
|
||||
|
||||
def update_default(self):
|
||||
# Current values
|
||||
current_default = []
|
||||
if self.property_name in self.node._data:
|
||||
current_default = [item for item in
|
||||
self.node._data[self.property_name]
|
||||
if item.condition_node is None]
|
||||
current_default = current_default[0].value_as(self.value_type)
|
||||
max_new = {}
|
||||
for item in self.new:
|
||||
key, value = item.value
|
||||
if value > max_new.get(key, 0):
|
||||
max_new[key] = value
|
||||
new_value = self.update_value(current_default,
|
||||
max_new.items(),
|
||||
allow_buffer=False)
|
||||
return True, new_value
|
||||
|
||||
|
||||
def group_conditionals(values, property_order=None, boolean_properties=None):
|
||||
"""Given a list of Value objects, return a list of
|
||||
(conditional_node, status) pairs representing the conditional
|
||||
|
|
|
@ -289,7 +289,9 @@ class ExpectedUpdater(object):
|
|||
"test_status": self.test_status,
|
||||
"test_end": self.test_end,
|
||||
"assertion_count": self.assertion_count,
|
||||
"lsan_leak": self.lsan_leak}
|
||||
"lsan_leak": self.lsan_leak,
|
||||
"mozleak_object": self.mozleak_object,
|
||||
"mozleak_total": self.mozleak_total}
|
||||
self.tests_visited = {}
|
||||
|
||||
def update_from_log(self, log_file):
|
||||
|
@ -340,6 +342,15 @@ class ExpectedUpdater(object):
|
|||
for item in data.get("lsan_leaks", []):
|
||||
action_map["lsan_leak"](item)
|
||||
|
||||
mozleak_data = data.get("mozleak", {})
|
||||
for scope, scope_data in mozleak_data.iteritems():
|
||||
for key, action in [("objects", "mozleak_object"),
|
||||
("total", "mozleak_total")]:
|
||||
for item in scope_data.get(key, []):
|
||||
item_data = {"scope": scope}
|
||||
item_data.update(item)
|
||||
action_map[action](item_data)
|
||||
|
||||
def suite_start(self, data):
|
||||
self.run_info = run_info_intern.store(data["run_info"])
|
||||
|
||||
|
@ -397,17 +408,36 @@ class ExpectedUpdater(object):
|
|||
if data["count"] < data["min_expected"] or data["count"] > data["max_expected"]:
|
||||
test_data.set_requires_update()
|
||||
|
||||
def lsan_leak(self, data):
|
||||
def test_for_scope(self, data):
|
||||
dir_path = data.get("scope", "/")
|
||||
dir_id = intern(os.path.join(dir_path, "__dir__").replace(os.path.sep, "/").encode("utf8"))
|
||||
if dir_id.startswith("/"):
|
||||
dir_id = dir_id[1:]
|
||||
test_data = self.id_test_map[dir_id]
|
||||
return dir_id, self.id_test_map[dir_id]
|
||||
|
||||
def lsan_leak(self, data):
|
||||
dir_id, test_data = self.test_for_scope(data)
|
||||
test_data.set(dir_id, None, "lsan",
|
||||
self.run_info, (data["frames"], data.get("allowed_match")))
|
||||
if not data.get("allowed_match"):
|
||||
test_data.set_requires_update()
|
||||
|
||||
def mozleak_object(self, data):
|
||||
dir_id, test_data = self.test_for_scope(data)
|
||||
test_data.set(dir_id, None, "leak-object",
|
||||
self.run_info, ("%s:%s", (data["process"], data["name"]),
|
||||
data.get("allowed")))
|
||||
if not data.get("allowed"):
|
||||
test_data.set_requires_update()
|
||||
|
||||
def mozleak_total(self, data):
|
||||
if data["bytes"]:
|
||||
dir_id, test_data = self.test_for_scope(data)
|
||||
test_data.set(dir_id, None, "leak-threshold",
|
||||
self.run_info, (data["process"], data["bytes"], data["threshold"]))
|
||||
if data["bytes"] > data["threshold"] or data["bytes"] < 0:
|
||||
test_data.set_requires_update()
|
||||
|
||||
|
||||
def create_test_tree(metadata_path, test_manifest):
|
||||
"""Create a map of test_id to TestFileData for that test.
|
||||
|
@ -552,6 +582,10 @@ class TestFileData(object):
|
|||
if subtest_id is None and test_id.endswith("__dir__"):
|
||||
if prop == "lsan":
|
||||
expected.set_lsan(run_info, value)
|
||||
elif prop == "leak-object":
|
||||
expected.set_leak_object(run_info, value)
|
||||
elif prop == "leak-threshold":
|
||||
expected.set_leak_threshold(run_info, value)
|
||||
continue
|
||||
|
||||
if prop == "status":
|
||||
|
|
|
@ -606,3 +606,98 @@ def test_update_wptreport_1():
|
|||
|
||||
assert len(updated) == 1
|
||||
assert updated[0][1].get("lsan-allowed") == ["baz"]
|
||||
|
||||
|
||||
def test_update_leak_total_0():
|
||||
test_id = "/path/to/test.htm"
|
||||
dir_id = "path/to/__dir__"
|
||||
tests = [("path/to/test.htm", [test_id], "testharness", ""),
|
||||
("path/to/__dir__", [dir_id], None, "")]
|
||||
|
||||
log_0 = suite_log([("mozleak_total", {"scope": "path/to/",
|
||||
"process": "default",
|
||||
"bytes": 100,
|
||||
"threshold": 0,
|
||||
"objects": []})])
|
||||
|
||||
updated = update(tests, log_0)
|
||||
new_manifest = updated[0][1]
|
||||
|
||||
assert not new_manifest.is_empty
|
||||
assert new_manifest.get("leak-threshold") == ['default:51200']
|
||||
|
||||
|
||||
def test_update_leak_total_1():
|
||||
test_id = "/path/to/test.htm"
|
||||
dir_id = "path/to/__dir__"
|
||||
tests = [("path/to/test.htm", [test_id], "testharness", ""),
|
||||
("path/to/__dir__", [dir_id], None, "")]
|
||||
|
||||
log_0 = suite_log([("mozleak_total", {"scope": "path/to/",
|
||||
"process": "default",
|
||||
"bytes": 100,
|
||||
"threshold": 1000,
|
||||
"objects": []})])
|
||||
|
||||
updated = update(tests, log_0)
|
||||
assert not updated
|
||||
|
||||
|
||||
def test_update_leak_total_2():
|
||||
test_id = "/path/to/test.htm"
|
||||
dir_id = "path/to/__dir__"
|
||||
tests = [("path/to/test.htm", [test_id], "testharness", ""),
|
||||
("path/to/__dir__", [dir_id], None, """
|
||||
leak-total: 110""")]
|
||||
|
||||
log_0 = suite_log([("mozleak_total", {"scope": "path/to/",
|
||||
"process": "default",
|
||||
"bytes": 100,
|
||||
"threshold": 110,
|
||||
"objects": []})])
|
||||
|
||||
updated = update(tests, log_0)
|
||||
assert not updated
|
||||
|
||||
|
||||
def test_update_leak_total_3():
|
||||
test_id = "/path/to/test.htm"
|
||||
dir_id = "path/to/__dir__"
|
||||
tests = [("path/to/test.htm", [test_id], "testharness", ""),
|
||||
("path/to/__dir__", [dir_id], None, """
|
||||
leak-total: 100""")]
|
||||
|
||||
log_0 = suite_log([("mozleak_total", {"scope": "path/to/",
|
||||
"process": "default",
|
||||
"bytes": 1000,
|
||||
"threshold": 100,
|
||||
"objects": []})])
|
||||
|
||||
updated = update(tests, log_0)
|
||||
new_manifest = updated[0][1]
|
||||
|
||||
assert not new_manifest.is_empty
|
||||
assert new_manifest.get("leak-threshold") == ['default:51200']
|
||||
|
||||
|
||||
def test_update_leak_total_4():
|
||||
test_id = "/path/to/test.htm"
|
||||
dir_id = "path/to/__dir__"
|
||||
tests = [("path/to/test.htm", [test_id], "testharness", ""),
|
||||
("path/to/__dir__", [dir_id], None, """
|
||||
leak-total: 110""")]
|
||||
|
||||
log_0 = suite_log([
|
||||
("lsan_leak", {"scope": "path/to/",
|
||||
"frames": ["foo", "bar"]}),
|
||||
("mozleak_total", {"scope": "path/to/",
|
||||
"process": "default",
|
||||
"bytes": 100,
|
||||
"threshold": 110,
|
||||
"objects": []})])
|
||||
|
||||
updated = update(tests, log_0)
|
||||
new_manifest = updated[0][1]
|
||||
|
||||
assert not new_manifest.is_empty
|
||||
assert new_manifest.has_key("leak-threshold") is False
|
||||
|
|
|
@ -261,8 +261,11 @@ scheme host and port.""")
|
|||
gecko_group.add_argument("--setpref", dest="extra_prefs", action='append',
|
||||
default=[], metavar="PREF=VALUE",
|
||||
help="Defines an extra user preference (overrides those in prefs_root)")
|
||||
gecko_group.add_argument("--leak-check", dest="leak_check", action="store_true",
|
||||
help="Enable leak checking")
|
||||
gecko_group.add_argument("--leak-check", dest="leak_check", action="store_true", default=None,
|
||||
help="Enable leak checking (enabled by default for debug builds, "
|
||||
"silently ignored for opt)")
|
||||
gecko_group.add_argument("--no-leak-check", dest="leak_check", action="store_false", default=None,
|
||||
help="Disable leak checking")
|
||||
gecko_group.add_argument("--stylo-threads", action="store", type=int, default=1,
|
||||
help="Number of parallel threads to use for stylo")
|
||||
gecko_group.add_argument("--reftest-internal", dest="reftest_internal", action="store_true",
|
||||
|
@ -270,7 +273,7 @@ scheme host and port.""")
|
|||
gecko_group.add_argument("--reftest-external", dest="reftest_internal", action="store_false",
|
||||
help="Disable reftest runner implemented inside Marionette")
|
||||
gecko_group.add_argument("--reftest-screenshot", dest="reftest_screenshot", action="store",
|
||||
choices=["always", "fail", "unexpected"], default="unexpected",
|
||||
choices=["always", "fail", "unexpected"], default=None,
|
||||
help="With --reftest-internal, when to take a screenshot")
|
||||
gecko_group.add_argument("--chaos", dest="chaos_mode_flags", action="store",
|
||||
nargs="?", const=0xFFFFFFFF, type=int,
|
||||
|
@ -532,6 +535,9 @@ def check_args(kwargs):
|
|||
if kwargs["lsan_dir"] is None:
|
||||
kwargs["lsan_dir"] = kwargs["prefs_root"]
|
||||
|
||||
if kwargs["reftest_screenshot"] is None:
|
||||
kwargs["reftest_screenshot"] = "unexpected"
|
||||
|
||||
return kwargs
|
||||
|
||||
|
||||
|
|
|
@ -242,6 +242,26 @@ class Test(object):
|
|||
return depth
|
||||
return None
|
||||
|
||||
@property
|
||||
def mozleak_allowed(self):
|
||||
mozleak_allowed = set()
|
||||
for meta in self.itermeta():
|
||||
mozleak_allowed |= meta.leak_allowed
|
||||
if atom_reset in mozleak_allowed:
|
||||
mozleak_allowed.remove(atom_reset)
|
||||
break
|
||||
return mozleak_allowed
|
||||
|
||||
@property
|
||||
def mozleak_threshold(self):
|
||||
rv = {}
|
||||
for meta in self.itermeta(None):
|
||||
threshold = meta.leak_threshold
|
||||
for key, value in threshold.iteritems():
|
||||
if key not in rv:
|
||||
rv[key] = value
|
||||
return rv
|
||||
|
||||
@property
|
||||
def tags(self):
|
||||
tags = set()
|
||||
|
|
|
@ -28,6 +28,7 @@ var kWasmV3 = 0;
|
|||
|
||||
var kHeaderSize = 8;
|
||||
var kPageSize = 65536;
|
||||
var kSpecMaxPages = 65535;
|
||||
|
||||
function bytesWithHeader() {
|
||||
var buffer = new ArrayBuffer(kHeaderSize + arguments.length);
|
||||
|
@ -63,7 +64,6 @@ let kStartSectionCode = 8; // Start function declaration
|
|||
let kElementSectionCode = 9; // Elements section
|
||||
let kCodeSectionCode = 10; // Function code
|
||||
let kDataSectionCode = 11; // Data segments
|
||||
let kNameSectionCode = 12; // Name section (encoded as string)
|
||||
|
||||
// Name section types
|
||||
let kModuleNameCode = 0;
|
||||
|
@ -74,6 +74,7 @@ let kWasmFunctionTypeForm = 0x60;
|
|||
let kWasmAnyFunctionTypeForm = 0x70;
|
||||
|
||||
let kHasMaximumFlag = 1;
|
||||
let kResizableMaximumFlag = 1;
|
||||
|
||||
// Function declaration flags
|
||||
let kDeclFunctionName = 0x01;
|
||||
|
@ -87,6 +88,7 @@ let kWasmI32 = 0x7f;
|
|||
let kWasmI64 = 0x7e;
|
||||
let kWasmF32 = 0x7d;
|
||||
let kWasmF64 = 0x7c;
|
||||
let kWasmS128 = 0x7b;
|
||||
|
||||
let kExternalFunction = 0;
|
||||
let kExternalTable = 1;
|
||||
|
@ -102,6 +104,8 @@ let kSig_l_l = makeSig([kWasmI64], [kWasmI64]);
|
|||
let kSig_i_l = makeSig([kWasmI64], [kWasmI32]);
|
||||
let kSig_i_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32]);
|
||||
let kSig_i_iii = makeSig([kWasmI32, kWasmI32, kWasmI32], [kWasmI32]);
|
||||
let kSig_v_iiii = makeSig([kWasmI32, kWasmI32, kWasmI32, kWasmI32], []);
|
||||
let kSig_f_ff = makeSig([kWasmF32, kWasmF32], [kWasmF32]);
|
||||
let kSig_d_dd = makeSig([kWasmF64, kWasmF64], [kWasmF64]);
|
||||
let kSig_l_ll = makeSig([kWasmI64, kWasmI64], [kWasmI64]);
|
||||
let kSig_i_dd = makeSig([kWasmF64, kWasmF64], [kWasmI32]);
|
||||
|
@ -118,6 +122,11 @@ let kSig_v_d = makeSig([kWasmF64], []);
|
|||
let kSig_v_dd = makeSig([kWasmF64, kWasmF64], []);
|
||||
let kSig_v_ddi = makeSig([kWasmF64, kWasmF64, kWasmI32], []);
|
||||
|
||||
let kSig_v_f = makeSig([kWasmF32], []);
|
||||
let kSig_f_f = makeSig([kWasmF32], [kWasmF32]);
|
||||
let kSig_f_d = makeSig([kWasmF64], [kWasmF32]);
|
||||
let kSig_d_d = makeSig([kWasmF64], [kWasmF64]);
|
||||
|
||||
function makeSig(params, results) {
|
||||
return {params: params, results: results};
|
||||
}
|
||||
|
@ -357,19 +366,19 @@ function assertTraps(trap, code) {
|
|||
throw new MjsUnitAssertionError('Did not trap, expected: ' + kTrapMsgs[trap]);
|
||||
}
|
||||
|
||||
function assertWasmThrows(value, code) {
|
||||
assertEquals('number', typeof value);
|
||||
try {
|
||||
if (typeof code === 'function') {
|
||||
code();
|
||||
} else {
|
||||
eval(code);
|
||||
function wasmI32Const(val) {
|
||||
let bytes = [kExprI32Const];
|
||||
for (let i = 0; i < 4; ++i) {
|
||||
bytes.push(0x80 | ((val >> (7 * i)) & 0x7f));
|
||||
}
|
||||
} catch (e) {
|
||||
assertEquals('number', typeof e);
|
||||
assertEquals(value, e);
|
||||
// Success.
|
||||
return;
|
||||
bytes.push((val >> (7 * 4)) & 0x7f);
|
||||
return bytes;
|
||||
}
|
||||
throw new MjsUnitAssertionError('Did not throw, expected: ' + value);
|
||||
|
||||
function wasmF32Const(f) {
|
||||
return [kExprF32Const].concat(Array.from(new Uint8Array((new Float32Array([f])).buffer)));
|
||||
}
|
||||
|
||||
function wasmF64Const(f) {
|
||||
return [kExprF64Const].concat(Array.from(new Uint8Array((new Float64Array([f])).buffer)));
|
||||
}
|
||||
|
|
|
@ -69,14 +69,13 @@ class Binary extends Array {
|
|||
// Emit section name.
|
||||
this.emit_u8(section_code);
|
||||
// Emit the section to a temporary buffer: its full length isn't know yet.
|
||||
const section = new Binary;
|
||||
let section = new Binary;
|
||||
content_generator(section);
|
||||
// Emit section length.
|
||||
this.emit_u32v(section.length);
|
||||
// Copy the temporary buffer.
|
||||
for (const b of section) {
|
||||
this.push(b);
|
||||
}
|
||||
// Avoid spread because {section} can be huge.
|
||||
for (let b of section) this.push(b);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,15 +87,6 @@ class WasmFunctionBuilder {
|
|||
this.body = [];
|
||||
}
|
||||
|
||||
numLocalNames() {
|
||||
if (this.local_names === undefined) return 0;
|
||||
let num_local_names = 0;
|
||||
for (let loc_name of this.local_names) {
|
||||
if (loc_name !== undefined) ++num_local_names;
|
||||
}
|
||||
return num_local_names;
|
||||
}
|
||||
|
||||
exportAs(name) {
|
||||
this.module.addExport(name, this.index);
|
||||
return this;
|
||||
|
@ -108,40 +98,12 @@ class WasmFunctionBuilder {
|
|||
}
|
||||
|
||||
addBody(body) {
|
||||
for (let b of body) {
|
||||
if (typeof b !== 'number' || (b & (~0xFF)) !== 0 )
|
||||
throw new Error('invalid body (entries must be 8 bit numbers): ' + body);
|
||||
}
|
||||
this.body = body.slice();
|
||||
// Automatically add the end for the function block to the body.
|
||||
this.body.push(kExprEnd);
|
||||
return this;
|
||||
}
|
||||
|
||||
addBodyWithEnd(body) {
|
||||
this.body = body;
|
||||
return this;
|
||||
}
|
||||
|
||||
getNumLocals() {
|
||||
let total_locals = 0;
|
||||
for (let l of this.locals || []) {
|
||||
for (let type of ["i32", "i64", "f32", "f64"]) {
|
||||
total_locals += l[type + "_count"] || 0;
|
||||
}
|
||||
}
|
||||
return total_locals;
|
||||
}
|
||||
|
||||
addLocals(locals, names) {
|
||||
const old_num_locals = this.getNumLocals();
|
||||
if (!this.locals) this.locals = []
|
||||
this.locals.push(locals);
|
||||
if (names) {
|
||||
if (!this.local_names) this.local_names = [];
|
||||
const missing_names = old_num_locals - this.local_names.length;
|
||||
this.local_names.push(...new Array(missing_names), ...names);
|
||||
}
|
||||
addLocals(locals) {
|
||||
this.locals = locals;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -176,6 +138,7 @@ class WasmModuleBuilder {
|
|||
this.table_length_max = undefined;
|
||||
this.element_segments = [];
|
||||
this.data_segments = [];
|
||||
this.segments = [];
|
||||
this.explicit = [];
|
||||
this.num_imported_funcs = 0;
|
||||
this.num_imported_globals = 0;
|
||||
|
@ -197,22 +160,6 @@ class WasmModuleBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
stringToBytes(name) {
|
||||
var result = new Binary();
|
||||
result.emit_u32v(name.length);
|
||||
for (var i = 0; i < name.length; i++) {
|
||||
result.emit_u8(name.charCodeAt(i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
addCustomSection(name, bytes) {
|
||||
name = this.stringToBytes(name);
|
||||
var length = new Binary();
|
||||
length.emit_u32v(name.length + bytes.length);
|
||||
this.explicit.push([0, ...length, ...name, ...bytes]);
|
||||
}
|
||||
|
||||
addType(type) {
|
||||
// TODO: canonicalize types?
|
||||
this.types.push(type);
|
||||
|
@ -235,21 +182,15 @@ class WasmModuleBuilder {
|
|||
}
|
||||
|
||||
addImport(module = "", name, type) {
|
||||
if (this.functions.length != 0) {
|
||||
throw new Error('Imported functions must be declared before local ones');
|
||||
}
|
||||
let type_index = (typeof type) == "number" ? type : this.addType(type);
|
||||
this.imports.push({module: module, name: name, kind: kExternalFunction,
|
||||
type: type_index});
|
||||
return this.num_imported_funcs++;
|
||||
}
|
||||
|
||||
addImportedGlobal(module = "", name, type, mutable = false) {
|
||||
if (this.globals.length != 0) {
|
||||
throw new Error('Imported globals must be declared before local ones');
|
||||
}
|
||||
addImportedGlobal(module = "", name, type) {
|
||||
let o = {module: module, name: name, kind: kExternalGlobal, type: type,
|
||||
mutable: mutable};
|
||||
mutable: false}
|
||||
this.imports.push(o);
|
||||
return this.num_imported_globals++;
|
||||
}
|
||||
|
@ -278,7 +219,8 @@ class WasmModuleBuilder {
|
|||
}
|
||||
|
||||
addDataSegment(addr, data, is_global = false) {
|
||||
this.data_segments.push({addr: addr, data: data, is_global: is_global});
|
||||
this.data_segments.push(
|
||||
{addr: addr, data: data, is_global: is_global});
|
||||
return this.data_segments.length - 1;
|
||||
}
|
||||
|
||||
|
@ -309,21 +251,15 @@ class WasmModuleBuilder {
|
|||
return this.addElementSegment(this.table_length_min, false, array);
|
||||
}
|
||||
|
||||
setTableBounds(min, max) {
|
||||
setTableBounds(min, max = undefined) {
|
||||
this.table_length_min = min;
|
||||
this.table_length_max = max;
|
||||
return this;
|
||||
}
|
||||
|
||||
setTableLength(length) {
|
||||
this.table_length_min = length;
|
||||
this.table_length_max = length;
|
||||
return this;
|
||||
}
|
||||
|
||||
setName(name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
// TODO(ssauleau): legacy, remove this
|
||||
setFunctionTableLength(length) {
|
||||
return this.setTableBounds(length);
|
||||
}
|
||||
|
||||
toArray(debug = false) {
|
||||
|
@ -385,11 +321,15 @@ class WasmModuleBuilder {
|
|||
}
|
||||
|
||||
// Add functions declarations
|
||||
let has_names = false;
|
||||
let names = false;
|
||||
if (wasm.functions.length > 0) {
|
||||
if (debug) print("emitting function decls @ " + binary.length);
|
||||
binary.emit_section(kFunctionSectionCode, section => {
|
||||
section.emit_u32v(wasm.functions.length);
|
||||
for (let func of wasm.functions) {
|
||||
has_names = has_names || (func.name != undefined &&
|
||||
func.name.length > 0);
|
||||
section.emit_u32v(func.type_index);
|
||||
}
|
||||
});
|
||||
|
@ -415,7 +355,7 @@ class WasmModuleBuilder {
|
|||
binary.emit_section(kMemorySectionCode, section => {
|
||||
section.emit_u8(1); // one memory entry
|
||||
const has_max = wasm.memory.max !== undefined;
|
||||
section.emit_u8(has_max ? kHasMaximumFlag : 0);
|
||||
section.emit_u8(has_max ? 1 : 0);
|
||||
section.emit_u32v(wasm.memory.min);
|
||||
if (has_max) section.emit_u32v(wasm.memory.max);
|
||||
});
|
||||
|
@ -438,7 +378,7 @@ class WasmModuleBuilder {
|
|||
break;
|
||||
case kWasmI64:
|
||||
section.emit_u8(kExprI64Const);
|
||||
section.emit_u32v(global.init);
|
||||
section.emit_u8(global.init);
|
||||
break;
|
||||
case kWasmF32:
|
||||
section.emit_u8(kExprF32Const);
|
||||
|
@ -492,7 +432,7 @@ class WasmModuleBuilder {
|
|||
}
|
||||
|
||||
// Add start function section.
|
||||
if (wasm.start_index !== undefined) {
|
||||
if (wasm.start_index != undefined) {
|
||||
if (debug) print("emitting start function @ " + binary.length);
|
||||
binary.emit_section(kStartSectionCode, section => {
|
||||
section.emit_u32v(wasm.start_index);
|
||||
|
@ -507,7 +447,7 @@ class WasmModuleBuilder {
|
|||
section.emit_u32v(inits.length);
|
||||
|
||||
for (let init of inits) {
|
||||
section.emit_u8(0); // table index
|
||||
section.emit_u8(0); // table index / flags
|
||||
if (init.is_global) {
|
||||
section.emit_u8(kExprGetGlobal);
|
||||
} else {
|
||||
|
@ -532,7 +472,9 @@ class WasmModuleBuilder {
|
|||
for (let func of wasm.functions) {
|
||||
// Function body length will be patched later.
|
||||
let local_decls = [];
|
||||
for (let l of func.locals || []) {
|
||||
let l = func.locals;
|
||||
if (l != undefined) {
|
||||
let local_decls_count = 0;
|
||||
if (l.i32_count > 0) {
|
||||
local_decls.push({count: l.i32_count, type: kWasmI32});
|
||||
}
|
||||
|
@ -567,7 +509,7 @@ class WasmModuleBuilder {
|
|||
binary.emit_section(kDataSectionCode, section => {
|
||||
section.emit_u32v(wasm.data_segments.length);
|
||||
for (let seg of wasm.data_segments) {
|
||||
section.emit_u8(0); // linear memory index 0
|
||||
section.emit_u8(0); // linear memory index 0 / flags
|
||||
if (seg.is_global) {
|
||||
// initializer is a global variable
|
||||
section.emit_u8(kExprGetGlobal);
|
||||
|
@ -590,50 +532,21 @@ class WasmModuleBuilder {
|
|||
binary.emit_bytes(exp);
|
||||
}
|
||||
|
||||
// Add names.
|
||||
let num_function_names = 0;
|
||||
let num_functions_with_local_names = 0;
|
||||
for (let func of wasm.functions) {
|
||||
if (func.name !== undefined) ++num_function_names;
|
||||
if (func.numLocalNames() > 0) ++num_functions_with_local_names;
|
||||
}
|
||||
if (num_function_names > 0 || num_functions_with_local_names > 0 ||
|
||||
wasm.name !== undefined) {
|
||||
if (debug) print('emitting names @ ' + binary.length);
|
||||
// Add function names.
|
||||
if (has_names) {
|
||||
if (debug) print("emitting names @ " + binary.length);
|
||||
binary.emit_section(kUnknownSectionCode, section => {
|
||||
section.emit_string('name');
|
||||
// Emit module name.
|
||||
if (wasm.name !== undefined) {
|
||||
section.emit_section(kModuleNameCode, name_section => {
|
||||
name_section.emit_string(wasm.name);
|
||||
});
|
||||
section.emit_string("name");
|
||||
var count = wasm.functions.length + wasm.num_imported_funcs;
|
||||
section.emit_u32v(count);
|
||||
for (var i = 0; i < wasm.num_imported_funcs; i++) {
|
||||
section.emit_u8(0); // empty string
|
||||
section.emit_u8(0); // local names count == 0
|
||||
}
|
||||
// Emit function names.
|
||||
if (num_function_names > 0) {
|
||||
section.emit_section(kFunctionNamesCode, name_section => {
|
||||
name_section.emit_u32v(num_function_names);
|
||||
for (let func of wasm.functions) {
|
||||
if (func.name === undefined) continue;
|
||||
name_section.emit_u32v(func.index);
|
||||
name_section.emit_string(func.name);
|
||||
}
|
||||
});
|
||||
}
|
||||
// Emit local names.
|
||||
if (num_functions_with_local_names > 0) {
|
||||
section.emit_section(kLocalNamesCode, name_section => {
|
||||
name_section.emit_u32v(num_functions_with_local_names);
|
||||
for (let func of wasm.functions) {
|
||||
if (func.numLocalNames() == 0) continue;
|
||||
name_section.emit_u32v(func.index);
|
||||
name_section.emit_u32v(func.numLocalNames());
|
||||
for (let i = 0; i < func.local_names.length; ++i) {
|
||||
if (func.local_names[i] === undefined) continue;
|
||||
name_section.emit_u32v(i);
|
||||
name_section.emit_string(func.local_names[i]);
|
||||
}
|
||||
}
|
||||
});
|
||||
var name = func.name == undefined ? "" : func.name;
|
||||
section.emit_string(name);
|
||||
section.emit_u8(0); // local names count == 0
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -650,21 +563,12 @@ class WasmModuleBuilder {
|
|||
if ((typeof val) == "string") val = val.charCodeAt(0);
|
||||
view[i] = val | 0;
|
||||
}
|
||||
return buffer;
|
||||
return new Uint8Array(buffer);
|
||||
}
|
||||
|
||||
instantiate(ffi) {
|
||||
instantiate(...args) {
|
||||
let module = new WebAssembly.Module(this.toBuffer());
|
||||
let instance = new WebAssembly.Instance(module, ffi);
|
||||
let instance = new WebAssembly.Instance(module, ...args);
|
||||
return instance;
|
||||
}
|
||||
|
||||
asyncInstantiate(ffi) {
|
||||
return WebAssembly.instantiate(this.toBuffer(), ffi)
|
||||
.then(({module, instance}) => instance);
|
||||
}
|
||||
|
||||
toModule(debug = false) {
|
||||
return new WebAssembly.Module(this.toBuffer(debug));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,15 +5,16 @@ let signal;
|
|||
let renderedBuffer;
|
||||
let renderedData;
|
||||
|
||||
let sampleRate = 44100.0;
|
||||
// Use a power of two to eliminate round-off in converting frame to time
|
||||
let sampleRate = 32768;
|
||||
let pulseLengthFrames = .1 * sampleRate;
|
||||
|
||||
// Maximum allowed error for the test to succeed. Experimentally determined.
|
||||
let maxAllowedError = 5.9e-8;
|
||||
|
||||
// This must be large enough so that the filtered result is
|
||||
// essentially zero. See comments for createTestAndRun.
|
||||
let timeStep = .1;
|
||||
// This must be large enough so that the filtered result is essentially zero.
|
||||
// See comments for createTestAndRun. This must be a whole number of frames.
|
||||
let timeStep = Math.ceil(.1 * sampleRate) / sampleRate;
|
||||
|
||||
// Maximum number of filters we can process (mostly for setting the
|
||||
// render length correctly.)
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
let sampleRate = 44100.0;
|
||||
// Use a power of two to eliminate round-off when converting frames to time and
|
||||
// vice versa.
|
||||
let sampleRate = 32768;
|
||||
|
||||
// How many panner nodes to create for the test.
|
||||
let nodesToCreate = 100;
|
||||
|
||||
// Time step when each panner node starts.
|
||||
let timeStep = 0.001;
|
||||
// Time step when each panner node starts. Make sure it starts on a frame
|
||||
// boundary.
|
||||
let timeStep = Math.floor(0.001 * sampleRate) / sampleRate;
|
||||
|
||||
// Make sure we render long enough to get all of our nodes.
|
||||
let renderLengthSeconds = timeStep * (nodesToCreate + 1);
|
||||
|
@ -134,7 +137,7 @@ function checkDistanceResult(renderedBuffer, model, should) {
|
|||
// The max allowed error between the actual gain and the expected
|
||||
// value. This is determined experimentally. Set to 0 to see
|
||||
// what the actual errors are.
|
||||
let maxAllowedError = 3.3e-6;
|
||||
let maxAllowedError = 2.2720e-6;
|
||||
|
||||
let success = true;
|
||||
|
||||
|
|
|
@ -1,17 +1,23 @@
|
|||
let sampleRate = 44100.0;
|
||||
// Use a power of two to eliminate round-off converting from frames to time.
|
||||
let sampleRate = 32768;
|
||||
|
||||
// How many grains to play.
|
||||
let numberOfTests = 100;
|
||||
|
||||
// Duration of each grain to be played
|
||||
let duration = 0.01;
|
||||
// Duration of each grain to be played. Make a whole number of frames
|
||||
let duration = Math.floor(0.01 * sampleRate) / sampleRate;
|
||||
|
||||
// A little extra bit of silence between grain boundaries. Must be a whole
|
||||
// number of frames.
|
||||
let grainGap = Math.floor(0.005 * sampleRate) / sampleRate;
|
||||
|
||||
// Time step between the start of each grain. We need to add a little
|
||||
// bit of silence so we can detect grain boundaries
|
||||
let timeStep = duration + .005;
|
||||
let timeStep = duration + grainGap;
|
||||
|
||||
// Time step between the start for each grain.
|
||||
let grainOffsetStep = 0.001;
|
||||
// Time step between the start for each grain. Must be a whole number of
|
||||
// frames.
|
||||
let grainOffsetStep = Math.floor(0.001 * sampleRate) / sampleRate;
|
||||
|
||||
// How long to render to cover all of the grains.
|
||||
let renderTime = (numberOfTests + 1) * timeStep;
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
let sampleRate = 44100.0;
|
||||
// Use a power of two to eliminate round-off when converting frames to time and
|
||||
// vice versa.
|
||||
let sampleRate = 32768;
|
||||
|
||||
let numberOfChannels = 1;
|
||||
|
||||
// Time step when each panner node starts.
|
||||
let timeStep = 0.001;
|
||||
// Time step when each panner node starts. Make sure it starts on a frame
|
||||
// boundary.
|
||||
let timeStep = Math.floor(0.001 * sampleRate) / sampleRate;
|
||||
|
||||
// Length of the impulse signal.
|
||||
let pulseLengthFrames = Math.round(timeStep * sampleRate);
|
||||
|
@ -114,7 +117,7 @@ function checkResult(renderedBuffer, should) {
|
|||
// The max error we allow between the rendered impulse and the
|
||||
// expected value. This value is experimentally determined. Set
|
||||
// to 0 to make the test fail to see what the actual error is.
|
||||
let maxAllowedError = 1.3e-6;
|
||||
let maxAllowedError = 1.1597e-6;
|
||||
|
||||
let success = true;
|
||||
|
||||
|
|
|
@ -3,10 +3,12 @@ let StereoPannerTest = (function() {
|
|||
// Constants
|
||||
let PI_OVER_TWO = Math.PI * 0.5;
|
||||
|
||||
let gSampleRate = 44100;
|
||||
// Use a power of two to eliminate any round-off when converting frames to
|
||||
// time.
|
||||
let gSampleRate = 32768;
|
||||
|
||||
// Time step when each panner node starts.
|
||||
let gTimeStep = 0.001;
|
||||
// Time step when each panner node starts. Make sure this is on a frame boundary.
|
||||
let gTimeStep = Math.floor(0.001 * gSampleRate) / gSampleRate;
|
||||
|
||||
// How many panner nodes to create for the test
|
||||
let gNodesToCreate = 100;
|
||||
|
@ -77,7 +79,7 @@ let StereoPannerTest = (function() {
|
|||
// The max error we allow between the rendered impulse and the
|
||||
// expected value. This value is experimentally determined. Set
|
||||
// to 0 to make the test fail to see what the actual error is.
|
||||
this.maxAllowedError = 1.3e-6;
|
||||
this.maxAllowedError = 9.8015e-8;
|
||||
|
||||
// Max (absolute) error and the index of the maxima for the left
|
||||
// and right channels.
|
||||
|
|
|
@ -74,6 +74,42 @@
|
|||
.then(() => task.done());
|
||||
});
|
||||
|
||||
audit.define('subsample start with playback rate 0', (task, should) => {
|
||||
let context = new OfflineAudioContext(1, renderLength, sampleRate);
|
||||
let rampBuffer = new AudioBuffer(
|
||||
{length: renderLength, sampleRate: context.sampleRate});
|
||||
let data = new Float32Array(renderLength);
|
||||
let startValue = 5;
|
||||
for (let k = 0; k < data.length; ++k) {
|
||||
data[k] = k + startValue;
|
||||
}
|
||||
rampBuffer.copyToChannel(data, 0);
|
||||
|
||||
let src = new AudioBufferSourceNode(
|
||||
context, {buffer: rampBuffer, playbackRate: 0});
|
||||
|
||||
src.connect(context.destination);
|
||||
|
||||
// Purposely start the source between frame boundaries
|
||||
let startFrame = 27.3;
|
||||
src.start(startFrame / context.sampleRate);
|
||||
|
||||
context.startRendering()
|
||||
.then(audioBuffer => {
|
||||
let actualStartFrame = Math.ceil(startFrame);
|
||||
let audio = audioBuffer.getChannelData(0);
|
||||
|
||||
should(
|
||||
audio.slice(0, actualStartFrame),
|
||||
`output[0:${actualStartFrame - 1}]`)
|
||||
.beConstantValueOf(0);
|
||||
should(
|
||||
audio.slice(actualStartFrame), `output[${actualStartFrame}:]`)
|
||||
.beConstantValueOf(startValue);
|
||||
})
|
||||
.then(() => task.done());
|
||||
});
|
||||
|
||||
audit.run();
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -0,0 +1,423 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Test Sub-Sample Accurate Scheduling for ABSN
|
||||
</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/webaudio/resources/audit-util.js"></script>
|
||||
<script src="/webaudio/resources/audit.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
// Power of two so there's no roundoff converting from integer frames to
|
||||
// time.
|
||||
let sampleRate = 32768;
|
||||
|
||||
let audit = Audit.createTaskRunner();
|
||||
|
||||
audit.define('sub-sample accurate start', (task, should) => {
|
||||
// There are two channels, one for each source. Only need to render
|
||||
// quanta for this test.
|
||||
let context = new OfflineAudioContext(
|
||||
{numberOfChannels: 2, length: 8192, sampleRate: sampleRate});
|
||||
let merger = new ChannelMergerNode(
|
||||
context, {numberOfInputs: context.destination.channelCount});
|
||||
|
||||
merger.connect(context.destination);
|
||||
|
||||
// Use a simple linear ramp for the sources with integer steps starting
|
||||
// at 1 to make it easy to verify and test that have sub-sample accurate
|
||||
// start. Ramp starts at 1 so we can easily tell when the source
|
||||
// starts.
|
||||
let rampBuffer = new AudioBuffer(
|
||||
{length: context.length, sampleRate: context.sampleRate});
|
||||
let r = rampBuffer.getChannelData(0);
|
||||
for (let k = 0; k < r.length; ++k) {
|
||||
r[k] = k + 1;
|
||||
}
|
||||
|
||||
const src0 = new AudioBufferSourceNode(context, {buffer: rampBuffer});
|
||||
const src1 = new AudioBufferSourceNode(context, {buffer: rampBuffer});
|
||||
|
||||
// Frame where sources should start. This is pretty arbitrary, but one
|
||||
// should be close to an integer and the other should be close to the
|
||||
// next integer. We do this to catch the case where rounding of the
|
||||
// start frame is being done. Rounding is incorrect.
|
||||
const startFrame = 33;
|
||||
const startFrame0 = startFrame + 0.1;
|
||||
const startFrame1 = startFrame + 0.9;
|
||||
|
||||
src0.connect(merger, 0, 0);
|
||||
src1.connect(merger, 0, 1);
|
||||
|
||||
src0.start(startFrame0 / context.sampleRate);
|
||||
src1.start(startFrame1 / context.sampleRate);
|
||||
|
||||
context.startRendering()
|
||||
.then(audioBuffer => {
|
||||
const output0 = audioBuffer.getChannelData(0);
|
||||
const output1 = audioBuffer.getChannelData(1);
|
||||
|
||||
// Compute the expected output by interpolating the ramp buffer of
|
||||
// the sources if they started at the given frame.
|
||||
const ramp = rampBuffer.getChannelData(0);
|
||||
const expected0 = interpolateRamp(ramp, startFrame0);
|
||||
const expected1 = interpolateRamp(ramp, startFrame1);
|
||||
|
||||
// Verify output0 has the correct values
|
||||
|
||||
// For information only
|
||||
should(startFrame0, 'src0 start frame').beEqualTo(startFrame0);
|
||||
|
||||
// Output must be zero before the source start frame, and it must
|
||||
// be interpolated correctly after the start frame. The
|
||||
// absoluteThreshold below is currently set for Chrome which does
|
||||
// linear interpolation. This needs to be updated eventually if
|
||||
// other browsers do not user interpolation.
|
||||
should(
|
||||
output0.slice(0, startFrame + 1), `output0[0:${startFrame}]`)
|
||||
.beConstantValueOf(0);
|
||||
should(
|
||||
output0.slice(startFrame + 1, expected0.length),
|
||||
`output0[${startFrame + 1}:${expected0.length - 1}]`)
|
||||
.beCloseToArray(
|
||||
expected0.slice(startFrame + 1), {absoluteThreshold: 0});
|
||||
|
||||
// Verify output1 has the correct values. Same approach as for
|
||||
// output0.
|
||||
should(startFrame1, 'src1 start frame').beEqualTo(startFrame1);
|
||||
|
||||
should(
|
||||
output1.slice(0, startFrame + 1), `output1[0:${startFrame}]`)
|
||||
.beConstantValueOf(0);
|
||||
should(
|
||||
output1.slice(startFrame + 1, expected1.length),
|
||||
`output1[${startFrame + 1}:${expected1.length - 1}]`)
|
||||
.beCloseToArray(
|
||||
expected1.slice(startFrame + 1), {absoluteThreshold: 0});
|
||||
})
|
||||
.then(() => task.done());
|
||||
});
|
||||
|
||||
audit.define('sub-sample accurate stop', (task, should) => {
|
||||
// There are threes channesl, one for each source. Only need to render
|
||||
// quanta for this test.
|
||||
let context = new OfflineAudioContext(
|
||||
{numberOfChannels: 3, length: 128, sampleRate: sampleRate});
|
||||
let merger = new ChannelMergerNode(
|
||||
context, {numberOfInputs: context.destination.channelCount});
|
||||
|
||||
merger.connect(context.destination);
|
||||
|
||||
// The source can be as simple constant for this test.
|
||||
let buffer = new AudioBuffer(
|
||||
{length: context.length, sampleRate: context.sampleRate});
|
||||
buffer.getChannelData(0).fill(1);
|
||||
|
||||
const src0 = new AudioBufferSourceNode(context, {buffer: buffer});
|
||||
const src1 = new AudioBufferSourceNode(context, {buffer: buffer});
|
||||
const src2 = new AudioBufferSourceNode(context, {buffer: buffer});
|
||||
|
||||
// Frame where sources should start. This is pretty arbitrary, but one
|
||||
// should be an integer, one should be close to an integer and the other
|
||||
// should be close to the next integer. This is to catch the case where
|
||||
// rounding is used for the end frame. Rounding is incorrect.
|
||||
const endFrame = 33;
|
||||
const endFrame1 = endFrame + 0.1;
|
||||
const endFrame2 = endFrame + 0.9;
|
||||
|
||||
src0.connect(merger, 0, 0);
|
||||
src1.connect(merger, 0, 1);
|
||||
src2.connect(merger, 0, 2);
|
||||
|
||||
src0.start(0);
|
||||
src1.start(0);
|
||||
src2.start(0);
|
||||
src0.stop(endFrame / context.sampleRate);
|
||||
src1.stop(endFrame1 / context.sampleRate);
|
||||
src2.stop(endFrame2 / context.sampleRate);
|
||||
|
||||
context.startRendering()
|
||||
.then(audioBuffer => {
|
||||
let actual0 = audioBuffer.getChannelData(0);
|
||||
let actual1 = audioBuffer.getChannelData(1);
|
||||
let actual2 = audioBuffer.getChannelData(2);
|
||||
|
||||
// Just verify that we stopped at the right time.
|
||||
|
||||
// This is case where the end frame is an integer. Since the first
|
||||
// output ends on an exact frame, the output must be zero at that
|
||||
// frame number. We print the end frame for information only; it
|
||||
// makes interpretation of the rest easier.
|
||||
should(endFrame - 1, 'src0 end frame')
|
||||
.beEqualTo(endFrame - 1);
|
||||
should(actual0[endFrame - 1], `output0[${endFrame - 1}]`)
|
||||
.notBeEqualTo(0);
|
||||
should(actual0.slice(endFrame),
|
||||
`output0[${endFrame}:]`)
|
||||
.beConstantValueOf(0);
|
||||
|
||||
// The case where the end frame is just a little above an integer.
|
||||
// The output must not be zero just before the end and must be zero
|
||||
// after.
|
||||
should(endFrame1, 'src1 end frame')
|
||||
.beEqualTo(endFrame1);
|
||||
should(actual1[endFrame], `output1[${endFrame}]`)
|
||||
.notBeEqualTo(0);
|
||||
should(actual1.slice(endFrame + 1),
|
||||
`output1[${endFrame + 1}:]`)
|
||||
.beConstantValueOf(0);
|
||||
|
||||
// The case where the end frame is just a little below an integer.
|
||||
// The output must not be zero just before the end and must be zero
|
||||
// after.
|
||||
should(endFrame2, 'src2 end frame')
|
||||
.beEqualTo(endFrame2);
|
||||
should(actual2[endFrame], `output2[${endFrame}]`)
|
||||
.notBeEqualTo(0);
|
||||
should(actual2.slice(endFrame + 1),
|
||||
`output2[${endFrame + 1}:]`)
|
||||
.beConstantValueOf(0);
|
||||
})
|
||||
.then(() => task.done());
|
||||
});
|
||||
|
||||
audit.define('sub-sample-grain', (task, should) => {
|
||||
let context = new OfflineAudioContext(
|
||||
{numberOfChannels: 2, length: 128, sampleRate: sampleRate});
|
||||
|
||||
let merger = new ChannelMergerNode(
|
||||
context, {numberOfInputs: context.destination.channelCount});
|
||||
|
||||
merger.connect(context.destination);
|
||||
|
||||
// The source can be as simple constant for this test.
|
||||
let buffer = new AudioBuffer(
|
||||
{length: context.length, sampleRate: context.sampleRate});
|
||||
buffer.getChannelData(0).fill(1);
|
||||
|
||||
let src0 = new AudioBufferSourceNode(context, {buffer: buffer});
|
||||
let src1 = new AudioBufferSourceNode(context, {buffer: buffer});
|
||||
|
||||
src0.connect(merger, 0, 0);
|
||||
src1.connect(merger, 0, 1);
|
||||
|
||||
// Start a short grain.
|
||||
const src0StartGrain = 3.1;
|
||||
const src0EndGrain = 37.2;
|
||||
src0.start(
|
||||
src0StartGrain / context.sampleRate, 0,
|
||||
(src0EndGrain - src0StartGrain) / context.sampleRate);
|
||||
|
||||
const src1StartGrain = 5.8;
|
||||
const src1EndGrain = 43.9;
|
||||
src1.start(
|
||||
src1StartGrain / context.sampleRate, 0,
|
||||
(src1EndGrain - src1StartGrain) / context.sampleRate);
|
||||
|
||||
context.startRendering()
|
||||
.then(audioBuffer => {
|
||||
let output0 = audioBuffer.getChannelData(0);
|
||||
let output1 = audioBuffer.getChannelData(1);
|
||||
|
||||
let expected = new Float32Array(context.length);
|
||||
|
||||
// Compute the expected output for output0 and verify the actual
|
||||
// output matches.
|
||||
expected.fill(1);
|
||||
for (let k = 0; k <= Math.floor(src0StartGrain); ++k) {
|
||||
expected[k] = 0;
|
||||
}
|
||||
for (let k = Math.ceil(src0EndGrain); k < expected.length; ++k) {
|
||||
expected[k] = 0;
|
||||
}
|
||||
|
||||
verifyGrain(should, output0, {
|
||||
startGrain: src0StartGrain,
|
||||
endGrain: src0EndGrain,
|
||||
sourceName: 'src0',
|
||||
outputName: 'output0'
|
||||
});
|
||||
|
||||
verifyGrain(should, output1, {
|
||||
startGrain: src1StartGrain,
|
||||
endGrain: src1EndGrain,
|
||||
sourceName: 'src1',
|
||||
outputName: 'output1'
|
||||
});
|
||||
})
|
||||
.then(() => task.done());
|
||||
});
|
||||
|
||||
audit.define(
|
||||
'sub-sample accurate start with playbackRate', (task, should) => {
|
||||
// There are two channels, one for each source. Only need to render
|
||||
// quanta for this test.
|
||||
let context = new OfflineAudioContext(
|
||||
{numberOfChannels: 2, length: 8192, sampleRate: sampleRate});
|
||||
let merger = new ChannelMergerNode(
|
||||
context, {numberOfInputs: context.destination.channelCount});
|
||||
|
||||
merger.connect(context.destination);
|
||||
|
||||
// Use a simple linear ramp for the sources with integer steps
|
||||
// starting at 1 to make it easy to verify and test that have
|
||||
// sub-sample accurate start. Ramp starts at 1 so we can easily
|
||||
// tell when the source starts.
|
||||
let buffer = new AudioBuffer(
|
||||
{length: context.length, sampleRate: context.sampleRate});
|
||||
let r = buffer.getChannelData(0);
|
||||
for (let k = 0; k < r.length; ++k) {
|
||||
r[k] = k + 1;
|
||||
}
|
||||
|
||||
// Two sources with different playback rates
|
||||
const src0 = new AudioBufferSourceNode(
|
||||
context, {buffer: buffer, playbackRate: .25});
|
||||
const src1 = new AudioBufferSourceNode(
|
||||
context, {buffer: buffer, playbackRate: 4});
|
||||
|
||||
// Frame where sources start. Pretty arbitrary but should not be an
|
||||
// integer.
|
||||
const startFrame = 17.8;
|
||||
|
||||
src0.connect(merger, 0, 0);
|
||||
src1.connect(merger, 0, 1);
|
||||
|
||||
src0.start(startFrame / context.sampleRate);
|
||||
src1.start(startFrame / context.sampleRate);
|
||||
|
||||
context.startRendering()
|
||||
.then(audioBuffer => {
|
||||
const output0 = audioBuffer.getChannelData(0);
|
||||
const output1 = audioBuffer.getChannelData(1);
|
||||
|
||||
const frameBefore = Math.floor(startFrame);
|
||||
const frameAfter = frameBefore + 1;
|
||||
|
||||
// Informative message so we know what the following output
|
||||
// indices really mean.
|
||||
should(startFrame, 'Source start frame')
|
||||
.beEqualTo(startFrame);
|
||||
|
||||
// Verify the output
|
||||
|
||||
// With a startFrame of 17.8, the first output is at frame 18,
|
||||
// but the actual start is at 17.8. So we would interpolate
|
||||
// the output 0.2 fraction of the way between 17.8 and 18, for
|
||||
// an output of 1.2 for our ramp. But the playback rate is
|
||||
// 0.25, so we're really only 1/4 as far along as we think so
|
||||
// the output is .2*0.25 of the way between 1 and 2 or 1.05.
|
||||
|
||||
const ramp0 = buffer.getChannelData(0)[0];
|
||||
const ramp1 = buffer.getChannelData(0)[1];
|
||||
|
||||
const src0Output = ramp0 +
|
||||
(ramp1 - ramp0) * (frameAfter - startFrame) *
|
||||
src0.playbackRate.value;
|
||||
|
||||
let playbackMessage =
|
||||
`With playbackRate ${src0.playbackRate.value}:`;
|
||||
|
||||
should(
|
||||
output0[frameBefore],
|
||||
`${playbackMessage} output0[${frameBefore}]`)
|
||||
.beEqualTo(0);
|
||||
should(
|
||||
output0[frameAfter],
|
||||
`${playbackMessage} output0[${frameAfter}]`)
|
||||
.beCloseTo(src0Output, {threshold: 4.542e-8});
|
||||
|
||||
const src1Output = ramp0 +
|
||||
(ramp1 - ramp0) * (frameAfter - startFrame) *
|
||||
src1.playbackRate.value;
|
||||
|
||||
playbackMessage =
|
||||
`With playbackRate ${src1.playbackRate.value}:`;
|
||||
|
||||
should(
|
||||
output1[frameBefore],
|
||||
`${playbackMessage} output1[${frameBefore}]`)
|
||||
.beEqualTo(0);
|
||||
should(
|
||||
output1[frameAfter],
|
||||
`${playbackMessage} output1[${frameAfter}]`)
|
||||
.beCloseTo(src1Output, {threshold: 4.542e-8});
|
||||
})
|
||||
.then(() => task.done());
|
||||
});
|
||||
|
||||
audit.run();
|
||||
|
||||
// Given an input ramp in |rampBuffer|, interpolate the signal assuming
|
||||
// this ramp is used for an ABSN that starts at frame |startFrame|, which
|
||||
// is not necessarily an integer. For simplicity we just use linear
|
||||
// interpolation here. The interpolation is not part of the spec but
|
||||
// this should be pretty close to whatever interpolation is being done.
|
||||
function interpolateRamp(rampBuffer, startFrame) {
|
||||
// |start| is the last zero sample before the ABSN actually starts.
|
||||
const start = Math.floor(startFrame);
|
||||
// One less than the rampBuffer because we can't linearly interpolate
|
||||
// the last frame.
|
||||
let result = new Float32Array(rampBuffer.length - 1);
|
||||
|
||||
for (let k = 0; k <= start; ++k) {
|
||||
result[k] = 0;
|
||||
}
|
||||
|
||||
// Now start linear interpolation.
|
||||
let frame = startFrame;
|
||||
let index = 1;
|
||||
for (let k = start + 1; k < result.length; ++k) {
|
||||
let s0 = rampBuffer[index];
|
||||
let s1 = rampBuffer[index - 1];
|
||||
let delta = frame - k;
|
||||
let s = s1 - delta * (s0 - s1);
|
||||
result[k] = s;
|
||||
++frame;
|
||||
++index;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function verifyGrain(should, output, options) {
|
||||
let {startGrain, endGrain, sourceName, outputName} = options;
|
||||
let expected = new Float32Array(output.length);
|
||||
// Compute the expected output for output and verify the actual
|
||||
// output matches.
|
||||
expected.fill(1);
|
||||
for (let k = 0; k <= Math.floor(startGrain); ++k) {
|
||||
expected[k] = 0;
|
||||
}
|
||||
for (let k = Math.ceil(endGrain); k < expected.length; ++k) {
|
||||
expected[k] = 0;
|
||||
}
|
||||
|
||||
should(startGrain, `${sourceName} grain start`).beEqualTo(startGrain);
|
||||
should(endGrain - startGrain, `${sourceName} grain duration`)
|
||||
.beEqualTo(endGrain - startGrain);
|
||||
should(endGrain, `${sourceName} grain end`).beEqualTo(endGrain);
|
||||
should(output, outputName).beEqualToArray(expected);
|
||||
should(
|
||||
output[Math.floor(startGrain)],
|
||||
`${outputName}[${Math.floor(startGrain)}]`)
|
||||
.beEqualTo(0);
|
||||
should(
|
||||
output[1 + Math.floor(startGrain)],
|
||||
`${outputName}[${1 + Math.floor(startGrain)}]`)
|
||||
.notBeEqualTo(0);
|
||||
should(
|
||||
output[Math.floor(endGrain)],
|
||||
`${outputName}[${Math.floor(endGrain)}]`)
|
||||
.notBeEqualTo(0);
|
||||
should(
|
||||
output[1 + Math.floor(endGrain)],
|
||||
`${outputName}[${1 + Math.floor(endGrain)}]`)
|
||||
.beEqualTo(0);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -14,7 +14,8 @@
|
|||
<script id="layout-test-code">
|
||||
let audit = Audit.createTaskRunner();
|
||||
let context = 0;
|
||||
let sampleRate = 44100;
|
||||
// Use a power of two to eliminate round-off converting frames to time.
|
||||
let sampleRate = 32768;
|
||||
let renderNumberOfChannels = 8;
|
||||
let singleTestFrameLength = 8;
|
||||
let testBuffers;
|
||||
|
|
|
@ -131,16 +131,20 @@
|
|||
|
||||
// Set listener properties to "random" values so that motion on one of
|
||||
// the attributes actually changes things relative to the panner
|
||||
// location.
|
||||
// location. And the up and forward directions should have a simple
|
||||
// relationship between them.
|
||||
listener.positionX.value = -1;
|
||||
listener.positionY.value = 1;
|
||||
listener.positionZ.value = -1;
|
||||
listener.forwardX.value = -1;
|
||||
listener.forwardY.value = 1;
|
||||
listener.forwardZ.value = -1;
|
||||
// Make the up vector not parallel or perpendicular to the forward and
|
||||
// position vectors so that automations of the up vector produce
|
||||
// noticeable differences.
|
||||
listener.upX.value = 1;
|
||||
listener.upY.value = 1;
|
||||
listener.upZ.value = 1;
|
||||
listener.upZ.value = 2;
|
||||
|
||||
let audioParam = listener[options.param];
|
||||
audioParam.automationRate = 'k-rate';
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
createTestAndRun(context, 'lowpass', {
|
||||
should: should,
|
||||
threshold: 9.7869e-8,
|
||||
threshold: 4.6943e-8,
|
||||
filterParameters: filterParameters
|
||||
}).then(task.done.bind(task));
|
||||
});
|
||||
|
|
|
@ -18,11 +18,19 @@
|
|||
|
||||
let audit = Audit.createTaskRunner();
|
||||
|
||||
let sampleRate = 44100.0;
|
||||
let bufferDurationSeconds = 0.125;
|
||||
// Use a power of two to eliminate any round-off when converting frame to
|
||||
// time.
|
||||
let sampleRate = 32768;
|
||||
// Make sure the buffer duration and spacing are all exact frame lengths
|
||||
// so that the note spacing is also on frame boundaries to eliminate
|
||||
// sub-sample accurate start of a ABSN.
|
||||
let bufferDurationSeconds = Math.floor(0.125 * sampleRate) / sampleRate;
|
||||
let numberOfNotes = 11;
|
||||
let noteSpacing = bufferDurationSeconds +
|
||||
0.020; // leave 20ms of silence between each "note"
|
||||
// Leave about 20ms of silence, being sure this is an exact frame
|
||||
// duration.
|
||||
let noteSilence = Math.floor(0.020 * sampleRate) / sampleRate;
|
||||
let noteSpacing = bufferDurationSeconds + noteSilence;
|
||||
|
||||
let lengthInSeconds = numberOfNotes * noteSpacing;
|
||||
|
||||
let context = 0;
|
||||
|
@ -131,18 +139,18 @@
|
|||
// Verify the channels are clsoe to the reference.
|
||||
should(actual0, 'Left output from gain node')
|
||||
.beCloseToArray(
|
||||
reference0, {relativeThreshold: 1.1908e-7});
|
||||
reference0, {relativeThreshold: 1.1877e-7});
|
||||
should(actual1, 'Right output from gain node')
|
||||
.beCloseToArray(
|
||||
reference1, {relativeThreshold: 1.1908e-7});
|
||||
reference1, {relativeThreshold: 1.1877e-7});
|
||||
|
||||
// Test the SNR too for both channels.
|
||||
let snr0 = 10 * Math.log10(computeSNR(actual0, reference0));
|
||||
let snr1 = 10 * Math.log10(computeSNR(actual1, reference1));
|
||||
should(snr0, 'Left SNR (in dB)')
|
||||
.beGreaterThanOrEqualTo(148.69);
|
||||
.beGreaterThanOrEqualTo(148.71);
|
||||
should(snr1, 'Right SNR (in dB)')
|
||||
.beGreaterThanOrEqualTo(148.69);
|
||||
.beGreaterThanOrEqualTo(148.71);
|
||||
})
|
||||
.then(() => task.done());
|
||||
;
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test Panner Azimuth Calculation</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../../resources/audit.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
const audit = Audit.createTaskRunner();
|
||||
|
||||
// Fairly arbitrary sample rate
|
||||
const sampleRate = 16000;
|
||||
|
||||
audit.define('Azimuth calculation', (task, should) => {
|
||||
// Two channels for the context so we can see each channel of the
|
||||
// panner node.
|
||||
let context = new OfflineAudioContext(2, sampleRate, sampleRate);
|
||||
|
||||
let src = new ConstantSourceNode(context);
|
||||
let panner = new PannerNode(context);
|
||||
|
||||
src.connect(panner).connect(context.destination);
|
||||
|
||||
// The source is still pointed directly at the listener, but is now
|
||||
// directly above. The audio should be the same in both the left and
|
||||
// right channels.
|
||||
panner.positionY.value = 1;
|
||||
|
||||
src.start();
|
||||
|
||||
context.startRendering()
|
||||
.then(audioBuffer => {
|
||||
// The left and right channels should contain the same signal.
|
||||
let c0 = audioBuffer.getChannelData(0);
|
||||
let c1 = audioBuffer.getChannelData(1);
|
||||
|
||||
let expected = Math.fround(Math.SQRT1_2);
|
||||
|
||||
should(c0, 'Left channel').beConstantValueOf(expected);
|
||||
should(c1, 'Righteft channel').beConstantValueOf(expected);
|
||||
})
|
||||
.then(() => task.done());
|
||||
});
|
||||
|
||||
audit.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -187,6 +187,17 @@ def test_height_width(session):
|
|||
})
|
||||
|
||||
|
||||
def test_height_width_smaller_than_minimum_browser_size(session):
|
||||
original = session.window.rect
|
||||
|
||||
response = set_window_rect(session, {"width": 10, "height": 10})
|
||||
rect = assert_success(response)
|
||||
assert rect["width"] < original["width"]
|
||||
assert rect["width"] > 10
|
||||
assert rect["height"] < original["height"]
|
||||
assert rect["height"] > 10
|
||||
|
||||
|
||||
def test_height_width_larger_than_max(session):
|
||||
screen_width, screen_height = screen_size(session)
|
||||
avail_width, avail_height = available_screen_size(session)
|
||||
|
@ -215,6 +226,36 @@ def test_height_width_as_current(session):
|
|||
})
|
||||
|
||||
|
||||
def test_height_as_current(session):
|
||||
original = session.window.rect
|
||||
|
||||
response = set_window_rect(session, {
|
||||
"width": original["width"] + 10,
|
||||
"height": original["height"]
|
||||
})
|
||||
assert_success(response, {
|
||||
"x": original["x"],
|
||||
"y": original["y"],
|
||||
"width": original["width"] + 10,
|
||||
"height": original["height"]
|
||||
})
|
||||
|
||||
|
||||
def test_width_as_current(session):
|
||||
original = session.window.rect
|
||||
|
||||
response = set_window_rect(session, {
|
||||
"width": original["width"],
|
||||
"height": original["height"] + 10
|
||||
})
|
||||
assert_success(response, {
|
||||
"x": original["x"],
|
||||
"y": original["y"],
|
||||
"width": original["width"],
|
||||
"height": original["height"] + 10
|
||||
})
|
||||
|
||||
|
||||
def test_x_y(session):
|
||||
original = session.window.rect
|
||||
response = set_window_rect(session, {
|
||||
|
@ -267,40 +308,49 @@ def test_negative_x_y(session):
|
|||
"height": original["height"]})
|
||||
|
||||
|
||||
def test_move_to_same_position(session):
|
||||
original_position = session.window.position
|
||||
position = session.window.position = original_position
|
||||
assert position == original_position
|
||||
def test_x_y_as_current(session):
|
||||
original = session.window.rect
|
||||
|
||||
response = set_window_rect(session, {
|
||||
"x": original["x"],
|
||||
"y": original["y"]
|
||||
})
|
||||
assert_success(response, {
|
||||
"x": original["x"],
|
||||
"y": original["y"],
|
||||
"width": original["width"],
|
||||
"height": original["height"]
|
||||
})
|
||||
|
||||
|
||||
def test_move_to_same_x(session):
|
||||
original_x = session.window.position[0]
|
||||
position = session.window.position = (original_x, 345)
|
||||
assert position == (original_x, 345)
|
||||
def test_x_as_current(session):
|
||||
original = session.window.rect
|
||||
|
||||
response = set_window_rect(session, {
|
||||
"x": original["x"],
|
||||
"y": original["y"] + 10
|
||||
})
|
||||
assert_success(response, {
|
||||
"x": original["x"],
|
||||
"y": original["y"] + 10,
|
||||
"width": original["width"],
|
||||
"height": original["height"]
|
||||
})
|
||||
|
||||
|
||||
def test_move_to_same_y(session):
|
||||
original_y = session.window.position[1]
|
||||
position = session.window.position = (456, original_y)
|
||||
assert position == (456, original_y)
|
||||
def test_y_as_current(session):
|
||||
original = session.window.rect
|
||||
|
||||
|
||||
def test_resize_to_same_size(session):
|
||||
original_size = session.window.size
|
||||
size = session.window.size = original_size
|
||||
assert size == original_size
|
||||
|
||||
|
||||
def test_resize_to_same_width(session):
|
||||
original_width = session.window.size[0]
|
||||
size = session.window.size = (original_width, 345)
|
||||
assert size == (original_width, 345)
|
||||
|
||||
|
||||
def test_resize_to_same_height(session):
|
||||
original_height = session.window.size[1]
|
||||
size = session.window.size = (456, original_height)
|
||||
assert size == (456, original_height)
|
||||
response = set_window_rect(session, {
|
||||
"x": original["x"] + 10,
|
||||
"y": original["y"]
|
||||
})
|
||||
assert_success(response, {
|
||||
"x": original["x"] + 10,
|
||||
"y": original["y"],
|
||||
"width": original["width"],
|
||||
"height": original["height"]
|
||||
})
|
||||
|
||||
|
||||
"""
|
||||
|
|
|
@ -2,6 +2,7 @@ SCRIPT_TIMEOUT = 30
|
|||
PAGE_LOAD_TIMEOUT = 300
|
||||
IMPLICIT_WAIT_TIMEOUT = 0
|
||||
|
||||
WINDOW_POSITION = (100, 100)
|
||||
WINDOW_SIZE = (800, 600)
|
||||
|
||||
DRIVER_HOST = '127.0.0.1'
|
||||
|
|
|
@ -152,8 +152,9 @@ def session(capabilities, configuration, request):
|
|||
if not _current_session.session_id:
|
||||
raise
|
||||
|
||||
# Enforce a fixed default window size
|
||||
# Enforce a fixed default window size and position
|
||||
_current_session.window.size = defaults.WINDOW_SIZE
|
||||
_current_session.window.position = defaults.WINDOW_POSITION
|
||||
|
||||
yield _current_session
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue