/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain ** additional rights. These rights are described in the Nokia Qt LGPL ** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this ** package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include //TESTED_CLASS= //TESTED_FILES= class MyScriptable : public QObject, public QScriptable { Q_OBJECT Q_PROPERTY(int baz READ baz WRITE setBaz) Q_PROPERTY(QObject* zab READ zab WRITE setZab) Q_PROPERTY(int 0 READ baz) Q_PROPERTY(QObject* 1 READ zab) Q_PROPERTY(int oof WRITE setOof) public: MyScriptable(QObject *parent = 0) : QObject(parent), m_lastEngine(0) { } ~MyScriptable() { } QScriptEngine *lastEngine() const; void setOof(int) { m_oofThisObject = context()->thisObject(); } QScriptValue oofThisObject() const { return m_oofThisObject; } void emitSig(int value) { emit sig(value); } public slots: void foo(); void setX(int x); void setX(const QString &x); void setX2(int x); bool isBar(); int baz(); void setBaz(int x); void evalIsBar(); bool useInAnotherEngine(); void setOtherEngine(); QObject *zab(); QObject *setZab(QObject *); QScriptValue getArguments(); int getArgumentCount(); signals: void sig(int); private: QScriptEngine *m_lastEngine; QScriptEngine *m_otherEngine; QScriptValue m_oofThisObject; }; QScriptEngine *MyScriptable::lastEngine() const { return m_lastEngine; } int MyScriptable::baz() { m_lastEngine = engine(); return 123; } void MyScriptable::setBaz(int) { m_lastEngine = engine(); } QObject *MyScriptable::zab() { return thisObject().toQObject(); } QObject *MyScriptable::setZab(QObject *) { return thisObject().toQObject(); } QScriptValue MyScriptable::getArguments() { return context()->argumentsObject(); } int MyScriptable::getArgumentCount() { return context()->argumentCount(); } void MyScriptable::foo() { m_lastEngine = engine(); QVERIFY(engine() != 0); context()->throwError("MyScriptable.foo"); } void MyScriptable::evalIsBar() { engine()->evaluate("this.isBar()"); m_lastEngine = engine(); } bool MyScriptable::useInAnotherEngine() { QScriptEngine eng; eng.globalObject().setProperty("foo", eng.newQObject(this)); eng.evaluate("foo.baz()"); m_lastEngine = engine(); return (m_otherEngine == &eng); } void MyScriptable::setOtherEngine() { m_otherEngine = engine(); } void MyScriptable::setX(int x) { m_lastEngine = engine(); Q_ASSERT(engine()); thisObject().setProperty("x", QScriptValue(engine(), x)); } void MyScriptable::setX(const QString &x) { m_lastEngine = engine(); Q_ASSERT(engine()); thisObject().setProperty("x", QScriptValue(engine(), x)); } void MyScriptable::setX2(int) { m_lastEngine = engine(); thisObject().setProperty("x", argument(0)); } bool MyScriptable::isBar() { m_lastEngine = engine(); QString str = thisObject().toString(); return str.contains(QLatin1Char('@')); } class tst_QScriptable : public QObject { Q_OBJECT public: tst_QScriptable(); virtual ~tst_QScriptable(); private slots: void initTestCase(); void cleanupTestCase(); void engine(); void thisObject(); void arguments(); void throwError(); private: QScriptEngine m_engine; MyScriptable m_scriptable; }; tst_QScriptable::tst_QScriptable() { } tst_QScriptable::~tst_QScriptable() { } void tst_QScriptable::initTestCase() { QScriptValue obj = m_engine.newQObject(&m_scriptable); m_engine.globalObject().setProperty("scriptable", obj); } void tst_QScriptable::cleanupTestCase() { } void tst_QScriptable::engine() { QCOMPARE(m_scriptable.engine(), (QScriptEngine*)0); QCOMPARE(m_scriptable.context(), (QScriptContext*)0); QCOMPARE(m_scriptable.lastEngine(), (QScriptEngine *)0); // reading property { QScriptValue ret = m_engine.evaluate("scriptable.baz"); QCOMPARE(ret.strictlyEquals(QScriptValue(&m_engine, 123)), true); } QCOMPARE(m_scriptable.lastEngine(), &m_engine); { QScriptValue ret = m_engine.evaluate("scriptable[0]"); QCOMPARE(ret.strictlyEquals(QScriptValue(&m_engine, 123)), true); } QCOMPARE(m_scriptable.lastEngine(), &m_engine); // when reading from C++, engine() should be 0 (void)m_scriptable.property("baz"); QCOMPARE(m_scriptable.lastEngine(), (QScriptEngine *)0); // writing property m_engine.evaluate("scriptable.baz = 123"); QCOMPARE(m_scriptable.lastEngine(), &m_engine); (void)m_scriptable.setProperty("baz", 123); QCOMPARE(m_scriptable.lastEngine(), (QScriptEngine *)0); // calling slot m_engine.evaluate("scriptable.setX(123)"); QCOMPARE(m_scriptable.lastEngine(), &m_engine); QCOMPARE(m_engine.evaluate("scriptable.x") .strictlyEquals(QScriptValue(&m_engine, 123)), true); (void)m_scriptable.setProperty("baz", 123); QCOMPARE(m_scriptable.lastEngine(), (QScriptEngine *)0); // calling overloaded slot m_engine.evaluate("scriptable.setX('123')"); QCOMPARE(m_scriptable.lastEngine(), &m_engine); QCOMPARE(m_engine.evaluate("scriptable.x") .strictlyEquals(QScriptValue(&m_engine, QLatin1String("123"))), true); // calling a slot from another slot m_engine.evaluate("scriptable.evalIsBar()"); QCOMPARE(m_scriptable.lastEngine(), &m_engine); // calling a slot that registers m_scriptable in a different engine // and calls evaluate() { QScriptValue ret = m_engine.evaluate("scriptable.useInAnotherEngine()"); QCOMPARE(m_scriptable.lastEngine(), &m_engine); } } void tst_QScriptable::thisObject() { m_engine.evaluate("o = { }"); { QScriptValue ret = m_engine.evaluate("o.__proto__ = scriptable;" "o.setX(123);" "o.__proto__ = Object.prototype;" "o.x"); QCOMPARE(ret.strictlyEquals(QScriptValue(&m_engine, 123)), true); } { QScriptValue ret = m_engine.evaluate("o.__proto__ = scriptable;" "o.setX2(456);" "o.__proto__ = Object.prototype;" "o.x"); QCOMPARE(ret.strictlyEquals(QScriptValue(&m_engine, 456)), true); } m_engine.evaluate("o.__proto__ = scriptable"); { QScriptValue ret = m_engine.evaluate("o.isBar()"); QCOMPARE(ret.strictlyEquals(QScriptValue(&m_engine, false)), true); } { QScriptValue ret = m_engine.evaluate("o.toString = function() { return 'foo@bar'; }; o.isBar()"); QCOMPARE(ret.strictlyEquals(QScriptValue(&m_engine, true)), true); } // property getter { QScriptValue ret = m_engine.evaluate("scriptable.zab"); QCOMPARE(ret.isQObject(), true); QCOMPARE(ret.toQObject(), (QObject *)&m_scriptable); } { QScriptValue ret = m_engine.evaluate("scriptable[1]"); QCOMPARE(ret.isQObject(), true); QCOMPARE(ret.toQObject(), (QObject *)&m_scriptable); } { QScriptValue ret = m_engine.evaluate("o.zab"); QCOMPARE(ret.toQObject(), (QObject *)0); } // property setter { QScriptValue ret = m_engine.evaluate("scriptable.setZab(null)"); QCOMPARE(ret.isQObject(), true); QCOMPARE(ret.toQObject(), (QObject *)&m_scriptable); } { QVERIFY(!m_scriptable.oofThisObject().isValid()); m_engine.evaluate("o.oof = 123"); QEXPECT_FAIL("", "Setter doesn't get called when it's in the prototype", Continue); QVERIFY(m_scriptable.oofThisObject().strictlyEquals(m_engine.evaluate("o"))); } { m_engine.evaluate("scriptable.oof = 123"); QVERIFY(m_scriptable.oofThisObject().strictlyEquals(m_engine.evaluate("scriptable"))); } // target of signal { { QScriptValue ret = m_engine.evaluate("scriptable.sig.connect(o, scriptable.setX)"); QVERIFY(ret.isUndefined()); } QVERIFY(m_engine.evaluate("o.x").strictlyEquals(QScriptValue(&m_engine, 456))); m_scriptable.emitSig(654321); QVERIFY(m_engine.evaluate("o.x").strictlyEquals(QScriptValue(&m_engine, 654321))); { QScriptValue ret = m_engine.evaluate("scriptable.sig.disconnect(o, scriptable.setX)"); QVERIFY(ret.isUndefined()); } } m_engine.evaluate("delete o"); } void tst_QScriptable::arguments() { // even though the C++ slot accepts zero arguments, it should // still be invoked; the arguments should be accessible through // the QScriptable API QScriptValue args = m_engine.evaluate("scriptable.getArguments(10, 20, 30, 'hi')"); QVERIFY(args.property("length").strictlyEquals(QScriptValue(&m_engine, 4))); QVERIFY(args.property("0").strictlyEquals(QScriptValue(&m_engine, 10))); QVERIFY(args.property("1").strictlyEquals(QScriptValue(&m_engine, 20))); QVERIFY(args.property("2").strictlyEquals(QScriptValue(&m_engine, 30))); QVERIFY(args.property("3").strictlyEquals(QScriptValue(&m_engine, "hi"))); QScriptValue argc = m_engine.evaluate("scriptable.getArgumentCount(1, 2, 3)"); QVERIFY(argc.isNumber()); QCOMPARE(argc.toInt32(), 3); QCOMPARE(m_scriptable.argumentCount(), -1); QVERIFY(!m_scriptable.argument(-1).isValid()); QVERIFY(!m_scriptable.argument(0).isValid()); } void tst_QScriptable::throwError() { QScriptValue ret = m_engine.evaluate("scriptable.foo()"); QCOMPARE(ret.isError(), true); QCOMPARE(ret.toString(), QString("Error: MyScriptable.foo")); } QTEST_MAIN(tst_QScriptable) #include "tst_qscriptable.moc"