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": [
|
||||||
[
|
[
|
||||||
"/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": [
|
||||||
[
|
[
|
||||||
"/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": [
|
"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": [
|
"css/css-values/support/1x1-green.png": [
|
||||||
[
|
[
|
||||||
{}
|
{}
|
||||||
|
@ -313917,6 +313951,11 @@
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"tools/docker/retry.py": [
|
||||||
|
[
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"tools/docker/start.sh": [
|
"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": [
|
"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": [
|
||||||
[
|
[
|
||||||
"/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": [
|
||||||
[
|
[
|
||||||
"/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": [
|
||||||
[
|
[
|
||||||
"/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": [
|
||||||
[
|
[
|
||||||
"/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": [
|
||||||
[
|
[
|
||||||
"/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"
|
"support"
|
||||||
],
|
],
|
||||||
".taskcluster.yml": [
|
".taskcluster.yml": [
|
||||||
"ae99c0960acc56ca0970d9a03538e20c42179811",
|
"1045e07c8df889205d8a719585e3dd3c388f77cc",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
".travis.yml": [
|
".travis.yml": [
|
||||||
|
@ -548801,6 +548875,10 @@
|
||||||
"f04eba57ce450541e9283f62718dd3ed71f3631c",
|
"f04eba57ce450541e9283f62718dd3ed71f3631c",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
|
"css/css-device-adapt/documentElement-clientWidth-on-minimum-scale-size.tentative.html": [
|
||||||
|
"74e2172510f8496bda64bb2ae3600b0e165347fd",
|
||||||
|
"testharness"
|
||||||
|
],
|
||||||
"css/css-device-adapt/idlharness.html": [
|
"css/css-device-adapt/idlharness.html": [
|
||||||
"b9cca1bb7ee2fbee354ec90a3afc5e8e33609bc8",
|
"b9cca1bb7ee2fbee354ec90a3afc5e8e33609bc8",
|
||||||
"testharness"
|
"testharness"
|
||||||
|
@ -549185,6 +549263,14 @@
|
||||||
"f8d6e85cee2325f3ae51a950a276430d26c04189",
|
"f8d6e85cee2325f3ae51a950a276430d26c04189",
|
||||||
"testharness"
|
"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": [
|
"css/css-display/inheritance.html": [
|
||||||
"bfd072651cb6ec82cca7d9be5b6768afbc39fca0",
|
"bfd072651cb6ec82cca7d9be5b6768afbc39fca0",
|
||||||
"testharness"
|
"testharness"
|
||||||
|
@ -568677,6 +568763,10 @@
|
||||||
"5d36710b6fe694b256d9841b3e7a0fff4535c85b",
|
"5d36710b6fe694b256d9841b3e7a0fff4535c85b",
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
|
"css/css-position/position-absolute-replaced-minmax.html": [
|
||||||
|
"644b147a227e100c500de2de9e4f8e8449a4a21e",
|
||||||
|
"testharness"
|
||||||
|
],
|
||||||
"css/css-position/position-relative-table-left-ref.html": [
|
"css/css-position/position-relative-table-left-ref.html": [
|
||||||
"7c1193b80007d8e7f89b35400a6d2ea2266cb3ac",
|
"7c1193b80007d8e7f89b35400a6d2ea2266cb3ac",
|
||||||
"support"
|
"support"
|
||||||
|
@ -573926,7 +574016,7 @@
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"css/css-syntax/escaped-eof.html": [
|
"css/css-syntax/escaped-eof.html": [
|
||||||
"66ac8e9442e22c8d5b445d556c667f769c0939e2",
|
"5d47c34ac512fab7eb9c37e64b0c677d09a8e3d3",
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"css/css-syntax/ident-three-code-points.html": [
|
"css/css-syntax/ident-three-code-points.html": [
|
||||||
|
@ -574153,6 +574243,10 @@
|
||||||
"a8745487b6702b8b8e8ac85bd843014dc296b717",
|
"a8745487b6702b8b8e8ac85bd843014dc296b717",
|
||||||
"reftest"
|
"reftest"
|
||||||
],
|
],
|
||||||
|
"css/css-tables/no-overflow-with-table-cell-margins.html": [
|
||||||
|
"9657da9c262cede13451978446508ff8917b53bd",
|
||||||
|
"testharness"
|
||||||
|
],
|
||||||
"css/css-tables/parsing/border-collapse-computed.html": [
|
"css/css-tables/parsing/border-collapse-computed.html": [
|
||||||
"1ad0b6d701a7bbc1b49a9f3d3a34270dbd64ed29",
|
"1ad0b6d701a7bbc1b49a9f3d3a34270dbd64ed29",
|
||||||
"testharness"
|
"testharness"
|
||||||
|
@ -590057,6 +590151,10 @@
|
||||||
"a88416a2c2da6532084dc77ded1d3d5ac15e120e",
|
"a88416a2c2da6532084dc77ded1d3d5ac15e120e",
|
||||||
"reftest"
|
"reftest"
|
||||||
],
|
],
|
||||||
|
"css/css-values/calc-letter-spacing.html": [
|
||||||
|
"444785ba14c21faefe56c22de0c23766ddb26c95",
|
||||||
|
"testharness"
|
||||||
|
],
|
||||||
"css/css-values/calc-parenthesis-stack.html": [
|
"css/css-values/calc-parenthesis-stack.html": [
|
||||||
"1d9033d7eecd14066ee9e4f9c52bf1a39e6ddd1b",
|
"1d9033d7eecd14066ee9e4f9c52bf1a39e6ddd1b",
|
||||||
"reftest"
|
"reftest"
|
||||||
|
@ -590213,6 +590311,10 @@
|
||||||
"5e35f6261e266be2981ae79038e464ac354cc8ef",
|
"5e35f6261e266be2981ae79038e464ac354cc8ef",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
|
"css/css-values/reference/viewport-unit-011-ref.html": [
|
||||||
|
"e56c6ec8451370e86fb16f76c50acd627bd5be78",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
"css/css-values/support/1x1-green.png": [
|
"css/css-values/support/1x1-green.png": [
|
||||||
"b98ca0ba0a03c580ac339e4a3653539cfa8edc71",
|
"b98ca0ba0a03c580ac339e4a3653539cfa8edc71",
|
||||||
"support"
|
"support"
|
||||||
|
@ -590473,6 +590575,10 @@
|
||||||
"dba2af8fa07b07d2ab7c6ca9f657b6e170cd9a41",
|
"dba2af8fa07b07d2ab7c6ca9f657b6e170cd9a41",
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
|
"css/css-values/viewport-unit-011.html": [
|
||||||
|
"055f3d1fd2d716a68d857738493815c8772bef06",
|
||||||
|
"reftest"
|
||||||
|
],
|
||||||
"css/css-values/viewport-units-css2-001.html": [
|
"css/css-values/viewport-units-css2-001.html": [
|
||||||
"c51237dd8a07546d31eef6f6f9b3c84b6ac2b65b",
|
"c51237dd8a07546d31eef6f6f9b3c84b6ac2b65b",
|
||||||
"testharness"
|
"testharness"
|
||||||
|
@ -611970,7 +612076,7 @@
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"dom/events/EventListener-handleEvent.html": [
|
"dom/events/EventListener-handleEvent.html": [
|
||||||
"b33b030a641dd0d2a4e1319f366e3db975e9dc3f",
|
"6630f273fff4b450d1fcc425828b5f1f53357e54",
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"dom/events/EventListener-incumbent-global-1.sub.html": [
|
"dom/events/EventListener-incumbent-global-1.sub.html": [
|
||||||
|
@ -638326,7 +638432,7 @@
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"html/webappapis/scripting/events/event-handler-attributes-frameset-window.html": [
|
"html/webappapis/scripting/events/event-handler-attributes-frameset-window.html": [
|
||||||
"ecfe90e88ea404604dfaeb649b8067c15fc03d5a",
|
"b583eca52da2b9b5e58fb25e73b3766452b7c472",
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"html/webappapis/scripting/events/event-handler-attributes-windowless-body.html": [
|
"html/webappapis/scripting/events/event-handler-attributes-windowless-body.html": [
|
||||||
|
@ -640034,7 +640140,7 @@
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"interfaces/webxr.idl": [
|
"interfaces/webxr.idl": [
|
||||||
"3054500f5903f72214b4bd8984488a186b2a5d8a",
|
"63643a11b6b0cb7ecf7aabc19b03edf1d47a6642",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"interfaces/worklets.idl": [
|
"interfaces/worklets.idl": [
|
||||||
|
@ -653050,7 +653156,7 @@
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"preload/link-header-preload-nonce.html": [
|
"preload/link-header-preload-nonce.html": [
|
||||||
"51b2224864d5a47c9642ded613efcfc702eb0f9d",
|
"240d6f11dd5979457ed8a4d6ab3c97e9d1ce9f9c",
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"preload/link-header-preload-nonce.html.headers": [
|
"preload/link-header-preload-nonce.html.headers": [
|
||||||
|
@ -653058,7 +653164,7 @@
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"preload/link-header-preload-srcset.tentative.html": [
|
"preload/link-header-preload-srcset.tentative.html": [
|
||||||
"9eb8ac4e00d20b9eb48ffd3a981b33b7604246f8",
|
"024da965796fb5960bc43cdf4de1806fbef74ffe",
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"preload/link-header-preload-srcset.tentative.html.headers": [
|
"preload/link-header-preload-srcset.tentative.html.headers": [
|
||||||
|
@ -653174,7 +653280,7 @@
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"preload/resources/preload_helper.js": [
|
"preload/resources/preload_helper.js": [
|
||||||
"5a23be74b8df48e56ac335a90a97bf79a75511b3",
|
"b2cf8323db0145fa4876fb40d0d1ed3ff1c6413b",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"preload/resources/sound_5.oga": [
|
"preload/resources/sound_5.oga": [
|
||||||
|
@ -673458,7 +673564,7 @@
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"tools/ci/taskcluster-run.py": [
|
"tools/ci/taskcluster-run.py": [
|
||||||
"f443903786e9ee9a8cb2f3ab20e1cf4bb11faf68",
|
"2b3270c17aaacd053bdff516fa1f1ee666011858",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"tools/ci/tcdownload.py": [
|
"tools/ci/tcdownload.py": [
|
||||||
|
@ -673478,11 +673584,15 @@
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"tools/docker/Dockerfile": [
|
"tools/docker/Dockerfile": [
|
||||||
"53564ac135c909d19138bee24780c28ddba04a03",
|
"0cb2352e5fdf6117d51c9f745d18bbf453c48a1c",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"tools/docker/retry.py": [
|
||||||
|
"6126b781bfadd15e82b8a3a3b9494050939eab6c",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"tools/docker/start.sh": [
|
"tools/docker/start.sh": [
|
||||||
"52a5127892ca0455c57de1e3b26e26ea6a3f8db2",
|
"bfc7e9960abf595c8319c1865a2ad3c4d1c51087",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"tools/gitignore/__init__.py": [
|
"tools/gitignore/__init__.py": [
|
||||||
|
@ -678486,7 +678596,7 @@
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"tools/wptrunner/wptrunner/browsers/firefox.py": [
|
"tools/wptrunner/wptrunner/browsers/firefox.py": [
|
||||||
"67d5b6ec2f5e97046c020947c8449d5205a713bf",
|
"ec317b8bed2ce515661bc056a37039ea44801299",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"tools/wptrunner/wptrunner/browsers/ie.py": [
|
"tools/wptrunner/wptrunner/browsers/ie.py": [
|
||||||
|
@ -678554,7 +678664,7 @@
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"tools/wptrunner/wptrunner/executors/executormarionette.py": [
|
"tools/wptrunner/wptrunner/executors/executormarionette.py": [
|
||||||
"d69e998e2c302f1983bd43541054ba84b745bbe3",
|
"d5692af77d39771d02af9bbaba9c04a54572bbb6",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"tools/wptrunner/wptrunner/executors/executoropera.py": [
|
"tools/wptrunner/wptrunner/executors/executoropera.py": [
|
||||||
|
@ -678634,11 +678744,11 @@
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"tools/wptrunner/wptrunner/formatters.py": [
|
"tools/wptrunner/wptrunner/formatters.py": [
|
||||||
"0a54624b7b447ba16c1fc80a3b9efc39487892a0",
|
"284868522eaf52b5132d46c223ad70e42aa6c81a",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"tools/wptrunner/wptrunner/manifestexpected.py": [
|
"tools/wptrunner/wptrunner/manifestexpected.py": [
|
||||||
"7ecef4b0b24ee062fb35f31fee776dd7c59d0c8f",
|
"f4fddc7a2a14d3170ea7afc72c5a1ef949ffa772",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"tools/wptrunner/wptrunner/manifestinclude.py": [
|
"tools/wptrunner/wptrunner/manifestinclude.py": [
|
||||||
|
@ -678646,11 +678756,11 @@
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"tools/wptrunner/wptrunner/manifestupdate.py": [
|
"tools/wptrunner/wptrunner/manifestupdate.py": [
|
||||||
"1f8ba77e8f9e0de32fa497d56ecc999ea722f452",
|
"90bcd593edec91d506d41aef2467859ba5d95c77",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"tools/wptrunner/wptrunner/metadata.py": [
|
"tools/wptrunner/wptrunner/metadata.py": [
|
||||||
"b170fc663165af2c20061184ebea8a0a93cf3b01",
|
"26dc71e64e4187b9595eb5f5d1729884763b36f2",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"tools/wptrunner/wptrunner/products.py": [
|
"tools/wptrunner/wptrunner/products.py": [
|
||||||
|
@ -678730,7 +678840,7 @@
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"tools/wptrunner/wptrunner/tests/test_update.py": [
|
"tools/wptrunner/wptrunner/tests/test_update.py": [
|
||||||
"36facdc9520f944899908f0eed0cd4c9914eaaec",
|
"032ac82dff6e6fddd65e329550b1d314cb89371b",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"tools/wptrunner/wptrunner/tests/test_wpttest.py": [
|
"tools/wptrunner/wptrunner/tests/test_wpttest.py": [
|
||||||
|
@ -678774,7 +678884,7 @@
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"tools/wptrunner/wptrunner/wptcommandline.py": [
|
"tools/wptrunner/wptrunner/wptcommandline.py": [
|
||||||
"0a3a8c2b6f7ea626b715b23b03b3765ef0c12808",
|
"1d6909daaca68e78083327915c0c30e2f9d1c34e",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"tools/wptrunner/wptrunner/wptlogging.py": [
|
"tools/wptrunner/wptrunner/wptlogging.py": [
|
||||||
|
@ -678838,7 +678948,7 @@
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"tools/wptrunner/wptrunner/wpttest.py": [
|
"tools/wptrunner/wptrunner/wpttest.py": [
|
||||||
"767a25de8c1b9411a15b255c3ecc0dd74caa5a89",
|
"7fa39be4de13aea1e3454d3c44dee86c5245546c",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"tools/wptserve/.gitignore": [
|
"tools/wptserve/.gitignore": [
|
||||||
|
@ -681646,11 +681756,11 @@
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"wasm/jsapi/wasm-constants.js": [
|
"wasm/jsapi/wasm-constants.js": [
|
||||||
"18748e6cf540db200a83de6d151dc8d77d1b25e1",
|
"e3846386b8dccada9c24da194950627f4c39836f",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"wasm/jsapi/wasm-module-builder.js": [
|
"wasm/jsapi/wasm-module-builder.js": [
|
||||||
"c01b71733d667b8d299971f99c3133be9bf08d8b",
|
"e13f4157873baf0896f42b9fd340588f4453a14a",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"wasm/resources/load_wasm.js": [
|
"wasm/resources/load_wasm.js": [
|
||||||
|
@ -682506,7 +682616,7 @@
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"webaudio/resources/biquad-testing.js": [
|
"webaudio/resources/biquad-testing.js": [
|
||||||
"7a0b6e6c1f8a3d616620425731603f0b43c5ff84",
|
"7f90a1f72bec6be2cfc3a1256a40132958632ca9",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"webaudio/resources/convolution-testing.js": [
|
"webaudio/resources/convolution-testing.js": [
|
||||||
|
@ -682518,7 +682628,7 @@
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"webaudio/resources/distance-model-testing.js": [
|
"webaudio/resources/distance-model-testing.js": [
|
||||||
"1b9adde403e37933100a7ef13369aa3e40d5515b",
|
"f8a6cf940a96f197461f605f1bf527175f63670a",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"webaudio/resources/merger-testing.js": [
|
"webaudio/resources/merger-testing.js": [
|
||||||
|
@ -682534,7 +682644,7 @@
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"webaudio/resources/note-grain-on-testing.js": [
|
"webaudio/resources/note-grain-on-testing.js": [
|
||||||
"1e941897161228f043d9acd128bd3b44b693b7d1",
|
"ad0631670df932c63c5029ea1f267de5032c9fa9",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"webaudio/resources/panner-formulas.js": [
|
"webaudio/resources/panner-formulas.js": [
|
||||||
|
@ -682542,7 +682652,7 @@
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"webaudio/resources/panner-model-testing.js": [
|
"webaudio/resources/panner-model-testing.js": [
|
||||||
"662fb1d68c5361464b21e8a08c5e23de1a558515",
|
"4df3e178134210d9bb55da1100dd98880aa86801",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"webaudio/resources/sin_440Hz_-6dBFS_1s.wav": [
|
"webaudio/resources/sin_440Hz_-6dBFS_1s.wav": [
|
||||||
|
@ -682554,7 +682664,7 @@
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"webaudio/resources/stereopanner-testing.js": [
|
"webaudio/resources/stereopanner-testing.js": [
|
||||||
"d6238a9cd367b00137027735fd0ff7d3c3aae3b7",
|
"2778493e3b6c12d4c00c77bd975e845063621522",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"webaudio/the-audio-api/the-analysernode-interface/.gitkeep": [
|
"webaudio/the-audio-api/the-analysernode-interface/.gitkeep": [
|
||||||
|
@ -682650,7 +682760,7 @@
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-playbackrate-zero.html": [
|
"webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-playbackrate-zero.html": [
|
||||||
"58ee49e42d279e5a28d78aa32c34e0e511850df2",
|
"5624054e3289a18d48fab3b4942f3bb16b9d1c03",
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-start.html": [
|
"webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-start.html": [
|
||||||
|
@ -682685,6 +682795,10 @@
|
||||||
"ab9d5fe5a9dbd736a079f0cfd7966d5e064ed7ef",
|
"ab9d5fe5a9dbd736a079f0cfd7966d5e064ed7ef",
|
||||||
"support"
|
"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": [
|
"webaudio/the-audio-api/the-audiobuffersourcenode-interface/sample-accurate-scheduling.html": [
|
||||||
"5fafd024eef9b476f4d97b2ebaa2190a4ca520d5",
|
"5fafd024eef9b476f4d97b2ebaa2190a4ca520d5",
|
||||||
"testharness"
|
"testharness"
|
||||||
|
@ -682718,7 +682832,7 @@
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"webaudio/the-audio-api/the-audionode-interface/audionode-channel-rules.html": [
|
"webaudio/the-audio-api/the-audionode-interface/audionode-channel-rules.html": [
|
||||||
"a1c3273cc3fef597eff30e13c6074bd99ddb7acf",
|
"9067e6869bcf682e4f3f945d567a2d8a300d9f4b",
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"webaudio/the-audio-api/the-audionode-interface/audionode-connect-method-chaining.html": [
|
"webaudio/the-audio-api/the-audionode-interface/audionode-connect-method-chaining.html": [
|
||||||
|
@ -682838,7 +682952,7 @@
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"webaudio/the-audio-api/the-audioparam-interface/k-rate-panner.html": [
|
"webaudio/the-audio-api/the-audioparam-interface/k-rate-panner.html": [
|
||||||
"ea2a4d1364595865d4c77e3b38449f5ffe3d5da5",
|
"60200b24712c29a92d73b6215b85f734999b8209",
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"webaudio/the-audio-api/the-audioparam-interface/k-rate-stereo-panner.html": [
|
"webaudio/the-audio-api/the-audioparam-interface/k-rate-stereo-panner.html": [
|
||||||
|
@ -683026,7 +683140,7 @@
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"webaudio/the-audio-api/the-biquadfilternode-interface/biquad-lowpass.html": [
|
"webaudio/the-audio-api/the-biquadfilternode-interface/biquad-lowpass.html": [
|
||||||
"d20786e36b16d7ba36841dd5fcfb30c081113fb2",
|
"69dc85a2e2be61da92d8d48f34472e3da8d35fb1",
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"webaudio/the-audio-api/the-biquadfilternode-interface/biquad-lowshelf.html": [
|
"webaudio/the-audio-api/the-biquadfilternode-interface/biquad-lowshelf.html": [
|
||||||
|
@ -683222,7 +683336,7 @@
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"webaudio/the-audio-api/the-gainnode-interface/gain.html": [
|
"webaudio/the-audio-api/the-gainnode-interface/gain.html": [
|
||||||
"cff609de4b795a9d6ab0c465af3b959563d45cce",
|
"c1ee0240cb9f87bc05fb4f5fb076d01b2de45899",
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"webaudio/the-audio-api/the-gainnode-interface/no-dezippering.html": [
|
"webaudio/the-audio-api/the-gainnode-interface/no-dezippering.html": [
|
||||||
|
@ -683329,6 +683443,10 @@
|
||||||
"8e09e869acb4b5a0e5dd94e2401494c690954208",
|
"8e09e869acb4b5a0e5dd94e2401494c690954208",
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
|
"webaudio/the-audio-api/the-pannernode-interface/panner-azimuth.html": [
|
||||||
|
"d09f2ec352f052e987178a7ea0cb8a2b83283ccf",
|
||||||
|
"testharness"
|
||||||
|
],
|
||||||
"webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping.html": [
|
"webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping.html": [
|
||||||
"96b99a2373bccdab74ebdfd409f0f8adb4acc94d",
|
"96b99a2373bccdab74ebdfd409f0f8adb4acc94d",
|
||||||
"testharness"
|
"testharness"
|
||||||
|
@ -684306,7 +684424,7 @@
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"webdriver/tests/set_window_rect/set.py": [
|
"webdriver/tests/set_window_rect/set.py": [
|
||||||
"4017bc198e41ea618e73c2d71cfcb68312b0c4d0",
|
"81432f293770d0fd0b5da66dc4bca19c1043f9a0",
|
||||||
"wdspec"
|
"wdspec"
|
||||||
],
|
],
|
||||||
"webdriver/tests/set_window_rect/user_prompts.py": [
|
"webdriver/tests/set_window_rect/user_prompts.py": [
|
||||||
|
@ -684330,11 +684448,11 @@
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"webdriver/tests/support/defaults.py": [
|
"webdriver/tests/support/defaults.py": [
|
||||||
"c2020527a6f38a628b2c1a4199caaff46cf0c36b",
|
"8dd171aa64c71fa031e0e14ef4344f4335e368cc",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"webdriver/tests/support/fixtures.py": [
|
"webdriver/tests/support/fixtures.py": [
|
||||||
"f662040e4066f14afa6a5f8c40778db23ccab29a",
|
"bd2381d2069ac64788446252d173ae1c052d5b71",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
"webdriver/tests/support/helpers.py": [
|
"webdriver/tests/support/helpers.py": [
|
||||||
|
|
|
@ -6,6 +6,3 @@
|
||||||
[Instant scrolling while doing history navigation.]
|
[Instant scrolling while doing history navigation.]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Smooth scrolling while doing history navigation.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -2,3 +2,9 @@
|
||||||
[EventListener::handleEvent()]
|
[EventListener::handleEvent()]
|
||||||
expected: FAIL
|
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.]
|
[Verifies the resolution of entry.startTime is at least 5 microseconds.]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
|
|
||||||
|
[Verifies the resolution of performance.now() is at least 5 microseconds.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
[No imports]
|
[No imports]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
[exports and imports]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
[constructor.any.worker.html]
|
[constructor.any.worker.html]
|
||||||
[exports]
|
[exports]
|
||||||
|
@ -13,3 +16,6 @@
|
||||||
[No imports]
|
[No imports]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
[exports and imports]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
[get-set.any.worker.html]
|
[get-set.any.worker.html]
|
||||||
|
expected: ERROR
|
||||||
[Setting out-of-range argument: NaN]
|
[Setting out-of-range argument: NaN]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -74,8 +75,12 @@
|
||||||
[Setting non-function]
|
[Setting non-function]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
[Stray argument]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
[get-set.any.html]
|
[get-set.any.html]
|
||||||
|
expected: ERROR
|
||||||
[Setting out-of-range argument: NaN]
|
[Setting out-of-range argument: NaN]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -151,3 +156,6 @@
|
||||||
[Setting non-function]
|
[Setting non-function]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
[Stray argument]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -8,3 +8,15 @@
|
||||||
[# AUDIT TASK RUNNER FINISHED: 1 out of 1 tasks were failed.]
|
[# AUDIT TASK RUNNER FINISHED: 1 out of 1 tasks were failed.]
|
||||||
expected: FAIL
|
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.]
|
[< [test\] 2 out of 4 assertions were failed.]
|
||||||
expected: FAIL
|
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]
|
[005.html]
|
||||||
|
expected: ERROR
|
||||||
[dedicated worker in shared worker in dedicated worker]
|
[dedicated worker in shared worker in dedicated worker]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ tasks:
|
||||||
owner: ${event.pusher.email}
|
owner: ${event.pusher.email}
|
||||||
source: ${event.repository.url}
|
source: ${event.repository.url}
|
||||||
payload:
|
payload:
|
||||||
image: harjgam/web-platform-tests:0.26
|
image: harjgam/web-platform-tests:0.29
|
||||||
maxRunTime: 7200
|
maxRunTime: 7200
|
||||||
artifacts:
|
artifacts:
|
||||||
public/results:
|
public/results:
|
||||||
|
@ -136,7 +136,7 @@ tasks:
|
||||||
owner: ${event.pull_request.user.login}@users.noreply.github.com
|
owner: ${event.pull_request.user.login}@users.noreply.github.com
|
||||||
source: ${event.repository.url}
|
source: ${event.repository.url}
|
||||||
payload:
|
payload:
|
||||||
image: harjgam/web-platform-tests:0.26
|
image: harjgam/web-platform-tests:0.29
|
||||||
maxRunTime: 7200
|
maxRunTime: 7200
|
||||||
artifacts:
|
artifacts:
|
||||||
public/results:
|
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>
|
<script>
|
||||||
test(()=>{
|
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
|
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.");
|
}, "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>
|
<title>EventListener::handleEvent()</title>
|
||||||
<script src="/resources/testharness.js"></script>
|
<script src="/resources/testharness.js"></script>
|
||||||
<script src="/resources/testharnessreport.js"></script>
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<link rel="help" href="https://dom.spec.whatwg.org/#callbackdef-eventlistener">
|
||||||
<div id=log></div>
|
<div id=log></div>
|
||||||
<table id="table" border="1" style="display: none">
|
<div id=target></div>
|
||||||
<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>
|
|
||||||
<script>
|
<script>
|
||||||
test(function(t) {
|
setup({ allow_uncaught_exception: true });
|
||||||
var event = "foo";
|
|
||||||
var target = document.getElementById("target");
|
|
||||||
|
|
||||||
var event_listener = {
|
test(function(t) {
|
||||||
"handleEvent": function(evt) {
|
var type = "foo";
|
||||||
|
var target = document.getElementById("target");
|
||||||
|
var eventListener = {
|
||||||
|
handleEvent: function(evt) {
|
||||||
var that = this;
|
var that = this;
|
||||||
t.step(function() {
|
t.step(function() {
|
||||||
assert_equals(evt.type, event);
|
assert_equals(evt.type, type);
|
||||||
assert_equals(evt.target, target);
|
assert_equals(evt.target, target);
|
||||||
assert_equals(evt.srcElement, target);
|
assert_equals(evt.srcElement, target);
|
||||||
assert_equals(that, event_listener);
|
assert_equals(that, eventListener);
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
var evt = document.createEvent("Event");
|
target.addEventListener(type, eventListener);
|
||||||
evt.initEvent(event, true, true);
|
target.dispatchEvent(new Event(type));
|
||||||
|
}, "calls `handleEvent` method of `EventListener`");
|
||||||
|
|
||||||
target.addEventListener(event, event_listener, true);
|
test(function(t) {
|
||||||
target.dispatchEvent(evt);
|
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>
|
</script>
|
||||||
|
|
|
@ -17,7 +17,9 @@ handlersListPromise.then(({ shadowedHandlers, notShadowedHandlers }) => {
|
||||||
add_completion_callback(() => {
|
add_completion_callback(() => {
|
||||||
const log_elem = document.getElementById("log");
|
const log_elem = document.getElementById("log");
|
||||||
const frame_elem = document.querySelector("frame");
|
const frame_elem = document.querySelector("frame");
|
||||||
frame_elem.contentDocument.body.innerHTML = log_elem.innerHTML;
|
if (log_elem) {
|
||||||
|
frame_elem.contentDocument.body.innerHTML = log_elem.innerHTML;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
done();
|
done();
|
||||||
|
|
|
@ -28,12 +28,10 @@ enum XREnvironmentBlendMode {
|
||||||
readonly attribute XRSessionMode mode;
|
readonly attribute XRSessionMode mode;
|
||||||
readonly attribute XRPresentationContext? outputContext;
|
readonly attribute XRPresentationContext? outputContext;
|
||||||
readonly attribute XREnvironmentBlendMode environmentBlendMode;
|
readonly attribute XREnvironmentBlendMode environmentBlendMode;
|
||||||
|
readonly attribute XRRenderState renderState;
|
||||||
attribute double depthNear;
|
|
||||||
attribute double depthFar;
|
|
||||||
attribute XRLayer? baseLayer;
|
|
||||||
|
|
||||||
// Methods
|
// Methods
|
||||||
|
void updateRenderState(optional XRRenderStateInit state);
|
||||||
Promise<XRReferenceSpace> requestReferenceSpace(XRReferenceSpaceOptions options);
|
Promise<XRReferenceSpace> requestReferenceSpace(XRReferenceSpaceOptions options);
|
||||||
|
|
||||||
FrozenArray<XRInputSource> getInputSources();
|
FrozenArray<XRInputSource> getInputSources();
|
||||||
|
@ -64,6 +62,18 @@ dictionary XRSessionCreationOptions {
|
||||||
XRPresentationContext? outputContext = null;
|
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);
|
callback XRFrameRequestCallback = void (DOMHighResTimeStamp time, XRFrame frame);
|
||||||
|
|
||||||
[SecureContext, Exposed=Window] interface XRFrame {
|
[SecureContext, Exposed=Window] interface XRFrame {
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
<script nonce="abc">
|
<script nonce="abc">
|
||||||
window.addEventListener('load', t.step_func(function() {
|
window.addEventListener('load', t.step_func(function() {
|
||||||
verifyPreloadAndRTSupport();
|
verifyPreloadAndRTSupport();
|
||||||
verifyNumberOfDownloads("resources/dummy.js?from-header&without-nonce", 0);
|
verifyNumberOfResourceTimingEntries("resources/dummy.js?from-header&without-nonce", 0);
|
||||||
verifyNumberOfDownloads("resources/dummy.js?from-header&with-nonce", 1);
|
verifyNumberOfResourceTimingEntries("resources/dummy.js?from-header&with-nonce", 1);
|
||||||
t.done();
|
t.done();
|
||||||
}));
|
}));
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -11,16 +11,16 @@
|
||||||
<script>
|
<script>
|
||||||
window.addEventListener("load", t.step_func(function() {
|
window.addEventListener("load", t.step_func(function() {
|
||||||
verifyPreloadAndRTSupport();
|
verifyPreloadAndRTSupport();
|
||||||
verifyNumberOfDownloads('resources/square.png?from-header&1x', 1);
|
verifyNumberOfResourceTimingEntries('resources/square.png?from-header&1x', 1);
|
||||||
verifyNumberOfDownloads('resources/square.png?from-header&2x', 0);
|
verifyNumberOfResourceTimingEntries('resources/square.png?from-header&2x', 0);
|
||||||
verifyNumberOfDownloads('resources/square.png?from-header&3x', 0);
|
verifyNumberOfResourceTimingEntries('resources/square.png?from-header&3x', 0);
|
||||||
verifyNumberOfDownloads('resources/square.png?from-header&base', 0);
|
verifyNumberOfResourceTimingEntries('resources/square.png?from-header&base', 0);
|
||||||
verifyNumberOfDownloads('resources/square.png?from-header&200', 0);
|
verifyNumberOfResourceTimingEntries('resources/square.png?from-header&200', 0);
|
||||||
verifyNumberOfDownloads('resources/square.png?from-header&400', 1);
|
verifyNumberOfResourceTimingEntries('resources/square.png?from-header&400', 1);
|
||||||
verifyNumberOfDownloads('resources/square.png?from-header&800', 0);
|
verifyNumberOfResourceTimingEntries('resources/square.png?from-header&800', 0);
|
||||||
verifyNumberOfDownloads('resources/square.png?from-header&150', 0);
|
verifyNumberOfResourceTimingEntries('resources/square.png?from-header&150', 0);
|
||||||
verifyNumberOfDownloads('resources/square.png?from-header&300', 1);
|
verifyNumberOfResourceTimingEntries('resources/square.png?from-header&300', 1);
|
||||||
verifyNumberOfDownloads('resources/square.png?from-header&600', 0);
|
verifyNumberOfResourceTimingEntries('resources/square.png?from-header&600', 0);
|
||||||
t.done();
|
t.done();
|
||||||
}));
|
}));
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -20,3 +20,9 @@ function verifyNumberOfDownloads(url, number)
|
||||||
});
|
});
|
||||||
assert_equals(numDownloads, number, url);
|
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-pause",
|
||||||
"--no-restart-on-unexpected",
|
"--no-restart-on-unexpected",
|
||||||
"--install-fonts",
|
"--install-fonts",
|
||||||
"--no-headless"
|
"--no-headless",
|
||||||
|
"--verify-log-full"
|
||||||
]
|
]
|
||||||
wpt_args += browser_specific_args.get(product, [])
|
wpt_args += browser_specific_args.get(product, [])
|
||||||
|
|
||||||
|
|
|
@ -66,9 +66,13 @@ WORKDIR /home/test
|
||||||
RUN sudo echo ""
|
RUN sudo echo ""
|
||||||
|
|
||||||
RUN mkdir -p /home/test/artifacts
|
RUN mkdir -p /home/test/artifacts
|
||||||
|
RUN mkdir -p /home/test/bin
|
||||||
|
|
||||||
|
ENV PATH="/home/test/bin:${PATH}"
|
||||||
|
|
||||||
WORKDIR /home/test/
|
WORKDIR /home/test/
|
||||||
|
|
||||||
COPY .bashrc /home/test/.bashrc
|
COPY .bashrc /home/test/.bashrc
|
||||||
|
|
||||||
COPY start.sh /home/test/start.sh
|
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}
|
git remote add origin ${REMOTE}
|
||||||
|
|
||||||
# Initially we just fetch 50 commits in order to save several minutes of fetching
|
# 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}` ]];
|
if [[ ! `git rev-parse --verify -q ${REVISION}` ]];
|
||||||
then
|
then
|
||||||
# But if for some reason the commit under test isn't in that range, we give in and
|
# But if for some reason the commit under test isn't in that range, we give in and
|
||||||
# fetch everything
|
# fetch everything
|
||||||
git fetch -q --unshallow ${REMOTE}
|
retry git fetch -q --unshallow ${REMOTE}
|
||||||
git rev-parse --verify ${REVISION}
|
git rev-parse --verify ${REVISION}
|
||||||
fi
|
fi
|
||||||
git checkout -b build ${REVISION}
|
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,
|
"timeout_multiplier": get_timeout_multiplier(test_type,
|
||||||
run_info_data,
|
run_info_data,
|
||||||
**kwargs),
|
**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"),
|
"asan": run_info_data.get("asan"),
|
||||||
"stylo_threads": kwargs["stylo_threads"],
|
"stylo_threads": kwargs["stylo_threads"],
|
||||||
"chaos_mode_flags": kwargs["chaos_mode_flags"],
|
"chaos_mode_flags": kwargs["chaos_mode_flags"],
|
||||||
|
@ -214,6 +214,8 @@ class FirefoxBrowser(Browser):
|
||||||
self.lsan_dir = lsan_dir
|
self.lsan_dir = lsan_dir
|
||||||
self.lsan_allowed = None
|
self.lsan_allowed = None
|
||||||
self.lsan_max_stack_depth = None
|
self.lsan_max_stack_depth = None
|
||||||
|
self.mozleak_allowed = None
|
||||||
|
self.mozleak_thresholds = None
|
||||||
self.leak_check = leak_check
|
self.leak_check = leak_check
|
||||||
self.leak_report_file = None
|
self.leak_report_file = None
|
||||||
self.lsan_handler = None
|
self.lsan_handler = None
|
||||||
|
@ -222,21 +224,27 @@ class FirefoxBrowser(Browser):
|
||||||
self.headless = headless
|
self.headless = headless
|
||||||
|
|
||||||
def settings(self, test):
|
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,
|
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):
|
def start(self, group_metadata=None, **kwargs):
|
||||||
if group_metadata is None:
|
if group_metadata is None:
|
||||||
group_metadata = {}
|
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:
|
if self.marionette_port is None:
|
||||||
self.marionette_port = get_free_port(2828, exclude=self.used_ports)
|
self.marionette_port = get_free_port(2828, exclude=self.used_ports)
|
||||||
self.used_ports.add(self.marionette_port)
|
self.used_ports.add(self.marionette_port)
|
||||||
|
|
||||||
if self.asan:
|
if self.asan:
|
||||||
print "Setting up LSAN"
|
|
||||||
self.lsan_handler = mozleak.LSANLeaks(self.logger,
|
self.lsan_handler = mozleak.LSANLeaks(self.logger,
|
||||||
scope=group_metadata.get("scope", "/"),
|
scope=group_metadata.get("scope", "/"),
|
||||||
allowed=self.lsan_allowed,
|
allowed=self.lsan_allowed,
|
||||||
|
@ -357,21 +365,18 @@ class FirefoxBrowser(Browser):
|
||||||
self.logger.debug("stopped")
|
self.logger.debug("stopped")
|
||||||
|
|
||||||
def process_leaks(self):
|
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:
|
if self.lsan_handler:
|
||||||
self.lsan_handler.process()
|
self.lsan_handler.process()
|
||||||
if self.leak_report_file is not None:
|
if self.leak_report_file is not None:
|
||||||
mozleak.process_leak_log(
|
mozleak.process_leak_log(
|
||||||
self.leak_report_file,
|
self.leak_report_file,
|
||||||
leak_thresholds={
|
leak_thresholds=self.mozleak_thresholds,
|
||||||
"default": 0,
|
ignore_missing_leaks=["gmplugin"],
|
||||||
"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"],
|
|
||||||
log=self.logger,
|
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):
|
def pid(self):
|
||||||
|
|
|
@ -595,6 +595,7 @@ class ExecuteAsyncScriptRun(object):
|
||||||
if self.protocol.is_alive:
|
if self.protocol.is_alive:
|
||||||
self.result = False, ("INTERNAL-ERROR", None)
|
self.result = False, ("INTERNAL-ERROR", None)
|
||||||
else:
|
else:
|
||||||
|
self.logger.info("Browser not responding, setting status to CRASH")
|
||||||
self.result = False, ("CRASH", None)
|
self.result = False, ("CRASH", None)
|
||||||
return self.result
|
return self.result
|
||||||
|
|
||||||
|
@ -608,15 +609,21 @@ class ExecuteAsyncScriptRun(object):
|
||||||
# This can happen on a crash
|
# This can happen on a crash
|
||||||
# Also, should check after the test if the firefox process is still running
|
# Also, should check after the test if the firefox process is still running
|
||||||
# and otherwise ignore any other result and set it to crash
|
# 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)
|
self.result = False, ("CRASH", None)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
message = getattr(e, "message", "")
|
if isinstance(e, errors.JavascriptException) and e.message.startswith("Document was unloaded"):
|
||||||
if message:
|
message = "Document unloaded; maybe test navigated the top-level-browsing context?"
|
||||||
message += "\n"
|
else:
|
||||||
message += traceback.format_exc(e)
|
message = getattr(e, "message", "")
|
||||||
self.logger.warning(message)
|
if message:
|
||||||
self.result = False, ("INTERNAL-ERROR", None)
|
message += "\n"
|
||||||
|
message += traceback.format_exc(e)
|
||||||
|
self.logger.warning(traceback.format_exc())
|
||||||
|
self.result = False, ("INTERNAL-ERROR", message)
|
||||||
finally:
|
finally:
|
||||||
self.result_flag.set()
|
self.result_flag.set()
|
||||||
|
|
||||||
|
|
|
@ -123,3 +123,32 @@ class WptreportFormatter(BaseFormatter):
|
||||||
"min": data["min_expected"],
|
"min": data["min_expected"],
|
||||||
"max": data["max_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
|
return rv
|
||||||
|
|
||||||
|
|
||||||
def lsan_allowed(node):
|
def set_prop(name, node):
|
||||||
try:
|
try:
|
||||||
node_items = node.get("lsan-allowed")
|
node_items = node.get(name)
|
||||||
if isinstance(node_items, (str, unicode)):
|
if isinstance(node_items, (str, unicode)):
|
||||||
rv = {node_items}
|
rv = {node_items}
|
||||||
else:
|
else:
|
||||||
|
@ -82,6 +82,20 @@ def lsan_allowed(node):
|
||||||
return rv
|
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):
|
class ExpectedManifest(ManifestItem):
|
||||||
def __init__(self, name, test_path, url_base):
|
def __init__(self, name, test_path, url_base):
|
||||||
"""Object representing all the tests in a particular manifest
|
"""Object representing all the tests in a particular manifest
|
||||||
|
@ -154,7 +168,15 @@ class ExpectedManifest(ManifestItem):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def lsan_allowed(self):
|
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
|
@property
|
||||||
def lsan_max_stack_depth(self):
|
def lsan_max_stack_depth(self):
|
||||||
|
@ -192,7 +214,15 @@ class DirectoryManifest(ManifestItem):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def lsan_allowed(self):
|
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
|
@property
|
||||||
def lsan_max_stack_depth(self):
|
def lsan_max_stack_depth(self):
|
||||||
|
@ -256,7 +286,15 @@ class TestNode(ManifestItem):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def lsan_allowed(self):
|
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
|
@property
|
||||||
def lsan_max_stack_depth(self):
|
def lsan_max_stack_depth(self):
|
||||||
|
|
|
@ -2,6 +2,7 @@ import itertools
|
||||||
import os
|
import os
|
||||||
import urlparse
|
import urlparse
|
||||||
from collections import namedtuple, defaultdict
|
from collections import namedtuple, defaultdict
|
||||||
|
from math import ceil
|
||||||
|
|
||||||
from wptmanifest.node import (DataNode, ConditionalNode, BinaryExpressionNode,
|
from wptmanifest.node import (DataNode, ConditionalNode, BinaryExpressionNode,
|
||||||
BinaryOperatorNode, VariableNode, StringNode, NumberNode,
|
BinaryOperatorNode, VariableNode, StringNode, NumberNode,
|
||||||
|
@ -81,6 +82,8 @@ class ExpectedManifest(ManifestItem):
|
||||||
self.property_order = property_order
|
self.property_order = property_order
|
||||||
self.update_properties = {
|
self.update_properties = {
|
||||||
"lsan": LsanUpdate(self),
|
"lsan": LsanUpdate(self),
|
||||||
|
"leak-object": LeakObjectUpdate(self),
|
||||||
|
"leak-threshold": LeakThresholdUpdate(self),
|
||||||
}
|
}
|
||||||
|
|
||||||
def append(self, child):
|
def append(self, child):
|
||||||
|
@ -122,6 +125,24 @@ class ExpectedManifest(ManifestItem):
|
||||||
|
|
||||||
self.update_properties["lsan"].set(run_info, result)
|
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):
|
def coalesce_properties(self, stability):
|
||||||
for prop_update in self.update_properties.itervalues():
|
for prop_update in self.update_properties.itervalues():
|
||||||
prop_update.coalesce(stability)
|
prop_update.coalesce(stability)
|
||||||
|
@ -432,6 +453,10 @@ class ExpectedUpdate(PropertyUpdate):
|
||||||
|
|
||||||
|
|
||||||
class MaxAssertsUpdate(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"
|
property_name = "max-asserts"
|
||||||
cls_default_value = 0
|
cls_default_value = 0
|
||||||
value_type = int
|
value_type = int
|
||||||
|
@ -447,9 +472,6 @@ class MaxAssertsUpdate(PropertyUpdate):
|
||||||
return old_value
|
return old_value
|
||||||
|
|
||||||
def update_default(self):
|
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
|
# Current values
|
||||||
values = []
|
values = []
|
||||||
current_default = None
|
current_default = None
|
||||||
|
@ -501,20 +523,11 @@ class MinAssertsUpdate(PropertyUpdate):
|
||||||
return True, new_value
|
return True, new_value
|
||||||
|
|
||||||
|
|
||||||
class LsanUpdate(PropertyUpdate):
|
class AppendOnlyListUpdate(PropertyUpdate):
|
||||||
property_name = "lsan-allowed"
|
|
||||||
cls_default_value = None
|
cls_default_value = None
|
||||||
|
|
||||||
def get_value(self, result):
|
def get_value(self, result):
|
||||||
# If we have an allowed_match that matched, return None
|
raise NotImplementedError
|
||||||
# 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]
|
|
||||||
|
|
||||||
def update_value(self, old_value, new_value):
|
def update_value(self, old_value, new_value):
|
||||||
if isinstance(new_value, (str, unicode)):
|
if isinstance(new_value, (str, unicode)):
|
||||||
|
@ -539,6 +552,96 @@ class LsanUpdate(PropertyUpdate):
|
||||||
return True, new_value if new_value else None
|
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):
|
def group_conditionals(values, property_order=None, boolean_properties=None):
|
||||||
"""Given a list of Value objects, return a list of
|
"""Given a list of Value objects, return a list of
|
||||||
(conditional_node, status) pairs representing the conditional
|
(conditional_node, status) pairs representing the conditional
|
||||||
|
|
|
@ -289,7 +289,9 @@ class ExpectedUpdater(object):
|
||||||
"test_status": self.test_status,
|
"test_status": self.test_status,
|
||||||
"test_end": self.test_end,
|
"test_end": self.test_end,
|
||||||
"assertion_count": self.assertion_count,
|
"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 = {}
|
self.tests_visited = {}
|
||||||
|
|
||||||
def update_from_log(self, log_file):
|
def update_from_log(self, log_file):
|
||||||
|
@ -340,6 +342,15 @@ class ExpectedUpdater(object):
|
||||||
for item in data.get("lsan_leaks", []):
|
for item in data.get("lsan_leaks", []):
|
||||||
action_map["lsan_leak"](item)
|
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):
|
def suite_start(self, data):
|
||||||
self.run_info = run_info_intern.store(data["run_info"])
|
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"]:
|
if data["count"] < data["min_expected"] or data["count"] > data["max_expected"]:
|
||||||
test_data.set_requires_update()
|
test_data.set_requires_update()
|
||||||
|
|
||||||
def lsan_leak(self, data):
|
def test_for_scope(self, data):
|
||||||
dir_path = data.get("scope", "/")
|
dir_path = data.get("scope", "/")
|
||||||
dir_id = intern(os.path.join(dir_path, "__dir__").replace(os.path.sep, "/").encode("utf8"))
|
dir_id = intern(os.path.join(dir_path, "__dir__").replace(os.path.sep, "/").encode("utf8"))
|
||||||
if dir_id.startswith("/"):
|
if dir_id.startswith("/"):
|
||||||
dir_id = dir_id[1:]
|
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",
|
test_data.set(dir_id, None, "lsan",
|
||||||
self.run_info, (data["frames"], data.get("allowed_match")))
|
self.run_info, (data["frames"], data.get("allowed_match")))
|
||||||
if not data.get("allowed_match"):
|
if not data.get("allowed_match"):
|
||||||
test_data.set_requires_update()
|
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):
|
def create_test_tree(metadata_path, test_manifest):
|
||||||
"""Create a map of test_id to TestFileData for that test.
|
"""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 subtest_id is None and test_id.endswith("__dir__"):
|
||||||
if prop == "lsan":
|
if prop == "lsan":
|
||||||
expected.set_lsan(run_info, value)
|
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
|
continue
|
||||||
|
|
||||||
if prop == "status":
|
if prop == "status":
|
||||||
|
|
|
@ -606,3 +606,98 @@ def test_update_wptreport_1():
|
||||||
|
|
||||||
assert len(updated) == 1
|
assert len(updated) == 1
|
||||||
assert updated[0][1].get("lsan-allowed") == ["baz"]
|
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',
|
gecko_group.add_argument("--setpref", dest="extra_prefs", action='append',
|
||||||
default=[], metavar="PREF=VALUE",
|
default=[], metavar="PREF=VALUE",
|
||||||
help="Defines an extra user preference (overrides those in prefs_root)")
|
help="Defines an extra user preference (overrides those in prefs_root)")
|
||||||
gecko_group.add_argument("--leak-check", dest="leak_check", action="store_true",
|
gecko_group.add_argument("--leak-check", dest="leak_check", action="store_true", default=None,
|
||||||
help="Enable leak checking")
|
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,
|
gecko_group.add_argument("--stylo-threads", action="store", type=int, default=1,
|
||||||
help="Number of parallel threads to use for stylo")
|
help="Number of parallel threads to use for stylo")
|
||||||
gecko_group.add_argument("--reftest-internal", dest="reftest_internal", action="store_true",
|
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",
|
gecko_group.add_argument("--reftest-external", dest="reftest_internal", action="store_false",
|
||||||
help="Disable reftest runner implemented inside Marionette")
|
help="Disable reftest runner implemented inside Marionette")
|
||||||
gecko_group.add_argument("--reftest-screenshot", dest="reftest_screenshot", action="store",
|
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")
|
help="With --reftest-internal, when to take a screenshot")
|
||||||
gecko_group.add_argument("--chaos", dest="chaos_mode_flags", action="store",
|
gecko_group.add_argument("--chaos", dest="chaos_mode_flags", action="store",
|
||||||
nargs="?", const=0xFFFFFFFF, type=int,
|
nargs="?", const=0xFFFFFFFF, type=int,
|
||||||
|
@ -532,6 +535,9 @@ def check_args(kwargs):
|
||||||
if kwargs["lsan_dir"] is None:
|
if kwargs["lsan_dir"] is None:
|
||||||
kwargs["lsan_dir"] = kwargs["prefs_root"]
|
kwargs["lsan_dir"] = kwargs["prefs_root"]
|
||||||
|
|
||||||
|
if kwargs["reftest_screenshot"] is None:
|
||||||
|
kwargs["reftest_screenshot"] = "unexpected"
|
||||||
|
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -242,6 +242,26 @@ class Test(object):
|
||||||
return depth
|
return depth
|
||||||
return None
|
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
|
@property
|
||||||
def tags(self):
|
def tags(self):
|
||||||
tags = set()
|
tags = set()
|
||||||
|
|
|
@ -28,6 +28,7 @@ var kWasmV3 = 0;
|
||||||
|
|
||||||
var kHeaderSize = 8;
|
var kHeaderSize = 8;
|
||||||
var kPageSize = 65536;
|
var kPageSize = 65536;
|
||||||
|
var kSpecMaxPages = 65535;
|
||||||
|
|
||||||
function bytesWithHeader() {
|
function bytesWithHeader() {
|
||||||
var buffer = new ArrayBuffer(kHeaderSize + arguments.length);
|
var buffer = new ArrayBuffer(kHeaderSize + arguments.length);
|
||||||
|
@ -52,18 +53,17 @@ let kDeclNoLocals = 0;
|
||||||
|
|
||||||
// Section declaration constants
|
// Section declaration constants
|
||||||
let kUnknownSectionCode = 0;
|
let kUnknownSectionCode = 0;
|
||||||
let kTypeSectionCode = 1; // Function signature declarations
|
let kTypeSectionCode = 1; // Function signature declarations
|
||||||
let kImportSectionCode = 2; // Import declarations
|
let kImportSectionCode = 2; // Import declarations
|
||||||
let kFunctionSectionCode = 3; // Function declarations
|
let kFunctionSectionCode = 3; // Function declarations
|
||||||
let kTableSectionCode = 4; // Indirect function table and other tables
|
let kTableSectionCode = 4; // Indirect function table and other tables
|
||||||
let kMemorySectionCode = 5; // Memory attributes
|
let kMemorySectionCode = 5; // Memory attributes
|
||||||
let kGlobalSectionCode = 6; // Global declarations
|
let kGlobalSectionCode = 6; // Global declarations
|
||||||
let kExportSectionCode = 7; // Exports
|
let kExportSectionCode = 7; // Exports
|
||||||
let kStartSectionCode = 8; // Start function declaration
|
let kStartSectionCode = 8; // Start function declaration
|
||||||
let kElementSectionCode = 9; // Elements section
|
let kElementSectionCode = 9; // Elements section
|
||||||
let kCodeSectionCode = 10; // Function code
|
let kCodeSectionCode = 10; // Function code
|
||||||
let kDataSectionCode = 11; // Data segments
|
let kDataSectionCode = 11; // Data segments
|
||||||
let kNameSectionCode = 12; // Name section (encoded as string)
|
|
||||||
|
|
||||||
// Name section types
|
// Name section types
|
||||||
let kModuleNameCode = 0;
|
let kModuleNameCode = 0;
|
||||||
|
@ -74,6 +74,7 @@ let kWasmFunctionTypeForm = 0x60;
|
||||||
let kWasmAnyFunctionTypeForm = 0x70;
|
let kWasmAnyFunctionTypeForm = 0x70;
|
||||||
|
|
||||||
let kHasMaximumFlag = 1;
|
let kHasMaximumFlag = 1;
|
||||||
|
let kResizableMaximumFlag = 1;
|
||||||
|
|
||||||
// Function declaration flags
|
// Function declaration flags
|
||||||
let kDeclFunctionName = 0x01;
|
let kDeclFunctionName = 0x01;
|
||||||
|
@ -87,6 +88,7 @@ let kWasmI32 = 0x7f;
|
||||||
let kWasmI64 = 0x7e;
|
let kWasmI64 = 0x7e;
|
||||||
let kWasmF32 = 0x7d;
|
let kWasmF32 = 0x7d;
|
||||||
let kWasmF64 = 0x7c;
|
let kWasmF64 = 0x7c;
|
||||||
|
let kWasmS128 = 0x7b;
|
||||||
|
|
||||||
let kExternalFunction = 0;
|
let kExternalFunction = 0;
|
||||||
let kExternalTable = 1;
|
let kExternalTable = 1;
|
||||||
|
@ -102,6 +104,8 @@ let kSig_l_l = makeSig([kWasmI64], [kWasmI64]);
|
||||||
let kSig_i_l = makeSig([kWasmI64], [kWasmI32]);
|
let kSig_i_l = makeSig([kWasmI64], [kWasmI32]);
|
||||||
let kSig_i_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32]);
|
let kSig_i_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32]);
|
||||||
let kSig_i_iii = makeSig([kWasmI32, 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_d_dd = makeSig([kWasmF64, kWasmF64], [kWasmF64]);
|
||||||
let kSig_l_ll = makeSig([kWasmI64, kWasmI64], [kWasmI64]);
|
let kSig_l_ll = makeSig([kWasmI64, kWasmI64], [kWasmI64]);
|
||||||
let kSig_i_dd = makeSig([kWasmF64, kWasmF64], [kWasmI32]);
|
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_dd = makeSig([kWasmF64, kWasmF64], []);
|
||||||
let kSig_v_ddi = makeSig([kWasmF64, kWasmF64, kWasmI32], []);
|
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) {
|
function makeSig(params, results) {
|
||||||
return {params: params, results: results};
|
return {params: params, results: results};
|
||||||
}
|
}
|
||||||
|
@ -357,19 +366,19 @@ function assertTraps(trap, code) {
|
||||||
throw new MjsUnitAssertionError('Did not trap, expected: ' + kTrapMsgs[trap]);
|
throw new MjsUnitAssertionError('Did not trap, expected: ' + kTrapMsgs[trap]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function assertWasmThrows(value, code) {
|
function wasmI32Const(val) {
|
||||||
assertEquals('number', typeof value);
|
let bytes = [kExprI32Const];
|
||||||
try {
|
for (let i = 0; i < 4; ++i) {
|
||||||
if (typeof code === 'function') {
|
bytes.push(0x80 | ((val >> (7 * i)) & 0x7f));
|
||||||
code();
|
|
||||||
} else {
|
|
||||||
eval(code);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
assertEquals('number', typeof e);
|
|
||||||
assertEquals(value, e);
|
|
||||||
// Success.
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
throw new MjsUnitAssertionError('Did not throw, expected: ' + value);
|
bytes.push((val >> (7 * 4)) & 0x7f);
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
// Emit section name.
|
||||||
this.emit_u8(section_code);
|
this.emit_u8(section_code);
|
||||||
// Emit the section to a temporary buffer: its full length isn't know yet.
|
// 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);
|
content_generator(section);
|
||||||
// Emit section length.
|
// Emit section length.
|
||||||
this.emit_u32v(section.length);
|
this.emit_u32v(section.length);
|
||||||
// Copy the temporary buffer.
|
// Copy the temporary buffer.
|
||||||
for (const b of section) {
|
// Avoid spread because {section} can be huge.
|
||||||
this.push(b);
|
for (let b of section) this.push(b);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,15 +87,6 @@ class WasmFunctionBuilder {
|
||||||
this.body = [];
|
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) {
|
exportAs(name) {
|
||||||
this.module.addExport(name, this.index);
|
this.module.addExport(name, this.index);
|
||||||
return this;
|
return this;
|
||||||
|
@ -108,40 +98,12 @@ class WasmFunctionBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
addBody(body) {
|
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;
|
this.body = body;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
getNumLocals() {
|
addLocals(locals) {
|
||||||
let total_locals = 0;
|
this.locals = locals;
|
||||||
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);
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,6 +138,7 @@ class WasmModuleBuilder {
|
||||||
this.table_length_max = undefined;
|
this.table_length_max = undefined;
|
||||||
this.element_segments = [];
|
this.element_segments = [];
|
||||||
this.data_segments = [];
|
this.data_segments = [];
|
||||||
|
this.segments = [];
|
||||||
this.explicit = [];
|
this.explicit = [];
|
||||||
this.num_imported_funcs = 0;
|
this.num_imported_funcs = 0;
|
||||||
this.num_imported_globals = 0;
|
this.num_imported_globals = 0;
|
||||||
|
@ -197,22 +160,6 @@ class WasmModuleBuilder {
|
||||||
return this;
|
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) {
|
addType(type) {
|
||||||
// TODO: canonicalize types?
|
// TODO: canonicalize types?
|
||||||
this.types.push(type);
|
this.types.push(type);
|
||||||
|
@ -235,21 +182,15 @@ class WasmModuleBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
addImport(module = "", name, type) {
|
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);
|
let type_index = (typeof type) == "number" ? type : this.addType(type);
|
||||||
this.imports.push({module: module, name: name, kind: kExternalFunction,
|
this.imports.push({module: module, name: name, kind: kExternalFunction,
|
||||||
type: type_index});
|
type: type_index});
|
||||||
return this.num_imported_funcs++;
|
return this.num_imported_funcs++;
|
||||||
}
|
}
|
||||||
|
|
||||||
addImportedGlobal(module = "", name, type, mutable = false) {
|
addImportedGlobal(module = "", name, type) {
|
||||||
if (this.globals.length != 0) {
|
|
||||||
throw new Error('Imported globals must be declared before local ones');
|
|
||||||
}
|
|
||||||
let o = {module: module, name: name, kind: kExternalGlobal, type: type,
|
let o = {module: module, name: name, kind: kExternalGlobal, type: type,
|
||||||
mutable: mutable};
|
mutable: false}
|
||||||
this.imports.push(o);
|
this.imports.push(o);
|
||||||
return this.num_imported_globals++;
|
return this.num_imported_globals++;
|
||||||
}
|
}
|
||||||
|
@ -278,7 +219,8 @@ class WasmModuleBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
addDataSegment(addr, data, is_global = false) {
|
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;
|
return this.data_segments.length - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,21 +251,15 @@ class WasmModuleBuilder {
|
||||||
return this.addElementSegment(this.table_length_min, false, array);
|
return this.addElementSegment(this.table_length_min, false, array);
|
||||||
}
|
}
|
||||||
|
|
||||||
setTableBounds(min, max) {
|
setTableBounds(min, max = undefined) {
|
||||||
this.table_length_min = min;
|
this.table_length_min = min;
|
||||||
this.table_length_max = max;
|
this.table_length_max = max;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
setTableLength(length) {
|
// TODO(ssauleau): legacy, remove this
|
||||||
this.table_length_min = length;
|
setFunctionTableLength(length) {
|
||||||
this.table_length_max = length;
|
return this.setTableBounds(length);
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
setName(name) {
|
|
||||||
this.name = name;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toArray(debug = false) {
|
toArray(debug = false) {
|
||||||
|
@ -385,11 +321,15 @@ class WasmModuleBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add functions declarations
|
// Add functions declarations
|
||||||
|
let has_names = false;
|
||||||
|
let names = false;
|
||||||
if (wasm.functions.length > 0) {
|
if (wasm.functions.length > 0) {
|
||||||
if (debug) print("emitting function decls @ " + binary.length);
|
if (debug) print("emitting function decls @ " + binary.length);
|
||||||
binary.emit_section(kFunctionSectionCode, section => {
|
binary.emit_section(kFunctionSectionCode, section => {
|
||||||
section.emit_u32v(wasm.functions.length);
|
section.emit_u32v(wasm.functions.length);
|
||||||
for (let func of wasm.functions) {
|
for (let func of wasm.functions) {
|
||||||
|
has_names = has_names || (func.name != undefined &&
|
||||||
|
func.name.length > 0);
|
||||||
section.emit_u32v(func.type_index);
|
section.emit_u32v(func.type_index);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -415,7 +355,7 @@ class WasmModuleBuilder {
|
||||||
binary.emit_section(kMemorySectionCode, section => {
|
binary.emit_section(kMemorySectionCode, section => {
|
||||||
section.emit_u8(1); // one memory entry
|
section.emit_u8(1); // one memory entry
|
||||||
const has_max = wasm.memory.max !== undefined;
|
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);
|
section.emit_u32v(wasm.memory.min);
|
||||||
if (has_max) section.emit_u32v(wasm.memory.max);
|
if (has_max) section.emit_u32v(wasm.memory.max);
|
||||||
});
|
});
|
||||||
|
@ -438,7 +378,7 @@ class WasmModuleBuilder {
|
||||||
break;
|
break;
|
||||||
case kWasmI64:
|
case kWasmI64:
|
||||||
section.emit_u8(kExprI64Const);
|
section.emit_u8(kExprI64Const);
|
||||||
section.emit_u32v(global.init);
|
section.emit_u8(global.init);
|
||||||
break;
|
break;
|
||||||
case kWasmF32:
|
case kWasmF32:
|
||||||
section.emit_u8(kExprF32Const);
|
section.emit_u8(kExprF32Const);
|
||||||
|
@ -492,7 +432,7 @@ class WasmModuleBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add start function section.
|
// Add start function section.
|
||||||
if (wasm.start_index !== undefined) {
|
if (wasm.start_index != undefined) {
|
||||||
if (debug) print("emitting start function @ " + binary.length);
|
if (debug) print("emitting start function @ " + binary.length);
|
||||||
binary.emit_section(kStartSectionCode, section => {
|
binary.emit_section(kStartSectionCode, section => {
|
||||||
section.emit_u32v(wasm.start_index);
|
section.emit_u32v(wasm.start_index);
|
||||||
|
@ -507,7 +447,7 @@ class WasmModuleBuilder {
|
||||||
section.emit_u32v(inits.length);
|
section.emit_u32v(inits.length);
|
||||||
|
|
||||||
for (let init of inits) {
|
for (let init of inits) {
|
||||||
section.emit_u8(0); // table index
|
section.emit_u8(0); // table index / flags
|
||||||
if (init.is_global) {
|
if (init.is_global) {
|
||||||
section.emit_u8(kExprGetGlobal);
|
section.emit_u8(kExprGetGlobal);
|
||||||
} else {
|
} else {
|
||||||
|
@ -532,7 +472,9 @@ class WasmModuleBuilder {
|
||||||
for (let func of wasm.functions) {
|
for (let func of wasm.functions) {
|
||||||
// Function body length will be patched later.
|
// Function body length will be patched later.
|
||||||
let local_decls = [];
|
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) {
|
if (l.i32_count > 0) {
|
||||||
local_decls.push({count: l.i32_count, type: kWasmI32});
|
local_decls.push({count: l.i32_count, type: kWasmI32});
|
||||||
}
|
}
|
||||||
|
@ -567,7 +509,7 @@ class WasmModuleBuilder {
|
||||||
binary.emit_section(kDataSectionCode, section => {
|
binary.emit_section(kDataSectionCode, section => {
|
||||||
section.emit_u32v(wasm.data_segments.length);
|
section.emit_u32v(wasm.data_segments.length);
|
||||||
for (let seg of wasm.data_segments) {
|
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) {
|
if (seg.is_global) {
|
||||||
// initializer is a global variable
|
// initializer is a global variable
|
||||||
section.emit_u8(kExprGetGlobal);
|
section.emit_u8(kExprGetGlobal);
|
||||||
|
@ -590,50 +532,21 @@ class WasmModuleBuilder {
|
||||||
binary.emit_bytes(exp);
|
binary.emit_bytes(exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add names.
|
// Add function names.
|
||||||
let num_function_names = 0;
|
if (has_names) {
|
||||||
let num_functions_with_local_names = 0;
|
if (debug) print("emitting names @ " + binary.length);
|
||||||
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);
|
|
||||||
binary.emit_section(kUnknownSectionCode, section => {
|
binary.emit_section(kUnknownSectionCode, section => {
|
||||||
section.emit_string('name');
|
section.emit_string("name");
|
||||||
// Emit module name.
|
var count = wasm.functions.length + wasm.num_imported_funcs;
|
||||||
if (wasm.name !== undefined) {
|
section.emit_u32v(count);
|
||||||
section.emit_section(kModuleNameCode, name_section => {
|
for (var i = 0; i < wasm.num_imported_funcs; i++) {
|
||||||
name_section.emit_string(wasm.name);
|
section.emit_u8(0); // empty string
|
||||||
});
|
section.emit_u8(0); // local names count == 0
|
||||||
}
|
}
|
||||||
// Emit function names.
|
for (let func of wasm.functions) {
|
||||||
if (num_function_names > 0) {
|
var name = func.name == undefined ? "" : func.name;
|
||||||
section.emit_section(kFunctionNamesCode, name_section => {
|
section.emit_string(name);
|
||||||
name_section.emit_u32v(num_function_names);
|
section.emit_u8(0); // local names count == 0
|
||||||
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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -650,21 +563,12 @@ class WasmModuleBuilder {
|
||||||
if ((typeof val) == "string") val = val.charCodeAt(0);
|
if ((typeof val) == "string") val = val.charCodeAt(0);
|
||||||
view[i] = val | 0;
|
view[i] = val | 0;
|
||||||
}
|
}
|
||||||
return buffer;
|
return new Uint8Array(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
instantiate(ffi) {
|
instantiate(...args) {
|
||||||
let module = new WebAssembly.Module(this.toBuffer());
|
let module = new WebAssembly.Module(this.toBuffer());
|
||||||
let instance = new WebAssembly.Instance(module, ffi);
|
let instance = new WebAssembly.Instance(module, ...args);
|
||||||
return instance;
|
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 renderedBuffer;
|
||||||
let renderedData;
|
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;
|
let pulseLengthFrames = .1 * sampleRate;
|
||||||
|
|
||||||
// Maximum allowed error for the test to succeed. Experimentally determined.
|
// Maximum allowed error for the test to succeed. Experimentally determined.
|
||||||
let maxAllowedError = 5.9e-8;
|
let maxAllowedError = 5.9e-8;
|
||||||
|
|
||||||
// This must be large enough so that the filtered result is
|
// This must be large enough so that the filtered result is essentially zero.
|
||||||
// essentially zero. See comments for createTestAndRun.
|
// See comments for createTestAndRun. This must be a whole number of frames.
|
||||||
let timeStep = .1;
|
let timeStep = Math.ceil(.1 * sampleRate) / sampleRate;
|
||||||
|
|
||||||
// Maximum number of filters we can process (mostly for setting the
|
// Maximum number of filters we can process (mostly for setting the
|
||||||
// render length correctly.)
|
// 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.
|
// How many panner nodes to create for the test.
|
||||||
let nodesToCreate = 100;
|
let nodesToCreate = 100;
|
||||||
|
|
||||||
// Time step when each panner node starts.
|
// Time step when each panner node starts. Make sure it starts on a frame
|
||||||
let timeStep = 0.001;
|
// boundary.
|
||||||
|
let timeStep = Math.floor(0.001 * sampleRate) / sampleRate;
|
||||||
|
|
||||||
// Make sure we render long enough to get all of our nodes.
|
// Make sure we render long enough to get all of our nodes.
|
||||||
let renderLengthSeconds = timeStep * (nodesToCreate + 1);
|
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
|
// The max allowed error between the actual gain and the expected
|
||||||
// value. This is determined experimentally. Set to 0 to see
|
// value. This is determined experimentally. Set to 0 to see
|
||||||
// what the actual errors are.
|
// what the actual errors are.
|
||||||
let maxAllowedError = 3.3e-6;
|
let maxAllowedError = 2.2720e-6;
|
||||||
|
|
||||||
let success = true;
|
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.
|
// How many grains to play.
|
||||||
let numberOfTests = 100;
|
let numberOfTests = 100;
|
||||||
|
|
||||||
// Duration of each grain to be played
|
// Duration of each grain to be played. Make a whole number of frames
|
||||||
let duration = 0.01;
|
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
|
// Time step between the start of each grain. We need to add a little
|
||||||
// bit of silence so we can detect grain boundaries
|
// 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.
|
// Time step between the start for each grain. Must be a whole number of
|
||||||
let grainOffsetStep = 0.001;
|
// frames.
|
||||||
|
let grainOffsetStep = Math.floor(0.001 * sampleRate) / sampleRate;
|
||||||
|
|
||||||
// How long to render to cover all of the grains.
|
// How long to render to cover all of the grains.
|
||||||
let renderTime = (numberOfTests + 1) * timeStep;
|
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;
|
let numberOfChannels = 1;
|
||||||
|
|
||||||
// Time step when each panner node starts.
|
// Time step when each panner node starts. Make sure it starts on a frame
|
||||||
let timeStep = 0.001;
|
// boundary.
|
||||||
|
let timeStep = Math.floor(0.001 * sampleRate) / sampleRate;
|
||||||
|
|
||||||
// Length of the impulse signal.
|
// Length of the impulse signal.
|
||||||
let pulseLengthFrames = Math.round(timeStep * sampleRate);
|
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
|
// The max error we allow between the rendered impulse and the
|
||||||
// expected value. This value is experimentally determined. Set
|
// expected value. This value is experimentally determined. Set
|
||||||
// to 0 to make the test fail to see what the actual error is.
|
// 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;
|
let success = true;
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,12 @@ let StereoPannerTest = (function() {
|
||||||
// Constants
|
// Constants
|
||||||
let PI_OVER_TWO = Math.PI * 0.5;
|
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.
|
// Time step when each panner node starts. Make sure this is on a frame boundary.
|
||||||
let gTimeStep = 0.001;
|
let gTimeStep = Math.floor(0.001 * gSampleRate) / gSampleRate;
|
||||||
|
|
||||||
// How many panner nodes to create for the test
|
// How many panner nodes to create for the test
|
||||||
let gNodesToCreate = 100;
|
let gNodesToCreate = 100;
|
||||||
|
@ -77,7 +79,7 @@ let StereoPannerTest = (function() {
|
||||||
// The max error we allow between the rendered impulse and the
|
// The max error we allow between the rendered impulse and the
|
||||||
// expected value. This value is experimentally determined. Set
|
// expected value. This value is experimentally determined. Set
|
||||||
// to 0 to make the test fail to see what the actual error is.
|
// 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
|
// Max (absolute) error and the index of the maxima for the left
|
||||||
// and right channels.
|
// and right channels.
|
||||||
|
|
|
@ -74,6 +74,42 @@
|
||||||
.then(() => task.done());
|
.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();
|
audit.run();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</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">
|
<script id="layout-test-code">
|
||||||
let audit = Audit.createTaskRunner();
|
let audit = Audit.createTaskRunner();
|
||||||
let context = 0;
|
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 renderNumberOfChannels = 8;
|
||||||
let singleTestFrameLength = 8;
|
let singleTestFrameLength = 8;
|
||||||
let testBuffers;
|
let testBuffers;
|
||||||
|
|
|
@ -131,16 +131,20 @@
|
||||||
|
|
||||||
// Set listener properties to "random" values so that motion on one of
|
// Set listener properties to "random" values so that motion on one of
|
||||||
// the attributes actually changes things relative to the panner
|
// 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.positionX.value = -1;
|
||||||
listener.positionY.value = 1;
|
listener.positionY.value = 1;
|
||||||
listener.positionZ.value = -1;
|
listener.positionZ.value = -1;
|
||||||
listener.forwardX.value = -1;
|
listener.forwardX.value = -1;
|
||||||
listener.forwardY.value = 1;
|
listener.forwardY.value = 1;
|
||||||
listener.forwardZ.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.upX.value = 1;
|
||||||
listener.upY.value = 1;
|
listener.upY.value = 1;
|
||||||
listener.upZ.value = 1;
|
listener.upZ.value = 2;
|
||||||
|
|
||||||
let audioParam = listener[options.param];
|
let audioParam = listener[options.param];
|
||||||
audioParam.automationRate = 'k-rate';
|
audioParam.automationRate = 'k-rate';
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
createTestAndRun(context, 'lowpass', {
|
createTestAndRun(context, 'lowpass', {
|
||||||
should: should,
|
should: should,
|
||||||
threshold: 9.7869e-8,
|
threshold: 4.6943e-8,
|
||||||
filterParameters: filterParameters
|
filterParameters: filterParameters
|
||||||
}).then(task.done.bind(task));
|
}).then(task.done.bind(task));
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,11 +18,19 @@
|
||||||
|
|
||||||
let audit = Audit.createTaskRunner();
|
let audit = Audit.createTaskRunner();
|
||||||
|
|
||||||
let sampleRate = 44100.0;
|
// Use a power of two to eliminate any round-off when converting frame to
|
||||||
let bufferDurationSeconds = 0.125;
|
// 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 numberOfNotes = 11;
|
||||||
let noteSpacing = bufferDurationSeconds +
|
// Leave about 20ms of silence, being sure this is an exact frame
|
||||||
0.020; // leave 20ms of silence between each "note"
|
// duration.
|
||||||
|
let noteSilence = Math.floor(0.020 * sampleRate) / sampleRate;
|
||||||
|
let noteSpacing = bufferDurationSeconds + noteSilence;
|
||||||
|
|
||||||
let lengthInSeconds = numberOfNotes * noteSpacing;
|
let lengthInSeconds = numberOfNotes * noteSpacing;
|
||||||
|
|
||||||
let context = 0;
|
let context = 0;
|
||||||
|
@ -131,18 +139,18 @@
|
||||||
// Verify the channels are clsoe to the reference.
|
// Verify the channels are clsoe to the reference.
|
||||||
should(actual0, 'Left output from gain node')
|
should(actual0, 'Left output from gain node')
|
||||||
.beCloseToArray(
|
.beCloseToArray(
|
||||||
reference0, {relativeThreshold: 1.1908e-7});
|
reference0, {relativeThreshold: 1.1877e-7});
|
||||||
should(actual1, 'Right output from gain node')
|
should(actual1, 'Right output from gain node')
|
||||||
.beCloseToArray(
|
.beCloseToArray(
|
||||||
reference1, {relativeThreshold: 1.1908e-7});
|
reference1, {relativeThreshold: 1.1877e-7});
|
||||||
|
|
||||||
// Test the SNR too for both channels.
|
// Test the SNR too for both channels.
|
||||||
let snr0 = 10 * Math.log10(computeSNR(actual0, reference0));
|
let snr0 = 10 * Math.log10(computeSNR(actual0, reference0));
|
||||||
let snr1 = 10 * Math.log10(computeSNR(actual1, reference1));
|
let snr1 = 10 * Math.log10(computeSNR(actual1, reference1));
|
||||||
should(snr0, 'Left SNR (in dB)')
|
should(snr0, 'Left SNR (in dB)')
|
||||||
.beGreaterThanOrEqualTo(148.69);
|
.beGreaterThanOrEqualTo(148.71);
|
||||||
should(snr1, 'Right SNR (in dB)')
|
should(snr1, 'Right SNR (in dB)')
|
||||||
.beGreaterThanOrEqualTo(148.69);
|
.beGreaterThanOrEqualTo(148.71);
|
||||||
})
|
})
|
||||||
.then(() => task.done());
|
.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):
|
def test_height_width_larger_than_max(session):
|
||||||
screen_width, screen_height = screen_size(session)
|
screen_width, screen_height = screen_size(session)
|
||||||
avail_width, avail_height = available_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):
|
def test_x_y(session):
|
||||||
original = session.window.rect
|
original = session.window.rect
|
||||||
response = set_window_rect(session, {
|
response = set_window_rect(session, {
|
||||||
|
@ -267,40 +308,49 @@ def test_negative_x_y(session):
|
||||||
"height": original["height"]})
|
"height": original["height"]})
|
||||||
|
|
||||||
|
|
||||||
def test_move_to_same_position(session):
|
def test_x_y_as_current(session):
|
||||||
original_position = session.window.position
|
original = session.window.rect
|
||||||
position = session.window.position = original_position
|
|
||||||
assert position == original_position
|
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):
|
def test_x_as_current(session):
|
||||||
original_x = session.window.position[0]
|
original = session.window.rect
|
||||||
position = session.window.position = (original_x, 345)
|
|
||||||
assert position == (original_x, 345)
|
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):
|
def test_y_as_current(session):
|
||||||
original_y = session.window.position[1]
|
original = session.window.rect
|
||||||
position = session.window.position = (456, original_y)
|
|
||||||
assert position == (456, original_y)
|
|
||||||
|
|
||||||
|
response = set_window_rect(session, {
|
||||||
def test_resize_to_same_size(session):
|
"x": original["x"] + 10,
|
||||||
original_size = session.window.size
|
"y": original["y"]
|
||||||
size = session.window.size = original_size
|
})
|
||||||
assert size == original_size
|
assert_success(response, {
|
||||||
|
"x": original["x"] + 10,
|
||||||
|
"y": original["y"],
|
||||||
def test_resize_to_same_width(session):
|
"width": original["width"],
|
||||||
original_width = session.window.size[0]
|
"height": original["height"]
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -2,6 +2,7 @@ SCRIPT_TIMEOUT = 30
|
||||||
PAGE_LOAD_TIMEOUT = 300
|
PAGE_LOAD_TIMEOUT = 300
|
||||||
IMPLICIT_WAIT_TIMEOUT = 0
|
IMPLICIT_WAIT_TIMEOUT = 0
|
||||||
|
|
||||||
|
WINDOW_POSITION = (100, 100)
|
||||||
WINDOW_SIZE = (800, 600)
|
WINDOW_SIZE = (800, 600)
|
||||||
|
|
||||||
DRIVER_HOST = '127.0.0.1'
|
DRIVER_HOST = '127.0.0.1'
|
||||||
|
|
|
@ -152,8 +152,9 @@ def session(capabilities, configuration, request):
|
||||||
if not _current_session.session_id:
|
if not _current_session.session_id:
|
||||||
raise
|
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.size = defaults.WINDOW_SIZE
|
||||||
|
_current_session.window.position = defaults.WINDOW_POSITION
|
||||||
|
|
||||||
yield _current_session
|
yield _current_session
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue