File: util.js

package info (click to toggle)
firefox-esr 140.5.0esr-1~deb13u1
  • links: PTS, VCS
  • area: main
  • in suites: trixie-proposed-updates
  • size: 4,539,036 kB
  • sloc: cpp: 7,381,527; javascript: 6,388,905; ansic: 3,710,087; python: 1,393,776; xml: 628,165; asm: 426,918; java: 184,004; sh: 65,744; makefile: 19,302; objc: 13,059; perl: 12,912; yacc: 4,583; cs: 3,846; pascal: 3,352; lex: 1,720; ruby: 1,226; exp: 762; php: 436; lisp: 258; awk: 247; sql: 66; sed: 54; csh: 10
file content (227 lines) | stat: -rw-r--r-- 7,529 bytes parent folder | download | duplicates (10)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
const kValidAvailabilities =
    ['unavailable', 'downloadable', 'downloading', 'available'];
const kAvailableAvailabilities = ['downloadable', 'downloading', 'available'];

const kTestPrompt = 'Please write a sentence in English.';
const kTestContext = 'This is a test; this is only a test.';

const getId = (() => {
  let idCount = 0;
  return () => idCount++;
})();

// Takes an array of dictionaries mapping keys to value arrays, e.g.:
//   [ {Shape: ["Square", "Circle", undefined]}, {Count: [1, 2]} ]
// Returns an array of dictionaries with all value combinations, i.e.:
//  [ {Shape: "Square", Count: 1}, {Shape: "Square", Count: 2},
//    {Shape: "Circle", Count: 1}, {Shape: "Circle", Count: 2},
//    {Shape: undefined, Count: 1}, {Shape: undefined, Count: 2} ]
// Omits dictionary members when the value is undefined; supports array values.
function generateOptionCombinations(optionsSpec) {
  // 1. Extract keys from the input specification.
  const keys = optionsSpec.map(o => Object.keys(o)[0]);
  // 2. Extract the arrays of possible values for each key.
  const valueArrays = optionsSpec.map(o => Object.values(o)[0]);
  // 3. Compute the Cartesian product of the value arrays using reduce.
  const valueCombinations = valueArrays.reduce((accumulator, currentValues) => {
    // Init the empty accumulator (first iteration), with single-element
    // arrays.
    if (accumulator.length === 0) {
      return currentValues.map(value => [value]);
    }
    // Otherwise, expand existing combinations with current values.
    return accumulator.flatMap(
        existingCombo => currentValues.map(
            currentValue => [...existingCombo, currentValue]));
  }, []);

  // 4. Map each value combination to a result dictionary, skipping
  // undefined.
  return valueCombinations.map(combination => {
    const result = {};
    keys.forEach((key, index) => {
      if (combination[index] !== undefined) {
        result[key] = combination[index];
      }
    });
    return result;
  });
}

// The method should take the AbortSignal as an option and return a promise.
async function testAbortPromise(t, method) {
  // Test abort signal without custom error.
  {
    const controller = new AbortController();
    const promise = method(controller.signal);
    controller.abort();
    await promise_rejects_dom(t, 'AbortError', promise);

    // Using the same aborted controller will get the `AbortError` as well.
    const anotherPromise = method(controller.signal);
    await promise_rejects_dom(t, 'AbortError', anotherPromise);
  }

  // Test abort signal with custom error.
  {
    const err = new Error('test');
    const controller = new AbortController();
    const promise = method(controller.signal);
    controller.abort(err);
    await promise_rejects_exactly(t, err, promise);

    // Using the same aborted controller will get the same error as well.
    const anotherPromise = method(controller.signal);
    await promise_rejects_exactly(t, err, anotherPromise);
  }
};

