// Dynamically generated sources should have their introduction script and
// offset set correctly.

var g = newGlobal();
var dbg = new Debugger;
var gDO = dbg.addDebuggee(g);
var log;

// Direct eval, while the frame is live.
dbg.onDebuggerStatement = function (frame) {
  log += 'd';
  var source = frame.script.source;
  var introducer = frame.older;
  assertEq(source.introductionScript, introducer.script);
  assertEq(source.introductionOffset, introducer.offset);
};
log = '';
g.eval('\n\neval("\\n\\ndebugger;");');
assertEq(log, 'd');

// Direct eval, after the frame has been popped.
var introducer, introduced;
dbg.onDebuggerStatement = function (frame) {
  log += 'de1';
  introducer = frame.script;
  dbg.onDebuggerStatement = function (frame) {
    log += 'de2';
    introduced = frame.script.source;
  };
};
log = '';
g.evaluate('debugger; eval("\\n\\ndebugger;");', { lineNumber: 1812 });
assertEq(log, 'de1de2');
assertEq(introduced.introductionScript, introducer);
assertEq(introducer.getOffsetLine(introduced.introductionOffset), 1812);

// Indirect eval, while the frame is live.
dbg.onDebuggerStatement = function (frame) {
  log += 'd';
  var source = frame.script.source;
  var introducer = frame.older;
  assertEq(source.introductionScript, introducer.script);
  assertEq(source.introductionOffset, introducer.offset);
};
log = '';
g.eval('\n\n(0,eval)("\\n\\ndebugger;");');
assertEq(log, 'd');

// Indirect eval, after the frame has been popped.
var introducer, introduced;
dbg.onDebuggerStatement = function (frame) {
  log += 'de1';
  introducer = frame.script;
  dbg.onDebuggerStatement = function (frame) {
    log += 'de2';
    introduced = frame.script.source;
  };
};
log = '';
g.evaluate('debugger; (0,eval)("\\n\\ndebugger;");', { lineNumber: 1066 });
assertEq(log, 'de1de2');
assertEq(introduced.introductionScript, introducer);
assertEq(introducer.getOffsetLine(introduced.introductionOffset), 1066);

// Function constructor.
dbg.onDebuggerStatement = function (frame) {
  log += 'o';
  var outerScript = frame.script;
  var outerOffset = frame.offset;
  dbg.onDebuggerStatement = function (frame) {
    log += 'i';
    var source = frame.script.source;
    assertEq(source.introductionScript, outerScript);
    assertEq(outerScript.getOffsetLine(source.introductionOffset),
             outerScript.getOffsetLine(outerOffset));
  };
};
log = '';
g.eval('\n\n\ndebugger; Function("debugger;")()');
assertEq(log, 'oi');

// Function constructor, after the the introduction call's frame has been
// popped.
var introducer;
dbg.onDebuggerStatement = function (frame) {
  log += 'F2';
  introducer = frame.script;
};
log = '';
var fDO = gDO.executeInGlobal('debugger; Function("origami;")', { lineNumber: 1685 }).return;
var source = fDO.script.source;
assertEq(log, 'F2');
assertEq(source.introductionScript, introducer);
assertEq(introducer.getOffsetLine(source.introductionOffset), 1685);

// If the introduction script is in a different global from the script it
// introduced, we don't record it.
dbg.onDebuggerStatement = function (frame) {
  log += 'x';
  var source = frame.script.source;
  assertEq(source.introductionScript, undefined);
  assertEq(source.introductionOffset, undefined);
};
log = '';
g.eval('debugger;'); // introduction script is this top-level script
assertEq(log, 'x');

// If the code is introduced by a function that doesn't provide
// introduction information, that shouldn't be a problem.
dbg.onDebuggerStatement = function (frame) {
  log += 'x';
  var source = frame.script.source;
  assertEq(source.introductionScript, undefined);
  assertEq(source.introductionOffset, undefined);
};
log = '';
g.eval('evaluate("debugger;", { lineNumber: 1729 });');
assertEq(log, 'x');
