tor-browser

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

from_async.js (7620B)


      1 // |reftest| skip-if(!xulRuntime.shell) -- needs drainJobQueue
      2 
      3 // Basic Smoke Test
      4 async function* asyncGen(n) {
      5  for (let i = 0; i < n; i++) {
      6    yield i * 2;
      7  }
      8 }
      9 
     10 let done = false;
     11 Array.fromAsync(asyncGen(4)).then((x) => {
     12  assertEq(Array.isArray(x), true);
     13  assertEq(x.length, 4);
     14  assertEq(x[0], 0);
     15  assertEq(x[1], 2);
     16  assertEq(x[2], 4);
     17  assertEq(x[3], 6);
     18  done = true;
     19 }
     20 );
     21 
     22 drainJobQueue();
     23 assertEq(done, true);
     24 
     25 (async function () {
     26  class InterruptableAsyncIterator {
     27    count = 0
     28    closed = false
     29    throwAfter = NaN
     30    constructor(n, throwAfter = NaN) {
     31      this.count = n;
     32      this.throwAfter = throwAfter;
     33    }
     34    [Symbol.asyncIterator] = function () {
     35      return {
     36        iter: this,
     37        i: 0,
     38        async next() {
     39          if (this.i > this.iter.throwAfter) {
     40            throw "Exception"
     41          }
     42          if (this.i++ < this.iter.count) {
     43            return Promise.resolve({ done: false, value: this.i - 1 });
     44          }
     45          return Promise.resolve({ done: true, value: undefined });
     46        },
     47        async return(x) {
     48          this.iter.closed = true;
     49          return { value: x, done: true };
     50        }
     51      }
     52    }
     53  }
     54 
     55  var one = await Array.fromAsync(new InterruptableAsyncIterator(2));
     56  assertEq(one.length, 2)
     57  assertEq(one[0], 0);
     58  assertEq(one[1], 1);
     59 
     60  var two = new InterruptableAsyncIterator(10, 2);
     61  var threw = false;
     62  try {
     63    var res = await Array.fromAsync(two);
     64  } catch (e) {
     65    threw = true;
     66    assertEq(e, "Exception");
     67  }
     68  assertEq(threw, true);
     69  // The iterator is not closed unless we have an abrupt completion while mapping.
     70  assertEq(two.closed, false);
     71 
     72  // Test throwing while mapping: Iterator should be closed.
     73  var three = new InterruptableAsyncIterator(10, 9);
     74  threw = false;
     75  try {
     76    var res = await Array.fromAsync(three, (x) => {
     77      if (x > 3) {
     78        throw "Range"
     79      }
     80      return x;
     81    });
     82  } catch (e) {
     83    assertEq(e, "Range");
     84    threw = true;
     85  }
     86  assertEq(threw, true);
     87  assertEq(three.closed, true);
     88 
     89  var sync = await Array.fromAsync([1, 2, 3]);
     90  assertEq(sync.length, 3);
     91  assertEq(sync[0], 1)
     92  assertEq(sync[1], 2)
     93  assertEq(sync[2], 3)
     94 
     95  let closed_frozen = false;
     96  class Frozen {
     97    constructor(x) {
     98      this.count = x;
     99      Object.freeze(this);
    100    }
    101    [Symbol.asyncIterator] = function () {
    102      return {
    103        iter: this,
    104        i: 0,
    105        async next() {
    106          if (this.i++ < this.iter.count) {
    107            return Promise.resolve({ done: false, value: this.i - 1 });
    108          }
    109          return Promise.resolve({ done: true, value: undefined });
    110        },
    111        async return(x) {
    112          // Can't use Frozen instance, becuse frozen is frozen.
    113          closed_frozen = true;
    114          return { value: x, done: true };
    115        }
    116      }
    117    }
    118  }
    119 
    120  // We should close the iterator when define property throws.
    121  // Test by defining into a frozen object. 
    122  var frozen = new Frozen(10);
    123  threw = false;
    124  try {
    125    var result = await Array.fromAsync.call(Frozen, frozen);
    126  } catch (e) {
    127    threw = true;
    128  }
    129 
    130  assertEq(threw, true);
    131  assertEq(closed_frozen, true);
    132 
    133 })();
    134 
    135 drainJobQueue();
    136 
    137 (async function () {
    138  var badSyncIterator = {
    139    [Symbol.iterator]() {
    140      return null;
    141    }
    142  };
    143 
    144  var badAsyncIterator = {
    145    [Symbol.asyncIterator]() {
    146      return null;
    147    }
    148  };
    149 
    150  async function errorMessage(fn) {
    151    try {
    152      await fn();
    153    } catch (e) {
    154      return e.message;
    155    }
    156    throw new Error("missing error");
    157  }
    158 
    159  // Ensure Array.from and Array.fromAsync use consistent error reporting.
    160  var expected = await errorMessage(() => Array.from(badSyncIterator));
    161  var actual = await errorMessage(() => Array.fromAsync(badSyncIterator));
    162  assertEq(actual, expected);
    163 
    164  // Ensure for-of iteration and Array.fromAsync use consistent error reporting.
    165  var expected = await errorMessage(() => { for (var _ of badSyncIterator); });
    166  var actual = await errorMessage(() => Array.fromAsync(badSyncIterator));
    167  assertEq(actual, expected);
    168 
    169  // Ensure await for-of iteration and Array.fromAsync use consistent error reporting.
    170  var expected = await errorMessage(async () => { for await (var _ of badAsyncIterator); });
    171  var actual = await errorMessage(() => Array.fromAsync(badAsyncIterator));
    172  assertEq(actual, expected);
    173 })();
    174 
    175 drainJobQueue();
    176 
    177 (async function () {
    178  function* gen() {
    179    for (let i = 0; i < 4; ++i) {
    180      yield Promise.resolve(i);
    181    }
    182  };
    183 
    184  var array = await Array.fromAsync(gen());
    185 
    186  // Promise values are unwrapped via AsyncFromSyncIterator.
    187  assertEqArray(array, [0, 1, 2, 3]);
    188 })();
    189 
    190 drainJobQueue();
    191 
    192 (async function () {
    193  var badSyncIterator = {
    194    [Symbol.iterator]: 123,
    195  };
    196 
    197  var badAsyncIterator = {
    198    [Symbol.asyncIterator]: 123,
    199  };
    200 
    201  async function errorMessage(fn) {
    202    try {
    203      await fn();
    204    } catch (e) {
    205      return e.message;
    206    }
    207    throw new Error("missing error");
    208  }
    209 
    210  // Ensure Array.from and Array.fromAsync use consistent error reporting.
    211  var expected = await errorMessage(() => Array.from(badSyncIterator));
    212  var actual = await errorMessage(() => Array.fromAsync(badSyncIterator));
    213  assertEq(actual.endsWith("is not iterable"), expected.endsWith("is not iterable"));
    214 
    215  // Ensure for-of iteration and Array.fromAsync use consistent error reporting.
    216  var expected = await errorMessage(() => { for (var _ of badSyncIterator); });
    217  var actual = await errorMessage(() => Array.fromAsync(badSyncIterator));
    218  assertEq(actual.endsWith("is not iterable"), expected.endsWith("is not iterable"));
    219 
    220  // Ensure await for-of iteration and Array.fromAsync use consistent error reporting.
    221  var expected = await errorMessage(async () => { for await (var _ of badAsyncIterator); });
    222  var actual = await errorMessage(() => Array.fromAsync(badAsyncIterator));
    223  assertEq(actual.endsWith("is not iterable"), expected.endsWith("is not iterable"));
    224 })();
    225 
    226 drainJobQueue();
    227 
    228 
    229 var g = newGlobal();
    230 g.asyncGen = asyncGen;
    231 var p = g.evaluate(`
    232 Array.fromAsync(asyncGen(4))
    233 `)
    234 
    235 p.then((x) => {
    236  assertEq(x instanceof Array, false); // Should use the other global's Array.
    237  assertEq(x instanceof g.Array, true);
    238 })
    239 
    240 drainJobQueue();
    241 
    242 
    243 var g2 = newGlobal({ newCompartment: true });
    244 g2.asyncGen = asyncGen;
    245 var p = g2.evaluate(`
    246 Array.fromAsync(asyncGen(4))
    247 `)
    248 
    249 p.then((x) => {
    250  assertEq(x instanceof Array, false); // Should use the other global's Array.
    251  assertEq(x instanceof g2.Array, true);
    252  nukeCCW(x); // this will throw if x happens to not be a CCW (it should be!)
    253 })
    254 drainJobQueue();
    255 
    256 // Test having a CCW 'this' value.
    257 g2.obj = {};
    258 var p2 = g2.evaluate(`
    259 Array.fromAsync.call(obj, asyncGen(4))
    260 `)
    261 
    262 p2.then((x) => {
    263  assertEq(x instanceof Array, false); // Should use the other global's Array.
    264  assertEq(x instanceof g2.Array, true);
    265  nukeCCW(x);
    266 })
    267 
    268 drainJobQueue();
    269 
    270 // Verify user promise resolution behaviour.
    271 var myThenCalled = false;
    272 var obj = { then: () => { myThenCalled = true; } }
    273 function* genO() {
    274  yield obj;
    275  return;
    276 }
    277 
    278 var res = Array.fromAsync(genO());
    279 res.then((x) => {
    280  assertEq(x[0], obj);
    281  assertEq(myThenCalled, true);
    282 });
    283 
    284 drainJobQueue();
    285 
    286 function* thrower() {
    287  throw new Error();
    288 }
    289 
    290 g2.thrower = thrower;
    291 var p = g2.evaluate(`Array.fromAsync(thrower())`)
    292 p.catch((e) => {
    293  assertEq(e instanceof Error, true, "Should throw an error from the current global");
    294 })
    295 drainJobQueue();
    296 
    297 p = g2.evaluate(`Array.fromAsync(thrower, 1)`);
    298 p.catch((e) => assertEq(e instanceof g2.Error, true, "Should throw error from g2"))
    299 drainJobQueue();
    300 
    301 if (typeof reportCompare === 'function')
    302  reportCompare(true, true);