tor-browser

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

audit-util.js (11103B)


      1 // Copyright 2016 The Chromium Authors
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 
      6 /**
      7 * @fileOverview  This file includes legacy utility functions for the layout
      8 *                test.
      9 */
     10 
     11 // How many frames in a WebAudio render quantum.
     12 let RENDER_QUANTUM_FRAMES = 128;
     13 
     14 // Compare two arrays (commonly extracted from buffer.getChannelData()) with
     15 // constraints:
     16 //   options.thresholdSNR: Minimum allowed SNR between the actual and expected
     17 //     signal. The default value is 10000.
     18 //   options.thresholdDiffULP: Maximum allowed difference between the actual
     19 //     and expected signal in ULP(Unit in the last place). The default is 0.
     20 //   options.thresholdDiffCount: Maximum allowed number of sample differences
     21 //     which exceeds the threshold. The default is 0.
     22 //   options.bitDepth: The expected result is assumed to come from an audio
     23 //     file with this number of bits of precision. The default is 16.
     24 function compareBuffersWithConstraints(should, actual, expected, options) {
     25  if (!options)
     26    options = {};
     27 
     28  // Only print out the message if the lengths are different; the
     29  // expectation is that they are the same, so don't clutter up the
     30  // output.
     31  if (actual.length !== expected.length) {
     32    should(
     33        actual.length === expected.length,
     34        'Length of actual and expected buffers should match')
     35        .beTrue();
     36  }
     37 
     38  let maxError = -1;
     39  let diffCount = 0;
     40  let errorPosition = -1;
     41  let thresholdSNR = (options.thresholdSNR || 10000);
     42 
     43  let thresholdDiffULP = (options.thresholdDiffULP || 0);
     44  let thresholdDiffCount = (options.thresholdDiffCount || 0);
     45 
     46  // By default, the bit depth is 16.
     47  let bitDepth = (options.bitDepth || 16);
     48  let scaleFactor = Math.pow(2, bitDepth - 1);
     49 
     50  let noisePower = 0, signalPower = 0;
     51 
     52  for (let i = 0; i < actual.length; i++) {
     53    let diff = actual[i] - expected[i];
     54    noisePower += diff * diff;
     55    signalPower += expected[i] * expected[i];
     56 
     57    if (Math.abs(diff) > maxError) {
     58      maxError = Math.abs(diff);
     59      errorPosition = i;
     60    }
     61 
     62    // The reference file is a 16-bit WAV file, so we will almost never get
     63    // an exact match between it and the actual floating-point result.
     64    if (Math.abs(diff) > scaleFactor)
     65      diffCount++;
     66  }
     67 
     68  let snr = 10 * Math.log10(signalPower / noisePower);
     69  let maxErrorULP = maxError * scaleFactor;
     70 
     71  should(snr, 'SNR').beGreaterThanOrEqualTo(thresholdSNR);
     72 
     73  should(
     74      maxErrorULP,
     75      options.prefix + ': Maximum difference (in ulp units (' + bitDepth +
     76          '-bits))')
     77      .beLessThanOrEqualTo(thresholdDiffULP);
     78 
     79  should(diffCount, options.prefix + ': Number of differences between results')
     80      .beLessThanOrEqualTo(thresholdDiffCount);
     81 }
     82 
     83 // Create an impulse in a buffer of length sampleFrameLength
     84 function createImpulseBuffer(context, sampleFrameLength) {
     85  let audioBuffer =
     86      context.createBuffer(1, sampleFrameLength, context.sampleRate);
     87  let n = audioBuffer.length;
     88  let dataL = audioBuffer.getChannelData(0);
     89 
     90  for (let k = 0; k < n; ++k) {
     91    dataL[k] = 0;
     92  }
     93  dataL[0] = 1;
     94 
     95  return audioBuffer;
     96 }
     97 
     98 // Create a buffer of the given length with a linear ramp having values 0 <= x <
     99 // 1.
    100 function createLinearRampBuffer(context, sampleFrameLength) {
    101  let audioBuffer =
    102      context.createBuffer(1, sampleFrameLength, context.sampleRate);
    103  let n = audioBuffer.length;
    104  let dataL = audioBuffer.getChannelData(0);
    105 
    106  for (let i = 0; i < n; ++i)
    107    dataL[i] = i / n;
    108 
    109  return audioBuffer;
    110 }
    111 
    112 // Create an AudioBuffer of length |sampleFrameLength| having a constant value
    113 // |constantValue|. If |constantValue| is a number, the buffer has one channel
    114 // filled with that value. If |constantValue| is an array, the buffer is created
    115 // wit a number of channels equal to the length of the array, and channel k is
    116 // filled with the k'th element of the |constantValue| array.
    117 function createConstantBuffer(context, sampleFrameLength, constantValue) {
    118  let channels;
    119  let values;
    120 
    121  if (typeof constantValue === 'number') {
    122    channels = 1;
    123    values = [constantValue];
    124  } else {
    125    channels = constantValue.length;
    126    values = constantValue;
    127  }
    128 
    129  let audioBuffer =
    130      context.createBuffer(channels, sampleFrameLength, context.sampleRate);
    131  let n = audioBuffer.length;
    132 
    133  for (let c = 0; c < channels; ++c) {
    134    let data = audioBuffer.getChannelData(c);
    135    for (let i = 0; i < n; ++i)
    136      data[i] = values[c];
    137  }
    138 
    139  return audioBuffer;
    140 }
    141 
    142 // Create a stereo impulse in a buffer of length sampleFrameLength
    143 function createStereoImpulseBuffer(context, sampleFrameLength) {
    144  let audioBuffer =
    145      context.createBuffer(2, sampleFrameLength, context.sampleRate);
    146  let n = audioBuffer.length;
    147  let dataL = audioBuffer.getChannelData(0);
    148  let dataR = audioBuffer.getChannelData(1);
    149 
    150  for (let k = 0; k < n; ++k) {
    151    dataL[k] = 0;
    152    dataR[k] = 0;
    153  }
    154  dataL[0] = 1;
    155  dataR[0] = 1;
    156 
    157  return audioBuffer;
    158 }
    159 
    160 // Convert time (in seconds) to sample frames.
    161 function timeToSampleFrame(time, sampleRate) {
    162  return Math.floor(0.5 + time * sampleRate);
    163 }
    164 
    165 // Compute the number of sample frames consumed by noteGrainOn with
    166 // the specified |grainOffset|, |duration|, and |sampleRate|.
    167 function grainLengthInSampleFrames(grainOffset, duration, sampleRate) {
    168  let startFrame = timeToSampleFrame(grainOffset, sampleRate);
    169  let endFrame = timeToSampleFrame(grainOffset + duration, sampleRate);
    170 
    171  return endFrame - startFrame;
    172 }
    173 
    174 // True if the number is not an infinity or NaN
    175 function isValidNumber(x) {
    176  return !isNaN(x) && (x != Infinity) && (x != -Infinity);
    177 }
    178 
    179 // Compute the (linear) signal-to-noise ratio between |actual| and
    180 // |expected|.  The result is NOT in dB!  If the |actual| and
    181 // |expected| have different lengths, the shorter length is used.
    182 function computeSNR(actual, expected) {
    183  let signalPower = 0;
    184  let noisePower = 0;
    185 
    186  let length = Math.min(actual.length, expected.length);
    187 
    188  for (let k = 0; k < length; ++k) {
    189    let diff = actual[k] - expected[k];
    190    signalPower += expected[k] * expected[k];
    191    noisePower += diff * diff;
    192  }
    193 
    194  return signalPower / noisePower;
    195 }
    196 
    197 /**
    198 * Asserts that all elements in the given array are equal to the specified value
    199 * If the value is NaN, checks that each element in the array is also NaN.
    200 * Throws an assertion error if any element does not match the expected value.
    201 *
    202 * @param {Array<number>} array - The array of numbers to check.
    203 * @param {number} value - The constant that each array element should match.
    204 * @param {string} [messagePrefix=''] - Optional for assertion error messages.
    205 */
    206 function assert_constant_value(array, value, messagePrefix = '') {
    207  for (let i = 0; i < array.length; ++i) {
    208    if (Number.isNaN(value)) {
    209      assert_true(
    210        Number.isNaN(array[i]),
    211        `${messagePrefix} entry ${i} should be NaN`
    212      );
    213    } else {
    214      assert_equals(
    215        array[i],
    216        value,
    217        `${messagePrefix} entry ${i} should be ${value}`
    218      );
    219    }
    220  }
    221 }
    222 
    223 /**
    224 * Asserts that two arrays are exactly equal, element by element.
    225 * @param {!Array<number>} actual The actual array of values.
    226 * @param {!Array<number>} expected The expected array of values.
    227 * @param {string} message Description used for assertion failures.
    228 */
    229 function assert_array_equals_exact(actual, expected, message) {
    230  assert_equals(actual.length, expected.length, 'Buffers must be same length');
    231  for (let i = 0; i < actual.length; ++i) {
    232    assert_equals(actual[i], expected[i], `${message} (at index ${i})`);
    233  }
    234 }
    235 
    236 /**
    237 * Asserts that an array is not a constant array
    238 * (i.e., not all values are equal to the given constant).
    239 * @param {!Array<number>} array The array to be checked.
    240 * @param {number} constantValue The constant value to compare against.
    241 * @param {string} message Description used for assertion failures.
    242 */
    243 function assert_not_constant_value(array, constantValue, message) {
    244  const notAllSame = array.some(value => value !== constantValue);
    245  assert_true(notAllSame, message);
    246 }
    247 
    248 /**
    249 * Asserts that all elements of an array are exactly equal to a constant value.
    250 * @param {!Array<number>} array The array to be checked.
    251 * @param {number} constantValue The expected constant value.
    252 * @param {string} message Description used for assertion failures.
    253 */
    254 function assert_strict_constant_value(array, constantValue, message) {
    255  const allSame = array.every(value => value === constantValue);
    256  assert_true(allSame, message);
    257 }
    258 
    259 /**
    260 * Asserts that all elements of an array are (approximately) equal to a value.
    261 *
    262 * @param {!Array<number>} array - The array to be checked.
    263 * @param {number} constantValue - The expected constant value.
    264 * @param {string} message - Description used for assertion failures.
    265 * @param {number=} epsilon - Allowed tolerance for floating-point comparison.
    266 * Default to 1e-7
    267 */
    268 function assert_array_constant_value(
    269    array, constantValue, message, epsilon = 1e-7) {
    270      for (let i = 0; i < array.length; ++i) {
    271        assert_approx_equals(
    272            array[i], constantValue, epsilon, `${message} sample[${i}]`);
    273      }
    274 }
    275 
    276 /**
    277 * Asserts that two arrays are equal within a given tolerance for each element.
    278 * The |threshold| can be:
    279 *   - A number (absolute epsilon)
    280 *   - An object with optional {absoluteThreshold, relativeThreshold}
    281 *   - If omitted, compares with exact equality (epsilon = 0)
    282 *
    283 * For each element i, we require:
    284 *   |actual[i] − expected[i]| ≤ max(absoluteThreshold,
    285 *                                   |expected[i]|·relativeThreshold)
    286 *
    287 * @param {!Array<number>|!TypedArray<number>} actual
    288 * @param {!Array<number>|!TypedArray<number>} expected
    289 * @param {number|{ absoluteThreshold?:number, relativeThreshold?:number }}
    290 *   [threshold=0]
    291 * @param {string} desc
    292 */
    293 function assert_array_equal_within_eps(
    294    actual, expected, threshold = 0, desc) {
    295  assert_equals(actual.length, expected.length, desc + ': length mismatch');
    296 
    297  let abs = 0;
    298  let rel = 0;
    299 
    300  if (typeof threshold === 'number') {
    301    abs = threshold;
    302  } else if (threshold && typeof threshold === 'object') {
    303    abs = threshold.absoluteThreshold ?? 0;
    304    rel = threshold.relativeThreshold ?? 0;
    305  }
    306 
    307  for (let i = 0; i < actual.length; ++i) {
    308    const epsilon = Math.max(abs, Math.abs(expected[i]) * rel);
    309    const diff = Math.abs(actual[i] - expected[i]);
    310    assert_approx_equals(
    311        actual[i],
    312        expected[i],
    313        epsilon,
    314        `${desc} sample[${i}] |${actual[i]} - ${expected[i]}|` +
    315            ` = ${diff} > ${epsilon}`);
    316  }
    317 }
    318 
    319 function assert_not_constant_value_of(array, value, description) {
    320  assert_true(array && typeof array.length === 'number' && array.length > 0,
    321      `${description}: input must be a non-empty array`);
    322 
    323  const hasDifferentValues = array.some(element => element !== value);
    324 
    325  // Pass if there's at least one element not strictly equal to `value`.
    326  assert_true(
    327      hasDifferentValues,
    328      `${description}: ${array} should have contained at least `+
    329          `one value different from ${value}.`
    330  );
    331 }