11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ci// Flags: --experimental-vm-modules
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ciconst common = require('../common');
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ciconst assert = require('assert');
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ciconst { SourceTextModule, createContext, Module } = require('vm');
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_ciasync function createEmptyLinkedModule() {
121cb0ef41Sopenharmony_ci  const m = new SourceTextModule('');
131cb0ef41Sopenharmony_ci  await m.link(common.mustNotCall());
141cb0ef41Sopenharmony_ci  return m;
151cb0ef41Sopenharmony_ci}
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_ciasync function checkArgType() {
181cb0ef41Sopenharmony_ci  assert.throws(() => {
191cb0ef41Sopenharmony_ci    new SourceTextModule();
201cb0ef41Sopenharmony_ci  }, {
211cb0ef41Sopenharmony_ci    code: 'ERR_INVALID_ARG_TYPE',
221cb0ef41Sopenharmony_ci    name: 'TypeError'
231cb0ef41Sopenharmony_ci  });
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci  for (const invalidOptions of [
261cb0ef41Sopenharmony_ci    0, 1, null, true, 'str', () => {}, { identifier: 0 }, Symbol.iterator,
271cb0ef41Sopenharmony_ci    { context: null }, { context: 'hucairz' }, { context: {} },
281cb0ef41Sopenharmony_ci  ]) {
291cb0ef41Sopenharmony_ci    assert.throws(() => {
301cb0ef41Sopenharmony_ci      new SourceTextModule('', invalidOptions);
311cb0ef41Sopenharmony_ci    }, {
321cb0ef41Sopenharmony_ci      code: 'ERR_INVALID_ARG_TYPE',
331cb0ef41Sopenharmony_ci      name: 'TypeError'
341cb0ef41Sopenharmony_ci    });
351cb0ef41Sopenharmony_ci  }
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci  for (const invalidLinker of [
381cb0ef41Sopenharmony_ci    0, 1, undefined, null, true, 'str', {}, Symbol.iterator,
391cb0ef41Sopenharmony_ci  ]) {
401cb0ef41Sopenharmony_ci    await assert.rejects(async () => {
411cb0ef41Sopenharmony_ci      const m = new SourceTextModule('');
421cb0ef41Sopenharmony_ci      await m.link(invalidLinker);
431cb0ef41Sopenharmony_ci    }, {
441cb0ef41Sopenharmony_ci      code: 'ERR_INVALID_ARG_TYPE',
451cb0ef41Sopenharmony_ci      name: 'TypeError'
461cb0ef41Sopenharmony_ci    });
471cb0ef41Sopenharmony_ci  }
481cb0ef41Sopenharmony_ci}
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ci// Check methods/properties can only be used under a specific state.
511cb0ef41Sopenharmony_ciasync function checkModuleState() {
521cb0ef41Sopenharmony_ci  await assert.rejects(async () => {
531cb0ef41Sopenharmony_ci    const m = new SourceTextModule('');
541cb0ef41Sopenharmony_ci    await m.link(common.mustNotCall());
551cb0ef41Sopenharmony_ci    assert.strictEqual(m.status, 'linked');
561cb0ef41Sopenharmony_ci    await m.link(common.mustNotCall());
571cb0ef41Sopenharmony_ci  }, {
581cb0ef41Sopenharmony_ci    code: 'ERR_VM_MODULE_ALREADY_LINKED'
591cb0ef41Sopenharmony_ci  });
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci  await assert.rejects(async () => {
621cb0ef41Sopenharmony_ci    const m = new SourceTextModule('');
631cb0ef41Sopenharmony_ci    m.link(common.mustNotCall());
641cb0ef41Sopenharmony_ci    assert.strictEqual(m.status, 'linking');
651cb0ef41Sopenharmony_ci    await m.link(common.mustNotCall());
661cb0ef41Sopenharmony_ci  }, {
671cb0ef41Sopenharmony_ci    code: 'ERR_VM_MODULE_STATUS'
681cb0ef41Sopenharmony_ci  });
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ci  await assert.rejects(async () => {
711cb0ef41Sopenharmony_ci    const m = new SourceTextModule('');
721cb0ef41Sopenharmony_ci    await m.evaluate();
731cb0ef41Sopenharmony_ci  }, {
741cb0ef41Sopenharmony_ci    code: 'ERR_VM_MODULE_STATUS',
751cb0ef41Sopenharmony_ci    message: 'Module status must be one of linked, evaluated, or errored'
761cb0ef41Sopenharmony_ci  });
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_ci  await assert.rejects(async () => {
791cb0ef41Sopenharmony_ci    const m = new SourceTextModule('');
801cb0ef41Sopenharmony_ci    await m.evaluate(false);
811cb0ef41Sopenharmony_ci  }, {
821cb0ef41Sopenharmony_ci    code: 'ERR_INVALID_ARG_TYPE',
831cb0ef41Sopenharmony_ci    message: 'The "options" argument must be of type object. ' +
841cb0ef41Sopenharmony_ci             'Received type boolean (false)'
851cb0ef41Sopenharmony_ci  });
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci  assert.throws(() => {
881cb0ef41Sopenharmony_ci    const m = new SourceTextModule('');
891cb0ef41Sopenharmony_ci    m.error; // eslint-disable-line no-unused-expressions
901cb0ef41Sopenharmony_ci  }, {
911cb0ef41Sopenharmony_ci    code: 'ERR_VM_MODULE_STATUS',
921cb0ef41Sopenharmony_ci    message: 'Module status must be errored'
931cb0ef41Sopenharmony_ci  });
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_ci  await assert.rejects(async () => {
961cb0ef41Sopenharmony_ci    const m = await createEmptyLinkedModule();
971cb0ef41Sopenharmony_ci    await m.evaluate();
981cb0ef41Sopenharmony_ci    m.error; // eslint-disable-line no-unused-expressions
991cb0ef41Sopenharmony_ci  }, {
1001cb0ef41Sopenharmony_ci    code: 'ERR_VM_MODULE_STATUS',
1011cb0ef41Sopenharmony_ci    message: 'Module status must be errored'
1021cb0ef41Sopenharmony_ci  });
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci  assert.throws(() => {
1051cb0ef41Sopenharmony_ci    const m = new SourceTextModule('');
1061cb0ef41Sopenharmony_ci    m.namespace; // eslint-disable-line no-unused-expressions
1071cb0ef41Sopenharmony_ci  }, {
1081cb0ef41Sopenharmony_ci    code: 'ERR_VM_MODULE_STATUS',
1091cb0ef41Sopenharmony_ci    message: 'Module status must not be unlinked or linking'
1101cb0ef41Sopenharmony_ci  });
1111cb0ef41Sopenharmony_ci}
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_ci// Check link() fails when the returned module is not valid.
1141cb0ef41Sopenharmony_ciasync function checkLinking() {
1151cb0ef41Sopenharmony_ci  await assert.rejects(async () => {
1161cb0ef41Sopenharmony_ci    const m = new SourceTextModule('import "foo";');
1171cb0ef41Sopenharmony_ci    try {
1181cb0ef41Sopenharmony_ci      await m.link(common.mustCall(() => ({})));
1191cb0ef41Sopenharmony_ci    } catch (err) {
1201cb0ef41Sopenharmony_ci      assert.strictEqual(m.status, 'errored');
1211cb0ef41Sopenharmony_ci      throw err;
1221cb0ef41Sopenharmony_ci    }
1231cb0ef41Sopenharmony_ci  }, {
1241cb0ef41Sopenharmony_ci    code: 'ERR_VM_MODULE_NOT_MODULE'
1251cb0ef41Sopenharmony_ci  });
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_ci  await assert.rejects(async () => {
1281cb0ef41Sopenharmony_ci    const c = createContext({ a: 1 });
1291cb0ef41Sopenharmony_ci    const foo = new SourceTextModule('', { context: c });
1301cb0ef41Sopenharmony_ci    await foo.link(common.mustNotCall());
1311cb0ef41Sopenharmony_ci    const bar = new SourceTextModule('import "foo";');
1321cb0ef41Sopenharmony_ci    try {
1331cb0ef41Sopenharmony_ci      await bar.link(common.mustCall(() => foo));
1341cb0ef41Sopenharmony_ci    } catch (err) {
1351cb0ef41Sopenharmony_ci      assert.strictEqual(bar.status, 'errored');
1361cb0ef41Sopenharmony_ci      throw err;
1371cb0ef41Sopenharmony_ci    }
1381cb0ef41Sopenharmony_ci  }, {
1391cb0ef41Sopenharmony_ci    code: 'ERR_VM_MODULE_DIFFERENT_CONTEXT'
1401cb0ef41Sopenharmony_ci  });
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_ci  const error = new Error();
1431cb0ef41Sopenharmony_ci  await assert.rejects(async () => {
1441cb0ef41Sopenharmony_ci    globalThis.error = error;
1451cb0ef41Sopenharmony_ci    const erroredModule = new SourceTextModule('throw error;');
1461cb0ef41Sopenharmony_ci    await erroredModule.link(common.mustNotCall());
1471cb0ef41Sopenharmony_ci    try {
1481cb0ef41Sopenharmony_ci      await erroredModule.evaluate();
1491cb0ef41Sopenharmony_ci    } catch {
1501cb0ef41Sopenharmony_ci      // ignored
1511cb0ef41Sopenharmony_ci    }
1521cb0ef41Sopenharmony_ci    delete globalThis.error;
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ci    assert.strictEqual(erroredModule.status, 'errored');
1551cb0ef41Sopenharmony_ci
1561cb0ef41Sopenharmony_ci    const rootModule = new SourceTextModule('import "errored";');
1571cb0ef41Sopenharmony_ci    await rootModule.link(common.mustCall(() => erroredModule));
1581cb0ef41Sopenharmony_ci  }, {
1591cb0ef41Sopenharmony_ci    code: 'ERR_VM_MODULE_LINK_FAILURE',
1601cb0ef41Sopenharmony_ci    cause: error,
1611cb0ef41Sopenharmony_ci  });
1621cb0ef41Sopenharmony_ci}
1631cb0ef41Sopenharmony_ci
1641cb0ef41Sopenharmony_ciassert.throws(() => {
1651cb0ef41Sopenharmony_ci  new SourceTextModule('', {
1661cb0ef41Sopenharmony_ci    importModuleDynamically: 'hucairz'
1671cb0ef41Sopenharmony_ci  });
1681cb0ef41Sopenharmony_ci}, {
1691cb0ef41Sopenharmony_ci  code: 'ERR_INVALID_ARG_TYPE',
1701cb0ef41Sopenharmony_ci  name: 'TypeError',
1711cb0ef41Sopenharmony_ci  message: 'The "options.importModuleDynamically" property must be of type ' +
1721cb0ef41Sopenharmony_ci    "function. Received type string ('hucairz')"
1731cb0ef41Sopenharmony_ci});
1741cb0ef41Sopenharmony_ci
1751cb0ef41Sopenharmony_ci// Check the JavaScript engine deals with exceptions correctly
1761cb0ef41Sopenharmony_ciasync function checkExecution() {
1771cb0ef41Sopenharmony_ci  await (async () => {
1781cb0ef41Sopenharmony_ci    const m = new SourceTextModule('import { nonexistent } from "module";');
1791cb0ef41Sopenharmony_ci
1801cb0ef41Sopenharmony_ci    // There is no code for this exception since it is thrown by the JavaScript
1811cb0ef41Sopenharmony_ci    // engine.
1821cb0ef41Sopenharmony_ci    await assert.rejects(() => {
1831cb0ef41Sopenharmony_ci      return m.link(common.mustCall(() => new SourceTextModule('')));
1841cb0ef41Sopenharmony_ci    }, SyntaxError);
1851cb0ef41Sopenharmony_ci  })();
1861cb0ef41Sopenharmony_ci
1871cb0ef41Sopenharmony_ci  await (async () => {
1881cb0ef41Sopenharmony_ci    const m = new SourceTextModule('throw new Error();');
1891cb0ef41Sopenharmony_ci    await m.link(common.mustNotCall());
1901cb0ef41Sopenharmony_ci    try {
1911cb0ef41Sopenharmony_ci      await m.evaluate();
1921cb0ef41Sopenharmony_ci    } catch (err) {
1931cb0ef41Sopenharmony_ci      assert.strictEqual(m.error, err);
1941cb0ef41Sopenharmony_ci      assert.strictEqual(m.status, 'errored');
1951cb0ef41Sopenharmony_ci      return;
1961cb0ef41Sopenharmony_ci    }
1971cb0ef41Sopenharmony_ci    assert.fail('Missing expected exception');
1981cb0ef41Sopenharmony_ci  })();
1991cb0ef41Sopenharmony_ci}
2001cb0ef41Sopenharmony_ci
2011cb0ef41Sopenharmony_ci// Check for error thrown when breakOnSigint is not a boolean for evaluate()
2021cb0ef41Sopenharmony_ciasync function checkInvalidOptionForEvaluate() {
2031cb0ef41Sopenharmony_ci  await assert.rejects(async () => {
2041cb0ef41Sopenharmony_ci    const m = new SourceTextModule('export const a = 1; export let b = 2');
2051cb0ef41Sopenharmony_ci    await m.evaluate({ breakOnSigint: 'a-string' });
2061cb0ef41Sopenharmony_ci  }, {
2071cb0ef41Sopenharmony_ci    name: 'TypeError',
2081cb0ef41Sopenharmony_ci    message:
2091cb0ef41Sopenharmony_ci      'The "options.breakOnSigint" property must be of type boolean. ' +
2101cb0ef41Sopenharmony_ci      "Received type string ('a-string')",
2111cb0ef41Sopenharmony_ci    code: 'ERR_INVALID_ARG_TYPE'
2121cb0ef41Sopenharmony_ci  });
2131cb0ef41Sopenharmony_ci
2141cb0ef41Sopenharmony_ci  {
2151cb0ef41Sopenharmony_ci    ['link', 'evaluate'].forEach(async (method) => {
2161cb0ef41Sopenharmony_ci      await assert.rejects(async () => {
2171cb0ef41Sopenharmony_ci        await Module.prototype[method]();
2181cb0ef41Sopenharmony_ci      }, {
2191cb0ef41Sopenharmony_ci        code: 'ERR_VM_MODULE_NOT_MODULE',
2201cb0ef41Sopenharmony_ci        message: /Provided module is not an instance of Module/
2211cb0ef41Sopenharmony_ci      });
2221cb0ef41Sopenharmony_ci    });
2231cb0ef41Sopenharmony_ci  }
2241cb0ef41Sopenharmony_ci}
2251cb0ef41Sopenharmony_ci
2261cb0ef41Sopenharmony_cifunction checkInvalidCachedData() {
2271cb0ef41Sopenharmony_ci  [true, false, 'foo', {}, Array, function() {}].forEach((invalidArg) => {
2281cb0ef41Sopenharmony_ci    const message = 'The "options.cachedData" property must be an ' +
2291cb0ef41Sopenharmony_ci                    'instance of Buffer, TypedArray, or DataView.' +
2301cb0ef41Sopenharmony_ci                    common.invalidArgTypeHelper(invalidArg);
2311cb0ef41Sopenharmony_ci    assert.throws(
2321cb0ef41Sopenharmony_ci      () => new SourceTextModule('import "foo";', { cachedData: invalidArg }),
2331cb0ef41Sopenharmony_ci      {
2341cb0ef41Sopenharmony_ci        code: 'ERR_INVALID_ARG_TYPE',
2351cb0ef41Sopenharmony_ci        name: 'TypeError',
2361cb0ef41Sopenharmony_ci        message,
2371cb0ef41Sopenharmony_ci      }
2381cb0ef41Sopenharmony_ci    );
2391cb0ef41Sopenharmony_ci  });
2401cb0ef41Sopenharmony_ci}
2411cb0ef41Sopenharmony_ci
2421cb0ef41Sopenharmony_cifunction checkGettersErrors() {
2431cb0ef41Sopenharmony_ci  const expectedError = {
2441cb0ef41Sopenharmony_ci    code: 'ERR_VM_MODULE_NOT_MODULE',
2451cb0ef41Sopenharmony_ci    message: /Provided module is not an instance of Module/
2461cb0ef41Sopenharmony_ci  };
2471cb0ef41Sopenharmony_ci  const getters = ['identifier', 'context', 'namespace', 'status', 'error'];
2481cb0ef41Sopenharmony_ci  getters.forEach((getter) => {
2491cb0ef41Sopenharmony_ci    assert.throws(() => {
2501cb0ef41Sopenharmony_ci      // eslint-disable-next-line no-unused-expressions
2511cb0ef41Sopenharmony_ci      Module.prototype[getter];
2521cb0ef41Sopenharmony_ci    }, expectedError);
2531cb0ef41Sopenharmony_ci    assert.throws(() => {
2541cb0ef41Sopenharmony_ci      // eslint-disable-next-line no-unused-expressions
2551cb0ef41Sopenharmony_ci      SourceTextModule.prototype[getter];
2561cb0ef41Sopenharmony_ci    }, expectedError);
2571cb0ef41Sopenharmony_ci  });
2581cb0ef41Sopenharmony_ci  // `dependencySpecifiers` getter is just part of SourceTextModule
2591cb0ef41Sopenharmony_ci  assert.throws(() => {
2601cb0ef41Sopenharmony_ci    // eslint-disable-next-line no-unused-expressions
2611cb0ef41Sopenharmony_ci    SourceTextModule.prototype.dependencySpecifiers;
2621cb0ef41Sopenharmony_ci  }, expectedError);
2631cb0ef41Sopenharmony_ci}
2641cb0ef41Sopenharmony_ci
2651cb0ef41Sopenharmony_ciconst finished = common.mustCall();
2661cb0ef41Sopenharmony_ci
2671cb0ef41Sopenharmony_ci(async function main() {
2681cb0ef41Sopenharmony_ci  await checkArgType();
2691cb0ef41Sopenharmony_ci  await checkModuleState();
2701cb0ef41Sopenharmony_ci  await checkLinking();
2711cb0ef41Sopenharmony_ci  await checkExecution();
2721cb0ef41Sopenharmony_ci  await checkInvalidOptionForEvaluate();
2731cb0ef41Sopenharmony_ci  checkInvalidCachedData();
2741cb0ef41Sopenharmony_ci  checkGettersErrors();
2751cb0ef41Sopenharmony_ci  finished();
2761cb0ef41Sopenharmony_ci})().then(common.mustCall());
277