зеркало из https://github.com/mozilla/gecko-dev.git
Bug 505798 - JSAPI test harness. r=Waldo.
This commit is contained in:
Родитель
e2597decfa
Коммит
49208058af
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
Загрузка…
Ссылка в новой задаче