Something went wrong. Try again.
The open source OpenXR runtime
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145// Copyright 2025-2026, NVIDIA CORPORATION.// SPDX-License-Identifier: BSL-1.0/*! * @file * @brief Tests for glue/g_device.hpp * @author Jakob Bornecrantz <tbornecrantz@nvidia.com> */
#include "glue/g_device.hpp"#include "util/u_device.h"#include "util/u_device_ni.h"
#include "catch_amalgamated.hpp"
#include <cstring>
//! Test device with minimal functionsconstexpr xrt::util::DeviceFunctions kMinimalFunctions = {};
//! Test device with hand tracking enabledconstexpr xrt::util::DeviceFunctions kHandTrackingFunctions = { .hand_tracking = true,};
//! Test device with HMD functions enabledconstexpr xrt::util::DeviceFunctions kHmdFunctions = { .hmd = true,};
//! Test device with body tracking enabledconstexpr xrt::util::DeviceFunctions kBodyTrackingFunctions = { .body_tracking = true,};
//! Test device with battery enabledconstexpr xrt::util::DeviceFunctions kBatteryFunctions = { .battery = true,};
//! Test device with brightness enabledconstexpr xrt::util::DeviceFunctions kBrightnessFunctions = { .brightness = true,};
//! Test device with all features enabledconstexpr xrt::util::DeviceFunctions kAllFunctions = { .hmd = true, .distortion = true, .visibility_mask = true, .update_inputs = true, .output = true, .output_limits = true, .hand_tracking = true, .face_tracking = true, .face_calibration_android = true, .body_tracking = true, .plane_detection = true, .reference_space = true, .battery = true, .brightness = true, .compositor_info = true, .features = true,};
/*! * Minimal test device */class MinimalTestDevice : public xrt::util::DeviceBase<MinimalTestDevice, kMinimalFunctions>{public: bool destroyed = false;
MinimalTestDevice() : DeviceBase() {}
xrt_result_t getTrackedPose(enum xrt_input_name name, int64_t at_timestamp_ns, struct xrt_space_relation *out_relation) { out_relation->relation_flags = XRT_SPACE_RELATION_BITMASK_NONE; return XRT_SUCCESS; }
static void destroyDevice(struct xrt_device *xdev) { auto *dev = MinimalTestDevice::fromXDev(xdev); dev->destroyed = true; }};
/*! * Hand tracking test device */class HandTrackingTestDevice : public xrt::util::DeviceBase<HandTrackingTestDevice, kHandTrackingFunctions>{public: bool destroyed = false; int hand_tracking_call_count = 0;
HandTrackingTestDevice() : DeviceBase() {}
xrt_result_t getTrackedPose(enum xrt_input_name name, int64_t at_timestamp_ns, struct xrt_space_relation *out_relation) { out_relation->relation_flags = XRT_SPACE_RELATION_BITMASK_NONE; return XRT_SUCCESS; }
xrt_result_t getHandTracking(enum xrt_input_name name, int64_t desired_timestamp_ns, struct xrt_hand_joint_set *out_value, int64_t *out_timestamp_ns) { hand_tracking_call_count++; return XRT_SUCCESS; }
static void destroyDevice(struct xrt_device *xdev) { auto *dev = HandTrackingTestDevice::fromXDev(xdev); dev->destroyed = true; }};
/*! * HMD test device */class HmdTestDevice : public xrt::util::DeviceBase<HmdTestDevice, kHmdFunctions>{public: bool destroyed = false; int get_view_poses_call_count = 0; int form_factor_call_count = 0;
HmdTestDevice() : DeviceBase() {}
xrt_result_t getTrackedPose(enum xrt_input_name name, int64_t at_timestamp_ns, struct xrt_space_relation *out_relation) { out_relation->relation_flags = XRT_SPACE_RELATION_BITMASK_NONE; return XRT_SUCCESS; }
xrt_result_t getViewPoses(const struct xrt_vec3 *default_eye_relation, int64_t at_timestamp_ns, enum xrt_view_type view_type, uint32_t view_count, struct xrt_space_relation *out_head_relation, struct xrt_fov *out_fovs, struct xrt_pose *out_poses) { get_view_poses_call_count++; return XRT_SUCCESS; }
xrt_result_t isFormFactorAvailable(enum xrt_form_factor form_factor, bool *out_available) { form_factor_call_count++; *out_available = false; return XRT_SUCCESS; }
static void destroyDevice(struct xrt_device *xdev) { auto *dev = HmdTestDevice::fromXDev(xdev); dev->destroyed = true; }};
/*! * Body tracking test device */class BodyTrackingTestDevice : public xrt::util::DeviceBase<BodyTrackingTestDevice, kBodyTrackingFunctions>{public: bool destroyed = false; int get_body_skeleton_call_count = 0; int get_body_joints_call_count = 0; int reset_calibration_call_count = 0; int set_calibration_call_count = 0;
BodyTrackingTestDevice() : DeviceBase() {}
xrt_result_t getTrackedPose(enum xrt_input_name name, int64_t at_timestamp_ns, struct xrt_space_relation *out_relation) { out_relation->relation_flags = XRT_SPACE_RELATION_BITMASK_NONE; return XRT_SUCCESS; }
xrt_result_t getBodySkeleton(enum xrt_input_name body_tracking_type, struct xrt_body_skeleton *out_value) { get_body_skeleton_call_count++; return XRT_SUCCESS; }
xrt_result_t getBodyJoints(enum xrt_input_name body_tracking_type, int64_t desired_timestamp_ns, struct xrt_body_joint_set *out_value) { get_body_joints_call_count++; return XRT_SUCCESS; }
xrt_result_t resetBodyTrackingCalibrationMeta() { reset_calibration_call_count++; return XRT_SUCCESS; }
xrt_result_t setBodyTrackingCalibrationOverrideMeta(float new_body_height) { set_calibration_call_count++; return XRT_SUCCESS; }
static void destroyDevice(struct xrt_device *xdev) { auto *dev = BodyTrackingTestDevice::fromXDev(xdev); dev->destroyed = true; }};
/*! * Battery test device */class BatteryTestDevice : public xrt::util::DeviceBase<BatteryTestDevice, kBatteryFunctions>{public: bool destroyed = false; int get_battery_call_count = 0;
BatteryTestDevice() : DeviceBase() {}
xrt_result_t getTrackedPose(enum xrt_input_name name, int64_t at_timestamp_ns, struct xrt_space_relation *out_relation) { out_relation->relation_flags = XRT_SPACE_RELATION_BITMASK_NONE; return XRT_SUCCESS; }
xrt_result_t getBatteryStatus(bool *out_present, bool *out_charging, float *out_charge) { get_battery_call_count++; *out_present = true; *out_charging = false; *out_charge = 0.75f; return XRT_SUCCESS; }
static void destroyDevice(struct xrt_device *xdev) { auto *dev = BatteryTestDevice::fromXDev(xdev); dev->destroyed = true; }};
/*! * Brightness test device */class BrightnessTestDevice : public xrt::util::DeviceBase<BrightnessTestDevice, kBrightnessFunctions>{public: bool destroyed = false; int get_brightness_call_count = 0; int set_brightness_call_count = 0;
BrightnessTestDevice() : DeviceBase() {}
xrt_result_t getTrackedPose(enum xrt_input_name name, int64_t at_timestamp_ns, struct xrt_space_relation *out_relation) { out_relation->relation_flags = XRT_SPACE_RELATION_BITMASK_NONE; return XRT_SUCCESS; }
xrt_result_t getBrightness(float *out_brightness) { get_brightness_call_count++; *out_brightness = 0.5f; return XRT_SUCCESS; }
xrt_result_t setBrightness(float brightness, bool relative) { set_brightness_call_count++; return XRT_SUCCESS; }
static void destroyDevice(struct xrt_device *xdev) { auto *dev = BrightnessTestDevice::fromXDev(xdev); dev->destroyed = true; }};
TEST_CASE("DeviceBase_MinimalDevice"){ MinimalTestDevice dev; auto *xdev = dev.getXDev();
SECTION("Basic properties") { REQUIRE(xdev != nullptr); REQUIRE_FALSE(dev.destroyed); }
SECTION("Function pointers are set") { REQUIRE(xdev->get_tracked_pose != nullptr); REQUIRE(xdev->destroy != nullptr); }
SECTION("Stub functions are set for disabled features") { REQUIRE(xdev->get_view_poses == u_device_ni_get_view_poses); REQUIRE(xdev->is_form_factor_available == u_device_ni_is_form_factor_available); REQUIRE(xdev->compute_distortion == u_device_ni_compute_distortion); // @todo Fix when u_device function is fixed. // REQUIRE(xdev->get_visibility_mask == u_device_ni_get_visibility_mask); REQUIRE(xdev->update_inputs == u_device_noop_update_inputs); REQUIRE(xdev->set_output == u_device_ni_set_output); REQUIRE(xdev->get_output_limits == u_device_ni_get_output_limits); REQUIRE(xdev->ref_space_usage == u_device_ni_ref_space_usage); REQUIRE(xdev->get_hand_tracking == u_device_ni_get_hand_tracking); REQUIRE(xdev->get_face_tracking == u_device_ni_get_face_tracking); REQUIRE(xdev->get_body_skeleton == u_device_ni_get_body_skeleton); REQUIRE(xdev->get_body_joints == u_device_ni_get_body_joints); REQUIRE(xdev->reset_body_tracking_calibration_meta == u_device_ni_reset_body_tracking_calibration_meta); REQUIRE(xdev->set_body_tracking_calibration_override_meta == u_device_ni_set_body_tracking_calibration_override_meta); REQUIRE(xdev->begin_plane_detection_ext == u_device_ni_begin_plane_detection_ext); REQUIRE(xdev->destroy_plane_detection_ext == u_device_ni_destroy_plane_detection_ext); REQUIRE(xdev->get_plane_detection_state_ext == u_device_ni_get_plane_detection_state_ext); REQUIRE(xdev->get_plane_detections_ext == u_device_ni_get_plane_detections_ext); REQUIRE(xdev->get_battery_status == u_device_ni_get_battery_status); REQUIRE(xdev->get_brightness == u_device_ni_get_brightness); REQUIRE(xdev->set_brightness == u_device_ni_set_brightness); REQUIRE(xdev->begin_feature == u_device_ni_begin_feature); REQUIRE(xdev->end_feature == u_device_ni_end_feature); }
SECTION("fromXDev conversion works") { auto *retrieved = MinimalTestDevice::fromXDev(xdev); REQUIRE(retrieved == &dev); }
SECTION("getTrackedPose can be called") { xrt_space_relation relation; memset(&relation, 0, sizeof(relation));
xrt_result_t result = xdev->get_tracked_pose(xdev, XRT_INPUT_GENERIC_HEAD_POSE, 0, &relation); REQUIRE(result == XRT_SUCCESS); REQUIRE(relation.relation_flags == XRT_SPACE_RELATION_BITMASK_NONE); }
SECTION("destroy calls destroyDevice") { REQUIRE_FALSE(dev.destroyed); xdev->destroy(xdev); REQUIRE(dev.destroyed); }}
TEST_CASE("DeviceBase_HandTrackingDevice"){ HandTrackingTestDevice dev; auto *xdev = dev.getXDev();
SECTION("Hand tracking function is set") { REQUIRE(xdev->get_hand_tracking != nullptr); REQUIRE(xdev->get_hand_tracking != u_device_ni_get_hand_tracking); }
SECTION("Other disabled features still use stubs") { REQUIRE(xdev->get_view_poses == u_device_ni_get_view_poses); REQUIRE(xdev->is_form_factor_available == u_device_ni_is_form_factor_available); REQUIRE(xdev->get_face_tracking == u_device_ni_get_face_tracking); }
SECTION("Hand tracking can be called") { xrt_hand_joint_set joint_set; int64_t timestamp;
REQUIRE(dev.hand_tracking_call_count == 0);
xrt_result_t result = xdev->get_hand_tracking(xdev, XRT_INPUT_HT_UNOBSTRUCTED_LEFT, 0, &joint_set, ×tamp);
REQUIRE(result == XRT_SUCCESS); REQUIRE(dev.hand_tracking_call_count == 1); }
SECTION("fromXDev conversion works") { auto *retrieved = HandTrackingTestDevice::fromXDev(xdev); REQUIRE(retrieved == &dev); }}
TEST_CASE("DeviceBase_HmdDevice"){ HmdTestDevice dev; auto *xdev = dev.getXDev();
SECTION("HMD functions are set") { REQUIRE(xdev->get_view_poses != nullptr); REQUIRE(xdev->get_view_poses != u_device_ni_get_view_poses); REQUIRE(xdev->is_form_factor_available != nullptr); REQUIRE(xdev->is_form_factor_available != u_device_ni_is_form_factor_available); }
SECTION("Other disabled features still use stubs") { REQUIRE(xdev->compute_distortion == u_device_ni_compute_distortion); REQUIRE(xdev->ref_space_usage == u_device_ni_ref_space_usage); REQUIRE(xdev->get_hand_tracking == u_device_ni_get_hand_tracking); REQUIRE(xdev->get_face_tracking == u_device_ni_get_face_tracking); REQUIRE(xdev->get_body_skeleton == u_device_ni_get_body_skeleton); REQUIRE(xdev->get_body_joints == u_device_ni_get_body_joints); REQUIRE(xdev->get_battery_status == u_device_ni_get_battery_status); REQUIRE(xdev->get_output_limits == u_device_ni_get_output_limits); }
SECTION("get_view_poses can be called") { xrt_vec3 default_eye_relation = {0.0f, 0.0f, 0.0f}; xrt_space_relation head_relation; xrt_fov fovs[2]; xrt_pose poses[2];
REQUIRE(dev.get_view_poses_call_count == 0);
xrt_result_t result = xdev->get_view_poses(xdev, &default_eye_relation, 0, XRT_VIEW_TYPE_STEREO, 2, &head_relation, fovs, poses);
REQUIRE(result == XRT_SUCCESS); REQUIRE(dev.get_view_poses_call_count == 1); }
SECTION("is_form_factor_available can be called") { REQUIRE(dev.form_factor_call_count == 0);
bool available = false; xrt_result_t result = xdev->is_form_factor_available(xdev, XRT_FORM_FACTOR_HMD, &available);
REQUIRE(result == XRT_SUCCESS); REQUIRE_FALSE(available); REQUIRE(dev.form_factor_call_count == 1); }
SECTION("fromXDev conversion works") { auto *retrieved = HmdTestDevice::fromXDev(xdev); REQUIRE(retrieved == &dev); }}
TEST_CASE("DeviceBase_MultipleInstances"){ MinimalTestDevice dev1; MinimalTestDevice dev2;
SECTION("Each device has its own xrt_device") { REQUIRE(dev1.getXDev() != dev2.getXDev()); }
SECTION("fromXDev returns correct instance") { auto *retrieved1 = MinimalTestDevice::fromXDev(dev1.getXDev()); auto *retrieved2 = MinimalTestDevice::fromXDev(dev2.getXDev());
REQUIRE(retrieved1 == &dev1); REQUIRE(retrieved2 == &dev2); REQUIRE(retrieved1 != retrieved2); }
SECTION("Destroying one doesn't affect the other") { dev1.getXDev()->destroy(dev1.getXDev());
REQUIRE(dev1.destroyed); REQUIRE_FALSE(dev2.destroyed); }}
TEST_CASE("DeviceBase_BodyTrackingDevice"){ BodyTrackingTestDevice dev; auto *xdev = dev.getXDev();
SECTION("Body tracking functions are set") { REQUIRE(xdev->get_body_skeleton != nullptr); REQUIRE(xdev->get_body_joints != nullptr); REQUIRE(xdev->reset_body_tracking_calibration_meta != nullptr); REQUIRE(xdev->set_body_tracking_calibration_override_meta != nullptr); }
SECTION("Other disabled features still use stubs") { REQUIRE(xdev->get_view_poses == u_device_ni_get_view_poses); REQUIRE(xdev->get_hand_tracking == u_device_ni_get_hand_tracking); REQUIRE(xdev->get_face_tracking == u_device_ni_get_face_tracking); REQUIRE(xdev->get_battery_status == u_device_ni_get_battery_status); }
SECTION("get_body_skeleton can be called") { xrt_body_skeleton skeleton;
REQUIRE(dev.get_body_skeleton_call_count == 0);
xrt_result_t result = xdev->get_body_skeleton(xdev, XRT_INPUT_GENERIC_BODY_TRACKING, &skeleton);
REQUIRE(result == XRT_SUCCESS); REQUIRE(dev.get_body_skeleton_call_count == 1); }
SECTION("get_body_joints can be called") { xrt_body_joint_set joint_set;
REQUIRE(dev.get_body_joints_call_count == 0);
xrt_result_t result = xdev->get_body_joints(xdev, XRT_INPUT_GENERIC_BODY_TRACKING, 0, &joint_set);
REQUIRE(result == XRT_SUCCESS); REQUIRE(dev.get_body_joints_call_count == 1); }
SECTION("reset_body_tracking_calibration_meta can be called") { REQUIRE(dev.reset_calibration_call_count == 0);
xrt_result_t result = xdev->reset_body_tracking_calibration_meta(xdev);
REQUIRE(result == XRT_SUCCESS); REQUIRE(dev.reset_calibration_call_count == 1); }
SECTION("set_body_tracking_calibration_override_meta can be called") { REQUIRE(dev.set_calibration_call_count == 0);
xrt_result_t result = xdev->set_body_tracking_calibration_override_meta(xdev, 1.75f);
REQUIRE(result == XRT_SUCCESS); REQUIRE(dev.set_calibration_call_count == 1); }
SECTION("fromXDev conversion works") { auto *retrieved = BodyTrackingTestDevice::fromXDev(xdev); REQUIRE(retrieved == &dev); }}
TEST_CASE("DeviceBase_BatteryDevice"){ BatteryTestDevice dev; auto *xdev = dev.getXDev();
SECTION("Battery function is set") { REQUIRE(xdev->get_battery_status != nullptr); }
SECTION("Other disabled features still use stubs") { REQUIRE(xdev->get_view_poses == u_device_ni_get_view_poses); REQUIRE(xdev->get_hand_tracking == u_device_ni_get_hand_tracking); REQUIRE(xdev->get_face_tracking == u_device_ni_get_face_tracking); REQUIRE(xdev->get_body_skeleton == u_device_ni_get_body_skeleton); REQUIRE(xdev->get_brightness == u_device_ni_get_brightness); REQUIRE(xdev->set_brightness == u_device_ni_set_brightness); }
SECTION("get_battery_status can be called") { bool present = false; bool charging = false; float charge = 0.0f;
REQUIRE(dev.get_battery_call_count == 0);
xrt_result_t result = xdev->get_battery_status(xdev, &present, &charging, &charge);
REQUIRE(result == XRT_SUCCESS); REQUIRE(present == true); REQUIRE(charging == false); REQUIRE(charge == 0.75f); REQUIRE(dev.get_battery_call_count == 1); }
SECTION("fromXDev conversion works") { auto *retrieved = BatteryTestDevice::fromXDev(xdev); REQUIRE(retrieved == &dev); }}
TEST_CASE("DeviceBase_BrightnessDevice"){ BrightnessTestDevice dev; auto *xdev = dev.getXDev();
SECTION("Brightness functions are set") { REQUIRE(xdev->get_brightness != nullptr); REQUIRE(xdev->set_brightness != nullptr); }
SECTION("Other disabled features still use stubs") { REQUIRE(xdev->get_view_poses == u_device_ni_get_view_poses); REQUIRE(xdev->get_hand_tracking == u_device_ni_get_hand_tracking); REQUIRE(xdev->get_face_tracking == u_device_ni_get_face_tracking); REQUIRE(xdev->get_body_skeleton == u_device_ni_get_body_skeleton); REQUIRE(xdev->get_battery_status == u_device_ni_get_battery_status); }
SECTION("get_brightness can be called") { float brightness = 0.0f;
REQUIRE(dev.get_brightness_call_count == 0);
xrt_result_t result = xdev->get_brightness(xdev, &brightness);
REQUIRE(result == XRT_SUCCESS); REQUIRE(brightness == 0.5f); REQUIRE(dev.get_brightness_call_count == 1); }
SECTION("set_brightness can be called") { REQUIRE(dev.set_brightness_call_count == 0);
xrt_result_t result = xdev->set_brightness(xdev, 0.8f, false);
REQUIRE(result == XRT_SUCCESS); REQUIRE(dev.set_brightness_call_count == 1); }
SECTION("fromXDev conversion works") { auto *retrieved = BrightnessTestDevice::fromXDev(xdev); REQUIRE(retrieved == &dev); }}
/*! * Comprehensive test device with all features enabled */class AllFeaturesTestDevice : public xrt::util::DeviceBase<AllFeaturesTestDevice, kAllFunctions>{public: bool destroyed = false; int update_inputs_count = 0; int tracked_pose_count = 0; int hand_tracking_count = 0; int face_tracking_count = 0; int face_calibration_android_count = 0; int body_skeleton_count = 0; int body_joints_count = 0; int reset_body_calibration_count = 0; int set_body_calibration_count = 0; int set_output_count = 0; int get_output_limits_count = 0; int begin_plane_detection_count = 0; int destroy_plane_detection_count = 0; int get_plane_detection_state_count = 0; int get_plane_detections_count = 0; int get_view_poses_count = 0; int compute_distortion_count = 0; int get_visibility_mask_count = 0; int ref_space_usage_count = 0; int is_form_factor_available_count = 0; int get_battery_status_count = 0; int get_brightness_count = 0; int set_brightness_count = 0; int get_compositor_info_count = 0; int begin_feature_count = 0; int end_feature_count = 0;
AllFeaturesTestDevice() : DeviceBase() {}
xrt_result_t updateInputs() { update_inputs_count++; return XRT_SUCCESS; }
xrt_result_t getTrackedPose(enum xrt_input_name name, int64_t at_timestamp_ns, struct xrt_space_relation *out_relation) { tracked_pose_count++; out_relation->relation_flags = XRT_SPACE_RELATION_BITMASK_NONE; return XRT_SUCCESS; }
xrt_result_t getHandTracking(enum xrt_input_name name, int64_t desired_timestamp_ns, struct xrt_hand_joint_set *out_value, int64_t *out_timestamp_ns) { hand_tracking_count++; return XRT_SUCCESS; }
xrt_result_t getFaceTracking(enum xrt_input_name facial_expression_type, int64_t at_timestamp_ns, struct xrt_facial_expression_set *out_value) { face_tracking_count++; return XRT_SUCCESS; }
xrt_result_t getFaceCalibrationStateAndroid(bool *out_face_is_calibrated) { face_calibration_android_count++; *out_face_is_calibrated = true; return XRT_SUCCESS; }
xrt_result_t getBodySkeleton(enum xrt_input_name body_tracking_type, struct xrt_body_skeleton *out_value) { body_skeleton_count++; return XRT_SUCCESS; }
xrt_result_t getBodyJoints(enum xrt_input_name body_tracking_type, int64_t desired_timestamp_ns, struct xrt_body_joint_set *out_value) { body_joints_count++; return XRT_SUCCESS; }
xrt_result_t resetBodyTrackingCalibrationMeta() { reset_body_calibration_count++; return XRT_SUCCESS; }
xrt_result_t setBodyTrackingCalibrationOverrideMeta(float new_body_height) { set_body_calibration_count++; return XRT_SUCCESS; }
xrt_result_t setOutput(enum xrt_output_name name, const struct xrt_output_value *value) { set_output_count++; return XRT_SUCCESS; }
xrt_result_t getOutputLimits(struct xrt_output_limits *limits) { get_output_limits_count++; return XRT_SUCCESS; }
xrt_result_t beginPlaneDetectionExt(const struct xrt_plane_detector_begin_info_ext *begin_info, uint64_t plane_detection_id, uint64_t *out_plane_detection_id) { begin_plane_detection_count++; *out_plane_detection_id = 42; return XRT_SUCCESS; }
xrt_result_t destroyPlaneDetectionExt(uint64_t plane_detection_id) { destroy_plane_detection_count++; return XRT_SUCCESS; }
xrt_result_t getPlaneDetectionStateExt(uint64_t plane_detection_id, enum xrt_plane_detector_state_ext *out_state) { get_plane_detection_state_count++; *out_state = XRT_PLANE_DETECTOR_STATE_DONE_EXT; return XRT_SUCCESS; }
xrt_result_t getPlaneDetectionsExt(uint64_t plane_detection_id, struct xrt_plane_detections_ext *out_detections) { get_plane_detections_count++; return XRT_SUCCESS; }
xrt_result_t getViewPoses(const struct xrt_vec3 *default_eye_relation, int64_t at_timestamp_ns, enum xrt_view_type view_type, uint32_t view_count, struct xrt_space_relation *out_head_relation, struct xrt_fov *out_fovs, struct xrt_pose *out_poses) { get_view_poses_count++; return XRT_SUCCESS; }
xrt_result_t computeDistortion(uint32_t view, float u, float v, struct xrt_uv_triplet *out_result) { compute_distortion_count++; return XRT_SUCCESS; }
xrt_result_t getVisibilityMask(enum xrt_visibility_mask_type type, uint32_t view_index, struct xrt_visibility_mask **out_mask) { get_visibility_mask_count++; return XRT_SUCCESS; }
xrt_result_t refSpaceUsage(enum xrt_reference_space_type type, enum xrt_input_name name, bool used) { ref_space_usage_count++; return XRT_SUCCESS; }
xrt_result_t isFormFactorAvailable(enum xrt_form_factor form_factor, bool *out_available) { is_form_factor_available_count++; *out_available = true; return XRT_SUCCESS; }
xrt_result_t getBatteryStatus(bool *out_present, bool *out_charging, float *out_charge) { get_battery_status_count++; *out_present = true; *out_charging = false; *out_charge = 0.85f; return XRT_SUCCESS; }
xrt_result_t getBrightness(float *out_brightness) { get_brightness_count++; *out_brightness = 0.7f; return XRT_SUCCESS; }
xrt_result_t setBrightness(float brightness, bool relative) { set_brightness_count++; return XRT_SUCCESS; }
xrt_result_t getCompositorInfo(const struct xrt_device_compositor_mode *mode, struct xrt_device_compositor_info *out_info) { get_compositor_info_count++; return XRT_SUCCESS; }
xrt_result_t beginFeature(enum xrt_device_feature_type type) { begin_feature_count++; return XRT_SUCCESS; }
xrt_result_t endFeature(enum xrt_device_feature_type type) { end_feature_count++; return XRT_SUCCESS; }
static void destroyDevice(struct xrt_device *xdev) { auto *dev = AllFeaturesTestDevice::fromXDev(xdev); dev->destroyed = true; }};
TEST_CASE("DeviceBase_AllFeaturesDevice"){ AllFeaturesTestDevice dev; auto *xdev = dev.getXDev();
SECTION("All function pointers are set") { REQUIRE(xdev->update_inputs != nullptr); REQUIRE(xdev->get_tracked_pose != nullptr); REQUIRE(xdev->get_hand_tracking != nullptr); REQUIRE(xdev->get_face_tracking != nullptr); REQUIRE(xdev->get_face_calibration_state_android != nullptr); REQUIRE(xdev->get_body_skeleton != nullptr); REQUIRE(xdev->get_body_joints != nullptr); REQUIRE(xdev->reset_body_tracking_calibration_meta != nullptr); REQUIRE(xdev->set_body_tracking_calibration_override_meta != nullptr); REQUIRE(xdev->set_output != nullptr); REQUIRE(xdev->get_output_limits != nullptr); REQUIRE(xdev->begin_plane_detection_ext != nullptr); REQUIRE(xdev->destroy_plane_detection_ext != nullptr); REQUIRE(xdev->get_plane_detection_state_ext != nullptr); REQUIRE(xdev->get_plane_detections_ext != nullptr); REQUIRE(xdev->get_view_poses != nullptr); REQUIRE(xdev->compute_distortion != nullptr); REQUIRE(xdev->get_visibility_mask != nullptr); REQUIRE(xdev->ref_space_usage != nullptr); REQUIRE(xdev->is_form_factor_available != nullptr); REQUIRE(xdev->get_battery_status != nullptr); REQUIRE(xdev->get_brightness != nullptr); REQUIRE(xdev->set_brightness != nullptr); REQUIRE(xdev->get_compositor_info != nullptr); REQUIRE(xdev->begin_feature != nullptr); REQUIRE(xdev->end_feature != nullptr); REQUIRE(xdev->destroy != nullptr); }
SECTION("All functions can be called and track call counts") { // Test update_inputs REQUIRE(dev.update_inputs_count == 0); xdev->update_inputs(xdev); REQUIRE(dev.update_inputs_count == 1);
// Test get_tracked_pose REQUIRE(dev.tracked_pose_count == 0); xrt_space_relation relation; xdev->get_tracked_pose(xdev, XRT_INPUT_GENERIC_HEAD_POSE, 0, &relation); REQUIRE(dev.tracked_pose_count == 1);
// Test get_hand_tracking REQUIRE(dev.hand_tracking_count == 0); xrt_hand_joint_set hand_joints; int64_t timestamp; xdev->get_hand_tracking(xdev, XRT_INPUT_HT_UNOBSTRUCTED_LEFT, 0, &hand_joints, ×tamp); REQUIRE(dev.hand_tracking_count == 1);
// Test get_face_tracking REQUIRE(dev.face_tracking_count == 0); xrt_facial_expression_set face_set; xdev->get_face_tracking(xdev, XRT_INPUT_GENERIC_FACE_TRACKING, 0, &face_set); REQUIRE(dev.face_tracking_count == 1);
// Test get_face_calibration_state_android REQUIRE(dev.face_calibration_android_count == 0); bool face_calibrated; xdev->get_face_calibration_state_android(xdev, &face_calibrated); REQUIRE(dev.face_calibration_android_count == 1); REQUIRE(face_calibrated == true);
// Test get_body_skeleton REQUIRE(dev.body_skeleton_count == 0); xrt_body_skeleton skeleton; xdev->get_body_skeleton(xdev, XRT_INPUT_GENERIC_BODY_TRACKING, &skeleton); REQUIRE(dev.body_skeleton_count == 1);
// Test get_body_joints REQUIRE(dev.body_joints_count == 0); xrt_body_joint_set body_joints; xdev->get_body_joints(xdev, XRT_INPUT_GENERIC_BODY_TRACKING, 0, &body_joints); REQUIRE(dev.body_joints_count == 1);
// Test reset_body_tracking_calibration_meta REQUIRE(dev.reset_body_calibration_count == 0); xdev->reset_body_tracking_calibration_meta(xdev); REQUIRE(dev.reset_body_calibration_count == 1);
// Test set_body_tracking_calibration_override_meta REQUIRE(dev.set_body_calibration_count == 0); xdev->set_body_tracking_calibration_override_meta(xdev, 1.8f); REQUIRE(dev.set_body_calibration_count == 1);
// Test set_output REQUIRE(dev.set_output_count == 0); xrt_output_value output_value; xdev->set_output(xdev, XRT_OUTPUT_NAME_SIMPLE_VIBRATION, &output_value); REQUIRE(dev.set_output_count == 1);
// Test get_output_limits REQUIRE(dev.get_output_limits_count == 0); xrt_output_limits limits; xdev->get_output_limits(xdev, &limits); REQUIRE(dev.get_output_limits_count == 1);
// Test begin_plane_detection_ext REQUIRE(dev.begin_plane_detection_count == 0); xrt_plane_detector_begin_info_ext begin_info = {}; uint64_t plane_detection_id; xdev->begin_plane_detection_ext(xdev, &begin_info, 0, &plane_detection_id); REQUIRE(dev.begin_plane_detection_count == 1); REQUIRE(plane_detection_id == 42);
// Test get_plane_detection_state_ext REQUIRE(dev.get_plane_detection_state_count == 0); xrt_plane_detector_state_ext state; xdev->get_plane_detection_state_ext(xdev, 42, &state); REQUIRE(dev.get_plane_detection_state_count == 1); REQUIRE(state == XRT_PLANE_DETECTOR_STATE_DONE_EXT);
// Test get_plane_detections_ext REQUIRE(dev.get_plane_detections_count == 0); xrt_plane_detections_ext detections; xdev->get_plane_detections_ext(xdev, 42, &detections); REQUIRE(dev.get_plane_detections_count == 1);
// Test destroy_plane_detection_ext REQUIRE(dev.destroy_plane_detection_count == 0); xdev->destroy_plane_detection_ext(xdev, 42); REQUIRE(dev.destroy_plane_detection_count == 1);
// Test get_view_poses REQUIRE(dev.get_view_poses_count == 0); xrt_vec3 eye_relation = {0.0f, 0.0f, 0.0f}; xrt_space_relation head_relation; xrt_fov fovs[2]; xrt_pose poses[2]; xdev->get_view_poses(xdev, &eye_relation, 0, XRT_VIEW_TYPE_STEREO, 2, &head_relation, fovs, poses); REQUIRE(dev.get_view_poses_count == 1);
// Test compute_distortion REQUIRE(dev.compute_distortion_count == 0); xrt_uv_triplet triplet; xdev->compute_distortion(xdev, 0, 0.5f, 0.5f, &triplet); REQUIRE(dev.compute_distortion_count == 1);
// Test get_visibility_mask REQUIRE(dev.get_visibility_mask_count == 0); xrt_visibility_mask *mask; xdev->get_visibility_mask(xdev, XRT_VISIBILITY_MASK_TYPE_VISIBLE_TRIANGLE_MESH, 0, &mask); REQUIRE(dev.get_visibility_mask_count == 1);
// Test ref_space_usage REQUIRE(dev.ref_space_usage_count == 0); xdev->ref_space_usage(xdev, XRT_SPACE_REFERENCE_TYPE_STAGE, XRT_INPUT_GENERIC_HEAD_POSE, true); REQUIRE(dev.ref_space_usage_count == 1);
// Test is_form_factor_available REQUIRE(dev.is_form_factor_available_count == 0); bool form_factor_available = false; xrt_result_t form_factor_result = xdev->is_form_factor_available(xdev, XRT_FORM_FACTOR_HMD, &form_factor_available); REQUIRE(form_factor_result == XRT_SUCCESS); REQUIRE(dev.is_form_factor_available_count == 1); REQUIRE(form_factor_available == true);
// Test get_battery_status REQUIRE(dev.get_battery_status_count == 0); bool battery_present, battery_charging; float battery_charge; xdev->get_battery_status(xdev, &battery_present, &battery_charging, &battery_charge); REQUIRE(dev.get_battery_status_count == 1); REQUIRE(battery_present == true); REQUIRE(battery_charging == false); REQUIRE(battery_charge == 0.85f);
// Test get_brightness REQUIRE(dev.get_brightness_count == 0); float brightness; xdev->get_brightness(xdev, &brightness); REQUIRE(dev.get_brightness_count == 1); REQUIRE(brightness == 0.7f);
// Test set_brightness REQUIRE(dev.set_brightness_count == 0); xdev->set_brightness(xdev, 0.9f, false); REQUIRE(dev.set_brightness_count == 1);
// Test get_compositor_info REQUIRE(dev.get_compositor_info_count == 0); xrt_device_compositor_mode mode = {}; xrt_device_compositor_info info; xdev->get_compositor_info(xdev, &mode, &info); REQUIRE(dev.get_compositor_info_count == 1);
// Test begin_feature REQUIRE(dev.begin_feature_count == 0); xdev->begin_feature(xdev, XRT_DEVICE_FEATURE_FACE_TRACKING); REQUIRE(dev.begin_feature_count == 1);
// Test end_feature REQUIRE(dev.end_feature_count == 0); xdev->end_feature(xdev, XRT_DEVICE_FEATURE_FACE_TRACKING); REQUIRE(dev.end_feature_count == 1);
// Test destroy REQUIRE_FALSE(dev.destroyed); xdev->destroy(xdev); REQUIRE(dev.destroyed); }
SECTION("fromXDev conversion works") { auto *retrieved = AllFeaturesTestDevice::fromXDev(xdev); REQUIRE(retrieved == &dev); }}