Bug 480199 - Add assertEq function to JS shell. r=mrbkap.
authorJason Orendorff <jorendorff@mozilla.com>
Fri, 27 Feb 2009 14:14:28 -0600
changeset 25699 e3bb1cc3d6b13c83b04d15cca66a4313089c6aa0
parent 25637 737ca70d654fc584ac8f3292e84afe73281783dc
child 25700 3aa214dd9ec84f1bbd219ceb097e5c5e1a7da210
push idunknown
push userunknown
push dateunknown
reviewersmrbkap
bugs480199
milestone1.9.2a1pre
Bug 480199 - Add assertEq function to JS shell. r=mrbkap.
js/src/jsshell.msg
js/src/shell/js.cpp
--- a/js/src/jsshell.msg
+++ b/js/src/jsshell.msg
@@ -44,8 +44,11 @@
 MSG_DEF(JSSMSG_NOT_AN_ERROR,             0, 0, JSEXN_NONE, "<Error #0 is reserved>")
 MSG_DEF(JSSMSG_CANT_OPEN,                1, 2, JSEXN_NONE, "can't open {0}: {1}") 
 MSG_DEF(JSSMSG_TRAP_USAGE,               2, 0, JSEXN_NONE, "usage: trap [fun] [pc] expr") 
 MSG_DEF(JSSMSG_LINE2PC_USAGE,            3, 0, JSEXN_NONE, "usage: line2pc [fun] line") 
 MSG_DEF(JSSMSG_FILE_SCRIPTS_ONLY,        4, 0, JSEXN_NONE, "only works on JS scripts read from files") 
 MSG_DEF(JSSMSG_UNEXPECTED_EOF,           5, 1, JSEXN_NONE, "unexpected EOF in {0}") 
 MSG_DEF(JSSMSG_DOEXP_USAGE,              6, 0, JSEXN_NONE, "usage: doexp obj id") 
 MSG_DEF(JSSMSG_SCRIPTS_ONLY,             7, 0, JSEXN_NONE, "only works on scripts") 
+MSG_DEF(JSSMSG_NOT_ENOUGH_ARGS,          8, 1, JSEXN_NONE, "{0}: not enough arguments")
+MSG_DEF(JSSMSG_TOO_MANY_ARGS,            9, 1, JSEXN_NONE, "{0}: too many arguments")
+MSG_DEF(JSSMSG_ASSERT_EQ_FAILED,        10, 2, JSEXN_NONE, "Assertion failed: got {0}, expected {1}")
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1012,16 +1012,58 @@ Quit(JSContext *cx, JSObject *obj, uintN
 #endif
 
     JS_ConvertArguments(cx, argc, argv,"/ i", &gExitCode);
 
     gQuitting = JS_TRUE;
     return JS_FALSE;
 }
 
+static const char *
+ToSource(JSContext *cx, jsval *vp)
+{
+    JSString *str = JS_ValueToSource(cx, *vp);
+    if (str) {
+        *vp = STRING_TO_JSVAL(str);
+        return JS_GetStringBytes(str);
+    }
+    JS_ClearPendingException(cx);
+    return "<<error converting value to string>>";
+}
+
+static JSBool
+AssertEq(JSContext *cx, uintN argc, jsval *vp)
+{
+    if (argc != 2) {
+        JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
+                             (argc > 2) ? JSSMSG_TOO_MANY_ARGS : JSSMSG_NOT_ENOUGH_ARGS,
+                             "assertEq");
+        return JS_FALSE;
+    }
+
+    jsval *argv = JS_ARGV(cx, vp);
+    if (!js_StrictlyEqual(cx, argv[0], argv[1])) {
+        const char *actual = ToSource(cx, &argv[0]);
+        const char *expected = ToSource(cx, &argv[1]);
+        JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_ASSERT_EQ_FAILED,
+                             actual, expected);
+        return JS_FALSE;
+    }
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    return JS_TRUE;
+}
+
+#ifdef JS_TRACER
+static jsval JS_FASTCALL
+AssertEq_tn(JSContext *cx, jsval v1, jsval v2)
+{
+    return (js_StrictlyEqual(cx, v1, v2)) ? JSVAL_VOID : JSVAL_ERROR_COOKIE;
+}
+#endif
+
 static JSBool
 GC(JSContext *cx, uintN argc, jsval *vp)
 {
     JSRuntime *rt;
     uint32 preBytes;
 
     rt = cx->runtime;
     preBytes = rt->gcBytes;
@@ -3357,16 +3399,17 @@ Elapsed(JSContext *cx, uintN argc, jsval
         if (data)
             d = js_IntervalNow() - data->startTime;
         return JS_NewNumberValue(cx, d, vp);
     }
     JS_ReportError(cx, "Wrong number of arguments");
     return JS_FALSE;
 }
 
+JS_DEFINE_TRCINFO_1(AssertEq, (3, (static, JSVAL_RETRY, AssertEq_tn, CONTEXT, JSVAL, JSVAL, 0, 0)))
 JS_DEFINE_TRCINFO_1(Print, (2, (static, JSVAL_FAIL, Print_tn, CONTEXT, STRING, 0, 0)))
 JS_DEFINE_TRCINFO_1(ShapeOf, (1, (static, INT32, ShapeOf_tn, OBJECT, 0, 0)))
 
 #ifdef XP_UNIX
 
 #include <fcntl.h>
 #include <sys/stat.h>
 
@@ -3489,16 +3532,17 @@ Snarf(JSContext *cx, JSObject *obj, uint
 static JSFunctionSpec shell_functions[] = {
     JS_FS("version",        Version,        0,0,0),
     JS_FS("options",        Options,        0,0,0),
     JS_FS("load",           Load,           1,0,0),
     JS_FN("readline",       ReadLine,       0,0),
     JS_TN("print",          Print,          0,0, Print_trcinfo),
     JS_FS("help",           Help,           0,0,0),
     JS_FS("quit",           Quit,           0,0,0),
+    JS_TN("assertEq",       AssertEq,       2,0, AssertEq_trcinfo),
     JS_FN("gc",             GC,             0,0),
     JS_FN("gcparam",        GCParameter,    2,0),
     JS_FN("countHeap",      CountHeap,      0,0),
 #ifdef JS_GC_ZEAL
     JS_FN("gczeal",         GCZeal,         1,0),
 #endif
     JS_FS("trap",           Trap,           3,0,0),
     JS_FS("untrap",         Untrap,         2,0,0),
@@ -3567,16 +3611,18 @@ static const char shell_help_header[] =
 static const char *const shell_help_messages[] = {
 "version([number])        Get or set JavaScript version number",
 "options([option ...])    Get or toggle JavaScript options",
 "load(['foo.js' ...])     Load files named by string arguments",
 "readline()               Read a single line from stdin",
 "print([exp ...])         Evaluate and print expressions",
 "help([name ...])         Display usage and help messages",
 "quit()                   Quit the shell",
+"assertEq(actual, expected)\n"
+"                         Throw if the two arguments are not ===",
 "gc()                     Run the garbage collector",
 "gcparam(name, value)\n"
 "  Wrapper for JS_SetGCParameter. The name must be either 'maxBytes' or\n"
 "  'maxMallocBytes' and the value must be convertable to a positive uint32",
 "countHeap([start[, kind]])\n"
 "  Count the number of live GC things in the heap or things reachable from\n"
 "  start when it is given and is not null. kind is either 'all' (default) to\n"
 "  count all things or one of 'object', 'double', 'string', 'function',\n"