Bug 505798 - JSAPI test harness. r=Waldo.

This commit is contained in:
Jason Orendorff 2009-08-20 17:20:14 -05:00
Родитель e2597decfa
Коммит 49208058af
8 изменённых файлов: 524 добавлений и 0 удалений

Просмотреть файл

@ -59,6 +59,10 @@ ifndef JS_DISABLE_SHELL
DIRS += shell
endif
ifdef ENABLE_TESTS
DIRS += jsapi-tests
endif
MODULE = js
LIBRARY_NAME = mozjs
STATIC_LIBRARY_NAME = js_static

Просмотреть файл

@ -5215,6 +5215,7 @@ MAKEFILES="
Makefile
shell/Makefile
lirasm/Makefile
jsapi-tests/Makefile
config/Makefile
config/autoconf.mk
config/mkdepend/Makefile

Просмотреть файл

@ -0,0 +1,70 @@
# -*- Mode: makefile -*-
#
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Spidermonkey build system.
#
# The Initial Developer of the Original Code is
# The Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2009
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Jason Orendorff
#
# Alternatively, the contents of this file may be used under the terms of
# either of the GNU General Public License Version 2 or later (the "GPL"),
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
PROGRAM = jsapi-tests$(BIN_SUFFIX)
CPPSRCS = \
tests.cpp \
selfTest.cpp \
testPropCache.cpp \
testXDR.cpp \
$(NULL)
DEFINES += -DEXPORT_JS_API
LIBS = $(NSPR_LIBS) $(DEPTH)/$(LIB_PREFIX)js_static.$(LIB_SUFFIX)
LOCAL_INCLUDES += -I$(topsrcdir) -I..
ifdef _MSC_VER
ifdef WINCE
WIN32_EXE_LDFLAGS += -ENTRY:mainACRTStartup
endif
endif
include $(topsrcdir)/config/rules.mk
check::
$(wildcard $(RUN_TEST_PROGRAM)) $(DIST)/bin/jsapi-tests$(BIN_SUFFIX)

Просмотреть файл

@ -0,0 +1,22 @@
#include "tests.h"
BEGIN_TEST(selfTest_NaNsAreSame)
{
jsvalRoot v1(cx), v2(cx);
EVAL("0/0", v1.addr()); // NaN
CHECK_SAME(v1, v1);
EVAL("Math.sin('no')", v2.addr()); // also NaN
CHECK_SAME(v1, v2);
return true;
}
END_TEST(selfTest_NaNsAreSame)
BEGIN_TEST(selfTest_negativeZeroIsNotTheSameAsZero)
{
jsvalRoot negativeZero(cx);
EVAL("-0", negativeZero.addr());
CHECK(!sameValue(negativeZero, JSVAL_ZERO));
return true;
}
END_TEST(selfTest_negativeZeroIsNotTheSameAsZero)

Просмотреть файл

@ -0,0 +1,32 @@
#include "tests.h"
static int g_counter;
static JSBool
CounterAdd(JSContext *cx, JSObject *obj, jsval idval, jsval *vp)
{
g_counter++;
return JS_TRUE;
}
static JSClass CounterClass = {
"Counter", /* name */
0, /* flags */
CounterAdd, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
JSCLASS_NO_OPTIONAL_MEMBERS
};
BEGIN_TEST(testPropCache_bug505798)
{
g_counter = 0;
EXEC("var x = {};");
CHECK(JS_DefineObject(cx, global, "y", &CounterClass, NULL, JSPROP_ENUMERATE));
EXEC("var arr = [x, y];\n"
"for (var i = 0; i < arr.length; i++)\n"
" arr[i].p = 1;\n");
knownFail = true;
CHECK(g_counter == 1);
return true;
}
END_TEST(testPropCache_bug505798)

Просмотреть файл

