michael@0: === JSAPI Test Suite michael@0: michael@0: The tests in this directory exercise the JSAPI. michael@0: michael@0: michael@0: --- Building and running the tests michael@0: michael@0: If you built JS, you already built the tests. michael@0: michael@0: If you did `make check` in your JS objdir, you already ran them. michael@0: michael@0: The tests are built by default when you build JS. All the tests are compiled michael@0: into a single binary named jsapi-tests. They all run in a single process. michael@0: michael@0: To run the tests in a debugger: michael@0: michael@0: cd $OBJDIR/jsapi-tests michael@0: gdb ./jsapi-tests michael@0: michael@0: michael@0: --- Creating new tests michael@0: michael@0: 1. You can either add to an existing test*.cpp file or make a new one. michael@0: Copy an existing test and replace the body with your test code. michael@0: The test harness provides `cx`, `rt`, and `global` for your use. michael@0: michael@0: 2. If you made a new .cpp file, add it to the CPPSRCS list in Makefile.in. michael@0: michael@0: michael@0: --- Writing test code michael@0: michael@0: Here is a sample test: michael@0: michael@0: #include "tests.h" michael@0: michael@0: BEGIN_TEST(testIntString_bug515273) michael@0: { michael@0: jsval v; michael@0: EVAL("'42';", &v); michael@0: michael@0: JSString *str = JSVAL_TO_STRING(v); michael@0: const char *bytes = JS_GetStringBytes(str); michael@0: CHECK(strcmp(bytes, "42") == 0); michael@0: return true; michael@0: } michael@0: END_TEST(testIntString_bug515273) michael@0: michael@0: The BEGIN_TEST and END_TEST macros bracket each test. By convention, the test michael@0: name is _. (The above test is in testIntString.cpp.) michael@0: michael@0: The curly braces are required. This block is the body of a C++ member function michael@0: that returns bool. The test harness calls this member function michael@0: automatically. If the function returns true, the test passes. False, it fails. michael@0: michael@0: JSAPI tests often need extra global C/C++ code: a JSClass, a getter or setter michael@0: function, a resolve hook. Put these before the BEGIN_TEST macro. michael@0: michael@0: The body of the test can use these member variables and macros, defined in michael@0: tests.h: michael@0: michael@0: JSRuntime *rt; michael@0: JSContext *cx; michael@0: JSObject *global; michael@0: michael@0: The test framework creates these fresh for each test. The default michael@0: environment has reasonable default settings, including michael@0: JSOPTION_VAROBJFIX, JSOPTION_JIT, a global object of a class with michael@0: JSCLASS_GLOBAL_FLAGS, and an error reporter that prints to stderr. michael@0: See also "Custom test setup" below. michael@0: michael@0: EXEC(const char *code); michael@0: michael@0: Execute some JS code in global scope, using JS_EvaluateScript. Return michael@0: false if that fails. (This means that if the code throws an uncaught JS michael@0: exception, the test fails.) michael@0: michael@0: EVAL(const char *code, jsval *vp); michael@0: michael@0: Same as EXEC, but store the result value in *vp. michael@0: michael@0: CHECK(bool cond); michael@0: michael@0: If the condition is not true, print an error message and return false, michael@0: failing the test. michael@0: michael@0: CHECK_SAME(jsval a, jsval b); michael@0: michael@0: If a and b are different values, print an error message and return michael@0: false, failing the test. michael@0: michael@0: This is like CHECK(sameValue(a, b)) but with a more detailed error michael@0: message. See sameValue below. michael@0: michael@0: bool knownFail; michael@0: michael@0: Set this to true if your test is known to fail. The test runner will michael@0: print a TEST-KNOWN-FAIL line rather than a TEST-UNEXPECTED-FAIL michael@0: line. This way you can check in a test illustrating a bug ahead of the michael@0: fix. michael@0: michael@0: If your test actually crashes the process or triggers an assertion, michael@0: this of course will not help, so you should add something like michael@0: michael@0: knownFail = true; // see bug 123456 michael@0: return false; // the code below crashes! michael@0: michael@0: as the first two lines of the test. michael@0: michael@0: bool isNegativeZero(jsval v); michael@0: bool isNaN(jsval v); michael@0: michael@0: Self-explanatory. michael@0: michael@0: bool sameValue(jsval v1, jsval v2); michael@0: michael@0: True if v1 and v2 are the same value according to the ES5 SameValue() michael@0: function, to wit: michael@0: michael@0: SameValue(NaN, NaN) is true. michael@0: SameValue(-0, 0) is false. michael@0: Otherwise SameValue(a, b) iff a === b. michael@0: michael@0: michael@0: --- Custom test setup michael@0: michael@0: Before executing each test, the test framework calls the tests' init() member michael@0: function, which populates the rt, cx, and global member variables. michael@0: michael@0: A test can customize the test setup process by overloading virtual member michael@0: functions, like this: michael@0: michael@0: const JSClass globalClassWithResolve = { ... }; michael@0: michael@0: BEGIN_TEST(testGlobalResolveHook) michael@0: { michael@0: RootedValue v; michael@0: EVAL("v", v.address()); michael@0: CHECK_SAME(v, JSVAL_VOID); michael@0: return true; michael@0: } michael@0: michael@0: // Other class members can go here. michael@0: michael@0: // This one overloads a base-class method. michael@0: virtual JSClass *getGlobalJSClass() { michael@0: return &globalClassWithResolve; michael@0: } michael@0: END_TEST(testGlobalResolveHook) michael@0: michael@0: The overloadable member functions are: michael@0: michael@0: virtual bool init(); michael@0: virtual void uninit(); michael@0: virtual JSRuntime * createRuntime(); michael@0: virtual JSContext * createContext(); michael@0: virtual JSClass * getGlobalClass(); michael@0: virtual JSObject * createGlobal(); michael@0: