Skip to content

Commit 76d145a

Browse files
committed
Merging changes to functional tests and getFunctionNameFromLines from Victor
2 parents ef4770f + 41e5786 commit 76d145a

File tree

4 files changed

+756
-546
lines changed

4 files changed

+756
-546
lines changed

stacktrace.js

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ function printStackTrace(options) {
5555
options = options || {guess: true};
5656
var ex = options.e || null, guess = !!options.guess;
5757
var p = new printStackTrace.implementation(), result = p.run(ex);
58-
return (guess) ? p.guessFunctions(result) : result;
58+
return (guess) ? p.guessAnonymousFunctions(result) : result;
5959
}
6060

6161
printStackTrace.implementation = function() {
@@ -91,7 +91,7 @@ printStackTrace.implementation.prototype = {
9191
mode: function(e) {
9292
if (e['arguments'] && e.stack) {
9393
return (this._mode = 'chrome');
94-
} else if (typeof window !== 'undefined' && window.opera) {
94+
} else if (e.message && typeof window !== 'undefined' && window.opera) {
9595
return (this._mode = e.stacktrace ? 'opera10' : 'opera');
9696
} else if (e.stack) {
9797
return (this._mode = 'firefox');
@@ -213,6 +213,7 @@ printStackTrace.implementation.prototype = {
213213
* @return {Array} of Strings with stringified arguments
214214
*/
215215
stringifyArguments: function(args) {
216+
var slice = Array.prototype.slice;
216217
for (var i = 0; i < args.length; ++i) {
217218
var arg = args[i];
218219
if (arg === undefined) {
@@ -224,7 +225,7 @@ printStackTrace.implementation.prototype = {
224225
if (arg.length < 3) {
225226
args[i] = '[' + this.stringifyArguments(arg) + ']';
226227
} else {
227-
args[i] = '[' + this.stringifyArguments(Array.prototype.slice.call(arg, 0, 1)) + '...' + this.stringifyArguments(Array.prototype.slice.call(arg, -1)) + ']';
228+
args[i] = '[' + this.stringifyArguments(slice.call(arg, 0, 1)) + '...' + this.stringifyArguments(slice.call(arg, -1)) + ']';
228229
}
229230
} else if (arg.constructor === Object) {
230231
args[i] = '#object';
@@ -306,48 +307,58 @@ printStackTrace.implementation.prototype = {
306307
return this.sourceCache[url];
307308
},
308309

309-
guessFunctions: function(stack) {
310+
guessAnonymousFunctions: function(stack) {
310311
for (var i = 0; i < stack.length; ++i) {
311312
var reStack = /\{anonymous\}\(.*\)@(\w+:\/\/([\-\w\.]+)+(:\d+)?[^:]+):(\d+):?(\d+)?/;
312313
var frame = stack[i], m = reStack.exec(frame);
313314
if (m) {
314-
var file = m[1], lineno = m[4]; //m[7] is character position in Chrome
315+
var file = m[1], lineno = m[4], charno = m[7] || 0; //m[7] is character position in Chrome
315316
if (file && this.isSameDomain(file) && lineno) {
316-
var functionName = this.guessFunctionName(file, lineno);
317+
var functionName = this.guessAnonymousFunction(file, lineno, charno);
317318
stack[i] = frame.replace('{anonymous}', functionName);
318319
}
319320
}
320321
}
321322
return stack;
322323
},
323324

324-
guessFunctionName: function(url, lineNo) {
325+
guessAnonymousFunction: function(url, lineNo, charNo) {
325326
var ret;
326327
try {
327-
ret = this.guessFunctionNameFromLines(lineNo, this.getSource(url));
328+
ret = this.findFunctionName(this.getSource(url), lineNo);
328329
} catch (e) {
329330
ret = 'getSource failed with url: ' + url + ', exception: ' + e.toString();
330331
}
331332
return ret;
332333
},
333334

334-
guessFunctionNameFromLines: function(lineNo, source) {
335-
var reFunctionArgNames = /function ([^(]*)\(([^)]*)\)/;
336-
var reGuessFunction = /['"]?([0-9A-Za-z_]+)['"]?\s*[:=]\s*(function|eval|new Function)/;
337-
// Walk backwards from the first line in the function until we find the line which
338-
// matches the pattern above, which is the function definition
339-
var line = "", maxLines = 10;
335+
findFunctionName: function(source, lineNo) {
336+
// TODO use captured args
337+
// function {name}({args}) m[1]=name m[2]=args
338+
var reFunctionDeclaration = /function\s+([^(]*?)\s*\(([^)]*)\)/;
339+
// {name} = function ({args}) TODO args capture
340+
var reFunctionExpression = /['"]?([0-9A-Za-z_]+)['"]?\s*[:=]\s*function(?:[^(]*)/;
341+
// {name} = eval()
342+
var reFunctionEvaluation = /['"]?([0-9A-Za-z_]+)['"]?\s*[:=]\s*(?:eval|new Function)/;
343+
// Walk backwards in the source lines until we find
344+
// the line which matches one of the patterns above
345+
var code = "", line, maxLines = 10, m;
340346
for (var i = 0; i < maxLines; ++i) {
341-
line = source[lineNo - i] + line;
342-
if (line !== undefined) {
343-
var m = reGuessFunction.exec(line);
347+
line = source[lineNo - i];
348+
if (line) {
349+
code = line + code;
350+
m = reFunctionExpression.exec(code);
351+
if (m && m[1]) {
352+
return m[1];
353+
}
354+
m = reFunctionDeclaration.exec(code);
355+
if (m && m[1]) {
356+
//return m[1] + "(" + (m[2] || "") + ")";
357+
return m[1];
358+
}
359+
m = reFunctionEvaluation.exec(code);
344360
if (m && m[1]) {
345361
return m[1];
346-
} else {
347-
m = reFunctionArgNames.exec(line);
348-
if (m && m[1]) {
349-
return m[1];
350-
}
351362
}
352363
}
353364
}

test/functional/testcase3.html

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,49 @@
11
<html>
2-
<head><title>window.onerror test</title></head>
3-
<body>
4-
<div id="output"></div>
5-
</body>
6-
<script type="text/javascript" src="../../stacktrace.js"></script>
7-
<script type="text/javascript">function printTrace(trace){var output=document.getElementById("output");if(!output){output=document.createElement("div");output.id="output";document.body.appendChild(output);}
8-
if(!expected){expected="";}
9-
trace.push("--------------Expected:-------------------")
10-
trace.push(expected);output.innerHTML=(trace.join('<br/>'));}
11-
function foo(){bar(2);}
12-
function bar(n){if(n<2){abc();}
13-
bar(n-1);}
14-
window.onerror=function(msg,file,line){printTrace(printStackTrace());return true;}
15-
var expected=["bar(1)","bar(2)","foo()"].join("<br/>");foo();</script>
2+
<head>
3+
<title>window.onerror test</title>
4+
<script type="text/javascript" src="../../stacktrace.js"></script>
5+
</head>
6+
<body>
7+
<div id="output"></div>
8+
<script type="text/javascript">
9+
function toList(array) {
10+
return "<ol><li>" + (array.join("</li><li>")) + "</li></ol>";
11+
}
12+
13+
var expected = [];
14+
15+
function printTrace(trace) {
16+
var output = document.getElementById("output");
17+
if (!output) {
18+
output = document.createElement("div");
19+
output.id = "output";
20+
document.body.appendChild(output);
21+
}
22+
23+
var content = [];
24+
content.push(toList(trace));
25+
content.push("--------------Expected:-------------------");
26+
content.push(toList(expected || []));
27+
output.innerHTML = (content.join("<br/>"));
28+
}
29+
30+
function bar(n) {
31+
if (n < 2) {
32+
window.abc();
33+
}
34+
bar(n - 1);
35+
}
36+
37+
function foo() {
38+
bar(2);
39+
}
40+
41+
window.onerror = function(msg, file, line) {
42+
printTrace(window.printStackTrace());
43+
return true;
44+
};
45+
expected = ["bar(1)", "bar(2)", "foo()"];
46+
foo();
47+
</script>
48+
</body>
1649
</html>

test/functional/testcase4.html

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,53 @@
11
<html>
2-
<head><title>function instrumentation test</title></head>
3-
<body>
4-
<div id="output"></div>
5-
</body>
6-
<script type="text/javascript" src="../../stacktrace.js"></script>
7-
<script type="text/javascript">function printTrace(trace){var output=document.getElementById("output");if(!output){output=document.createElement("div");output.id="output";document.body.appendChild(output);}
8-
if(!expected){expected="";}
9-
trace.push("--------------Expected:-------------------")
10-
trace.push(expected);output.innerHTML=(trace.join('<br/>'));}
11-
var p=new printStackTrace.implementation();p.instrumentFunction(this,'bar',logStackTrace);function logStackTrace(stack){printTrace(stack);}
12-
var foo=function(){var a=1;bar();}
13-
function bar(){var baz=2;}
14-
var expected=["baz()","bar()","foo()"].join("<br/>");foo();p.deinstrumentFunction(this,'bar');</script>
2+
<head>
3+
<title>function instrumentation test</title>
4+
<script type="text/javascript" src="../../stacktrace.js"></script>
5+
</head>
6+
<body>
7+
<div id="output"></div>
8+
<script type="text/javascript">
9+
function toList(array) {
10+
return "<ol><li>" + (array.join("</li><li>")) + "</li></ol>";
11+
}
12+
13+
var expected = [];
14+
15+
function printTrace(trace) {
16+
var output = document.getElementById("output");
17+
if (!output) {
18+
output = document.createElement("div");
19+
output.id = "output";
20+
document.body.appendChild(output);
21+
}
22+
23+
var content = [];
24+
content.push(toList(trace));
25+
content.push("--------------Expected:-------------------");
26+
content.push(toList(expected || []));
27+
output.innerHTML = (content.join("<br/>"));
28+
}
29+
30+
function baz() {
31+
var c = 3;
32+
}
33+
34+
function bar() {
35+
var b = 2;
36+
baz();
37+
}
38+
39+
var foo = function() {
40+
var a = 1;
41+
bar();
42+
};
43+
44+
var p = new window.printStackTrace.implementation();
45+
p.instrumentFunction(this, 'baz', printTrace);
46+
47+
expected = ["bar()", "foo()"];
48+
foo();
49+
50+
p.deinstrumentFunction(this, 'bar');
51+
</script>
52+
</body>
1553
</html>

0 commit comments

Comments
 (0)