async function testCreateMonitorWithAbortAt(
    t, loadedToAbortAt, method, options = {}) {
  const {promise: eventPromise, resolve} = Promise.withResolvers();
  let hadEvent = false;
  function monitor(m) {
    m.addEventListener('downloadprogress', e => {
      if (e.loaded != loadedToAbortAt) {
        return;
      }

      if (hadEvent) {
        assert_unreached(
            'This should never be reached since LanguageDetector.create() was aborted.');
        return;
      }

      resolve();
      hadEvent = true;
    });
  }

  const controller = new AbortController();

  const createPromise =
      method({...options, monitor, signal: controller.signal});

  await eventPromise;

  const err = new Error('test');
  controller.abort(err);
  await promise_rejects_exactly(t, err, createPromise);
}

async function testCreateMonitorWithAbort(t, method, options = {}) {
  await testCreateMonitorWithAbortAt(t, 0, method, options);
  await testCreateMonitorWithAbortAt(t, 1, method, options);
}

// The method should take the AbortSignal as an option and return a
// ReadableStream.
async function testAbortReadableStream(t, method) {
  // Test abort signal without custom error.
  {
    const controller = new AbortController();
    const stream = method(controller.signal);
    controller.abort();
    let writableStream = new WritableStream();
    await promise_rejects_dom(t, 'AbortError', stream.pipeTo(writableStream));

    // Using the same aborted controller will get the `AbortError` as well.
    await promise_rejects_dom(t, 'AbortError', new Promise(() => {
                                method(controller.signal);
                              }));
  }

  // Test abort signal with custom error.
  {
    const error = new DOMException('test', 'VersionError');
    const controller = new AbortController();
    const stream = method(controller.signal);
    controller.abort(error);
    let writableStream = new WritableStream();
    await promise_rejects_exactly(t, error, stream.pipeTo(writableStream));

    // Using the same aborted controller will get the same error.
    await promise_rejects_exactly(t, error, new Promise(() => {
                                    method(controller.signal);
                                  }));
  }
};

async function testMonitor(createFunc, options = {}) {
  let created = false;
  const progressEvents = [];
  function monitor(m) {
    m.addEventListener('downloadprogress', e => {
      // No progress events should be fired after `createFunc` resolves.
      assert_false(created);

      progressEvents.push(e);
    });
  }

  result = await createFunc({...options, monitor});
  created = true;

  assert_greater_than_equal(progressEvents.length, 2);
  assert_equals(progressEvents.at(0).loaded, 0);
  assert_equals(progressEvents.at(-1).loaded, 1);

  let lastProgressEventLoaded = -1;
  for (const progressEvent of progressEvents) {
    assert_equals(progressEvent.lengthComputable, true);
    assert_equals(progressEvent.total, 1);
    assert_less_than_equal(progressEvent.loaded, progressEvent.total);

    // `loaded` must be rounded to the nearest 0x10000th.
    assert_equals(progressEvent.loaded % (1 / 0x10000), 0);

    // Progress events should have monotonically increasing `loaded` values.
    assert_greater_than(progressEvent.loaded, lastProgressEventLoaded);
    lastProgressEventLoaded = progressEvent.loaded;
  }
  return result;
}

function run_iframe_test(iframe, test_name) {
  const id = getId();
  iframe.contentWindow.postMessage({id, type: test_name}, '*');
  const {promise, resolve, reject} = Promise.withResolvers();
  window.onmessage = message => {
    if (message.data.id !== id) {
      return;
    }
    if (message.data.success) {
      resolve(message.data.success);
    } else {
      reject(message.data.err)
    }
  };
  return promise;
}

function load_iframe(src, permission_policy) {
  let iframe = document.createElement('iframe');
  const {promise, resolve} = Promise.withResolvers();
  iframe.onload = () => {
    resolve(iframe);
  };
  iframe.src = src;
  iframe.allow = permission_policy;
  document.body.appendChild(iframe);
  return promise;
}

async function createSummarizer(options = {}) {
  await test_driver.bless();
  return await Summarizer.create(options);
}

async function createWriter(options = {}) {
  await test_driver.bless();
  return await Writer.create(options);
}

async function createRewriter(options = {}) {
  await test_driver.bless();
  return await Rewriter.create(options);
}