@ -0,0 +1,52 @@
#include "tests.h"
#include "jsxdrapi.h"
BEGIN_TEST(testXDR_bug506491)
{
const char *s =
"function makeClosure(s, name, value) {\n"
" eval(s);\n"
" return let (n = name, v = value) function () { return String(v); };\n"
"}\n"
"var f = makeClosure('0;', 'status', 'ok');\n";
// compile
JSScript *script = JS_CompileScript(cx, global, s, strlen(s), __FILE__, __LINE__);
CHECK(script);
JSObject *scrobj = JS_NewScriptObject(cx, script);
CHECK(scrobj);
jsvalRoot v(cx, OBJECT_TO_JSVAL(scrobj));
// freeze
JSXDRState *w = JS_XDRNewMem(cx, JSXDR_ENCODE);
CHECK(w);
CHECK(JS_XDRScript(w, &script));
uint32 nbytes;
void *p = JS_XDRMemGetData(w, &nbytes);
CHECK(p);
void *frozen = malloc(nbytes);
CHECK(frozen);
memcpy(frozen, p, nbytes);
JS_XDRDestroy(w);
// thaw
script = NULL;
JSXDRState *r = JS_XDRNewMem(cx, JSXDR_DECODE);
JS_XDRMemSetData(r, frozen, nbytes);
CHECK(JS_XDRScript(r, &script));
JS_XDRDestroy(r); // this frees `frozen`
// execute
jsvalRoot v2(cx);
CHECK(JS_ExecuteScript(cx, global, script, v2.addr()));
// try to break the Block object that is the parent of f
JS_GC(cx);
// confirm
EVAL("f() === 'ok';\n", v2.addr());
jsvalRoot trueval(cx, JSVAL_TRUE);
CHECK_SAME(v2, trueval);
return true;
}
END_TEST(testXDR_bug506491)

Просмотреть файл

@ -0,0 +1,79 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=78:
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is JSAPI tests.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Jason Orendorff
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "tests.h"
#include <iostream>
using namespace std;
JSAPITest *JSAPITest::list;
int main()
{
int failures = 0;
for (JSAPITest *test = JSAPITest::list; test; test = test->next) {
string name = test->name();
cout << name << endl;
if (!test->init()) {
cout << "TEST-UNEXPECTED-FAIL | " << name << " | Failed to initialize." << endl;
failures++;
continue;
}
if (test->run()) {
cout << "TEST-PASS | " << name << " | ok" << endl;
} else {
cout << (test->knownFail ? "TEST-KNOWN-FAIL" : "TEST-UNEXPECTED-FAIL")
<< " | " << name << " | " << test->messages() << endl;
if (!test->knownFail)
failures++;
}
test->uninit();
}
if (failures) {
cout << "\n" << failures << " unexpected failure" << (failures == 1 ? "." : "s.") << endl;
return 1;
}
cout << "\nPassed." << endl;
return 0;
}

264
js/src/jsapi-tests/tests.h Normal file
Просмотреть файл

