tests/auto/qscriptclass/tst_qscriptclass.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the test suite of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 
       
    43 #include <QtTest/QtTest>
       
    44 
       
    45 #include <QtScript/qscriptengine.h>
       
    46 #include <QtScript/qscriptclass.h>
       
    47 #include <QtScript/qscriptclasspropertyiterator.h>
       
    48 #include <QtScript/qscriptstring.h>
       
    49 #include <QtScript/qscriptvalueiterator.h>
       
    50 
       
    51 Q_DECLARE_METATYPE(QScriptContext*)
       
    52 Q_DECLARE_METATYPE(QScriptValueList)
       
    53 Q_DECLARE_METATYPE(QScriptValue)
       
    54 
       
    55 //TESTED_CLASS=
       
    56 //TESTED_FILES=script/qscriptclass.h script/qscriptclass.cpp script/qscriptclasspropertyiterator.h script/qscriptclasspropertyiterator.cpp
       
    57 
       
    58 class tst_QScriptClass : public QObject
       
    59 {
       
    60     Q_OBJECT
       
    61 
       
    62 public:
       
    63     tst_QScriptClass();
       
    64     virtual ~tst_QScriptClass();
       
    65 
       
    66 private slots:
       
    67     void newInstance();
       
    68     void getAndSetProperty();
       
    69     void enumerate();
       
    70     void extension();
       
    71 };
       
    72 
       
    73 tst_QScriptClass::tst_QScriptClass()
       
    74 {
       
    75 }
       
    76 
       
    77 tst_QScriptClass::~tst_QScriptClass()
       
    78 {
       
    79 }
       
    80 
       
    81 
       
    82 
       
    83 class TestClass : public QScriptClass
       
    84 {
       
    85 public:
       
    86     struct CustomProperty {
       
    87         QueryFlags qflags;
       
    88         uint id;
       
    89         QScriptValue::PropertyFlags pflags;
       
    90         QScriptValue value;
       
    91 
       
    92         CustomProperty(QueryFlags qf, uint i, QScriptValue::PropertyFlags pf,
       
    93                        const QScriptValue &val)
       
    94             : qflags(qf), id(i), pflags(pf), value(val) { }
       
    95     };
       
    96 
       
    97     enum CallableMode {
       
    98         NotCallable,
       
    99         CallableReturnsSum,
       
   100         CallableReturnsArgument,
       
   101         CallableReturnsInvalidVariant
       
   102     };
       
   103 
       
   104     TestClass(QScriptEngine *engine);
       
   105     ~TestClass();
       
   106 
       
   107     void addCustomProperty(const QScriptString &name, QueryFlags qflags,
       
   108                            uint id, QScriptValue::PropertyFlags pflags,
       
   109                            const QScriptValue &value);
       
   110     void removeCustomProperty(const QScriptString &name);
       
   111 
       
   112     QueryFlags queryProperty(const QScriptValue &object,
       
   113                              const QScriptString &name,
       
   114                              QueryFlags flags, uint *id);
       
   115 
       
   116     QScriptValue property(const QScriptValue &object,
       
   117                           const QScriptString &name, uint id);
       
   118 
       
   119     void setProperty(QScriptValue &object, const QScriptString &name,
       
   120                      uint id, const QScriptValue &value);
       
   121 
       
   122     QScriptValue::PropertyFlags propertyFlags(
       
   123         const QScriptValue &object, const QScriptString &name, uint id);
       
   124 
       
   125     QScriptClassPropertyIterator *newIterator(const QScriptValue &object);
       
   126 
       
   127     QScriptValue prototype() const;
       
   128 
       
   129     QString name() const;
       
   130 
       
   131     bool supportsExtension(Extension extension) const;
       
   132     QVariant extension(Extension extension,
       
   133                        const QVariant &argument = QVariant());
       
   134 
       
   135     QScriptValue lastQueryPropertyObject() const;
       
   136     QScriptString lastQueryPropertyName() const;
       
   137     QueryFlags lastQueryPropertyFlags() const;
       
   138 
       
   139     QScriptValue lastPropertyObject() const;
       
   140     QScriptString lastPropertyName() const;
       
   141     uint lastPropertyId() const;
       
   142 
       
   143     QScriptValue lastSetPropertyObject() const;
       
   144     QScriptString lastSetPropertyName() const;
       
   145     uint lastSetPropertyId() const;
       
   146     QScriptValue lastSetPropertyValue() const;
       
   147 
       
   148     QScriptValue lastPropertyFlagsObject() const;
       
   149     QScriptString lastPropertyFlagsName() const;
       
   150     uint lastPropertyFlagsId() const;
       
   151 
       
   152     QScriptClass::Extension lastExtensionType() const;
       
   153     QVariant lastExtensionArgument() const;
       
   154 
       
   155     void clearReceivedArgs();
       
   156 
       
   157     void setIterationEnabled(bool enable);
       
   158     bool isIterationEnabled() const;
       
   159 
       
   160     void setCallableMode(CallableMode mode);
       
   161     CallableMode callableMode() const;
       
   162 
       
   163     void setHasInstance(bool hasInstance);
       
   164     bool hasInstance() const;
       
   165 
       
   166 private:
       
   167     CustomProperty *findCustomProperty(const QScriptString &name);
       
   168 
       
   169     QHash<QScriptString, CustomProperty*> customProperties;
       
   170 
       
   171     QScriptValue m_lastQueryPropertyObject;
       
   172     QScriptString m_lastQueryPropertyName;
       
   173     QScriptClass::QueryFlags m_lastQueryPropertyFlags;
       
   174 
       
   175     QScriptValue m_lastPropertyObject;
       
   176     QScriptString m_lastPropertyName;
       
   177     uint m_lastPropertyId;
       
   178 
       
   179     QScriptValue m_lastSetPropertyObject;
       
   180     QScriptString m_lastSetPropertyName;
       
   181     uint m_lastSetPropertyId;
       
   182     QScriptValue m_lastSetPropertyValue;
       
   183 
       
   184     QScriptValue m_lastPropertyFlagsObject;
       
   185     QScriptString m_lastPropertyFlagsName;
       
   186     uint m_lastPropertyFlagsId;
       
   187 
       
   188     QScriptClass::Extension m_lastExtensionType;
       
   189     QVariant m_lastExtensionArgument;
       
   190 
       
   191     QScriptValue m_prototype;
       
   192     bool m_iterationEnabled;
       
   193     CallableMode m_callableMode;
       
   194     bool m_hasInstance;
       
   195 };
       
   196 
       
   197 class TestClassPropertyIterator : public QScriptClassPropertyIterator
       
   198 {
       
   199 public:
       
   200     TestClassPropertyIterator(const QHash<QScriptString, TestClass::CustomProperty*> &props,
       
   201                       const QScriptValue &object);
       
   202     ~TestClassPropertyIterator();
       
   203 
       
   204     bool hasNext() const;
       
   205     void next();
       
   206 
       
   207     bool hasPrevious() const;
       
   208     void previous();
       
   209 
       
   210     void toFront();
       
   211     void toBack();
       
   212 
       
   213     QScriptString name() const;
       
   214     uint id() const;
       
   215     QScriptValue::PropertyFlags flags() const;
       
   216 
       
   217 private:
       
   218     int m_index;
       
   219     int m_last;
       
   220     QHash<QScriptString, TestClass::CustomProperty*> m_props;
       
   221 };
       
   222 
       
   223 
       
   224 
       
   225 TestClass::TestClass(QScriptEngine *engine)
       
   226     : QScriptClass(engine), m_iterationEnabled(true),
       
   227       m_callableMode(NotCallable), m_hasInstance(false)
       
   228 {
       
   229     m_prototype = engine->newObject();
       
   230     clearReceivedArgs();
       
   231 }
       
   232 
       
   233 TestClass::~TestClass()
       
   234 {
       
   235     qDeleteAll(customProperties);
       
   236 }
       
   237 
       
   238 TestClass::CustomProperty* TestClass::findCustomProperty(const QScriptString &name)
       
   239 {
       
   240     QHash<QScriptString, CustomProperty*>::const_iterator it;
       
   241     it = customProperties.constFind(name);
       
   242     if (it == customProperties.constEnd())
       
   243         return 0;
       
   244     return it.value();
       
   245 
       
   246 }
       
   247 
       
   248 void TestClass::addCustomProperty(const QScriptString &name, QueryFlags qflags,
       
   249                                   uint id, QScriptValue::PropertyFlags pflags,
       
   250                                   const QScriptValue &value)
       
   251 {
       
   252     customProperties.insert(name, new CustomProperty(qflags, id, pflags, value));
       
   253 }
       
   254 
       
   255 void TestClass::removeCustomProperty(const QScriptString &name)
       
   256 {
       
   257     CustomProperty *prop = customProperties.take(name);
       
   258     if (prop)
       
   259         delete prop;
       
   260 }
       
   261 
       
   262 QScriptClass::QueryFlags TestClass::queryProperty(const QScriptValue &object,
       
   263                                     const QScriptString &name,
       
   264                                     QueryFlags flags, uint *id)
       
   265 {
       
   266     m_lastQueryPropertyObject = object;
       
   267     m_lastQueryPropertyName = name;
       
   268     m_lastQueryPropertyFlags = flags;
       
   269     CustomProperty *prop = findCustomProperty(name);
       
   270     if (!prop)
       
   271         return 0;
       
   272     *id = prop->id;
       
   273     return prop->qflags & flags;
       
   274 }
       
   275 
       
   276 QScriptValue TestClass::property(const QScriptValue &object,
       
   277                                  const QScriptString &name, uint id)
       
   278 {
       
   279     m_lastPropertyObject = object;
       
   280     m_lastPropertyName = name;
       
   281     m_lastPropertyId = id;
       
   282     CustomProperty *prop = findCustomProperty(name);
       
   283     if (!prop)
       
   284         return QScriptValue();
       
   285     return prop->value;
       
   286 }
       
   287 
       
   288 void TestClass::setProperty(QScriptValue &object, const QScriptString &name,
       
   289                             uint id, const QScriptValue &value)
       
   290 {
       
   291     m_lastSetPropertyObject = object;
       
   292     m_lastSetPropertyName = name;
       
   293     m_lastSetPropertyId = id;
       
   294     m_lastSetPropertyValue = value;
       
   295     CustomProperty *prop = findCustomProperty(name);
       
   296     if (!prop)
       
   297         return;
       
   298     prop->value = value;
       
   299 }
       
   300 
       
   301 QScriptValue::PropertyFlags TestClass::propertyFlags(
       
   302     const QScriptValue &object, const QScriptString &name, uint id)
       
   303 {
       
   304     m_lastPropertyFlagsObject = object;
       
   305     m_lastPropertyFlagsName = name;
       
   306     m_lastPropertyFlagsId = id;
       
   307     CustomProperty *prop = findCustomProperty(name);
       
   308     if (!prop)
       
   309         return 0;
       
   310     return prop->pflags;
       
   311 }
       
   312 
       
   313 QScriptClassPropertyIterator *TestClass::newIterator(const QScriptValue &object)
       
   314 {
       
   315     if (!m_iterationEnabled)
       
   316         return 0;
       
   317     return new TestClassPropertyIterator(customProperties, object);
       
   318 }
       
   319 
       
   320 QScriptValue TestClass::prototype() const
       
   321 {
       
   322     return m_prototype;
       
   323 }
       
   324 
       
   325 QString TestClass::name() const
       
   326 {
       
   327     return QLatin1String("TestClass");
       
   328 }
       
   329 
       
   330 bool TestClass::supportsExtension(Extension extension) const
       
   331 {
       
   332     if (extension == Callable)
       
   333         return (m_callableMode != NotCallable);
       
   334     if (extension == HasInstance)
       
   335         return m_hasInstance;
       
   336     return false;
       
   337 }
       
   338 
       
   339 QVariant TestClass::extension(Extension extension,
       
   340                               const QVariant &argument)
       
   341 {
       
   342     m_lastExtensionType = extension;
       
   343     m_lastExtensionArgument = argument;
       
   344     if (extension == Callable) {
       
   345         Q_ASSERT(m_callableMode != NotCallable);
       
   346         QScriptContext *ctx = qvariant_cast<QScriptContext*>(argument);
       
   347         if (m_callableMode == CallableReturnsSum) {
       
   348             qsreal sum = 0;
       
   349             for (int i = 0; i < ctx->argumentCount(); ++i)
       
   350                 sum += ctx->argument(i).toNumber();
       
   351             QScriptValueIterator it(ctx->thisObject());
       
   352             while (it.hasNext()) {
       
   353                 it.next();
       
   354                 sum += it.value().toNumber();
       
   355             }
       
   356             return sum;
       
   357         } else if (m_callableMode == CallableReturnsArgument) {
       
   358             return qVariantFromValue(ctx->argument(0));
       
   359         } else if (m_callableMode == CallableReturnsInvalidVariant) {
       
   360             return QVariant();
       
   361         }
       
   362     } else if (extension == HasInstance) {
       
   363         Q_ASSERT(m_hasInstance);
       
   364         QScriptValueList args = qvariant_cast<QScriptValueList>(argument);
       
   365         QScriptValue obj = args.at(0);
       
   366         QScriptValue value = args.at(1);
       
   367         return value.property("foo").equals(obj.property("foo"));
       
   368     }
       
   369     return QVariant();
       
   370 }
       
   371 
       
   372 QScriptValue TestClass::lastQueryPropertyObject() const
       
   373 {
       
   374     return m_lastQueryPropertyObject;
       
   375 }
       
   376 
       
   377 QScriptString TestClass::lastQueryPropertyName() const
       
   378 {
       
   379     return m_lastQueryPropertyName;
       
   380 }
       
   381 
       
   382 QScriptClass::QueryFlags TestClass::lastQueryPropertyFlags() const
       
   383 {
       
   384     return m_lastQueryPropertyFlags;
       
   385 }
       
   386 
       
   387 QScriptValue TestClass::lastPropertyObject() const
       
   388 {
       
   389     return m_lastPropertyObject;
       
   390 }
       
   391 
       
   392 QScriptString TestClass::lastPropertyName() const
       
   393 {
       
   394     return m_lastPropertyName;
       
   395 }
       
   396 
       
   397 uint TestClass::lastPropertyId() const
       
   398 {
       
   399     return m_lastPropertyId;
       
   400 }
       
   401 
       
   402 QScriptValue TestClass::lastSetPropertyObject() const
       
   403 {
       
   404     return m_lastSetPropertyObject;
       
   405 }
       
   406 
       
   407 QScriptString TestClass::lastSetPropertyName() const
       
   408 {
       
   409     return m_lastSetPropertyName;
       
   410 }
       
   411 
       
   412 uint TestClass::lastSetPropertyId() const
       
   413 {
       
   414     return m_lastSetPropertyId;
       
   415 }
       
   416 
       
   417 QScriptValue TestClass::lastSetPropertyValue() const
       
   418 {
       
   419     return m_lastSetPropertyValue;
       
   420 }
       
   421 
       
   422 QScriptValue TestClass::lastPropertyFlagsObject() const
       
   423 {
       
   424     return m_lastPropertyFlagsObject;
       
   425 }
       
   426 
       
   427 QScriptString TestClass::lastPropertyFlagsName() const
       
   428 {
       
   429     return m_lastPropertyFlagsName;
       
   430 }
       
   431 
       
   432 uint TestClass::lastPropertyFlagsId() const
       
   433 {
       
   434     return m_lastPropertyFlagsId;
       
   435 }
       
   436 
       
   437 QScriptClass::Extension TestClass::lastExtensionType() const
       
   438 {
       
   439     return m_lastExtensionType;
       
   440 }
       
   441 
       
   442 QVariant TestClass::lastExtensionArgument() const
       
   443 {
       
   444     return m_lastExtensionArgument;
       
   445 }
       
   446 
       
   447 void TestClass::clearReceivedArgs()
       
   448 {
       
   449     m_lastQueryPropertyObject = QScriptValue();
       
   450     m_lastQueryPropertyName = QScriptString();
       
   451     m_lastQueryPropertyFlags = 0;
       
   452 
       
   453     m_lastPropertyObject = QScriptValue();
       
   454     m_lastPropertyName = QScriptString();
       
   455     m_lastPropertyId = uint(-1);
       
   456 
       
   457     m_lastSetPropertyObject = QScriptValue();
       
   458     m_lastSetPropertyName = QScriptString();
       
   459     m_lastSetPropertyId = uint(-1);
       
   460     m_lastSetPropertyValue = QScriptValue();
       
   461 
       
   462     m_lastPropertyFlagsObject = QScriptValue();
       
   463     m_lastPropertyFlagsName = QScriptString();
       
   464     m_lastPropertyFlagsId = uint(-1);
       
   465 
       
   466     m_lastExtensionType = static_cast<QScriptClass::Extension>(-1);
       
   467     m_lastExtensionArgument = QVariant();
       
   468 }
       
   469 
       
   470 void TestClass::setIterationEnabled(bool enable)
       
   471 {
       
   472     m_iterationEnabled = enable;
       
   473 }
       
   474 
       
   475 bool TestClass::isIterationEnabled() const
       
   476 {
       
   477     return m_iterationEnabled;
       
   478 }
       
   479 
       
   480 void TestClass::setCallableMode(CallableMode mode)
       
   481 {
       
   482     m_callableMode = mode;
       
   483 }
       
   484 
       
   485 TestClass::CallableMode TestClass::callableMode() const
       
   486 {
       
   487     return m_callableMode;
       
   488 }
       
   489 
       
   490 void TestClass::setHasInstance(bool hasInstance)
       
   491 {
       
   492     m_hasInstance = hasInstance;
       
   493 }
       
   494 
       
   495 bool TestClass::hasInstance() const
       
   496 {
       
   497     return m_hasInstance;
       
   498 }
       
   499 
       
   500 
       
   501 TestClassPropertyIterator::TestClassPropertyIterator(const QHash<QScriptString, TestClass::CustomProperty*> &props,
       
   502                                      const QScriptValue &object)
       
   503     : QScriptClassPropertyIterator(object)
       
   504 {
       
   505     m_props = props;
       
   506     toFront();
       
   507 }
       
   508 
       
   509 TestClassPropertyIterator::~TestClassPropertyIterator()
       
   510 {
       
   511 }
       
   512 
       
   513 bool TestClassPropertyIterator::hasNext() const
       
   514 {
       
   515     return m_index < m_props.size();
       
   516 }
       
   517 
       
   518 void TestClassPropertyIterator::next()
       
   519 {
       
   520     m_last = m_index;
       
   521     ++m_index;
       
   522 }
       
   523 
       
   524 bool TestClassPropertyIterator::hasPrevious() const
       
   525 {
       
   526     return m_index > 0;
       
   527 }
       
   528 
       
   529 void TestClassPropertyIterator::previous()
       
   530 {
       
   531     --m_index;
       
   532     m_last = m_index;
       
   533 }
       
   534 
       
   535 void TestClassPropertyIterator::toFront()
       
   536 {
       
   537     m_index = 0;
       
   538     m_last = -1;
       
   539 }
       
   540 
       
   541 void TestClassPropertyIterator::toBack()
       
   542 {
       
   543     m_index = m_props.size();
       
   544     m_last = -1;
       
   545 }
       
   546 
       
   547 QScriptString TestClassPropertyIterator::name() const
       
   548 {
       
   549     return m_props.keys().value(m_last);
       
   550 }
       
   551 
       
   552 uint TestClassPropertyIterator::id() const
       
   553 {
       
   554     QScriptString key = m_props.keys().value(m_last);
       
   555     if (!key.isValid())
       
   556         return 0;
       
   557     TestClass::CustomProperty *prop = m_props.value(key);
       
   558     return prop->id;
       
   559 }
       
   560 
       
   561 QScriptValue::PropertyFlags TestClassPropertyIterator::flags() const
       
   562 {
       
   563     QScriptString key = m_props.keys().value(m_last);
       
   564     if (!key.isValid())
       
   565         return 0;
       
   566     TestClass::CustomProperty *prop = m_props.value(key);
       
   567     return prop->pflags;
       
   568 }
       
   569 
       
   570 
       
   571 
       
   572 void tst_QScriptClass::newInstance()
       
   573 {
       
   574     QScriptEngine eng;
       
   575 
       
   576     TestClass cls(&eng);
       
   577 
       
   578     QScriptValue obj1 = eng.newObject(&cls);
       
   579     QVERIFY(!obj1.data().isValid());
       
   580     QVERIFY(obj1.prototype().strictlyEquals(cls.prototype()));
       
   581     QEXPECT_FAIL("", "classname is not implemented", Continue);
       
   582     QCOMPARE(obj1.toString(), QString::fromLatin1("[object TestClass]"));
       
   583     QCOMPARE(obj1.scriptClass(), (QScriptClass*)&cls);
       
   584 
       
   585     QScriptValue num(&eng, 456);
       
   586     QScriptValue obj2 = eng.newObject(&cls, num);
       
   587     QVERIFY(obj2.data().strictlyEquals(num));
       
   588     QVERIFY(obj2.prototype().strictlyEquals(cls.prototype()));
       
   589     QCOMPARE(obj2.scriptClass(), (QScriptClass*)&cls);
       
   590 
       
   591     QScriptValue obj3 = eng.newObject();
       
   592     QCOMPARE(obj3.scriptClass(), (QScriptClass*)0);
       
   593     obj3.setScriptClass(&cls);
       
   594     QCOMPARE(obj3.scriptClass(), (QScriptClass*)&cls);
       
   595 
       
   596     obj3.setScriptClass(0);
       
   597     QCOMPARE(obj3.scriptClass(), (QScriptClass*)0);
       
   598     obj3.setScriptClass(&cls);
       
   599     QCOMPARE(obj3.scriptClass(), (QScriptClass*)&cls);
       
   600 
       
   601     TestClass cls2(&eng);
       
   602     obj3.setScriptClass(&cls2);
       
   603     QCOMPARE(obj3.scriptClass(), (QScriptClass*)&cls2);
       
   604 
       
   605     // undefined behavior really, but shouldn't crash
       
   606     QScriptValue arr = eng.newArray();
       
   607     QVERIFY(arr.isArray());
       
   608     QCOMPARE(arr.scriptClass(), (QScriptClass*)0);
       
   609     QTest::ignoreMessage(QtWarningMsg, "QScriptValue::setScriptClass() failed: cannot change class of non-QScriptObject");
       
   610     arr.setScriptClass(&cls);
       
   611     QEXPECT_FAIL("", "Changing class of arbitrary script object is not allowed (it's OK)", Continue);
       
   612     QCOMPARE(arr.scriptClass(), (QScriptClass*)&cls);
       
   613     QEXPECT_FAIL("", "Changing class of arbitrary script object is not allowed (it's OK)", Continue);
       
   614     QVERIFY(!arr.isArray());
       
   615     QVERIFY(arr.isObject());
       
   616 }
       
   617 
       
   618 void tst_QScriptClass::getAndSetProperty()
       
   619 {
       
   620     QScriptEngine eng;
       
   621 
       
   622     TestClass cls(&eng);
       
   623 
       
   624     QScriptValue obj1 = eng.newObject(&cls);
       
   625     QScriptValue obj2 = eng.newObject(&cls);
       
   626     QScriptString foo = eng.toStringHandle("foo");
       
   627     QScriptString bar = eng.toStringHandle("bar");
       
   628     QScriptValue num(&eng, 123);
       
   629 
       
   630     // should behave just like normal
       
   631     for (int x = 0; x < 2; ++x) {
       
   632         QScriptValue &o = (x == 0) ? obj1 : obj2;
       
   633         for (int y = 0; y < 2; ++y) {
       
   634             QScriptString &s = (y == 0) ? foo : bar;
       
   635 
       
   636             // read property
       
   637             cls.clearReceivedArgs();
       
   638             QScriptValue ret = o.property(s);
       
   639             QVERIFY(!ret.isValid());
       
   640             QVERIFY(cls.lastQueryPropertyObject().strictlyEquals(o));
       
   641             QVERIFY(cls.lastQueryPropertyName() == s);
       
   642             QVERIFY(!cls.lastPropertyObject().isValid());
       
   643             QVERIFY(!cls.lastSetPropertyObject().isValid());
       
   644             QVERIFY(cls.lastQueryPropertyFlags() == QScriptClass::HandlesReadAccess);
       
   645 
       
   646             // write property
       
   647             cls.clearReceivedArgs();
       
   648             o.setProperty(s, num);
       
   649             QVERIFY(cls.lastQueryPropertyObject().strictlyEquals(o));
       
   650             QVERIFY(cls.lastQueryPropertyName() == s);
       
   651             QVERIFY(!cls.lastPropertyObject().isValid());
       
   652             QVERIFY(!cls.lastSetPropertyObject().isValid());
       
   653             QVERIFY(cls.lastQueryPropertyFlags() == QScriptClass::HandlesWriteAccess);
       
   654 
       
   655             // re-read property
       
   656             // When a QScriptClass doesn't want to handle a property write,
       
   657             // that property becomes a normal property and the QScriptClass
       
   658             // shall not be queried about it again.
       
   659             cls.clearReceivedArgs();
       
   660             QVERIFY(o.property(s).strictlyEquals(num));
       
   661             QVERIFY(!cls.lastQueryPropertyObject().isValid());
       
   662         }
       
   663     }
       
   664 
       
   665     // add a custom property
       
   666     QScriptString foo2 = eng.toStringHandle("foo2");
       
   667     const uint foo2Id = 123;
       
   668     const QScriptValue::PropertyFlags foo2Pflags = QScriptValue::Undeletable;
       
   669     QScriptValue foo2Value(&eng, 456);
       
   670     cls.addCustomProperty(foo2, QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess,
       
   671                           foo2Id, foo2Pflags, foo2Value);
       
   672 
       
   673     {
       
   674         // read property
       
   675         cls.clearReceivedArgs();
       
   676         {
       
   677             QScriptValue ret = obj1.property(foo2);
       
   678             QVERIFY(ret.strictlyEquals(foo2Value));
       
   679         }
       
   680         QVERIFY(cls.lastQueryPropertyObject().strictlyEquals(obj1));
       
   681         QVERIFY(cls.lastQueryPropertyName() == foo2);
       
   682         QVERIFY(cls.lastPropertyObject().strictlyEquals(obj1));
       
   683         QVERIFY(cls.lastPropertyName() == foo2);
       
   684         QCOMPARE(cls.lastPropertyId(), foo2Id);
       
   685 
       
   686         // read flags
       
   687         cls.clearReceivedArgs();
       
   688         QCOMPARE(obj1.propertyFlags(foo2), foo2Pflags);
       
   689         QVERIFY(cls.lastQueryPropertyObject().strictlyEquals(obj1));
       
   690         QVERIFY(cls.lastQueryPropertyName() == foo2);
       
   691         QVERIFY(!cls.lastPropertyObject().isValid());
       
   692         QVERIFY(cls.lastPropertyFlagsObject().strictlyEquals(obj1));
       
   693         QVERIFY(cls.lastPropertyFlagsName() == foo2);
       
   694         QCOMPARE(cls.lastPropertyFlagsId(), foo2Id);
       
   695 
       
   696         // write property
       
   697         cls.clearReceivedArgs();
       
   698         QScriptValue newFoo2Value(&eng, 789);
       
   699         obj1.setProperty(foo2, newFoo2Value);
       
   700         QVERIFY(cls.lastQueryPropertyObject().strictlyEquals(obj1));
       
   701         QVERIFY(cls.lastQueryPropertyName() == foo2);
       
   702 
       
   703         // read property again
       
   704         cls.clearReceivedArgs();
       
   705         {
       
   706             QScriptValue ret = obj1.property(foo2);
       
   707             QVERIFY(ret.strictlyEquals(newFoo2Value));
       
   708         }
       
   709         QVERIFY(cls.lastQueryPropertyObject().strictlyEquals(obj1));
       
   710         QVERIFY(cls.lastQueryPropertyName() == foo2);
       
   711         QVERIFY(cls.lastPropertyObject().strictlyEquals(obj1));
       
   712         QVERIFY(cls.lastPropertyName() == foo2);
       
   713         QCOMPARE(cls.lastPropertyId(), foo2Id);
       
   714     }
       
   715 
       
   716     // remove script class; normal properties should remain
       
   717     obj1.setScriptClass(0);
       
   718     QCOMPARE(obj1.scriptClass(), (QScriptClass*)0);
       
   719     QVERIFY(obj1.property(foo).equals(num));
       
   720     QVERIFY(obj1.property(bar).equals(num));
       
   721     obj1.setProperty(foo, QScriptValue());
       
   722     QVERIFY(!obj1.property(foo).isValid());
       
   723     obj1.setProperty(bar, QScriptValue());
       
   724     QVERIFY(!obj1.property(bar).isValid());
       
   725 }
       
   726 
       
   727 void tst_QScriptClass::enumerate()
       
   728 {
       
   729     QScriptEngine eng;
       
   730 
       
   731     TestClass cls(&eng);
       
   732 
       
   733     QScriptValue obj = eng.newObject(&cls);
       
   734     QScriptString foo = eng.toStringHandle("foo");
       
   735     obj.setProperty(foo, QScriptValue(&eng, 123));
       
   736 
       
   737     cls.setIterationEnabled(false);
       
   738     {
       
   739         QScriptValueIterator it(obj);
       
   740         QVERIFY(it.hasNext());
       
   741         it.next();
       
   742         QVERIFY(it.scriptName() == foo);
       
   743         QVERIFY(!it.hasNext());
       
   744     }
       
   745 
       
   746     // add a custom property
       
   747     QScriptString foo2 = eng.toStringHandle("foo2");
       
   748     const uint foo2Id = 123;
       
   749     const QScriptValue::PropertyFlags foo2Pflags = QScriptValue::Undeletable;
       
   750     QScriptValue foo2Value(&eng, 456);
       
   751     cls.addCustomProperty(foo2, QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess,
       
   752                           foo2Id, foo2Pflags, QScriptValue());
       
   753 
       
   754     cls.setIterationEnabled(true);
       
   755     QScriptValueIterator it(obj);
       
   756     for (int x = 0; x < 2; ++x) {
       
   757         QVERIFY(it.hasNext());
       
   758         it.next();
       
   759         QEXPECT_FAIL("", "", Abort);
       
   760         QVERIFY(it.scriptName() == foo);
       
   761         QVERIFY(it.hasNext());
       
   762         it.next();
       
   763         QVERIFY(it.scriptName() == foo2);
       
   764         QCOMPARE(it.flags(), foo2Pflags);
       
   765         QVERIFY(!it.hasNext());
       
   766 
       
   767         QVERIFY(it.hasPrevious());
       
   768         it.previous();
       
   769         QVERIFY(it.scriptName() == foo2);
       
   770         QCOMPARE(it.flags(), foo2Pflags);
       
   771         QVERIFY(it.hasPrevious());
       
   772         it.previous();
       
   773         QVERIFY(it.scriptName() == foo);
       
   774         QVERIFY(!it.hasPrevious());
       
   775     }
       
   776 }
       
   777 
       
   778 void tst_QScriptClass::extension()
       
   779 {
       
   780     QScriptEngine eng;
       
   781     {
       
   782         TestClass cls(&eng);
       
   783         cls.setCallableMode(TestClass::NotCallable);
       
   784         QVERIFY(!cls.supportsExtension(QScriptClass::Callable));
       
   785         QVERIFY(!cls.supportsExtension(QScriptClass::HasInstance));
       
   786         QScriptValue obj = eng.newObject(&cls);
       
   787         QVERIFY(!obj.call().isValid());
       
   788         QCOMPARE((int)cls.lastExtensionType(), -1);
       
   789         QVERIFY(!obj.instanceOf(obj));
       
   790         QCOMPARE((int)cls.lastExtensionType(), -1);
       
   791     }
       
   792     // Callable
       
   793     {
       
   794         TestClass cls(&eng);
       
   795         cls.setCallableMode(TestClass::CallableReturnsSum);
       
   796         QVERIFY(cls.supportsExtension(QScriptClass::Callable));
       
   797 
       
   798         QScriptValue obj = eng.newObject(&cls);
       
   799         obj.setProperty("one", QScriptValue(&eng, 1));
       
   800         obj.setProperty("two", QScriptValue(&eng, 2));
       
   801         obj.setProperty("three", QScriptValue(&eng, 3));
       
   802         cls.clearReceivedArgs();
       
   803         {
       
   804             QScriptValueList args;
       
   805             args << QScriptValue(&eng, 4) << QScriptValue(&eng, 5);
       
   806             QScriptValue ret = obj.call(obj, args);
       
   807             QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
       
   808             QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
       
   809             QVERIFY(ret.isNumber());
       
   810             QCOMPARE(ret.toNumber(), qsreal(15));
       
   811         }
       
   812 
       
   813         cls.setCallableMode(TestClass::CallableReturnsArgument);
       
   814         cls.clearReceivedArgs();
       
   815         {
       
   816             QScriptValue ret = obj.call(obj, QScriptValueList() << 123);
       
   817             QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
       
   818             QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
       
   819             QVERIFY(ret.isNumber());
       
   820             QCOMPARE(ret.toInt32(), 123);
       
   821         }
       
   822         cls.clearReceivedArgs();
       
   823         {
       
   824             QScriptValue ret = obj.call(obj, QScriptValueList() << true);
       
   825             QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
       
   826             QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
       
   827             QVERIFY(ret.isBoolean());
       
   828             QCOMPARE(ret.toBoolean(), true);
       
   829         }
       
   830         {
       
   831             QScriptValue ret = obj.call(obj, QScriptValueList() << QString::fromLatin1("ciao"));
       
   832             QVERIFY(ret.isString());
       
   833             QCOMPARE(ret.toString(), QString::fromLatin1("ciao"));
       
   834         }
       
   835         {
       
   836             QScriptValue objobj = eng.newObject();
       
   837             QScriptValue ret = obj.call(obj, QScriptValueList() << objobj);
       
   838             QVERIFY(ret.isObject());
       
   839             QVERIFY(ret.strictlyEquals(objobj));
       
   840         }
       
   841         {
       
   842             QScriptValue ret = obj.call(obj, QScriptValueList() << QScriptValue());
       
   843             QVERIFY(ret.isUndefined());
       
   844         }
       
   845 
       
   846         cls.setCallableMode(TestClass::CallableReturnsInvalidVariant);
       
   847         {
       
   848             QScriptValue ret = obj.call(obj);
       
   849             QVERIFY(ret.isUndefined());
       
   850         }
       
   851 
       
   852         // construct()
       
   853         cls.clearReceivedArgs();
       
   854         {
       
   855             QScriptValue ret = obj.construct();
       
   856             QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
       
   857             QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
       
   858             QVERIFY(ret.isObject());
       
   859         }
       
   860     }
       
   861     // HasInstance
       
   862     {
       
   863         TestClass cls(&eng);
       
   864         cls.setHasInstance(true);
       
   865         QVERIFY(cls.supportsExtension(QScriptClass::HasInstance));
       
   866 
       
   867         QScriptValue obj = eng.newObject(&cls);
       
   868         obj.setProperty("foo", QScriptValue(&eng, 123));
       
   869         QScriptValue plain = eng.newObject();
       
   870         QVERIFY(!plain.instanceOf(obj));
       
   871 
       
   872         eng.globalObject().setProperty("HasInstanceTester", obj);
       
   873         eng.globalObject().setProperty("hasInstanceValue", plain);
       
   874         cls.clearReceivedArgs();
       
   875         {
       
   876             QScriptValue ret = eng.evaluate("hasInstanceValue instanceof HasInstanceTester");
       
   877             QCOMPARE(cls.lastExtensionType(), QScriptClass::HasInstance);
       
   878             QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptValueList>());
       
   879             QScriptValueList lst = qvariant_cast<QScriptValueList>(cls.lastExtensionArgument());
       
   880             QCOMPARE(lst.size(), 2);
       
   881             QVERIFY(lst.at(0).strictlyEquals(obj));
       
   882             QVERIFY(lst.at(1).strictlyEquals(plain));
       
   883             QVERIFY(ret.isBoolean());
       
   884             QVERIFY(!ret.toBoolean());
       
   885         }
       
   886 
       
   887         plain.setProperty("foo", QScriptValue(&eng, 456));
       
   888         QVERIFY(!plain.instanceOf(obj));
       
   889         {
       
   890             QScriptValue ret = eng.evaluate("hasInstanceValue instanceof HasInstanceTester");
       
   891             QVERIFY(ret.isBoolean());
       
   892             QVERIFY(!ret.toBoolean());
       
   893         }
       
   894 
       
   895         plain.setProperty("foo", obj.property("foo"));
       
   896         QVERIFY(plain.instanceOf(obj));
       
   897         {
       
   898             QScriptValue ret = eng.evaluate("hasInstanceValue instanceof HasInstanceTester");
       
   899             QVERIFY(ret.isBoolean());
       
   900             QVERIFY(ret.toBoolean());
       
   901         }
       
   902     }
       
   903 }
       
   904 
       
   905 QTEST_MAIN(tst_QScriptClass)
       
   906 #include "tst_qscriptclass.moc"