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-06-02 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