@ -0,0 +1,264 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=78:
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is JSAPI tests.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Jason Orendorff
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "jsapi.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
class jsvalRoot
{
public:
explicit jsvalRoot(JSContext *context, jsval value = JSVAL_NULL)
: cx(context), v(value)
{
if (!JS_AddRoot(cx, &v)) {
fprintf(stderr, "Out of memory in jsvalRoot constructor, aborting\n");
abort();
}
}
~jsvalRoot() { JS_RemoveRoot(cx, &v); }
operator jsval() const { return v; }
jsvalRoot & operator=(jsval value) {
v = value;
return *this;
}
jsval * addr() { return &v; }
private:
JSContext *cx;
jsval v;
};
class JSAPITest
{
public:
static JSAPITest *list;
JSAPITest *next;
JSRuntime *rt;
JSContext *cx;
JSObject *global;
bool knownFail;
std::string msgs;
JSAPITest() : rt(NULL), cx(NULL), global(NULL), knownFail(false) {
next = list;
list = this;
}
virtual ~JSAPITest() { uninit(); }
virtual bool init() {
rt = createRuntime();
if (!rt)
return false;
cx = createContext();
if (!cx)
return false;
global = createGlobal();
return global != NULL;
}
virtual void uninit() {
if (cx) {
JS_DestroyContext(cx);
cx = NULL;
}
if (rt) {
JS_DestroyRuntime(rt);
rt = NULL;
}
}
virtual const char * name() = 0;
virtual bool run() = 0;
bool isNegativeZero(jsval v) {
if (!JSVAL_IS_DOUBLE(v))
return false;
union {
uint64 u64;
jsdouble d;
} pun;
pun.d = *JSVAL_TO_DOUBLE(v);
return pun.d == jsdouble(-0.0) && pun.u64 != uint64(0);
}
bool isNaN(jsval v) {
if (!JSVAL_IS_DOUBLE(v))
return false;
jsdouble d = *JSVAL_TO_DOUBLE(v);
return d != d;
}
bool sameValue(jsval v1, jsval v2) {
if ((isNegativeZero(v1) && v2 == JSVAL_ZERO) ||
(isNegativeZero(v2) && v1 == JSVAL_ZERO)) {
return false;
}
if (isNaN(v1) && isNaN(v2))
return true;
return JS_StrictlyEqual(cx, v1, v2);
}
#define EXEC(s) do { if (!exec(s, __FILE__, __LINE__)) return false; } while (false)
bool exec(const char *bytes, const char *filename, int lineno) {
jsvalRoot v(cx);
return JS_EvaluateScript(cx, global, bytes, strlen(bytes), filename, lineno, v.addr()) ||
fail(bytes, filename, lineno);
return true;
}
#define EVAL(s, vp) do { if (!evaluate(s, __FILE__, __LINE__, vp)) return false; } while (false)
bool evaluate(const char *bytes, const char *filename, int lineno, jsval *vp) {
return JS_EvaluateScript(cx, global, bytes, strlen(bytes), filename, lineno, vp) ||
fail(bytes, filename, lineno);
}
std::string toSource(jsval v) {
JSString *str = JS_ValueToSource(cx, v);
if (str)
return std::string(JS_GetStringBytes(str));
JS_ClearPendingException(cx);
return std::string("<<error converting value to string>>");
}
#define CHECK_SAME(actual, expected) \
do { \
if (!checkSame(actual, expected, #actual, #expected, __FILE__, __LINE__)) \
return false; \
} while (false)
bool checkSame(jsval actual, jsval expected,
const char *actualExpr, const char *expectedExpr,
const char *filename, int lineno) {
return sameValue(actual, expected) ||
fail(std::string("CHECK_SAME failed: expected sameValue(") +
actualExpr + ", " + expectedExpr + "), got !sameValue(" +
toSource(actual) + ", " + toSource(expected) + ")", filename, lineno);
}
#define CHECK(expr) \
do { \
if (!(expr)) \
return fail("CHECK failed: " #expr, __FILE__, __LINE__); \
} while (false)
bool fail(std::string msg = std::string(), const char *filename = "-", int lineno = 0) {
if (JS_IsExceptionPending(cx)) {
jsvalRoot v(cx);
JS_GetPendingException(cx, v.addr());
JS_ClearPendingException(cx);
JSString *s = JS_ValueToString(cx, v);
if (s)
msg += JS_GetStringBytes(s);
}
fprintf(stderr, "%s:%d:%s\n", filename, lineno, msg.c_str());
msgs += msg;
return false;
}
std::string messages() const { return msgs; }
protected:
virtual JSRuntime * createRuntime() {
return JS_NewRuntime(8L * 1024 * 1024);
}
static void reportError(JSContext *cx, const char *message, JSErrorReport *report) {
fprintf(stderr, "%s:%u:%s\n",
report->filename ? report->filename : "<no filename>",
(unsigned int) report->lineno,
message);
}
virtual JSContext * createContext() {
JSContext *cx = JS_NewContext(rt, 8192);
if (!cx)
return NULL;
JS_SetOptions(cx, JSOPTION_VAROBJFIX);
JS_SetVersion(cx, JSVERSION_LATEST);
JS_SetErrorReporter(cx, &reportError);
return cx;
}
virtual JSClass * getGlobalClass() {
static JSClass basicGlobalClass = {
"global", JSCLASS_GLOBAL_FLAGS,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
JSCLASS_NO_OPTIONAL_MEMBERS
};
return &basicGlobalClass;
}
virtual JSObject * createGlobal() {
/* Create the global object. */
JSObject *global = JS_NewObject(cx, getGlobalClass(), NULL, NULL);
if (!global)
return NULL;
/* Populate the global object with the standard globals,
like Object and Array. */
if (!JS_InitStandardClasses(cx, global))
return NULL;
return global;
}
};
#define BEGIN_TEST(testname) \
class cls_##testname : public JSAPITest { \
public: \
virtual const char * name() { return #testname; } \
virtual bool run()
#define END_TEST(testname) \
}; \
static cls_##testname cls_##testname##_instance;