<!--
  Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
  <title>WebAssembly.compile Test</title>
  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script>
const wasmTextToBinary = SpecialPowers.unwrap(SpecialPowers.Cu.getJSTestingFunctions().wasmTextToBinary);
const wasmIsSupported = SpecialPowers.Cu.getJSTestingFunctions().wasmIsSupported
const fooModuleCode = wasmTextToBinary(`(module
  (func $foo (result i32) (i32.const 42))
  (export "foo" $foo)
)`, 'new-format');

function checkFooModule(m) {
  ok(m instanceof WebAssembly.Module, "got a module");
  var i = new WebAssembly.Instance(m);
  ok(i instanceof WebAssembly.Instance, "got an instance");
  ok(i.exports.foo() === 42, "got 42");
}

function checkFooInstance(i) {
  ok(i instanceof WebAssembly.Instance, "got a module");
  ok(i.exports.foo() === 42, "got 42");
}

function propertiesExist() {
  if (!wasmIsSupported()) {
    ok(!this["WebAssembly"], "If the device doesn't support, there will be no WebAssembly object");
    SimpleTest.finish();
    return;
  }

  ok(WebAssembly, "WebAssembly object should exist");
  ok(WebAssembly.compile, "WebAssembly.compile function should exist");
  runTest();
}

function compileFail() {
  WebAssembly.compile().then(
    () => { ok(false, "should have failed"); runTest() }
  ).catch(
    err => { ok(err instanceof TypeError, "empty compile failed"); runTest() }
  );
}

function compileSuccess() {
  WebAssembly.compile(fooModuleCode).then(
    m => { checkFooModule(m); runTest() }
  ).catch(
    err => { ok(false, String(err)); runTest() }
  );
}

function compileManySuccess() {
  const N = 100;

  var arr = [];
  for (var i = 0; i < N; i++)
    arr.push(WebAssembly.compile(fooModuleCode));

  SpecialPowers.gc();

  Promise.all(arr).then (ms => {
    ok(ms.length === N, "got the right number");
    for (var i = 0; i < N; i++)
      checkFooModule(ms[i]);
    runTest();
  }).catch(
    err => { ok(false, String(err)); runTest() }
  );
}

function compileInWorker() {
  var w = new Worker(`data:text/plain,
    onmessage = e => {
      WebAssembly.compile(e.data).then(m => {
          var i = new WebAssembly.Instance(m);
          if (i.exports.foo() !== 42)
            throw "bad i.exports.foo() result";
          postMessage("ok");
          close();
      }).catch(err => { throw err });
    }
  `);
  w.postMessage(fooModuleCode);
  w.onmessage = e => {
    ok(e.data === "ok", "worker test");
    runTest();
  }
}

function terminateCompileInWorker() {
    var w = new Worker(`data:text/plain,
      var fooModuleCode;
      function spawnWork() {
        const N = 100;
        var arr = [];
        for (var i = 0; i < N; i++)
          arr.push(WebAssembly.compile(fooModuleCode));
        Promise.all(arr).then(spawnWork);
      }
      onmessage = e => {
        fooModuleCode = e.data;
        spawnWork();
        postMessage("ok");
      }
    `);
    w.postMessage(fooModuleCode);
    w.onmessage = e => {
      ok(e.data === "ok", "worker finished first step");
      w.terminate();
      runTest();
    }
}

function instantiateFail() {
  WebAssembly.instantiate().then(
    () => { ok(false, "should have failed"); runTest() }
  ).catch(
    err => { ok(err instanceof TypeError, "empty compile failed"); runTest() }
  );
}

function instantiateSuccess() {
  WebAssembly.instantiate(fooModuleCode).then(
    r => { checkFooModule(r.module); checkFooInstance(r.instance); runTest() }
  ).catch(
    err => { ok(false, String(err)); runTest() }
  );
}

function chainSuccess() {
  WebAssembly.compile(fooModuleCode).then(
    m => WebAssembly.instantiate(m)
  ).then(
    i => { checkFooInstance(i); runTest() }
  ).catch(
    err => { ok(false, String(err)); runTest() }
  );
}

var tests = [ propertiesExist,
              compileFail,
              compileSuccess,
              compileManySuccess,
              compileInWorker,
              terminateCompileInWorker,
              instantiateFail,
              instantiateSuccess,
              chainSuccess
            ];

function runTest() {
  if (!tests.length) {
    SimpleTest.finish();
    return;
  }

  var test = tests.shift();
  test();
}

SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["javascript.options.wasm", true]]}, runTest);
</script>
</body>
</html>