LCOV - app.info - js/src/jsapi-tests/tests.h

LCOV - code coverage report
| Current view: | directory - js/src/jsapi-tests - tests.h (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 176 | 103 | 58.5 %
| Date: | 2012-04-21 | Functions: | 54 | 34 | 63.0 %

           1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
           2                 :  * vim: set ts=8 sw=4 et tw=99:
           3                 :  *
           4                 :  * ***** BEGIN LICENSE BLOCK *****
           5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           6                 :  *
           7                 :  * The contents of this file are subject to the Mozilla Public License Version
           8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           9                 :  * the License. You may obtain a copy of the License at
          10                 :  * http://www.mozilla.org/MPL/
          11                 :  *
          12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          14                 :  * for the specific language governing rights and limitations under the
          15                 :  * License.
          16                 :  *
          17                 :  * The Original Code is JSAPI tests.
          18                 :  *
          19                 :  * The Initial Developer of the Original Code is
          20                 :  * Mozilla Corporation.
          21                 :  * Portions created by the Initial Developer are Copyright (C) 2009
          22                 :  * the Initial Developer. All Rights Reserved.
          23                 :  *
          24                 :  * Contributor(s):
          25                 :  *     Jason Orendorff
          26                 :  *
          27                 :  * Alternatively, the contents of this file may be used under the terms of
          28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
          29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          31                 :  * of those above. If you wish to allow use of your version of this file only
          32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          33                 :  * use your version of this file under the terms of the MPL, indicate your
          34                 :  * decision by deleting the provisions above and replace them with the notice
          35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          36                 :  * the provisions above, a recipient may use your version of this file under
          37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          38                 :  *
          39                 :  * ***** END LICENSE BLOCK ***** */
          40                 :
          41                 : #include "mozilla/Util.h"
          42                 :
          43                 : #include "jsapi.h"
          44                 : #include "jsprvtd.h"
          45                 : #include "jsalloc.h"
          46                 :
          47                 : #include "js/Vector.h"
          48                 :
          49                 : #include <errno.h>
          50                 : #include <string.h>
          51                 : #include <stdio.h>
          52                 : #include <stdlib.h>
          53                 :
          54                 : class jsvalRoot
          55                 : {
          56                 :   public:
          57             171 :     explicit jsvalRoot(JSContext *context, jsval value = JSVAL_NULL)
          58             171 :         : cx(context), v(value)
          59                 :     {
          60             171 :         if (!JS_AddValueRoot(cx, &v)) {
          61               0 :             fprintf(stderr, "Out of memory in jsvalRoot constructor, aborting\n");
          62               0 :             abort();
          63                 :         }
          64             171 :     }
          65                 :
          66             171 :     ~jsvalRoot() { JS_RemoveValueRoot(cx, &v); }
          67                 :
          68             227 :     operator jsval() const { return value(); }
          69                 :
          70             108 :     jsvalRoot & operator=(jsval value) {
          71             108 :         v = value;
          72             108 :         return *this;
          73                 :     }
          74                 :
          75              75 :     jsval * addr() { return &v; }
          76             248 :     jsval value() const { return v; }
          77                 :
          78                 :   private:
          79                 :     JSContext *cx;
          80                 :     jsval v;
          81                 : };
          82                 :
          83                 : /* Note: Aborts on OOM. */
          84              92 : class JSAPITestString {
          85                 :     js::Vector<char, 0, js::SystemAllocPolicy> chars;
          86                 :   public:
          87              92 :     JSAPITestString() {}
          88               0 :     JSAPITestString(const char *s) { *this += s; }
          89               0 :     JSAPITestString(const JSAPITestString &s) { *this += s; }
          90                 :
          91               0 :     const char *begin() const { return chars.begin(); }
          92                 :     const char *end() const { return chars.end(); }
          93               0 :     size_t length() const { return chars.length(); }
          94                 :
          95               0 :     JSAPITestString & operator +=(const char *s) {
          96               0 :         if (!chars.append(s, strlen(s)))
          97               0 :             abort();
          98               0 :         return *this;
          99                 :     }
         100                 :
         101               0 :     JSAPITestString & operator +=(const JSAPITestString &s) {
         102               0 :         if (!chars.append(s.begin(), s.length()))
         103               0 :             abort();
         104               0 :         return *this;
         105                 :     }
         106                 : };
         107                 :
         108               0 : inline JSAPITestString operator+(JSAPITestString a, const char *b) { return a += b; }
         109               0 : inline JSAPITestString operator+(JSAPITestString a, const JSAPITestString &b) { return a += b; }
         110                 :
         111                 : class JSAPITest
         112                 : {
         113                 :   public:
         114                 :     static JSAPITest *list;
         115                 :     JSAPITest *next;
         116                 :
         117                 :     JSRuntime *rt;
         118                 :     JSContext *cx;
         119                 :     JSObject *global;
         120                 :     bool knownFail;
         121                 :     JSAPITestString msgs;
         122                 :     JSCrossCompartmentCall *call;
         123                 :
         124              92 :     JSAPITest() : rt(NULL), cx(NULL), global(NULL), knownFail(false), call(NULL) {
         125              92 :         next = list;
         126              92 :         list = this;
         127              92 :     }
         128                 :
         129              92 :     virtual ~JSAPITest() { uninit(); }
         130                 :
         131              92 :     virtual bool init() {
         132              92 :         rt = createRuntime();
         133              92 :         if (!rt)
         134               0 :             return false;
         135              92 :         cx = createContext();
         136              92 :         if (!cx)
         137               0 :             return false;
         138              92 :         JS_BeginRequest(cx);
         139              92 :         global = createGlobal();
         140              92 :         if (!global)
         141               0 :             return false;
         142              92 :         call = JS_EnterCrossCompartmentCall(cx, global);
         143              92 :         return call != NULL;
         144                 :     }
         145                 :
         146             184 :     virtual void uninit() {
         147             184 :         if (call) {
         148              92 :             JS_LeaveCrossCompartmentCall(call);
         149              92 :             call = NULL;
         150                 :         }
         151             184 :         if (cx) {
         152              92 :             JS_EndRequest(cx);
         153              92 :             JS_DestroyContext(cx);
         154              92 :             cx = NULL;
         155                 :         }
         156             184 :         if (rt) {
         157              92 :             destroyRuntime();
         158              92 :             rt = NULL;
         159                 :         }
         160             184 :     }
         161                 :
         162                 :     virtual const char * name() = 0;
         163                 :     virtual bool run() = 0;
         164                 :
         165                 : #define EXEC(s) do { if (!exec(s, __FILE__, __LINE__)) return false; } while (false)
         166                 :
         167              27 :     bool exec(const char *bytes, const char *filename, int lineno) {
         168              54 :         jsvalRoot v(cx);
         169              27 :         return JS_EvaluateScript(cx, global, bytes, strlen(bytes), filename, lineno, v.addr()) ||
         170              54 :                fail(bytes, filename, lineno);
         171                 :     }
         172                 :
         173                 : #define EVAL(s, vp) do { if (!evaluate(s, __FILE__, __LINE__, vp)) return false; } while (false)
         174                 :
         175             127 :     bool evaluate(const char *bytes, const char *filename, int lineno, jsval *vp) {
         176             127 :         return JS_EvaluateScript(cx, global, bytes, strlen(bytes), filename, lineno, vp) ||
         177             254 :                fail(bytes, filename, lineno);
         178                 :     }
         179                 :
         180               0 :     JSAPITestString jsvalToSource(jsval v) {
         181               0 :         JSString *str = JS_ValueToSource(cx, v);
         182               0 :         if (str) {
         183               0 :             JSAutoByteString bytes(cx, str);
         184               0 :             if (!!bytes)
         185               0 :                 return JSAPITestString(bytes.ptr());
         186                 :         }
         187               0 :         JS_ClearPendingException(cx);
         188               0 :         return JSAPITestString("<<error converting value to string>>");
         189                 :     }
         190                 :
         191               0 :     JSAPITestString toSource(long v) {
         192                 :         char buf[40];
         193               0 :         sprintf(buf, "%ld", v);
         194               0 :         return JSAPITestString(buf);
         195                 :     }
         196                 :
         197               0 :     JSAPITestString toSource(unsigned long v) {
         198                 :         char buf[40];
         199               0 :         sprintf(buf, "%lu", v);
         200               0 :         return JSAPITestString(buf);
         201                 :     }
         202                 :
         203                 :     JSAPITestString toSource(long long v) {
         204                 :         char buf[40];
         205                 :         sprintf(buf, "%lld", v);
         206                 :         return JSAPITestString(buf);
         207                 :     }
         208                 :
         209                 :     JSAPITestString toSource(unsigned long long v) {
         210                 :         char buf[40];
         211                 :         sprintf(buf, "%llu", v);
         212                 :         return JSAPITestString(buf);
         213                 :     }
         214                 :
         215               0 :     JSAPITestString toSource(unsigned int v) {
         216               0 :         return toSource((unsigned long)v);
         217                 :     }
         218                 :
         219               0 :     JSAPITestString toSource(int v) {
         220               0 :         return toSource((long)v);
         221                 :     }
         222                 :
         223               0 :     JSAPITestString toSource(bool v) {
         224               0 :         return JSAPITestString(v ? "true" : "false");
         225                 :     }
         226                 :
         227               0 :     JSAPITestString toSource(JSAtom *v) {
         228               0 :         return jsvalToSource(STRING_TO_JSVAL((JSString*)v));
         229                 :     }
         230                 :
         231               0 :     JSAPITestString toSource(JSVersion v) {
         232               0 :         return JSAPITestString(JS_VersionToString(v));
         233                 :     }
         234                 :
         235                 :     template<typename T>
         236              47 :     bool checkEqual(const T &actual, const T &expected,
         237                 :                     const char *actualExpr, const char *expectedExpr,
         238                 :                     const char *filename, int lineno) {
         239                 :         return (actual == expected) ||
         240                 :             fail(JSAPITestString("CHECK_EQUAL failed: expected (") +
         241                 :                  expectedExpr + ") = " + toSource(expected) +
         242              47 :                  ", got (" + actualExpr + ") = " + toSource(actual), filename, lineno);
         243                 :     }
         244                 :
         245                 :     // There are many cases where the static types of 'actual' and 'expected'
         246                 :     // are not identical, and C++ is understandably cautious about automatic
         247                 :     // coercions. So catch those cases and forcibly coerce, then use the
         248                 :     // identical-type specialization. This may do bad things if the types are
         249                 :     // actually *not* compatible.
         250                 :     template<typename T, typename U>
         251              25 :     bool checkEqual(const T &actual, const U &expected,
         252                 :                    const char *actualExpr, const char *expectedExpr,
         253                 :                    const char *filename, int lineno) {
         254              25 :         return checkEqual(U(actual), expected, actualExpr, expectedExpr, filename, lineno);
         255                 :     }
         256                 :
         257                 : #define CHECK_EQUAL(actual, expected) \
         258                 :     do { \
         259                 :         if (!checkEqual(actual, expected, #actual, #expected, __FILE__, __LINE__)) \
         260                 :             return false; \
         261                 :     } while (false)
         262                 :
         263            1531 :     bool checkSame(jsval actual, jsval expected,
         264                 :                    const char *actualExpr, const char *expectedExpr,
         265                 :                    const char *filename, int lineno) {
         266                 :         JSBool same;
         267            1531 :         return (JS_SameValue(cx, actual, expected, &same) && same) ||
         268               0 :                fail(JSAPITestString("CHECK_SAME failed: expected JS_SameValue(cx, ") +
         269               0 :                     actualExpr + ", " + expectedExpr + "), got !JS_SameValue(cx, " +
         270           10717 :                     jsvalToSource(actual) + ", " + jsvalToSource(expected) + ")", filename, lineno);
         271                 :     }
         272                 :
         273                 : #define CHECK_SAME(actual, expected) \
         274                 :     do { \
         275                 :         if (!checkSame(actual, expected, #actual, #expected, __FILE__, __LINE__)) \
         276                 :             return false; \
         277                 :     } while (false)
         278                 :
         279                 : #define CHECK(expr) \
         280                 :     do { \
         281                 :         if (!(expr)) \
         282                 :             return fail("CHECK failed: " #expr, __FILE__, __LINE__); \
         283                 :     } while (false)
         284                 :
         285               0 :     bool fail(JSAPITestString msg = JSAPITestString(), const char *filename = "-", int lineno = 0) {
         286               0 :         if (JS_IsExceptionPending(cx)) {
         287               0 :             jsvalRoot v(cx);
         288               0 :             JS_GetPendingException(cx, v.addr());
         289               0 :             JS_ClearPendingException(cx);
         290               0 :             JSString *s = JS_ValueToString(cx, v);
         291               0 :             if (s) {
         292               0 :                 JSAutoByteString bytes(cx, s);
         293               0 :                 if (!!bytes)
         294               0 :                     msg += bytes.ptr();
         295                 :             }
         296                 :         }
         297               0 :         fprintf(stderr, "%s:%d:%.*s\n", filename, lineno, (int) msg.length(), msg.begin());
         298               0 :         msgs += msg;
         299               0 :         return false;
         300                 :     }
         301                 :
         302               0 :     JSAPITestString messages() const { return msgs; }
         303                 :
         304             102 :     static JSClass * basicGlobalClass() {
         305                 :         static JSClass c = {
         306                 :             "global", JSCLASS_GLOBAL_FLAGS,
         307                 :             JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
         308                 :             JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
         309                 :             JSCLASS_NO_OPTIONAL_MEMBERS
         310                 :         };
         311             102 :         return &c;
         312                 :     }
         313                 :
         314                 :   protected:
         315                 :     static JSBool
         316                 :     print(JSContext *cx, unsigned argc, jsval *vp)
         317                 :     {
         318                 :         jsval *argv = JS_ARGV(cx, vp);
         319                 :         for (unsigned i = 0; i < argc; i++) {
         320                 :             JSString *str = JS_ValueToString(cx, argv[i]);
         321                 :             if (!str)
         322                 :                 return JS_FALSE;
         323                 :             char *bytes = JS_EncodeString(cx, str);
         324                 :             if (!bytes)
         325                 :                 return JS_FALSE;
         326                 :             printf("%s%s", i ? " " : "", bytes);
         327                 :             JS_free(cx, bytes);
         328                 :         }
         329                 :
         330                 :         putchar('\n');
         331                 :         fflush(stdout);
         332                 :         JS_SET_RVAL(cx, vp, JSVAL_VOID);
         333                 :         return JS_TRUE;
         334                 :     }
         335                 :
         336                 :     bool definePrint() {
         337                 :         return JS_DefineFunction(cx, global, "print", (JSNative) print, 0, 0);
         338                 :     }
         339                 :
         340              90 :     virtual JSRuntime * createRuntime() {
         341              90 :         JSRuntime *rt = JS_NewRuntime(8L * 1024 * 1024);
         342              90 :         if (!rt)
         343               0 :             return NULL;
         344                 :
         345                 :         const size_t MAX_STACK_SIZE =
         346                 : /* Assume we can't use more than 5e5 bytes of C stack by default. */
         347                 : #if (defined(DEBUG) && defined(__SUNPRO_CC))  || defined(JS_CPU_SPARC)
         348                 :             /*
         349                 :              * Sun compiler uses a larger stack space for js::Interpret() with
         350                 :              * debug.  Use a bigger gMaxStackSize to make "make check" happy.
         351                 :              */
         352                 :             5000000
         353                 : #else
         354              90 :             500000
         355                 : #endif
         356                 :         ;
         357                 :
         358              90 :         JS_SetNativeStackQuota(rt, MAX_STACK_SIZE);
         359              90 :         return rt;
         360                 :     }
         361                 :
         362              91 :     virtual void destroyRuntime() {
         363              91 :         JS_ASSERT(!cx);
         364              91 :         JS_ASSERT(rt);
         365              91 :         JS_DestroyRuntime(rt);
         366              91 :     }
         367                 :
         368               0 :     static void reportError(JSContext *cx, const char *message, JSErrorReport *report) {
         369                 :         fprintf(stderr, "%s:%u:%s\n",
         370                 :                 report->filename ? report->filename : "<no filename>",
         371                 :                 (unsigned int) report->lineno,
         372               0 :                 message);
         373               0 :     }
         374                 :
         375              92 :     virtual JSContext * createContext() {
         376              92 :         JSContext *cx = JS_NewContext(rt, 8192);
         377              92 :         if (!cx)
         378               0 :             return NULL;
         379              92 :         JS_SetOptions(cx, JSOPTION_VAROBJFIX);
         380              92 :         JS_SetVersion(cx, JSVERSION_LATEST);
         381              92 :         JS_SetErrorReporter(cx, &reportError);
         382              92 :         return cx;
         383                 :     }
         384                 :
         385             102 :     virtual JSClass * getGlobalClass() {
         386             102 :         return basicGlobalClass();
         387                 :     }
         388                 :
         389              96 :     virtual JSObject * createGlobal(JSPrincipals *principals = NULL) {
         390                 :         /* Create the global object. */
         391              96 :         JSObject *global = JS_NewCompartmentAndGlobalObject(cx, getGlobalClass(), principals);
         392              96 :         if (!global)
         393               0 :             return NULL;
         394                 :
         395             192 :         JSAutoEnterCompartment ac;
         396              96 :         if (!ac.enter(cx, global))
         397               0 :             return NULL;
         398                 :
         399                 :         /* Populate the global object with the standard globals,
         400                 :            like Object and Array. */
         401              96 :         if (!JS_InitStandardClasses(cx, global))
         402               0 :             return NULL;
         403              96 :         return global;
         404                 :     }
         405                 : };
         406                 :
         407                 : #define BEGIN_TEST(testname)                                            \
         408                 :     class cls_##testname : public JSAPITest {                           \
         409                 :       public:                                                           \
         410                 :         virtual const char * name() { return #testname; }               \
         411                 :         virtual bool run()
         412                 :
         413                 : #define END_TEST(testname)                                              \
         414                 :     };                                                                  \
         415                 :     static cls_##testname cls_##testname##_instance;
         416                 :
         417                 : /*
         418                 :  * A "fixture" is a subclass of JSAPITest that holds common definitions for a
         419                 :  * set of tests. Each test that wants to use the fixture should use
         420                 :  * BEGIN_FIXTURE_TEST and END_FIXTURE_TEST, just as one would use BEGIN_TEST and
         421                 :  * END_TEST, but include the fixture class as the first argument. The fixture
         422                 :  * class's declarations are then in scope for the test bodies.
         423                 :  */
         424                 :
         425                 : #define BEGIN_FIXTURE_TEST(fixture, testname)                           \
         426                 :     class cls_##testname : public fixture {                             \
         427                 :       public:                                                           \
         428                 :         virtual const char * name() { return #testname; }               \
         429                 :         virtual bool run()
         430                 :
         431                 : #define END_FIXTURE_TEST(fixture, testname)                             \
         432                 :     };                                                                  \
         433                 :     static cls_##testname cls_##testname##_instance;
         434                 :
         435                 : /*
         436                 :  * A class for creating and managing one temporary file.
         437                 :  *
         438                 :  * We could use the ISO C temporary file functions here, but those try to
         439                 :  * create files in the root directory on Windows, which fails for users
         440                 :  * without Administrator privileges.
         441                 :  */
         442                 : class TempFile {
         443                 :     const char *name;
         444                 :     FILE *stream;
         445                 :
         446                 :   public:
         447               5 :     TempFile() : name(), stream() { }
         448               5 :     ~TempFile() {
         449               5 :         if (stream)
         450               3 :             close();
         451               5 :         if (name)
         452               3 :             remove();
         453               5 :     }
         454                 :
         455                 :     /*
         456                 :      * Return a stream for a temporary file named |fileName|. Infallible.
         457                 :      * Use only once per TempFile instance. If the file is not explicitly
         458                 :      * closed and deleted via the member functions below, this object's
         459                 :      * destructor will clean them up.
         460                 :      */
         461               5 :     FILE *open(const char *fileName)
         462                 :     {
         463               5 :         stream = fopen(fileName, "wb+");
         464               5 :         if (!stream) {
         465                 :             fprintf(stderr, "error opening temporary file '%s': %s\n",
         466               0 :                     fileName, strerror(errno));
         467               0 :             exit(1);
         468                 :         }
         469               5 :         name = fileName;
         470               5 :         return stream;
         471                 :     }
         472                 :
         473                 :     /* Close the temporary file's stream. */
         474               5 :     void close() {
         475               5 :         if (fclose(stream) == EOF) {
         476                 :             fprintf(stderr, "error closing temporary file '%s': %s\n",
         477               0 :                     name, strerror(errno));
         478               0 :             exit(1);
         479                 :         }
         480               5 :         stream = NULL;
         481               5 :     }
         482                 :
         483                 :     /* Delete the temporary file. */
         484               5 :     void remove() {
         485               5 :         if (::remove(name) != 0) {
         486                 :             fprintf(stderr, "error deleting temporary file '%s': %s\n",
         487               0 :                     name, strerror(errno));
         488               0 :             exit(1);
         489                 :         }
         490               5 :         name = NULL;
         491               5 :     }
         492                 : };

Generated by: LCOV version 1.7