diff options
-rw-r--r-- | jim-package.c | 3 | ||||
-rw-r--r-- | jim.c | 283 | ||||
-rw-r--r-- | jim.h | 6 | ||||
-rw-r--r-- | stdlib.tcl | 39 | ||||
-rw-r--r-- | tcltest.tcl | 46 | ||||
-rw-r--r-- | tests/error.test | 12 | ||||
-rw-r--r-- | tests/event.test | 6 | ||||
-rw-r--r-- | tests/infoframe.test | 30 | ||||
-rw-r--r-- | tests/misc.test | 13 | ||||
-rw-r--r-- | tests/stacktrace.test | 84 |
10 files changed, 234 insertions, 288 deletions
diff --git a/jim-package.c b/jim-package.c index 1d42197..be53688 100644 --- a/jim-package.c +++ b/jim-package.c @@ -181,9 +181,6 @@ static int package_cmd_provide(Jim_Interp *interp, int argc, Jim_Obj *const *arg */ static int package_cmd_require(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - /* package require failing is important enough to add to the stack */ - interp->addStackTrace++; - return Jim_PackageRequire(interp, Jim_String(argv[0]), JIM_ERRMSG); } @@ -150,6 +150,7 @@ static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen); static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len); static int JimSetNewVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr, Jim_Var *var); static Jim_Var *JimFindVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr); +static void JimSetErrorStack(Jim_Interp *interp); /* Fast access to the int (wide) value of an object which is known to be of int type */ #define JimWideValue(objPtr) (objPtr)->internalRep.wideValue @@ -3748,12 +3749,10 @@ static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) objPtr->typePtr = &scriptObjType; } -static void JimAddErrorToStack(Jim_Interp *interp, ScriptObj *script); - /** * Returns the parsed script. * Note that if there is any possibility that the script is not valid, - * call JimScriptValid() to check + * call JimParseCheckMissing() to check */ static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr) { @@ -3769,21 +3768,6 @@ static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr) return (ScriptObj *)Jim_GetIntRepPtr(objPtr); } -/** - * Returns 1 if the script is valid (parsed ok), otherwise returns 0 - * and leaves an error message in the interp result. - * - */ -static int JimScriptValid(Jim_Interp *interp, ScriptObj *script) -{ - if (JimParseCheckMissing(interp, script->missing) == JIM_ERR) { - JimAddErrorToStack(interp, script); - return 0; - } - return 1; -} - - /* ----------------------------------------------------------------------------- * Commands * ---------------------------------------------------------------------------*/ @@ -5686,7 +5670,6 @@ Jim_Interp *Jim_CreateInterp(void) i->trueObj = Jim_NewIntObj(i, 1); i->falseObj = Jim_NewIntObj(i, 0); i->framePtr = i->topFramePtr = JimCreateCallFrame(i, NULL, i->emptyObj); - i->errorFileNameObj = i->emptyObj; i->result = i->emptyObj; i->stackTrace = Jim_NewListObj(i, NULL, 0); i->unknown = Jim_NewStringObj(i, "unknown", -1); @@ -5695,7 +5678,6 @@ Jim_Interp *Jim_CreateInterp(void) i->nullScriptObj = Jim_NewEmptyStringObj(i); i->evalFrame = &i->topEvalFrame; Jim_IncrRefCount(i->emptyObj); - Jim_IncrRefCount(i->errorFileNameObj); Jim_IncrRefCount(i->result); Jim_IncrRefCount(i->stackTrace); Jim_IncrRefCount(i->unknown); @@ -5718,6 +5700,7 @@ Jim_Interp *Jim_CreateInterp(void) Jim_SetVariableStrWithStr(i, "tcl_platform(bootstrap)", "0"); Jim_SetVariableStr(i, "tcl_platform(pointerSize)", Jim_NewIntObj(i, sizeof(void *))); Jim_SetVariableStr(i, "tcl_platform(wordSize)", Jim_NewIntObj(i, sizeof(jim_wide))); + Jim_SetVariableStr(i, "tcl_platform(stackFormat)", Jim_NewIntObj(i, 4)); return i; } @@ -5746,7 +5729,6 @@ void Jim_FreeInterp(Jim_Interp *i) Jim_DecrRefCount(i, i->errorProc); Jim_DecrRefCount(i, i->unknown); Jim_DecrRefCount(i, i->defer); - Jim_DecrRefCount(i, i->errorFileNameObj); Jim_DecrRefCount(i, i->nullScriptObj); /* This will disard any cached commands */ @@ -5924,76 +5906,75 @@ static Jim_EvalFrame *JimGetEvalFrameByProcLevel(Jim_Interp *interp, int proclev return NULL; } +/* Find the proc for a given eval frame. + * When a proc is called (JimCallProcedure), the command name is stored in the eval frame. + * So to find the proc that called the code that is currently executing, we need + * to look back through eval frames until we find one that has a command name + */ +static Jim_Obj *JimProcForEvalFrame(Jim_Interp *interp, Jim_EvalFrame *frame) +{ + /* If at the lowest level or if this level called a proc directly, go + * look for the caller + */ + if (frame == interp->evalFrame || (frame->cmd && frame->cmd->cmdNameObj)) { + Jim_EvalFrame *e; + for (e = frame->parent; e; e = e->parent) { + if (e->cmd && e->cmd->isproc && e->cmd->cmdNameObj) { + break; + } + } + if (e && e->cmd && e->cmd->cmdNameObj) { + return e->cmd->cmdNameObj; + } + } + return NULL; +} -static void JimResetStackTrace(Jim_Interp *interp) +/** + * Append stack trace info (proc, file, line, cmd) from the eval frame + * to listObj + */ +static void JimAddStackFrame(Jim_Interp *interp, Jim_EvalFrame *frame, Jim_Obj *listObj) { - Jim_DecrRefCount(interp, interp->stackTrace); - interp->stackTrace = Jim_NewListObj(interp, NULL, 0); - Jim_IncrRefCount(interp->stackTrace); + Jim_Obj *procNameObj = JimProcForEvalFrame(interp, frame); + Jim_Obj *fileNameObj = interp->emptyObj; + int linenr = 1; + + if (frame->scriptObj) { + ScriptObj *script = JimGetScript(interp, frame->scriptObj); + fileNameObj = script->fileNameObj; + linenr = script->linenr; + } + + Jim_ListAppendElement(interp, listObj, procNameObj ? procNameObj : interp->emptyObj); + Jim_ListAppendElement(interp, listObj, fileNameObj); + Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, linenr)); + Jim_ListAppendElement(interp, listObj, Jim_NewListObj(interp, frame->argv, frame->argc)); } static void JimSetStackTrace(Jim_Interp *interp, Jim_Obj *stackTraceObj) { - int len; - /* Increment reference first in case these are the same object */ Jim_IncrRefCount(stackTraceObj); Jim_DecrRefCount(interp, interp->stackTrace); interp->stackTrace = stackTraceObj; interp->errorFlag = 1; - - /* This is a bit ugly. - * If the filename of the last entry of the stack trace is empty, - * the next stack level should be added. - */ - len = Jim_ListLength(interp, interp->stackTrace); - if (len >= 3) { - if (Jim_Length(Jim_ListGetIndex(interp, interp->stackTrace, len - 2)) == 0) { - interp->addStackTrace = 1; - } - } } -static void JimAppendStackTrace(Jim_Interp *interp, const char *procname, - Jim_Obj *fileNameObj, int linenr) +static void JimSetErrorStack(Jim_Interp *interp) { - if (strcmp(procname, "unknown") == 0) { - procname = ""; - } - if (!*procname && !Jim_Length(fileNameObj)) { - /* No useful info here */ - return; - } - - if (Jim_IsShared(interp->stackTrace)) { - Jim_DecrRefCount(interp, interp->stackTrace); - interp->stackTrace = Jim_DuplicateObj(interp, interp->stackTrace); - Jim_IncrRefCount(interp->stackTrace); - } - - /* If we have no procname but the previous element did, merge with that frame */ - if (!*procname && Jim_Length(fileNameObj)) { - /* Just a filename. Check the previous entry */ - int len = Jim_ListLength(interp, interp->stackTrace); + if (!interp->errorFlag) { + int i; + Jim_Obj *stackTrace = Jim_NewListObj(interp, NULL, 0); - if (len >= 3) { - Jim_Obj *objPtr = Jim_ListGetIndex(interp, interp->stackTrace, len - 3); - if (Jim_Length(objPtr)) { - /* Yes, the previous level had procname */ - objPtr = Jim_ListGetIndex(interp, interp->stackTrace, len - 2); - if (Jim_Length(objPtr) == 0) { - /* But no filename, so merge the new info with that frame */ - ListSetIndex(interp, interp->stackTrace, len - 2, fileNameObj, 0); - ListSetIndex(interp, interp->stackTrace, len - 1, Jim_NewIntObj(interp, linenr), 0); - return; - } + for (i = 0; i <= interp->procLevel; i++) { + Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i); + if (frame) { + JimAddStackFrame(interp, frame, stackTrace); } } + JimSetStackTrace(interp, stackTrace); } - - Jim_ListAppendElement(interp, interp->stackTrace, Jim_NewStringObj(interp, procname, -1)); - Jim_ListAppendElement(interp, interp->stackTrace, fileNameObj); - Jim_ListAppendElement(interp, interp->stackTrace, Jim_NewIntObj(interp, linenr)); } int Jim_SetAssocData(Jim_Interp *interp, const char *key, Jim_InterpDeleteProc * delProc, @@ -10759,10 +10740,7 @@ static int JimInvokeCommand(Jim_Interp *interp, int objc, Jim_Obj *const *objv) } interp->evalDepth++; prevPrivData = interp->cmdPrivData; - /* XXX We should consider creating a struct here (on the stack) with a back pointer - * so that the entire call chain can be walked. This would allow 'info frame' to walk - * the full call chain, not just call frames - */ + tailcall: interp->evalFrame->argc = objc; @@ -10780,6 +10758,9 @@ tailcall: interp->cmdPrivData = cmdPtr->u.native.privData; retcode = cmdPtr->u.native.cmdProc(interp, objc, objv); } + if (retcode == JIM_ERR) { + JimSetErrorStack(interp); + } } if (tailcallObj) { @@ -10788,6 +10769,10 @@ tailcall: tailcallObj = NULL; } + /* These are now invalid */ + interp->evalFrame->argc = 0; + interp->evalFrame->argv = NULL; + /* If a tailcall is returned for this frame, loop to invoke the new command */ if (retcode == JIM_EVAL && interp->framePtr->tailcallObj) { JimDecrCmdRefCount(interp, cmdPtr); @@ -10811,6 +10796,10 @@ tailcall: out: JimDecrCmdRefCount(interp, cmdPtr); + if (retcode == JIM_ERR) { + JimSetErrorStack(interp); + } + if (interp->framePtr->tailcallObj) { /* We might have skipped invoking a tailcall, perhaps because of an error * in defer handling so cleanup now @@ -10870,41 +10859,6 @@ int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix, int objc, Jim_Obj *co return ret; } -static void JimAddErrorToStack(Jim_Interp *interp, ScriptObj *script) -{ - if (!interp->errorFlag) { - /* This is the first error, so save the file/line information and reset the stack */ - interp->errorFlag = 1; - Jim_IncrRefCount(script->fileNameObj); - Jim_DecrRefCount(interp, interp->errorFileNameObj); - interp->errorFileNameObj = script->fileNameObj; - interp->errorLine = script->linenr; - - JimResetStackTrace(interp); - /* Always add a level where the error first occurs */ - interp->addStackTrace++; - } - - /* Now if this is an "interesting" level, add it to the stack trace */ - if (interp->addStackTrace > 0) { - /* Add the stack info for the current level */ - - JimAppendStackTrace(interp, Jim_String(interp->errorProc), script->fileNameObj, script->linenr); - - /* Note: if we didn't have a filename for this level, - * don't clear the addStackTrace flag - * so we can pick it up at the next level - */ - if (Jim_Length(script->fileNameObj)) { - interp->addStackTrace = 0; - } - - Jim_DecrRefCount(interp, interp->errorProc); - interp->errorProc = interp->emptyObj; - Jim_IncrRefCount(interp->errorProc); - } -} - static int JimSubstOneToken(Jim_Interp *interp, const ScriptToken *token, Jim_Obj **objPtrPtr) { Jim_Obj *objPtr; @@ -11060,7 +11014,6 @@ static int JimEvalObjList(Jim_Interp *interp, Jim_Obj *listPtr) JimPanic((Jim_IsList(listPtr) == 0, "JimEvalObjList() invoked on non-list.")); - /* XXX should we pass listPtr as scriptObj here? */ JimPushEvalFrame(interp, &frame, NULL); if (listPtr->internalRep.listValue.len) { @@ -11099,7 +11052,8 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr) Jim_IncrRefCount(scriptObjPtr); /* Make sure it's shared. */ script = JimGetScript(interp, scriptObjPtr); - if (!JimScriptValid(interp, script)) { + if (JimParseCheckMissing(interp, script->missing) == JIM_ERR) { + JimSetErrorStack(interp); Jim_DecrRefCount(interp, scriptObjPtr); return JIM_ERR; } @@ -11151,6 +11105,7 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr) JimPushEvalFrame(interp, &frame, scriptObjPtr); + /* Collect a new error stack trace if an error occurs */ interp->errorFlag = 0; argv = sargv; @@ -11301,12 +11256,7 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr) /* Possibly add to the error stack trace */ if (retcode == JIM_ERR) { - JimAddErrorToStack(interp, script); - } - /* Propagate the addStackTrace value through 'return -code error' */ - else if (retcode != JIM_RETURN || interp->returnCode != JIM_ERR) { - /* No need to add stack trace */ - interp->addStackTrace = 0; + JimSetErrorStack(interp); } JimPopEvalFrame(interp); @@ -11538,12 +11488,6 @@ badargset: interp->returnLevel = 0; } } - else if (retcode == JIM_ERR) { - interp->addStackTrace++; - Jim_DecrRefCount(interp, interp->errorProc); - interp->errorProc = argv[0]; - Jim_IncrRefCount(interp->errorProc); - } interp->procLevel--; return retcode; @@ -11639,10 +11583,6 @@ int Jim_EvalFile(Jim_Interp *interp, const char *filename) interp->returnLevel = 0; } } - if (retcode == JIM_ERR) { - /* EvalFile changes context, so add a stack frame here */ - interp->addStackTrace++; - } Jim_DecrRefCount(interp, scriptObjPtr); @@ -11957,54 +11897,36 @@ static int JimInfoFrame(Jim_Interp *interp, Jim_Obj *levelObjPtr, Jim_Obj **objP long level; if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) { - Jim_EvalFrame *targetEvalFrame = JimGetEvalFrameByProcLevel(interp, level); - if (targetEvalFrame) { + Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, level); + if (frame) { Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0); - int linenr; - Jim_Obj *fileNameObj; - /*Jim_EvalFrame *procEvalFrame;*/ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1)); Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "source", -1)); - if (targetEvalFrame->scriptObj) { - ScriptObj *script = JimGetScript(interp, targetEvalFrame->scriptObj); - linenr = script->linenr; - fileNameObj = script->fileNameObj; + if (frame->scriptObj) { + ScriptObj *script = JimGetScript(interp, frame->scriptObj); Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "line", -1)); - Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, linenr)); + Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, script->linenr)); Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "file", -1)); - Jim_ListAppendElement(interp, listObj, fileNameObj); + Jim_ListAppendElement(interp, listObj, script->fileNameObj); } #ifndef JIM_NO_INTROSPECTION { - Jim_Obj *cmdObj = Jim_NewListObj(interp, targetEvalFrame->argv, targetEvalFrame->argc); + Jim_Obj *cmdObj = Jim_NewListObj(interp, frame->argv, frame->argc); Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "cmd", -1)); Jim_ListAppendElement(interp, listObj, cmdObj); } #endif - /* XXX explain how this works */ - if (targetEvalFrame == interp->evalFrame || (targetEvalFrame->cmd && targetEvalFrame->cmd->isproc && targetEvalFrame->cmd->cmdNameObj)) { - Jim_EvalFrame *e, *p = NULL; - for (e = targetEvalFrame->parent; e; e = e->parent) { - if (e->cmd && e->cmd->isproc && e->cmd->cmdNameObj) { - p = e; - break; - } - } - if (p && p->level) { - if (p->cmd && p->cmd->isproc) { - if (p->cmd->cmdNameObj) { - Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "proc", -1)); - Jim_ListAppendElement(interp, listObj, p->cmd->cmdNameObj); - } - } + { + Jim_Obj *procNameObj = JimProcForEvalFrame(interp, frame); + if (procNameObj) { + Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "proc", -1)); + Jim_ListAppendElement(interp, listObj, procNameObj); } } Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "level", -1)); - Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, interp->framePtr->level - targetEvalFrame->framePtr->level)); - Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "proclevel", -1)); - Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, targetEvalFrame->procLevel)); + Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, interp->framePtr->level - frame->framePtr->level)); *objPtrPtr = listObj; return JIM_OK; @@ -13733,10 +13655,6 @@ static int Jim_EvalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg rc = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1)); } - if (rc == JIM_ERR) { - /* eval is "interesting", so add a stack frame here */ - interp->addStackTrace++; - } return rc; } @@ -13844,6 +13762,37 @@ static int Jim_ContinueCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const return JimBreakContinueHelper(interp, argc, argv, JIM_CONTINUE); } +/* [stacktrace] */ +static int Jim_StacktraceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + Jim_Obj *listObj; + int i; + jim_wide skip = 0; + jim_wide last = 0; + + if (argc > 1) { + if (Jim_GetWideExpr(interp, argv[1], &skip) != JIM_OK) { + return JIM_ERR; + } + } + if (argc > 2) { + if (Jim_GetWideExpr(interp, argv[2], &last) != JIM_OK) { + return JIM_ERR; + } + } + + listObj = Jim_NewListObj(interp, NULL, 0); + for (i = skip; i <= interp->procLevel; i++) { + Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i); + if (frame->procLevel < last) { + break; + } + JimAddStackFrame(interp, frame, listObj); + } + Jim_SetResult(interp, listObj); + return JIM_OK; +} + /* [return] */ static int Jim_ReturnCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { @@ -14851,7 +14800,7 @@ wrongargs: } else { exitCode = Jim_EvalObj(interp, argv[idx]); - /* Don't want any caught error included in a later stack trace */ + /* Once caught, a new error will set a stack trace again */ interp->errorFlag = 0; } interp->signal_level -= sig; @@ -16117,7 +16066,6 @@ static int Jim_ErrorCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar JimSetStackTrace(interp, argv[2]); return JIM_ERR; } - interp->addStackTrace++; return JIM_ERR; } @@ -16443,6 +16391,7 @@ static const struct { {"local", Jim_LocalCoreCommand}, {"upcall", Jim_UpcallCoreCommand}, {"apply", Jim_ApplyCoreCommand}, + {"stacktrace", Jim_StacktraceCoreCommand}, {NULL, NULL}, }; @@ -540,9 +540,9 @@ typedef struct Jim_PrngState { * ---------------------------------------------------------------------------*/ typedef struct Jim_Interp { Jim_Obj *result; /* object returned by the last command called. */ - int errorLine; /* Error line where an error occurred. */ - Jim_Obj *errorFileNameObj; /* Error file where an error occurred. */ - int addStackTrace; /* > 0 if a level should be added to the stack trace */ + int unused_errorLine; /* Error line where an error occurred. */ + Jim_Obj *unused_errorFileNameObj; /* Error file where an error occurred. */ + int unused_addStackTrace; int maxCallFrameDepth; /* Used for infinite loop detection. */ int maxEvalDepth; /* Used for infinite loop detection. */ int evalDepth; /* Current eval depth */ @@ -33,39 +33,28 @@ proc function {value} { return $value } -# Returns a live stack trace as a list of proc filename line ... -# with 3 entries for each stack frame (proc), -# (deepest level first) -proc stacktrace {{skip 0}} { - set frames {} - loop level $skip+1 [info frame] { - set frame [info frame -$level] - if {[dict exists $frame proc]} { - lappend frames $frame(proc) $frame(file) $frame(line) - } - } - return $frames -} - # Returns a human-readable version of a stack trace proc stackdump {stacktrace} { set lines {} - foreach {l f p} [lreverse $stacktrace] { + lappend lines "Traceback (most recent call last):" + foreach {cmd l f p} [lreverse $stacktrace] { set line {} - if {$p ne ""} { - append line "in procedure '$p' " - if {$f ne ""} { - append line "called " - } - } if {$f ne ""} { - append line "at file \"$f\", line $l" + append line " File \"$f\", line $l" + } + if {$p ne ""} { + append line ", in $p" } if {$line ne ""} { lappend lines $line + if {$cmd ne ""} { + lappend lines " $cmd" + } } } - join $lines \n + if {[llength $lines] > 1} { + return [join $lines \n] + } } # Add the given script to $jim::defer, to be evaluated when the current @@ -81,10 +70,8 @@ proc errorInfo {msg {stacktrace ""}} { if {$stacktrace eq ""} { # By default add the stack backtrace and the live stacktrace set stacktrace [info stacktrace] - # omit the procedure 'errorInfo' from the stack - lappend stacktrace {*}[stacktrace 1] } - lassign $stacktrace p f l + lassign $stacktrace p f l cmd if {$f ne ""} { set result "$f:$l: Error: " } diff --git a/tcltest.tcl b/tcltest.tcl index 2b8d3d8..9478dcd 100644 --- a/tcltest.tcl +++ b/tcltest.tcl @@ -78,11 +78,20 @@ proc skiptest {{msg {}}} { # Also convert proc name ::a into a for compatibility between Tcl and Jim proc basename-stacktrace {stacktrace} { set result {} - foreach {p f l} $stacktrace { - if {[string match ::* $p]} { + foreach {p f l cmd} $stacktrace { + if {[string match *tcltest-* $f]} { + #break + } + if {$p eq "::tcltest::RunTest"} { + set p test + } elseif {[string match ::* $p]} { set p [string range $p 2 end] } - lappend result $p [file tail $f] $l + set cmd [string map [list \n \\n] $cmd] + if {[string length $cmd] > 20} { + set cmd [string range $cmd 0 20]... + } + lappend result $p [file tail $f] $l $cmd } return $result } @@ -101,28 +110,23 @@ if {[catch {info version}]} { proc testreport {} { ::tcltest::cleanupTests } - proc stacktrace {{skip 0}} { - set trace {} - # Need to skip info frame 0 and this (stacktrace) level - incr skip 1 - set maxlevel [info frame] - for {set level $skip} {$level < $maxlevel} {incr level} { + proc stacktrace {{skip 0} {last 0}} { + set frames {} + incr skip + for {set level $skip} {$level < [info frame] - $last} {incr level} { set frame [info frame -$level] - if {[dict get $frame type] eq "source" && [dict exists $frame proc]} { + puts $frame + if {[dict get $frame type] ne "source"} { + continue + } + if {[dict exists $frame proc]} { set proc [dict get $frame proc] - # make it look like it is running under Jim tcltest - if {$proc eq "::tcltest::RunTest"} { - set proc test - } else { - set proc [string range $proc 2 end] - } - lappend trace $proc [dict get $frame file] [dict get $frame line] - if {$proc eq "test"} { - break - } + } else { + set proc "" } + lappend frames $proc [dict get $frame file] [dict get $frame line] [dict get $frame cmd] } - return $trace + return $frames } return } diff --git a/tests/error.test b/tests/error.test index d226900..5669b7b 100644 --- a/tests/error.test +++ b/tests/error.test @@ -11,12 +11,12 @@ proc b {} { } } -test error-1.1 "Rethrow caught error" { +test error-1.1 {Rethrow caught error} -body { set rc [catch {b} msg] #puts stderr "error-1.1\n[errorInfo $msg]\n" list $rc $msg [basename-stacktrace [info stacktrace]] -} {1 {error thrown from a} {{} error.test 4 a error.test 8 b error.test 15}} +} -result {1 {error thrown from a} {a error.test 4 error\ \{error\ thrown\ f... b error.test 8 a test error.test 15 b {} error.test 14 test\ error-1.1\ \{Rethr...}} proc c {} { a @@ -30,22 +30,22 @@ proc e {} { d } -test error-1.2 "Modify stacktrace" { +test error-1.2 {Modify stacktrace} -body { set rc [catch {e} msg] set st [info stacktrace] # Now elide one entry from the stacktrace #puts [errorInfo $msg] set newst {} - foreach {p f l} $st { + foreach {p f l cmd} $st { if {$p ne "d"} { - lappend newst $p $f $l + lappend newst $p $f $l $cmd } } # Now rethrow with the new stack set rc [catch {error $msg $newst} msg] #puts [errorInfo $msg] basename-stacktrace [info stacktrace] -} {{} error.test 4 a error.test 22 c error.test 26 e error.test 34} +} -result {a error.test 4 error\ \{error\ thrown\ f... c error.test 22 a e error.test 30 d test error.test 34 e {} error.test 33 test\ error-1.2\ \{Modif...} # Package should be able to invoke exit, which should exit if not caught test error-2.1 "Exit from package" { diff --git a/tests/event.test b/tests/event.test index 278f4e3..b95f76e 100644 --- a/tests/event.test +++ b/tests/event.test @@ -92,7 +92,11 @@ test event-7.4 {bgerror throws an error} -constraints jim -body { update } } -result {stdin:3: Error: inside bgerror -at file "stdin", line 3} +Traceback (most recent call last): + File "stdin", line 6 + bgerror err1 + File "stdin", line 3, in bgerror + error {inside bgerror}} # end of bgerror tests catch {rename bgerror {}} diff --git a/tests/infoframe.test b/tests/infoframe.test index e8544b1..ef827bc 100644 --- a/tests/infoframe.test +++ b/tests/infoframe.test @@ -1,44 +1,50 @@ source [file dirname [info script]]/testing.tcl -proc a {n} { +proc a {n args} { if {$n eq "trace"} { - return [basename-stacktrace [stacktrace]] + return [basename-stacktrace [stacktrace {*}$args]] } set frame [info frame $n] if {![dict exists $frame proc]} { dict set frame proc {} } - basename-stacktrace [list [dict get $frame proc] [file tail [dict get $frame file]] [dict get $frame line]] + basename-stacktrace [list [dict get $frame proc] [file tail [dict get $frame file]] [dict get $frame line] [dict get $frame cmd]] } -proc b {n} { - a $n +proc b {args} { + a {*}$args } -proc c {n} { - b $n +proc c {args} { + b {*}$args } # --- Don't change line numbers above test info-frame-1.1 {Current command} -body { c 0 -} -result {a infoframe.test 7} +} -result {a infoframe.test 7 {info frame 0}} test info-frame-1.2 {Current Proc} -body { c -1 -} -result {b infoframe.test 15} +} -result {b infoframe.test 15 {a -1}} test info-frame-1.3 Caller -body { c -2 -} -result {c infoframe.test 19} +} -result {c infoframe.test 19 {b -2}} test info-frame-1.4 {Caller of Caller} -body { c -3 -} -result {test infoframe.test 37} +} -result {test infoframe.test 37 {c -3}} test stacktrace-1.1 {Full stack trace} -body { c trace -} -result {a infoframe.test 5 b infoframe.test 15 c infoframe.test 19 test infoframe.test 41} +} -result {a infoframe.test 5 stacktrace b infoframe.test 15 {a trace} c infoframe.test 19 {b trace} test infoframe.test 41 {c trace} {} infoframe.test 40 test\ stacktrace-1.1\ \{...} + +test stacktrace-1.2 {Stack trace with limited depth} -body { + # This will limit the stack trace to omit "this" level and below + c trace 0 [info frame] +} -result {a infoframe.test 5 {stacktrace 0 2} b infoframe.test 15 {a trace 0 2} c infoframe.test 19 {b trace 0 2}} + testreport diff --git a/tests/misc.test b/tests/misc.test index a997057..cffb0a6 100644 --- a/tests/misc.test +++ b/tests/misc.test @@ -301,25 +301,24 @@ test catch-1.9 "catch no error has no -errorinfo" { list $rc [info exists opts(-errorinfo)] } {0 0} -test return-1.1 "return can rethrow an error" { +test return-1.1 {return can rethrow an error} -body { proc a {} { error "from a" } proc b {} { catch {a} msg opts; return {*}$opts $msg } set rc [catch {b} msg opts] - list $rc $msg [llength $opts(-errorinfo)] -} {1 {from a} 9} + list $rc $msg [basename-stacktrace $opts(-errorinfo)] +} -result {1 {from a} {a misc.test 305 {error {from a}} b misc.test 306 a test misc.test 307 b {} misc.test 304 test\ return-1.1\ \{retu...}} -test return-1.2 "error can rethrow an error" { +test return-1.2 {error can rethrow an error} -body { proc a {} { error "from a" } proc b {} { catch {a} msg; error $msg [info stacktrace] } set rc [catch {b} msg opts] - list $rc $msg [llength $opts(-errorinfo)] -} {1 {from a} 9} + list $rc $msg [basename-stacktrace $opts(-errorinfo)] +} -result {1 {from a} {a misc.test 312 {error {from a}} b misc.test 313 a test misc.test 314 b {} misc.test 311 test\ return-1.2\ \{erro...}} test return-1.3 "return can rethrow no error" { proc a {} { return "from a" } proc b {} { catch {a} msg opts; return {*}$opts $msg } set rc [catch {b} msg opts] - #list $rc $msg [llength $opts(-errorinfo)] list $rc $msg [info exists opts(-errorinfo)] } {0 {from a} 0} diff --git a/tests/stacktrace.test b/tests/stacktrace.test index 9dcc657..4d6b432 100644 --- a/tests/stacktrace.test +++ b/tests/stacktrace.test @@ -34,13 +34,13 @@ proc main {} { error "from unknown" } - test err-10.1 "Stacktrace on error from unknown (badcmd, call)" { + test err-10.1 {Stacktrace on error from unknown (badcmd, call)} -body { set rc [catch {error_caller badcmd call} msg] #puts stderr "err-10.1\n[errorInfo $msg]\n" #puts stderr "\terr-10.1 {[list $rc $msg [basename-stacktrace [info stacktrace]]]}" list $rc $msg [basename-stacktrace [info stacktrace]] - } {1 {from unknown} {{} stacktrace.test 34 {} errors.tcl 6 error_generator errors.tcl 44 error_caller stacktrace.test 38}} + } -result {1 {from unknown} {unknown stacktrace.test 34 {error {from unknown}} error_generator errors.tcl 6 {unknown bogus command...} error_caller errors.tcl 44 {error_generator badcm...} test stacktrace.test 38 {error_caller badcmd c...} main stacktrace.test 37 test\ err-10.1\ \{Stackt... {} stacktrace.test 127 main}} rename unknown "" @@ -74,50 +74,50 @@ proc main {} { } set expected { - err-1.1 {1 {invalid command name "bogus"} {{} errors.tcl 6 error_generator errors.tcl 44 error_caller stacktrace.test 25}} - err-1.2 {1 {invalid command name "bogus"} {{} errors.tcl 6 error_generator errors.tcl 47 error_caller stacktrace.test 25}} - err-1.3 {1 {invalid command name "bogus"} {{} errors.tcl 6 error_generator errors.tcl 50 error_caller stacktrace.test 25}} - err-1.4 {1 {invalid command name "bogus"} {{} errors.tcl 6 error_generator errors.tcl 53 error_caller stacktrace.test 25}} - err-2.1 {1 {can't read "bogus": no such variable} {{} errors.tcl 9 error_generator errors.tcl 44 error_caller stacktrace.test 25}} - err-2.2 {1 {can't read "bogus": no such variable} {{} errors.tcl 9 error_generator errors.tcl 47 error_caller stacktrace.test 25}} - err-2.3 {1 {can't read "bogus": no such variable} {{} errors.tcl 9 error_generator errors.tcl 50 error_caller stacktrace.test 25}} - err-2.4 {1 {can't read "bogus": no such variable} {{} errors.tcl 9 error_generator errors.tcl 53 error_caller stacktrace.test 25}} - err-3.1 {1 {unmatched "["} {{} errors.tcl 62 error_badproc errors.tcl 33 error_generator errors.tcl 44 error_caller stacktrace.test 25}} - err-3.2 {1 {unmatched "["} {{} errors.tcl 62 error_badproc errors.tcl 33 error_generator errors.tcl 47 error_caller stacktrace.test 25}} - err-3.3 {1 {unmatched "["} {{} errors.tcl 62 error_badproc errors.tcl 33 error_generator errors.tcl 50 error_caller stacktrace.test 25}} - err-3.4 {1 {unmatched "["} {{} errors.tcl 62 error_badproc errors.tcl 33 error_generator errors.tcl 53 error_caller stacktrace.test 25}} - err-4.1 {1 bogus {{} errors.tcl 12 error_generator errors.tcl 44 error_caller stacktrace.test 25}} - err-4.2 {1 bogus {{} errors.tcl 12 error_generator errors.tcl 47 error_caller stacktrace.test 25}} - err-4.3 {1 bogus {{} errors.tcl 12 error_generator errors.tcl 50 error_caller stacktrace.test 25}} - err-4.4 {1 bogus {{} errors.tcl 12 error_generator errors.tcl 53 error_caller stacktrace.test 25}} - err-5.1 {1 {can't read "bogus": no such variable} {{} errors.tcl 15 error_generator errors.tcl 44 error_caller stacktrace.test 25}} - err-5.2 {1 {can't read "bogus": no such variable} {{} errors.tcl 15 error_generator errors.tcl 47 error_caller stacktrace.test 25}} - err-5.3 {1 {can't read "bogus": no such variable} {{} errors.tcl 15 error_generator errors.tcl 50 error_caller stacktrace.test 25}} - err-5.4 {1 {can't read "bogus": no such variable} {{} errors.tcl 15 error_generator errors.tcl 53 error_caller stacktrace.test 25}} - err-6.1 {1 {can't read "bogus": no such variable} {{} errors.tcl 18 error_generator errors.tcl 44 error_caller stacktrace.test 25}} - err-6.2 {1 {can't read "bogus": no such variable} {{} errors.tcl 18 error_generator errors.tcl 47 error_caller stacktrace.test 25}} - err-6.3 {1 {can't read "bogus": no such variable} {{} errors.tcl 18 error_generator errors.tcl 50 error_caller stacktrace.test 25}} - err-6.4 {1 {can't read "bogus": no such variable} {{} errors.tcl 18 error_generator errors.tcl 53 error_caller stacktrace.test 25}} + err-1.1 {1 {invalid command name "bogus"} {error_generator errors.tcl 6 {} error_caller errors.tcl 44 {error_generator badcm...} test stacktrace.test 25 {error_caller badcmd c...} main stacktrace.test 24 test\ err-1.1\ \{Stacktr... {} stacktrace.test 127 main}} + err-1.2 {1 {invalid command name "bogus"} {error_generator errors.tcl 6 {} error_caller errors.tcl 47 {error_generator badcm...} test stacktrace.test 25 {error_caller badcmd u...} main stacktrace.test 24 test\ err-1.2\ \{Stacktr... {} stacktrace.test 127 main}} + err-1.3 {1 {invalid command name "bogus"} {error_generator errors.tcl 6 {} error_caller errors.tcl 50 {error_generator badcm...} test stacktrace.test 25 {error_caller badcmd e...} main stacktrace.test 24 test\ err-1.3\ \{Stacktr... {} stacktrace.test 127 main}} + err-1.4 {1 {invalid command name "bogus"} {error_generator errors.tcl 6 {} error_caller {} 1 {error_generator badcm...} test stacktrace.test 25 {error_caller badcmd e...} main stacktrace.test 24 test\ err-1.4\ \{Stacktr... {} stacktrace.test 127 main}} + err-2.1 {1 {can't read "bogus": no such variable} {error_generator errors.tcl 9 {set bogus} error_caller errors.tcl 44 {error_generator badva...} test stacktrace.test 25 {error_caller badvar c...} main stacktrace.test 24 test\ err-2.1\ \{Stacktr... {} stacktrace.test 127 main}} + err-2.2 {1 {can't read "bogus": no such variable} {error_generator errors.tcl 9 {set bogus} error_caller errors.tcl 47 {error_generator badva...} test stacktrace.test 25 {error_caller badvar u...} main stacktrace.test 24 test\ err-2.2\ \{Stacktr... {} stacktrace.test 127 main}} + err-2.3 {1 {can't read "bogus": no such variable} {error_generator errors.tcl 9 {set bogus} error_caller errors.tcl 50 {error_generator badva...} test stacktrace.test 25 {error_caller badvar e...} main stacktrace.test 24 test\ err-2.3\ \{Stacktr... {} stacktrace.test 127 main}} + err-2.4 {1 {can't read "bogus": no such variable} {error_generator errors.tcl 9 {set bogus} error_caller {} 1 {error_generator badva...} test stacktrace.test 25 {error_caller badvar e...} main stacktrace.test 24 test\ err-2.4\ \{Stacktr... {} stacktrace.test 127 main}} + err-3.1 {1 {unmatched "["} {error_generator errors.tcl 33 error_badproc error_generator errors.tcl 33 error_badproc error_caller errors.tcl 44 {error_generator badpr...} test stacktrace.test 25 {error_caller badproc ...} main stacktrace.test 24 test\ err-3.1\ \{Stacktr... {} stacktrace.test 127 main}} + err-3.2 {1 {unmatched "["} {error_generator errors.tcl 33 error_badproc error_generator errors.tcl 33 error_badproc error_caller errors.tcl 47 {error_generator badpr...} test stacktrace.test 25 {error_caller badproc ...} main stacktrace.test 24 test\ err-3.2\ \{Stacktr... {} stacktrace.test 127 main}} + err-3.3 {1 {unmatched "["} {error_generator errors.tcl 33 error_badproc error_generator errors.tcl 33 error_badproc error_caller errors.tcl 50 {error_generator badpr...} test stacktrace.test 25 {error_caller badproc ...} main stacktrace.test 24 test\ err-3.3\ \{Stacktr... {} stacktrace.test 127 main}} + err-3.4 {1 {unmatched "["} {error_generator errors.tcl 33 error_badproc error_generator errors.tcl 33 error_badproc error_caller {} 1 {error_generator badpr...} test stacktrace.test 25 {error_caller badproc ...} main stacktrace.test 24 test\ err-3.4\ \{Stacktr... {} stacktrace.test 127 main}} + err-4.1 {1 bogus {error_generator errors.tcl 12 {error bogus} error_caller errors.tcl 44 {error_generator error...} test stacktrace.test 25 {error_caller error ca...} main stacktrace.test 24 test\ err-4.1\ \{Stacktr... {} stacktrace.test 127 main}} + err-4.2 {1 bogus {error_generator errors.tcl 12 {error bogus} error_caller errors.tcl 47 {error_generator error...} test stacktrace.test 25 {error_caller error up...} main stacktrace.test 24 test\ err-4.2\ \{Stacktr... {} stacktrace.test 127 main}} + err-4.3 {1 bogus {error_generator errors.tcl 12 {error bogus} error_caller errors.tcl 50 {error_generator error...} test stacktrace.test 25 {error_caller error ev...} main stacktrace.test 24 test\ err-4.3\ \{Stacktr... {} stacktrace.test 127 main}} + err-4.4 {1 bogus {error_generator errors.tcl 12 {error bogus} error_caller {} 1 {error_generator error...} test stacktrace.test 25 {error_caller error ev...} main stacktrace.test 24 test\ err-4.4\ \{Stacktr... {} stacktrace.test 127 main}} + err-5.1 {1 {can't read "bogus": no such variable} {error_generator errors.tcl 15 {} error_caller errors.tcl 44 {error_generator inter...} test stacktrace.test 25 {error_caller interpba...} main stacktrace.test 24 test\ err-5.1\ \{Stacktr... {} stacktrace.test 127 main}} + err-5.2 {1 {can't read "bogus": no such variable} {error_generator errors.tcl 15 {} error_caller errors.tcl 47 {error_generator inter...} test stacktrace.test 25 {error_caller interpba...} main stacktrace.test 24 test\ err-5.2\ \{Stacktr... {} stacktrace.test 127 main}} + err-5.3 {1 {can't read "bogus": no such variable} {error_generator errors.tcl 15 {} error_caller errors.tcl 50 {error_generator inter...} test stacktrace.test 25 {error_caller interpba...} main stacktrace.test 24 test\ err-5.3\ \{Stacktr... {} stacktrace.test 127 main}} + err-5.4 {1 {can't read "bogus": no such variable} {error_generator errors.tcl 15 {} error_caller {} 1 {error_generator inter...} test stacktrace.test 25 {error_caller interpba...} main stacktrace.test 24 test\ err-5.4\ \{Stacktr... {} stacktrace.test 127 main}} + err-6.1 {1 {can't read "bogus": no such variable} {error_generator errors.tcl 18 {} error_caller errors.tcl 44 {error_generator inter...} test stacktrace.test 25 {error_caller interpba...} main stacktrace.test 24 test\ err-6.1\ \{Stacktr... {} stacktrace.test 127 main}} + err-6.2 {1 {can't read "bogus": no such variable} {error_generator errors.tcl 18 {} error_caller errors.tcl 47 {error_generator inter...} test stacktrace.test 25 {error_caller interpba...} main stacktrace.test 24 test\ err-6.2\ \{Stacktr... {} stacktrace.test 127 main}} + err-6.3 {1 {can't read "bogus": no such variable} {error_generator errors.tcl 18 {} error_caller errors.tcl 50 {error_generator inter...} test stacktrace.test 25 {error_caller interpba...} main stacktrace.test 24 test\ err-6.3\ \{Stacktr... {} stacktrace.test 127 main}} + err-6.4 {1 {can't read "bogus": no such variable} {error_generator errors.tcl 18 {} error_caller {} 1 {error_generator inter...} test stacktrace.test 25 {error_caller interpba...} main stacktrace.test 24 test\ err-6.4\ \{Stacktr... {} stacktrace.test 127 main}} err-7.1 {1 {from dummyproc -Can't load package dummy} {{} dummy.tcl 3 dummyproc dummy.tcl 6 {} errors.tcl 21 error_generator errors.tcl 44 error_caller stacktrace.test 25}} +Can't load package dummy} {dummyproc dummy.tcl 3 error\ \{from\ dummyproc... error_generator dummy.tcl 6 dummyproc error_caller errors.tcl 44 {error_generator packa...} test stacktrace.test 25 {error_caller package ...} main stacktrace.test 24 test\ err-7.1\ \{Stacktr... {} stacktrace.test 127 main}} err-7.2 {1 {from dummyproc -Can't load package dummy} {{} dummy.tcl 3 dummyproc dummy.tcl 6 {} errors.tcl 21 error_generator errors.tcl 47 error_caller stacktrace.test 25}} +Can't load package dummy} {dummyproc dummy.tcl 3 error\ \{from\ dummyproc... error_generator dummy.tcl 6 dummyproc error_caller errors.tcl 47 {error_generator packa...} test stacktrace.test 25 {error_caller package ...} main stacktrace.test 24 test\ err-7.2\ \{Stacktr... {} stacktrace.test 127 main}} err-7.3 {1 {from dummyproc -Can't load package dummy} {{} dummy.tcl 3 dummyproc dummy.tcl 6 {} errors.tcl 21 error_generator errors.tcl 50 error_caller stacktrace.test 25}} +Can't load package dummy} {dummyproc dummy.tcl 3 error\ \{from\ dummyproc... error_generator dummy.tcl 6 dummyproc error_caller errors.tcl 50 {error_generator packa...} test stacktrace.test 25 {error_caller package ...} main stacktrace.test 24 test\ err-7.3\ \{Stacktr... {} stacktrace.test 127 main}} err-7.4 {1 {from dummyproc -Can't load package dummy} {{} dummy.tcl 3 dummyproc dummy.tcl 6 {} errors.tcl 21 error_generator errors.tcl 53 error_caller stacktrace.test 25}} - err-8.1 {1 {from dummyproc} {{} dummy.tcl 3 dummyproc dummy.tcl 6 {} errors.tcl 24 error_generator errors.tcl 44 error_caller stacktrace.test 25}} - err-8.2 {1 {from dummyproc} {{} dummy.tcl 3 dummyproc dummy.tcl 6 {} errors.tcl 24 error_generator errors.tcl 47 error_caller stacktrace.test 25}} - err-8.3 {1 {from dummyproc} {{} dummy.tcl 3 dummyproc dummy.tcl 6 {} errors.tcl 24 error_generator errors.tcl 50 error_caller stacktrace.test 25}} - err-8.4 {1 {from dummyproc} {{} dummy.tcl 3 dummyproc dummy.tcl 6 {} errors.tcl 24 error_generator errors.tcl 53 error_caller stacktrace.test 25}} - err-9.1 {1 {Can't load package bogus} {{} errors.tcl 27 error_generator errors.tcl 44 error_caller stacktrace.test 25}} - err-9.2 {1 {Can't load package bogus} {{} errors.tcl 27 error_generator errors.tcl 47 error_caller stacktrace.test 25}} - err-9.3 {1 {Can't load package bogus} {{} errors.tcl 27 error_generator errors.tcl 50 error_caller stacktrace.test 25}} - err-9.4 {1 {Can't load package bogus} {{} errors.tcl 27 error_generator errors.tcl 53 error_caller stacktrace.test 25}} - err-10.1 {1 failure {{} errors.tcl 44 error_caller stacktrace.test 25}} - err-10.2 {1 failure {{} errors.tcl 47 error_caller stacktrace.test 25}} - err-10.3 {1 failure {{} errors.tcl 50 error_caller stacktrace.test 25}} - err-10.4 {1 failure {{} errors.tcl 53 error_caller stacktrace.test 25}} +Can't load package dummy} {dummyproc dummy.tcl 3 error\ \{from\ dummyproc... error_generator dummy.tcl 6 dummyproc error_caller {} 1 {error_generator packa...} test stacktrace.test 25 {error_caller package ...} main stacktrace.test 24 test\ err-7.4\ \{Stacktr... {} stacktrace.test 127 main}} + err-8.1 {1 {from dummyproc} {dummyproc dummy.tcl 3 error\ \{from\ dummyproc... error_generator dummy.tcl 6 dummyproc error_caller errors.tcl 44 {error_generator sourc...} test stacktrace.test 25 {error_caller source c...} main stacktrace.test 24 test\ err-8.1\ \{Stacktr... {} stacktrace.test 127 main}} + err-8.2 {1 {from dummyproc} {dummyproc dummy.tcl 3 error\ \{from\ dummyproc... error_generator dummy.tcl 6 dummyproc error_caller errors.tcl 47 {error_generator sourc...} test stacktrace.test 25 {error_caller source u...} main stacktrace.test 24 test\ err-8.2\ \{Stacktr... {} stacktrace.test 127 main}} + err-8.3 {1 {from dummyproc} {dummyproc dummy.tcl 3 error\ \{from\ dummyproc... error_generator dummy.tcl 6 dummyproc error_caller errors.tcl 50 {error_generator sourc...} test stacktrace.test 25 {error_caller source e...} main stacktrace.test 24 test\ err-8.3\ \{Stacktr... {} stacktrace.test 127 main}} + err-8.4 {1 {from dummyproc} {dummyproc dummy.tcl 3 error\ \{from\ dummyproc... error_generator dummy.tcl 6 dummyproc error_caller {} 1 {error_generator sourc...} test stacktrace.test 25 {error_caller source e...} main stacktrace.test 24 test\ err-8.4\ \{Stacktr... {} stacktrace.test 127 main}} + err-9.1 {1 {Can't load package bogus} {error_generator errors.tcl 27 {package require bogus...} error_caller errors.tcl 44 {error_generator badpa...} test stacktrace.test 25 {error_caller badpacka...} main stacktrace.test 24 test\ err-9.1\ \{Stacktr... {} stacktrace.test 127 main}} + err-9.2 {1 {Can't load package bogus} {error_generator errors.tcl 27 {package require bogus...} error_caller errors.tcl 47 {error_generator badpa...} test stacktrace.test 25 {error_caller badpacka...} main stacktrace.test 24 test\ err-9.2\ \{Stacktr... {} stacktrace.test 127 main}} + err-9.3 {1 {Can't load package bogus} {error_generator errors.tcl 27 {package require bogus...} error_caller errors.tcl 50 {error_generator badpa...} test stacktrace.test 25 {error_caller badpacka...} main stacktrace.test 24 test\ err-9.3\ \{Stacktr... {} stacktrace.test 127 main}} + err-9.4 {1 {Can't load package bogus} {error_generator errors.tcl 27 {package require bogus...} error_caller {} 1 {error_generator badpa...} test stacktrace.test 25 {error_caller badpacka...} main stacktrace.test 24 test\ err-9.4\ \{Stacktr... {} stacktrace.test 127 main}} + err-10.1 {1 failure {error_caller errors.tcl 44 {error_generator retur...} test stacktrace.test 25 {error_caller returnco...} main stacktrace.test 24 test\ err-10.1\ \{Stackt... {} stacktrace.test 127 main}} + err-10.2 {1 failure {error_caller errors.tcl 47 {error_generator retur...} test stacktrace.test 25 {error_caller returnco...} main stacktrace.test 24 test\ err-10.2\ \{Stackt... {} stacktrace.test 127 main}} + err-10.3 {1 failure {error_caller errors.tcl 50 {error_generator retur...} test stacktrace.test 25 {error_caller returnco...} main stacktrace.test 24 test\ err-10.3\ \{Stackt... {} stacktrace.test 127 main}} + err-10.4 {1 failure {error_caller {} 1 {error_generator retur...} test stacktrace.test 25 {error_caller returnco...} main stacktrace.test 24 test\ err-10.4\ \{Stackt... {} stacktrace.test 127 main}} } # Set this to output expected results to stderr |