diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /testing/web-platform/tests/webxr/anchors | |
parent | Initial commit. (diff) | |
download | thunderbird-upstream.tar.xz thunderbird-upstream.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/webxr/anchors')
8 files changed, 592 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webxr/anchors/META.yml b/testing/web-platform/tests/webxr/anchors/META.yml new file mode 100644 index 0000000000..0b7f740ac5 --- /dev/null +++ b/testing/web-platform/tests/webxr/anchors/META.yml @@ -0,0 +1 @@ +spec: https://immersive-web.github.io/anchors/ diff --git a/testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_create_move.https.html b/testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_create_move.https.html new file mode 100644 index 0000000000..87f7556007 --- /dev/null +++ b/testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_create_move.https.html @@ -0,0 +1,94 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../resources/webxr_util.js"></script> +<script src="../resources/webxr_test_asserts.js"></script> +<script src="../resources/webxr_test_constants.js"></script> +<script src="../resources/webxr_test_constants_fake_world.js"></script> + +<script> + +// 1m above world origin. +const VIEWER_ORIGIN_TRANSFORM = { + position: [0, 1, 0], + orientation: [0, 0, 0, 1], +}; + +const fakeDeviceInitParams = { + supportedModes: ["immersive-ar"], + views: VALID_VIEWS, + supportedFeatures: ALL_FEATURES, + viewerOrigin: VIEWER_ORIGIN_TRANSFORM, +}; + +// All test cases require anchors. +const sessionInit = { 'requiredFeatures': ['anchors'] }; + +// Create an anchor, move it and verify that new pose gets propagated to the caller. +const anchorCreateAndMove = function(session, fakeDeviceController, t) { + const debug = xr_debug.bind(this, 'anchorCreateAndMove'); + + let anchorController = null; + fakeDeviceController.setAnchorCreationCallback((parameters, controller) => { + anchorController = controller; + return Promise.resolve(true); + }); + + const watcherDone = new Event("watcherdone"); + const eventWatcher = new EventWatcher(t, session, ["watcherdone"]); + const eventPromise = eventWatcher.wait_for(["watcherdone"]); + + session.requestReferenceSpace('local').then((localRefSpace) => { + debug("requesting animation frame"); + + session.requestAnimationFrame((time, frame) => { + debug("rAF 1"); + + let createdAnchor = null; + frame.createAnchor(new XRRigidTransform(), localRefSpace) + .then((anchor) => { + createdAnchor = anchor; + }); + + session.requestAnimationFrame((time_2, frame_2) => { + debug("rAF 2"); + + const pre_move_pose = frame_2.getPose(createdAnchor.anchorSpace, localRefSpace); + + t.step(() => { + assert_true(frame_2.trackedAnchors.has(createdAnchor), + "Newly created anchor must be in tracked anchors set on subsequent RAF (2)!"); + // We have created an anchor with an identity pose relative to local space and have not moved it yet: + assert_matrix_approx_equals(pre_move_pose.transform.matrix, + IDENTITY_MATRIX, FLOAT_EPSILON); + }); + + anchorController.setAnchorOrigin(VALID_POSE_TRANSFORM); + + session.requestAnimationFrame((time_3, frame_3) => { + debug("rAF 3"); + + const post_move_pose = frame_3.getPose(createdAnchor.anchorSpace, localRefSpace); + + t.step(() => { + assert_true(frame_3.trackedAnchors.has(createdAnchor), + "Newly created anchor must be in tracked anchors set on subsequent RAF (3)!"); + // The anchor was moved by VALID_POSE_TRANSFORM, validate that its pose got adjusted: + assert_matrix_approx_equals(post_move_pose.transform.matrix, + VALID_POSE_MATRIX, FLOAT_EPSILON); + }); + + session.dispatchEvent(watcherDone); + }); + }); + }); + }); // session.requestReferenceSpace(...).then({...}); + + return eventPromise; +}; + +xr_session_promise_test( + "Ensures free-floating anchor move gets propagated to anchor poses", + anchorCreateAndMove, fakeDeviceInitParams, 'immersive-ar', sessionInit); + +</script> diff --git a/testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_delay_creation.https.html b/testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_delay_creation.https.html new file mode 100644 index 0000000000..686eacf848 --- /dev/null +++ b/testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_delay_creation.https.html @@ -0,0 +1,122 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../resources/webxr_util.js"></script> +<script src="../resources/webxr_test_asserts.js"></script> +<script src="../resources/webxr_test_constants.js"></script> +<script src="../resources/webxr_test_constants_fake_world.js"></script> + +<script> + +// 1m above world origin. +const VIEWER_ORIGIN_TRANSFORM = { + position: [0, 1, 0], + orientation: [0, 0, 0, 1], +}; + +const fakeDeviceInitParams = { + supportedModes: ["immersive-ar"], + views: VALID_VIEWS, + supportedFeatures: ALL_FEATURES, + viewerOrigin: VIEWER_ORIGIN_TRANSFORM, +}; + +// All test cases require anchors. +const sessionInit = { 'requiredFeatures': ['anchors'] }; + +// Creates a test function that will attempt to create an anchor with a delay. +// In case the anchor creation is expected to succeed, the test will then +// validate whether the anchor belongs to frame.trackedAnchors, has a valid pose, +// and that after deleting it, it no longer allows access to its anchorSpace. +// |shouldSucceed| - true if the anchor creation is expected to succeed. +const anchorCreationDelayedCreator = function(shouldSucceed) { + return function(session, fakeDeviceController, t) { + const debug = xr_debug.bind(this, 'anchorCreationDelayed' + (shouldSucceed ? 'Success' : 'Failure')); + + let anchorCreationResolve = null; + fakeDeviceController.setAnchorCreationCallback((parameters, controller) => { + return new Promise((resolve) => { + anchorCreationResolve = resolve; + }); + }); + + const watcherDone = new Event("watcherdone"); + const creationDelayedEvent = new Event("creationdelayed"); + const eventWatcher = new EventWatcher(t, session, ["creationdelayed", "watcherdone"]); + const eventPromise = eventWatcher.wait_for(["creationdelayed", "watcherdone"]); + + session.requestReferenceSpace('local').then((localRefSpace) => { + debug("requesting animation frame"); + + session.requestAnimationFrame((time, frame) => { + debug("rAF 1"); + + let createdAnchor = null; + frame.createAnchor(new XRRigidTransform(), localRefSpace) + .then((anchor) => { + createdAnchor = anchor; + + t.step(() => { + assert_true(anchor != null, "Returned anchor should not be null!"); + assert_true(shouldSucceed, + "Anchor creation succeeded when it was expected to fail!"); + }); + }) + .catch((error) => { + t.step(() => { + assert_false(shouldSucceed, + "Anchor creation failed when it was expected to succeed!"); + }); + + session.dispatchEvent(watcherDone); + }); + + session.requestAnimationFrame(() => { + debug("rAF 2"); + + session.dispatchEvent(creationDelayedEvent); + + anchorCreationResolve(shouldSucceed); + + session.requestAnimationFrame((time_2, frame_2) => { + debug("rAF 3"); + + if(shouldSucceed) { + t.step(() => { + assert_true(createdAnchor != null); + assert_true(frame_2.trackedAnchors.has(createdAnchor), + "Newly created anchor must be in tracked anchors set!"); + assert_true(createdAnchor.anchorSpace != null, + "Newly created anchor must have a non-null anchor space!"); + assert_true(frame_2.getPose(createdAnchor.anchorSpace, localRefSpace) != null, + "Newly created anchor should have a pose!"); + }); + + createdAnchor.delete(); + + t.step(() => { + assert_throws_dom('InvalidStateError', () => { + createdAnchor.anchorSpace; + }); + }); + + session.dispatchEvent(watcherDone); + } + }); + }); + }); + }); // session.requestReferenceSpace(...).then({...}); + + return eventPromise; + }; +}; + +xr_session_promise_test( + "Ensures free-floating anchor creation with delayed success is handled correctly", + anchorCreationDelayedCreator(true), fakeDeviceInitParams, 'immersive-ar', sessionInit); + +xr_session_promise_test( + "Ensures free-floating anchor creation with delayed failure is handled correctly", + anchorCreationDelayedCreator(false), fakeDeviceInitParams, 'immersive-ar', sessionInit); + +</script> diff --git a/testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_failure.https.html b/testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_failure.https.html new file mode 100644 index 0000000000..dd03be0ad5 --- /dev/null +++ b/testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_failure.https.html @@ -0,0 +1,72 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../resources/webxr_util.js"></script> +<script src="../resources/webxr_test_asserts.js"></script> +<script src="../resources/webxr_test_constants.js"></script> +<script src="../resources/webxr_test_constants_fake_world.js"></script> + +<script> + +// 1m above world origin. +const VIEWER_ORIGIN_TRANSFORM = { + position: [0, 1, 0], + orientation: [0, 0, 0, 1], +}; + +const fakeDeviceInitParams = { + supportedModes: ["immersive-ar"], + views: VALID_VIEWS, + supportedFeatures: ALL_FEATURES, + viewerOrigin: VIEWER_ORIGIN_TRANSFORM, +}; + +// All test cases require anchors. +const sessionInit = { 'requiredFeatures': ['anchors'] }; + +// Fail the anchor creation & see if it gets communicated to the caller. +// The concrete error is not specified by the WebXR Test API / WebXR Anchors. +const anchorCreationFail = function(session, fakeDeviceController, t) { + const debug = xr_debug.bind(this, 'anchorCreationFail'); + + fakeDeviceController.setAnchorCreationCallback((parameters, controller) => { + // Immediately fail anchor creation. + return Promise.resolve(false); + }); + + const watcherDone = new Event("watcherdone"); + const eventWatcher = new EventWatcher(t, session, ["watcherdone"]); + const eventPromise = eventWatcher.wait_for(["watcherdone"]); + + session.requestReferenceSpace('local').then((localRefSpace) => { + debug("requesting animation frame"); + + session.requestAnimationFrame((time, frame) => { + debug("rAF 1"); + + frame.createAnchor(new XRRigidTransform(), localRefSpace) + .then((anchor) => { + t.step(() => { + assert_false(true, "Anchor creation should fail!"); + }); + }) + .catch((error) => { + session.dispatchEvent(watcherDone); + }); + + // Anchor result will only take effect with frame data - schedule + // a frame after we requested anchor creation, otherwise the test will time out. + session.requestAnimationFrame(() => { + debug("rAF 2"); + }); + }); + }); // session.requestReferenceSpace(...).then({...}); + + return eventPromise; +} + +xr_session_promise_test( + "Ensures free-floating anchor creation failure is handled correctly", + anchorCreationFail, fakeDeviceInitParams, 'immersive-ar', sessionInit); + +</script> diff --git a/testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_pause_resume_stop.https.html b/testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_pause_resume_stop.https.html new file mode 100644 index 0000000000..6eb6bc76e6 --- /dev/null +++ b/testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_pause_resume_stop.https.html @@ -0,0 +1,115 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../resources/webxr_util.js"></script> +<script src="../resources/webxr_test_asserts.js"></script> +<script src="../resources/webxr_test_constants.js"></script> +<script src="../resources/webxr_test_constants_fake_world.js"></script> + +<script> + +// 1m above world origin. +const VIEWER_ORIGIN_TRANSFORM = { + position: [0, 1, 0], + orientation: [0, 0, 0, 1], +}; + +const fakeDeviceInitParams = { + supportedModes: ["immersive-ar"], + views: VALID_VIEWS, + supportedFeatures: ALL_FEATURES, + viewerOrigin: VIEWER_ORIGIN_TRANSFORM, +}; + +// All test cases require anchors. +const sessionInit = { 'requiredFeatures': ['anchors'] }; + +// Create an anchor, pause tracking, resume tracking, & stop tracking and validate +// that the state changes are propagated to the caller. +const anchorCreatePauseTrackingResumeAndDelete = function(session, fakeDeviceController, t) { + const debug = xr_debug.bind(this, 'anchorCreatePauseTrackingResumeAndDelete'); + + let anchorController = null; + fakeDeviceController.setAnchorCreationCallback((parameters, controller) => { + anchorController = controller; + return Promise.resolve(true); + }); + + const watcherDone = new Event("watcherdone"); + const eventWatcher = new EventWatcher(t, session, ["watcherdone"]); + const eventPromise = eventWatcher.wait_for(["watcherdone"]); + + session.requestReferenceSpace('local').then((localRefSpace) => { + debug("requesting animation frame"); + + session.requestAnimationFrame((time, frame) => { + debug("rAF 1"); + + let createdAnchor = null; + frame.createAnchor(new XRRigidTransform(), localRefSpace) + .then((anchor) => { + createdAnchor = anchor; + }); + + session.requestAnimationFrame((time_2, frame_2) => { + debug("rAF 2"); + + t.step(() => { + assert_true(frame_2.getPose(createdAnchor.anchorSpace, localRefSpace) != null, + "Newly created anchor should have a pose!"); + assert_true(frame_2.trackedAnchors.has(createdAnchor), + "Newly created anchor must be in tracked anchors set on subsequent RAF (2)!"); + }); + + anchorController.pauseTracking(); + + session.requestAnimationFrame((time_3, frame_3) => { + debug("rAF 3"); + + t.step(() => { + assert_true(frame_3.getPose(createdAnchor.anchorSpace, localRefSpace) == null, + "Newly created anchor with paused tracking should not have a pose!"); + assert_true(frame_3.trackedAnchors.has(createdAnchor), + "Newly created anchor with paused tracking must be in tracked anchors set on subsequent RAF (3)!"); + }); + + anchorController.resumeTracking(); + + session.requestAnimationFrame((time_4, frame_4) => { + debug("rAF 4"); + + t.step(() => { + assert_true(frame_4.trackedAnchors.has(createdAnchor), + "Newly created anchor with resumed tracking must be in tracked anchors set on subsequent RAF (4)!"); + assert_true(frame_4.getPose(createdAnchor.anchorSpace, localRefSpace) != null, + "Newly created anchor with resumed tracking should have a pose!"); + }); + + anchorController.stopTracking(); + + session.requestAnimationFrame((time_5, frame_5) => { + debug("rAF 5"); + + t.step(() => { + assert_false(frame_5.trackedAnchors.has(createdAnchor), + "Newly created anchor with stopped tracking must not be in tracked anchors set on subsequent RAF (5)!"); + }); + + session.dispatchEvent(watcherDone); + }); + }); + }); + }); + }); + }); // session.requestReferenceSpace(...).then({...}); + + return eventPromise; +}; + + +xr_session_promise_test( + "Ensures free-floating anchor state changes get propagated", + anchorCreatePauseTrackingResumeAndDelete, fakeDeviceInitParams, + 'immersive-ar', sessionInit); + +</script> diff --git a/testing/web-platform/tests/webxr/anchors/ar_anchor_getAnchors.https.html b/testing/web-platform/tests/webxr/anchors/ar_anchor_getAnchors.https.html new file mode 100644 index 0000000000..50664b0a4b --- /dev/null +++ b/testing/web-platform/tests/webxr/anchors/ar_anchor_getAnchors.https.html @@ -0,0 +1,58 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../resources/webxr_util.js"></script> +<script src="../resources/webxr_test_asserts.js"></script> +<script src="../resources/webxr_test_constants.js"></script> +<script src="../resources/webxr_test_constants_fake_world.js"></script> + +<script> + +// 1m above world origin. +const VIEWER_ORIGIN_TRANSFORM = { + position: [0, 1, 0], + orientation: [0, 0, 0, 1], +}; + +const fakeDeviceInitParams = { + supportedModes: ["immersive-ar"], + views: VALID_VIEWS, + supportedFeatures: ALL_FEATURES, + viewerOrigin: VIEWER_ORIGIN_TRANSFORM, +}; + +// Attempts to access XRFrame.trackedAnchors and expects to get empty set +// since no anchors are being created. +const testFunction = function(session, fakeDeviceController, t) { + const debug = xr_debug.bind(this, 'testGetAnchors'); + + let done = false; + + session.requestReferenceSpace('local').then((localRefSpace) => { + const onFrame = function(time, frame) { + const trackedAnchors = frame.trackedAnchors; + t.step(() => { + assert_equals(trackedAnchors.size, 0); + }); + + done = true; + }; + + session.requestAnimationFrame(onFrame); + }); // session.requestReferenceSpace(...) + + return t.step_wait(() => done); +}; // testFunction + + +xr_session_promise_test("XRFrame's trackedAnchors is empty when the feature was not requested", + testFunction, + fakeDeviceInitParams, + 'immersive-ar', { }); + +xr_session_promise_test("XRFrame's trackedAnchors is empty when the feature was requested", + testFunction, + fakeDeviceInitParams, + 'immersive-ar', { 'requiredFeatures': ['anchors'] }); + +</script> diff --git a/testing/web-platform/tests/webxr/anchors/ar_anchor_states.https.html b/testing/web-platform/tests/webxr/anchors/ar_anchor_states.https.html new file mode 100644 index 0000000000..8369549852 --- /dev/null +++ b/testing/web-platform/tests/webxr/anchors/ar_anchor_states.https.html @@ -0,0 +1,114 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../resources/webxr_util.js"></script> +<script src="../resources/webxr_test_asserts.js"></script> +<script src="../resources/webxr_test_constants.js"></script> +<script src="../resources/webxr_test_constants_fake_world.js"></script> + +<script> + +// 1m above world origin. +const VIEWER_ORIGIN_TRANSFORM = { + position: [0, 1, 0], + orientation: [0, 0, 0, 1], +}; + +const fakeDeviceInitParams = { + supportedModes: ["immersive-ar"], + views: VALID_VIEWS, + supportedFeatures: ALL_FEATURES, + viewerOrigin: VIEWER_ORIGIN_TRANSFORM, +}; + +// Creates a test method that leverages anchors API. +// |expectSucceeded| - true if the anchors creation request is expected to succeed, false otherwise +// |endSession| - true if the test case should call session.end() prior to creating an anchor +// |expectedError| - expected error name that should be returned in case expectSucceeded is false +const testFunctionGenerator = function(expectSucceeded, endSession, expectedError) { + + const testFunction = function(session, fakeDeviceController, t) { + + const debug = xr_debug.bind(this, 'testAnchorStates'); + + fakeDeviceController.setAnchorCreationCallback((parameters, controller) => { + // All anchor creation requests that reach this stage should be marked as successful. + // If this test is expected to fail, the failure will happen earlier in the anchor + // creation process. + return Promise.resolve(true); + }); + + const watcherDone = new Event("watcherdone"); + const eventWatcher = new EventWatcher(t, session, ["watcherdone"]); + const eventPromise = eventWatcher.wait_for(["watcherdone"]); + + session.requestReferenceSpace('local').then((localRefSpace) => { + + const onFrame = function(time, frame) { + debug("rAF 1"); + + let setUpPromise = Promise.resolve(); + if(endSession) { + debug("ending session"); + setUpPromise = session.end(); + } + + setUpPromise.then(() => { + debug("creating anchor"); + frame.createAnchor(new XRRigidTransform(), localRefSpace) + .then((anchor) => { + debug("anchor created"); + + t.step(() => { + assert_true(expectSucceeded, + "`createAnchor` succeeded when it was expected to fail"); + }); + + session.dispatchEvent(watcherDone); + }).catch((error) => { + debug("anchor creation failed"); + + t.step(() => { + assert_false(expectSucceeded, + "`createAnchor` failed when it was expected to succeed, error: " + error); + assert_equals(error.name, expectedError, + "`createAnchor` failed with unexpected error name"); + }); + + session.dispatchEvent(watcherDone); + }); + + // Anchor result will only take effect with frame data - schedule + // a frame after we requested anchor creation, otherwise the test will time out. + session.requestAnimationFrame(() => { + debug("rAF 2"); + }); + }); // setUpPromise.then(() => { ... }) + }; // onFrame() { ... } + + debug("requesting animation frame"); + session.requestAnimationFrame(onFrame); + }); // session.requestReferenceSpace(...) + + return eventPromise; + }; // testFunction + + return testFunction; +}; + +xr_session_promise_test("Anchor creation succeeds if the feature was requested", + testFunctionGenerator(/*expectSucceeded=*/true, /*endSession=*/false), + fakeDeviceInitParams, + 'immersive-ar', { 'requiredFeatures': ['anchors'] }); + +xr_session_promise_test("Anchor creation fails if the feature was not requested", + testFunctionGenerator(/*expectSucceeded=*/false, /*endSession=*/false, "NotSupportedError"), + fakeDeviceInitParams, + 'immersive-ar', {}); + +xr_session_promise_test("Anchor creation fails if the feature was requested but the session already ended", + testFunctionGenerator(/*expectSucceeded=*/false, /*endSession=*/true, "InvalidStateError"), + fakeDeviceInitParams, + 'immersive-ar', { 'requiredFeatures': ['anchors'] }); + +</script> diff --git a/testing/web-platform/tests/webxr/anchors/idlharness.https.window.js b/testing/web-platform/tests/webxr/anchors/idlharness.https.window.js new file mode 100644 index 0000000000..b69a327229 --- /dev/null +++ b/testing/web-platform/tests/webxr/anchors/idlharness.https.window.js @@ -0,0 +1,16 @@ +// META: script=/resources/WebIDLParser.js +// META: script=/resources/idlharness.js + +'use strict'; + +// https://immersive-web.github.io/anchors/ + +idl_test( + ['anchors'], + ['webxr-hit-test', 'webxr', 'dom'], + async idl_array => { + idl_array.add_objects({ + // TODO: Add object instances + }); + } +); |