// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

let {session, contextGroup, Protocol} = InspectorTest.start(
  'Tests for break on exception.');

Protocol.Debugger.enable();
Protocol.Debugger.onPaused(({params:{data}}) => {
  InspectorTest.log('paused on exception:');
  InspectorTest.logMessage(data);
  Protocol.Debugger.resume();
});

contextGroup.addInlineScript(`
function throws() {
  throw 1;
}
function caught() {
  try {
    throws();
  } catch (e) {
  }
}
function uncaught() {
  throws();
}
function uncaughtFinally() {
  try {
    throws();
  } finally {
  }
}
function caughtFinally() {
  L: try {
    throws();
  } finally {
    break L;
  }
}
`, 'test.js');

InspectorTest.runAsyncTestSuite([
  async function testPauseOnInitialState() {
    await evaluate('caught()');
    await evaluate('uncaught()');
    await evaluate('uncaughtFinally()');
    await evaluate('caughtFinally()');
  },

  async function testPauseOnExceptionOff() {
    await Protocol.Debugger.setPauseOnExceptions({state: 'none'});
    await evaluate('caught()');
    await evaluate('uncaught()');
    await evaluate('uncaughtFinally()');
    await evaluate('caughtFinally()');
    await Protocol.Debugger.setPauseOnExceptions({state: 'none'});
  },

  async function testBreakOnUncaughtException() {
    await Protocol.Debugger.setPauseOnExceptions({state: 'uncaught'});
    await evaluate('caught()');
    await evaluate('uncaught()');
    await evaluate('uncaughtFinally()');
    await evaluate('caughtFinally()');
    await Protocol.Debugger.setPauseOnExceptions({state: 'none'});
  },

  async function testBreakOnAll() {
    await Protocol.Debugger.setPauseOnExceptions({state: 'all'});
    await evaluate('caught()');
    await evaluate('uncaught()');
    await evaluate('uncaughtFinally()');
    await evaluate('caughtFinally()');
    await Protocol.Debugger.setPauseOnExceptions({state: 'none'});
  },

  async function testTryFinallyOriginalMessage() {
    await Protocol.Debugger.setPauseOnExceptions({state: 'all'});
    await evaluate(`
      try {
        throw 1;
      } finally {
      }
    `);
    await Protocol.Debugger.setPauseOnExceptions({state: 'none'});
  },

  async function testPromiseRejectedByCallback() {
    await Protocol.Debugger.setPauseOnExceptions({state: 'uncaught'});
    await evaluate(`
      function fun() { eval("throw 'rejection';") }
      var p = new Promise(function(res, rej) { fun(); res(); });
      var r;
      p.then(() => { r = 'resolved'; }, (e) => { r = 'rejected' + e; });
    `);
    InspectorTest.log('r = ');
    InspectorTest.logMessage((await Protocol.Runtime.evaluate({
      expression: 'r'
    })).result.result);
    await Protocol.Debugger.setPauseOnExceptions({state: 'none'});
  },

  async function testBreakOnExceptionAfterReconnect() {
    contextGroup.addInlineScript('function f() { throw new Error(); }');
    await Protocol.Debugger.setPauseOnExceptions({state: 'uncaught'});
    await evaluate('f()');
    InspectorTest.log('\nreconnect..');
    session.reconnect();
    await evaluate('f()');
    await Protocol.Debugger.setPauseOnExceptions({state: 'none'});
  },

  async function testBreakOnExceptionInSilentMode(next) {
    await Protocol.Debugger.setPauseOnExceptions({ state: "all" });
    InspectorTest.log(`evaluate 'caught()'`);
    await Protocol.Runtime.evaluate({expression: 'caught()', silent: true});
    InspectorTest.log(`evaluate 'uncaught()'`);
    await Protocol.Runtime.evaluate({expression: 'uncaught()', silent: true});
    InspectorTest.log(`evaluate 'uncaughtFinally()'`);
    await Protocol.Runtime.evaluate({
      expression: 'uncaughtFinally()',
      silent: true
    });
    InspectorTest.log(`evaluate 'caughtFinally()'`);
    await Protocol.Runtime.evaluate({
      xpression: 'caughtFinally()',
      silent: true
    });
    await Protocol.Debugger.setPauseOnExceptions({state: 'none'});
  }
]);

async function evaluate(expression) {
  InspectorTest.log(`\nevaluate '${expression}'..`);
  contextGroup.addInlineScript(expression);
  await InspectorTest.waitForPendingTasks();
}