tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

webxr_test_asserts.js (12553B)


      1 // Utility assert functions.
      2 // Relies on resources/testharness.js to be included before this file.
      3 // Relies on webxr_test_constants.js to be included before this file.
      4 // Relies on webxr_math_utils.js to be included before this file.
      5 
      6 
      7 // |p1|, |p2| - objects with x, y, z, w components that are floating point numbers.
      8 // Returns the name of mismatching component between p1 and p2.
      9 const get_mismatched_component = function(p1, p2, epsilon = FLOAT_EPSILON) {
     10  for (const v of ['x', 'y', 'z', 'w']) {
     11    if (Math.abs(p1[v] - p2[v]) > epsilon) {
     12      return v;
     13    }
     14  }
     15 
     16  return null;
     17 }
     18 
     19 // Internal helper to find the mismatched component for orientations.
     20 // Considers that q and -q represent the same orientation.
     21 // Returns the component name ('x', 'y', 'z', 'w') of the first mismatch
     22 // Returns null if q1 is approximately equal to q2 or -q2.
     23 const get_mismatched_orientation_component = function(q1, q2, epsilon) {
     24  const direct_mismatch = get_mismatched_component(q1, q2, epsilon);
     25  // q1 == q2, for our purposes there is no mismatched component.
     26  if (direct_mismatch === null) {
     27    return null;
     28  }
     29  // q1 != q2, but check q1 vs -q2
     30  const q2_flipped = flip_quaternion(q2);
     31  if (get_mismatched_component(q1, q2_flipped, epsilon) === null) {
     32    return null;
     33  }
     34  // q1 is not approx equal to q2 or -q2.
     35  // both q2 and q2_flipped have non-null mismatchecs, but for ease of debugging
     36  // return the mismatch from the direct comparison.
     37  return direct_mismatch;
     38 };
     39 
     40 // Internal helper to find the index of the first mismatched matrix element.
     41 // Returns the index (0-15) or -1 if matrices are approximately equal.
     42 const get_mismatched_matrix_element_index = function(m1, m2, epsilon, prefix="") {
     43  assert_equals(m1.length, 16, prefix + "m1 must have length of 16");
     44  assert_equals(m2.length, 16, prefix + "m2 must have length of 16");
     45 
     46  for (let i = 0; i < 16; ++i) {
     47    if (Math.abs(m1[i] - m2[i]) > epsilon) {
     48      return i;
     49    }
     50  }
     51  return -1;
     52 }
     53 
     54 // |p1|, |p2| - objects with x, y, z, w components that are floating point numbers.
     55 // |epsilon| - float specifying precision
     56 // |prefix| - string used as a prefix for logging
     57 const assert_point_approx_equals = function(p1, p2, epsilon = FLOAT_EPSILON, prefix = "") {
     58  if (p1 == null && p2 == null) {
     59    return;
     60  }
     61 
     62  assert_not_equals(p1, null, prefix + "p1 must be non-null");
     63  assert_not_equals(p2, null, prefix + "p2 must be non-null");
     64 
     65  const mismatched_component = get_mismatched_component(p1, p2, epsilon);
     66 
     67  if (mismatched_component !== null) {
     68    let error_message = prefix + ' Point comparison failed.\n';
     69    error_message += ` p1: {x: ${p1.x}, y: ${p1.y}, z: ${p1.z}, w: ${p1.w}}\n`;
     70    error_message += ` p2: {x: ${p2.x}, y: ${p2.y}, z: ${p2.z}, w: ${p2.w}}\n`;
     71    error_message += ` Difference in component ${mismatched_component} exceeded the given epsilon.\n`;
     72    assert_approx_equals(p2[mismatched_component], p1[mismatched_component], epsilon, error_message);
     73  }
     74 };
     75 
     76 // |p1|, |p2| - objects with x, y, z, w components that are floating point numbers.
     77 // |epsilon| - float specifying precision
     78 // |prefix| - string used as a prefix for logging
     79 const assert_point_significantly_not_equals = function(p1, p2, epsilon = FLOAT_EPSILON, prefix = "") {
     80  if (p1 == null || p2 == null) {
     81    assert_not_equals(p2, p1, prefix + "p1 and p2 are both null");
     82    return;
     83  }
     84 
     85  const mismatched_component = get_mismatched_component(p1, p2, epsilon);
     86  if (mismatched_component === null) {
     87    let error_message = prefix + ' Point comparison failed (expected significant difference).\n';
     88    error_message += ` p1: {x: ${p1.x}, y: ${p1.y}, z: ${p1.z}, w: ${p1.w}}\n`;
     89    error_message += ` p2: {x: ${p2.x}, y: ${p2.y}, z: ${p2.z}, w: ${p2.w}}\n`;
     90    error_message += ` Difference in components did not exceeded the given epsilon.\n`;
     91    assert_unreached(error_message);
     92  }
     93 };
     94 
     95 // |q1|, |q2| - objects with x, y, z, w components that are floating point numbers.
     96 // |epsilon| - float specifying precision
     97 // |prefix| - string used as a prefix for logging
     98 const assert_orientation_approx_equals = function(q1, q2, epsilon = FLOAT_EPSILON, prefix = "") {
     99  if (q1 == null && q2 == null) {
    100    return;
    101  }
    102 
    103  assert_not_equals(q1, null, prefix + "q1 must be non-null");
    104  assert_not_equals(q2, null, prefix + "q2 must be non-null");
    105 
    106  const mismatched_component = get_mismatched_orientation_component(q1, q2, epsilon);
    107  // q1 doesn't match neither q2 nor -q2, so it definitely does not represent the same orientations,
    108  // log an assert failure.
    109  if (mismatched_component !== null) {
    110    let error_message = prefix + ' Orientation comparison failed.\n';
    111    error_message += ` q1: {x: ${q1.x}, y: ${q1.y}, z: ${q1.z}, w: ${q1.w}}\n`;
    112    error_message += ` q2: {x: ${q2.x}, y: ${q2.y}, z: ${q2.z}, w: ${q2.w}}\n`;
    113    error_message += ` Neither q2 nor -q2 are approximately equal to q1.\n`;
    114    error_message += ` For q1 vs q2, difference in component ${mismatched_component} exceeded the given epsilon.\n`;
    115    assert_approx_equals(q2[mismatched_component], q1[mismatched_component], epsilon, error_message);
    116  }
    117 };
    118 
    119 // |q1|, |q2| - objects with x, y, z, w components that are floating point numbers.
    120 // |epsilon| - float specifying precision
    121 // |prefix| - string used as a prefix for logging
    122 const assert_orientation_significantly_not_equals = function(q1, q2, epsilon = FLOAT_EPSILON, prefix = "") {
    123  if (q1 == null || q2 == null) {
    124    assert_not_equals(q2, q1, prefix + "q1 and q2 are both null");
    125    return;
    126  }
    127 
    128  const mismatched_component = get_mismatched_orientation_component(q1, q2, epsilon);
    129  // IF there is no mismatch q1 matches either q2 or -q2 (which are equivalent).
    130  if (mismatched_component === null) {
    131    let error_message = prefix + ' Orientation comparison failed (expected significant difference).\n';
    132    error_message += ` q1: {x: ${q1.x}, y: ${q1.y}, z: ${q1.z}, w: ${q1.w}}\n`;
    133    error_message += ` q2: {x: ${q2.x}, y: ${q2.y}, z: ${q2.z}, w: ${q2.w}}\n`;
    134    error_message += ` q1 is approximately equal to q2 or -q2, but a significant difference was expected.\n`;
    135    assert_unreached(error_message);
    136  }
    137 };
    138 
    139 // |t1|, |t2| - objects containing position and orientation.
    140 // |epsilon| - float specifying precision
    141 // |prefix| - string used as a prefix for logging
    142 const assert_transform_approx_equals = function(t1, t2, epsilon = FLOAT_EPSILON, prefix = "") {
    143  if (t1 == null && t2 == null) {
    144    return;
    145  }
    146 
    147  assert_not_equals(t1, null, prefix + "t1 must be non-null");
    148  assert_not_equals(t2, null, prefix + "t2 must be non-null");
    149 
    150  assert_point_approx_equals(t1.position, t2.position, epsilon, prefix + "positions must be equal");
    151  assert_orientation_approx_equals(t1.orientation, t2.orientation, epsilon, prefix + "orientations must be equal");
    152 };
    153 
    154 // |t1|, |t2| - objects containing position and orientation.
    155 // |epsilon| - float specifying precision
    156 // |prefix| - string used as a prefix for logging
    157 const assert_transform_significantly_not_equals = function(t1, t2, epsilon = FLOAT_EPSILON, prefix = "") {
    158  if (t1 == null || t2 == null) {
    159    assert_not_equals(t1, t2, prefix + "t1 and t2 cannot both be null.");
    160    return;
    161  }
    162 
    163  // It is okay for one of position or orientation to be equal; but not for both
    164  // to be equal in order for the transform to not be equal.
    165  let mismatched_position = get_mismatched_component(t1.position, t2.position, epsilon);
    166  let mismatched_orientation = get_mismatched_orientation_component(t1.orientation, t2.orientation, epsilon);
    167  if (mismatched_position === null && mismatched_orientation === null) {
    168      assert_point_significantly_not_equals(t1.position, t2.position, epsilon, prefix + "positions must not be equal");
    169      assert_orientation_significantly_not_equals(t1.orientation, t2.orientation, epsilon, prefix + "orientations must not be equal");
    170  }
    171 }
    172 
    173 // |m1|, |m2| - arrays of floating point numbers
    174 // |epsilon| - float specifying precision
    175 // |prefix| - string used as a prefix for logging
    176 const assert_matrix_approx_equals = function(m1, m2, epsilon = FLOAT_EPSILON, prefix = "") {
    177  if (m1 == null && m2 == null) {
    178    return;
    179  }
    180 
    181  assert_not_equals(m1, null, prefix + "m1 must be non-null");
    182  assert_not_equals(m2, null, prefix + "m2 must be non-null");
    183 
    184  assert_equals(m1.length, 16, prefix + "m1 must have length of 16");
    185  assert_equals(m2.length, 16, prefix + "m2 must have length of 16");
    186 
    187  const mismatched_element = get_mismatched_matrix_element_index(m1, m2, epsilon, prefix);
    188  if (mismatched_element !== -1) {
    189    let error_message = prefix + 'Matrix comparison failed.\n';
    190    error_message += ' Difference in element ' + mismatched_element +
    191        ' exceeded the given epsilon.\n';
    192 
    193    error_message += ' Matrix 1: [' + m1.join(',') + ']\n';
    194    error_message += ' Matrix 2: [' + m2.join(',') + ']\n';
    195 
    196    assert_approx_equals(
    197        m1[mismatched_element], m2[mismatched_element], epsilon,
    198        error_message);
    199  }
    200 };
    201 
    202 // |m1|, |m2| - arrays of floating point numbers.
    203 // |epsilon| - float specifying precision
    204 // |prefix| - string used as a prefix for logging
    205 const assert_matrix_significantly_not_equals = function(m1, m2, epsilon = FLOAT_EPSILON, prefix = "") {
    206  if (m1 == null || m2 == null) {
    207    assert_not_equals(m1, m2, prefix + "m1 and m2 must not both be null");
    208    return;
    209  }
    210 
    211  assert_equals(m1.length, 16, prefix + "m1 must have length of 16");
    212  assert_equals(m2.length, 16, prefix + "m2 must have length of 16");
    213 
    214  const mismatched_index = get_mismatched_matrix_element_index(m1, m2, epsilon, prefix);
    215  if (mismatched_index === -1) {
    216    let error_message = prefix + ' Matrix comparison failed (expected significant difference).\n';
    217    error_message +=
    218        ' No element exceeded the given epsilon ' + epsilon + '.\n';
    219 
    220    error_message += ' Matrix 1: [' + m1.join(',') + ']\n';
    221    error_message += ' Matrix 2: [' + m2.join(',') + ']\n';
    222 
    223    assert_unreached(error_message);
    224  }
    225 };
    226 
    227 // |r1|, |r2| - XRRay objects
    228 // |epsilon| - float specifying precision
    229 // |prefix| - string used as a prefix for logging
    230 const assert_ray_approx_equals = function(r1, r2, epsilon = FLOAT_EPSILON, prefix = "") {
    231  assert_point_approx_equals(r1.origin, r2.origin, epsilon, prefix + "origin:");
    232  assert_point_approx_equals(r1.direction, r2.direction, epsilon, prefix + "direction:");
    233  assert_matrix_approx_equals(r1.matrix, r2.matrix, epsilon, prefix + "matrix:");
    234 };
    235 
    236 // |actualBuffer|, |expectedBuffer| - ArrayBuffer objects
    237 // |message| - string used as a prefix for logging
    238 const assert_array_buffer_equals = function(actualBuffer, expectedBuffer, message = "ArrayBuffers should be equal") {
    239  if (actualBuffer == null && expectedBuffer == null) {
    240    return;
    241  }
    242 
    243  assert_not_equals(actualBuffer, null, message + " (actualBuffer is null)");
    244  assert_not_equals(expectedBuffer, null, message + " (expectedBuffer is null)");
    245 
    246  assert_equals(actualBuffer.byteLength, expectedBuffer.byteLength, message + " (byteLength mismatch)");
    247 
    248  const actualView = new Uint8Array(actualBuffer);
    249  const expectedView = new Uint8Array(expectedBuffer);
    250 
    251  for (let i = 0; i < actualView.length; i++) {
    252    // Check each byte. If a mismatch is found, assert_equals will fail the test
    253    // and provide a detailed message.
    254    if (actualView[i] !== expectedView[i]) {
    255      assert_equals(actualView[i], expectedView[i], `${message} (mismatch at byte ${i})`);
    256      return;
    257    }
    258  }
    259  // If the loop completes without an assert_equals failure, the buffers are identical.
    260 };
    261 
    262 // |actualBuffer|, |expectedBuffer| - ArrayBuffer objects
    263 // |message| - string used as a prefix for logging
    264 const assert_array_buffer_not_equals = function(actualBuffer, expectedBuffer, message = "ArrayBuffers should not be equal") {
    265  if (actualBuffer == null || expectedBuffer == null) {
    266    assert_not_equals(actualBuffer, expectedBuffer, message+ " (actualBuffer and expectedBuffer both null)");
    267    return;
    268  }
    269 
    270  assert_not_equals(actualBuffer, null, message + " (actualBuffer is null)");
    271  assert_not_equals(expectedBuffer, null, message + " (expectedBuffer is null)");
    272 
    273  if (actualBuffer.byteLength !== expectedBuffer.byteLength) {
    274    return;
    275  }
    276 
    277  const actualView = new Uint8Array(actualBuffer);
    278  const expectedView = new Uint8Array(expectedBuffer);
    279 
    280  for (let i = 0; i < actualView.length; i++) {
    281    // Once one byte is different, then the two buffers aren't the same and we
    282    // can return.
    283    if (actualView[i] !== expectedView[i]) {
    284      return;
    285    }
    286  }
    287  assert_unreached(`${message} (buffers are identical`);
    288 };