void tst_QScriptContext::thisObject()
{
    QScriptEngine eng;

    QScriptValue fun = eng.newFunction(get_thisObject);
    eng.globalObject().setProperty("get_thisObject", fun);

    {
        QScriptValue result = eng.evaluate("get_thisObject()");
        QCOMPARE(result.isObject(), true);
        QCOMPARE(result.toString(), QString("[object global]"));
    }

    {
        QScriptValue result = eng.evaluate("get_thisObject.apply(new Number(123))");
        QCOMPARE(result.isObject(), true);
        QCOMPARE(result.toNumber(), 123.0);
    }

    {
        QScriptValue obj = eng.newObject();
        eng.currentContext()->setThisObject(obj);
        QVERIFY(eng.currentContext()->thisObject().equals(obj));
        eng.currentContext()->setThisObject(QScriptValue());
        QVERIFY(eng.currentContext()->thisObject().equals(obj));

        QScriptEngine eng2;
        QScriptValue obj2 = eng2.newObject();
        QTest::ignoreMessage(QtWarningMsg, "QScriptContext::setThisObject() failed: cannot set an object created in a different engine");
        eng.currentContext()->setThisObject(obj2);
    }
}
void tst_QScriptContext::returnValue()
{
    QSKIP("Internal function not implemented in JSC-based back-end", SkipAll);
    QScriptEngine eng;
    eng.evaluate("123");
    QCOMPARE(eng.currentContext()->returnValue().toNumber(), 123.0);
    eng.evaluate("\"ciao\"");
    QCOMPARE(eng.currentContext()->returnValue().toString(), QString("ciao"));
}
QScriptValue ScriptFunctionWrapper::callWith(const QScriptValue &val) {
	//qDebug() << "Call called" << d->name;
	QScriptEngine *eng = val.engine();
	if (!eng) {
		qDebug() << "We cannot access the script-engine, fail!";
		return QScriptValue();
	}
	QScriptContext *ctx = eng->currentContext();
	return d->object.property(d->name).call(QScriptValue(), ctx->argumentsObject());
}
Example #4
0
bool XTreeView::throwScriptException(const QString &message)
{
   QObject *ancestor = this;
   QScriptEngine *engine = 0;
   for ( ; ancestor; ancestor = ancestor->parent())
   {
     engine = ancestor->findChild<QScriptEngine*>();
     if (engine)
       break;
   } 
   if (engine)
   {
      QScriptContext *ctx = engine->currentContext();
      ctx->throwError(message);
      return true;
   }
   return false;
}
void tst_QScriptContext::scopeChain()
{
    QScriptEngine eng;
    {
        QScriptValueList ret = eng.currentContext()->scopeChain();
        QCOMPARE(ret.size(), 1);
        QVERIFY(ret.at(0).strictlyEquals(eng.globalObject()));
    }
    {
        eng.globalObject().setProperty("getScopeChain", eng.newFunction(getScopeChain));
        QScriptValueList ret = qscriptvalue_cast<QScriptValueList>(eng.evaluate("getScopeChain()"));
        QCOMPARE(ret.size(), 1);
        QVERIFY(ret.at(0).strictlyEquals(eng.globalObject()));
    }
    {
        eng.evaluate("function foo() { function bar() { return getScopeChain(); } return bar() }");
        QScriptValueList ret = qscriptvalue_cast<QScriptValueList>(eng.evaluate("foo()"));
        QEXPECT_FAIL("", "Number of items in returned scope chain is incorrect", Abort);
        QCOMPARE(ret.size(), 3);
        QVERIFY(ret.at(2).strictlyEquals(eng.globalObject()));
        QCOMPARE(ret.at(1).toString(), QString::fromLatin1("activation"));
        QVERIFY(ret.at(1).property("arguments").isObject());
        QCOMPARE(ret.at(0).toString(), QString::fromLatin1("activation"));
        QVERIFY(ret.at(0).property("arguments").isObject());
    }
    {
        QScriptValueList ret = qscriptvalue_cast<QScriptValueList>(eng.evaluate("o = { x: 123 }; with(o) getScopeChain();"));
        QCOMPARE(ret.size(), 2);
        QVERIFY(ret.at(1).strictlyEquals(eng.globalObject()));
        QVERIFY(ret.at(0).isObject());
        QCOMPARE(ret.at(0).property("x").toInt32(), 123);
    }
    {
        QScriptValueList ret = qscriptvalue_cast<QScriptValueList>(
            eng.evaluate("o1 = { x: 123}; o2 = { y: 456 }; with(o1) { with(o2) { getScopeChain(); } }"));
        QCOMPARE(ret.size(), 3);
        QVERIFY(ret.at(2).strictlyEquals(eng.globalObject()));
        QVERIFY(ret.at(1).isObject());
        QCOMPARE(ret.at(1).property("x").toInt32(), 123);
        QVERIFY(ret.at(0).isObject());
        QCOMPARE(ret.at(0).property("y").toInt32(), 456);
    }
}
void tst_QScriptContext::getSetActivationObject()
{
    QScriptEngine eng;
    QScriptContext *ctx = eng.currentContext();
    QVERIFY(ctx->activationObject().equals(eng.globalObject()));

    ctx->setActivationObject(QScriptValue());
    QVERIFY(ctx->activationObject().equals(eng.globalObject()));
    QCOMPARE(ctx->engine(), &eng);

    QScriptValue obj = eng.newObject();
    ctx->setActivationObject(obj);
    QVERIFY(ctx->activationObject().equals(obj));
    QCOMPARE(ctx->scopeChain().size(), 1);
    QVERIFY(ctx->scopeChain().at(0).equals(obj));

    {
        QScriptEngine eng2;
        QScriptValue obj2 = eng2.newObject();
        QTest::ignoreMessage(QtWarningMsg, "QScriptContext::setActivationObject() failed: cannot set an object created in a different engine");
        QScriptValue was = ctx->activationObject();
        ctx->setActivationObject(obj2);
        QVERIFY(ctx->activationObject().equals(was));
    }

    ctx->setActivationObject(eng.globalObject());
    QVERIFY(ctx->activationObject().equals(eng.globalObject()));
    QScriptValue fun = eng.newFunction(get_activationObject);
    eng.globalObject().setProperty("get_activationObject", fun);
    {
        QScriptValue ret = eng.evaluate("get_activationObject(1, 2, 3)");
        QVERIFY(ret.isObject());
        QScriptValue arguments = ret.property("arguments");
        QEXPECT_FAIL("", "Getting arguments property of activation object doesn't work", Abort);
        QVERIFY(arguments.isObject());
        QCOMPARE(arguments.property("length").toInt32(), 3);
        QCOMPARE(arguments.property("0").toInt32(), 1);
        QCOMPARE(arguments.property("1").toInt32(), 1);
        QCOMPARE(arguments.property("2").toInt32(), 1);
    }
}
void tst_QScriptContext::pushAndPopScope()
{
    QScriptEngine eng;
    QScriptContext *ctx = eng.currentContext();
    QCOMPARE(ctx->scopeChain().size(), 1);
    QVERIFY(ctx->scopeChain().at(0).strictlyEquals(eng.globalObject()));

    QVERIFY(ctx->popScope().strictlyEquals(eng.globalObject()));
    ctx->pushScope(eng.globalObject());
    QCOMPARE(ctx->scopeChain().size(), 1);
    QVERIFY(ctx->scopeChain().at(0).strictlyEquals(eng.globalObject()));

    QScriptValue obj = eng.newObject();
    ctx->pushScope(obj);
    QCOMPARE(ctx->scopeChain().size(), 2);
    QVERIFY(ctx->scopeChain().at(0).strictlyEquals(obj));
    QVERIFY(ctx->scopeChain().at(1).strictlyEquals(eng.globalObject()));

    QVERIFY(ctx->popScope().strictlyEquals(obj));
    QCOMPARE(ctx->scopeChain().size(), 1);
    QVERIFY(ctx->scopeChain().at(0).strictlyEquals(eng.globalObject()));

    {
        QScriptValue ret = eng.evaluate("x");
        QVERIFY(ret.isError());
        eng.clearExceptions();
    }
    QCOMPARE(ctx->scopeChain().size(), 1);
    QVERIFY(ctx->scopeChain().at(0).strictlyEquals(eng.globalObject()));

    // task 236685
    QScriptValue qobj = eng.newQObject(this, QScriptEngine::QtOwnership, QScriptEngine::AutoCreateDynamicProperties);
    ctx->pushScope(qobj);
    QCOMPARE(ctx->scopeChain().size(), 2);
    QVERIFY(ctx->scopeChain().at(0).strictlyEquals(qobj));
    QVERIFY(ctx->scopeChain().at(1).strictlyEquals(eng.globalObject()));
    {
        QScriptValue ret = eng.evaluate("print");
        QVERIFY(ret.isFunction());
    }
    ctx->popScope();

    ctx->pushScope(obj);
    QCOMPARE(ctx->scopeChain().size(), 2);
    QVERIFY(ctx->scopeChain().at(0).strictlyEquals(obj));
    obj.setProperty("x", 123);
    {
        QScriptValue ret = eng.evaluate("x");
        QVERIFY(ret.isNumber());
        QCOMPARE(ret.toInt32(), 123);
    }
    QVERIFY(ctx->popScope().strictlyEquals(obj));
    QCOMPARE(ctx->scopeChain().size(), 1);
    QVERIFY(ctx->scopeChain().at(0).strictlyEquals(eng.globalObject()));

    ctx->pushScope(QScriptValue());
    QCOMPARE(ctx->scopeChain().size(), 1);

    QVERIFY(ctx->popScope().strictlyEquals(eng.globalObject()));
    QVERIFY(ctx->scopeChain().isEmpty());

    // Used to work with old back-end, doesn't with new one because JSC requires that the last object in
    // a scope chain is the Global Object.
    QTest::ignoreMessage(QtWarningMsg, "QScriptContext::pushScope() failed: initial object in scope chain has to be the Global Object");
    ctx->pushScope(obj);
    QCOMPARE(ctx->scopeChain().size(), 0);

    QScriptEngine eng2;
    QScriptValue obj2 = eng2.newObject();
    QTest::ignoreMessage(QtWarningMsg, "QScriptContext::pushScope() failed: cannot push an object created in a different engine");
    ctx->pushScope(obj2);
    QVERIFY(ctx->scopeChain().isEmpty());

    QVERIFY(!ctx->popScope().isValid());
}
void tst_QScriptContext::pushAndPopContext()
{
    QScriptEngine eng;
    QScriptContext *topLevel = eng.currentContext();
    QCOMPARE(topLevel->engine(), &eng);

    QScriptContext *ctx = eng.pushContext();
    QVERIFY(ctx != 0);
    QCOMPARE(ctx->parentContext(), topLevel);
    QCOMPARE(eng.currentContext(), ctx);
    QCOMPARE(ctx->engine(), &eng);
    QCOMPARE(ctx->state(), QScriptContext::NormalState);
    QCOMPARE(ctx->isCalledAsConstructor(), false);
    QCOMPARE(ctx->argumentCount(), 0);
    QCOMPARE(ctx->argument(0).isUndefined(), true);
    QVERIFY(!ctx->argument(-1).isValid());
    QCOMPARE(ctx->argumentsObject().isObject(), true);
    QCOMPARE(ctx->activationObject().isObject(), true);
    QCOMPARE(ctx->callee().isValid(), false);
    QCOMPARE(ctx->thisObject().strictlyEquals(eng.globalObject()), true);
    QCOMPARE(ctx->scopeChain().size(), 2);
    QVERIFY(ctx->scopeChain().at(0).equals(ctx->activationObject()));
    QVERIFY(ctx->scopeChain().at(1).equals(eng.globalObject()));

    QScriptContext *ctx2 = eng.pushContext();
    QCOMPARE(ctx2->parentContext(), ctx);
    QCOMPARE(eng.currentContext(), ctx2);

    eng.popContext();
    QCOMPARE(eng.currentContext(), ctx);
    eng.popContext();
    QCOMPARE(eng.currentContext(), topLevel);

    // popping the top-level context is not allowed
    QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::popContext() doesn't match with pushContext()");
    eng.popContext();
    QCOMPARE(eng.currentContext(), topLevel);

    {
        QScriptContext *ctx3 = eng.pushContext();
        ctx3->activationObject().setProperty("foo", QScriptValue(&eng, 123));
        QVERIFY(eng.evaluate("foo").strictlyEquals(QScriptValue(&eng, 123)));
        eng.evaluate("var bar = 'ciao'");
        QVERIFY(ctx3->activationObject().property("bar", QScriptValue::ResolveLocal).strictlyEquals(QScriptValue(&eng, "ciao")));
        eng.popContext();
    }

    {
        QScriptContext *ctx4 = eng.pushContext();
        QScriptValue obj = eng.newObject();
        obj.setProperty("prop", QScriptValue(&eng, 456));
        ctx4->setThisObject(obj);
        QScriptValue ret = eng.evaluate("var tmp = this.prop; tmp + 1");
        QCOMPARE(eng.currentContext(), ctx4);
        QVERIFY(ret.strictlyEquals(QScriptValue(&eng, 457)));
        eng.popContext();
    }

    // throwing an exception
    {
        QScriptContext *ctx5 = eng.pushContext();
        QScriptValue ret = eng.evaluate("throw new Error('oops')");
        QVERIFY(ret.isError());
        QVERIFY(eng.hasUncaughtException());
        QCOMPARE(eng.currentContext(), ctx5);
        eng.popContext();
    }
}
void tst_QScriptContext::arguments()
{
    QScriptEngine eng;

    {
        QScriptValue args = eng.currentContext()->argumentsObject();
        QVERIFY(args.isObject());
        QCOMPARE(args.property("length").toInt32(), 0);
    }
    {
        QScriptValue fun = eng.newFunction(get_arguments);
        eng.globalObject().setProperty("get_arguments", fun);
    }

    for (int x = 0; x < 2; ++x) {
        QString prefix;
        if (x == 0)
            prefix = "";
        else
            prefix = "new ";
        {
            QScriptValue result = eng.evaluate(prefix+"get_arguments()");
            QCOMPARE(result.isArray(), true);
            QCOMPARE(result.property("length").toUInt32(), quint32(0));
        }

        {
            QScriptValue result = eng.evaluate(prefix+"get_arguments(123)");
            QCOMPARE(result.isArray(), true);
            QCOMPARE(result.property("length").toUInt32(), quint32(1));
            QCOMPARE(result.property("0").isNumber(), true);
            QCOMPARE(result.property("0").toNumber(), 123.0);
        }

        {
            QScriptValue result = eng.evaluate(prefix+"get_arguments(\"ciao\", null, true, undefined)");
            QCOMPARE(result.isArray(), true);
            QCOMPARE(result.property("length").toUInt32(), quint32(4));
            QCOMPARE(result.property("0").isString(), true);
            QCOMPARE(result.property("0").toString(), QString("ciao"));
            QCOMPARE(result.property("1").isNull(), true);
            QCOMPARE(result.property("2").isBoolean(), true);
            QCOMPARE(result.property("2").toBoolean(), true);
            QCOMPARE(result.property("3").isUndefined(), true);
        }

        {
            QScriptValue fun = eng.newFunction(get_argumentsObject);
            eng.globalObject().setProperty("get_argumentsObject", fun);
        }

        {
            QScriptValue fun = eng.evaluate("get_argumentsObject");
            QCOMPARE(fun.isFunction(), true);
            QScriptValue result = eng.evaluate(prefix+"get_argumentsObject()");
            QCOMPARE(result.isArray(), false);
            QVERIFY(result.isObject());
            QCOMPARE(result.property("length").toUInt32(), quint32(0));
            QCOMPARE(result.propertyFlags("length"), QScriptValue::SkipInEnumeration);
            QCOMPARE(result.property("callee").strictlyEquals(fun), true);
            QCOMPARE(result.propertyFlags("callee"), QScriptValue::SkipInEnumeration);
            QScriptValue replacedCallee(&eng, 123);
            result.setProperty("callee", replacedCallee);
            QVERIFY(result.property("callee").equals(replacedCallee));
            QScriptValue replacedLength(&eng, 456);
            result.setProperty("length", replacedLength);
            QVERIFY(result.property("length").equals(replacedLength));
            result.setProperty("callee", QScriptValue());
            QVERIFY(!result.property("callee").isValid());
            result.setProperty("length", QScriptValue());
            QVERIFY(!result.property("length").isValid());
        }

        {
            QScriptValue result = eng.evaluate(prefix+"get_argumentsObject(123)");
            eng.evaluate("function nestedArg(x,y,z) { var w = get_argumentsObject('ABC' , x+y+z); return w; }");
            QScriptValue result2 = eng.evaluate("nestedArg(1, 'a', 2)");
            QCOMPARE(result.isArray(), false);
            QVERIFY(result.isObject());
            QCOMPARE(result.property("length").toUInt32(), quint32(1));
            QCOMPARE(result.property("0").isNumber(), true);
            QCOMPARE(result.property("0").toNumber(), 123.0);
            QVERIFY(result2.isObject());
            QCOMPARE(result2.property("length").toUInt32(), quint32(2));
            QCOMPARE(result2.property("0").toString(), QString::fromLatin1("ABC"));
            QCOMPARE(result2.property("1").toString(), QString::fromLatin1("1a2"));
        }

        {
            QScriptValue result = eng.evaluate(prefix+"get_argumentsObject(\"ciao\", null, true, undefined)");
            QCOMPARE(result.isArray(), false);
            QCOMPARE(result.property("length").toUInt32(), quint32(4));
            QCOMPARE(result.property("0").isString(), true);
            QCOMPARE(result.property("0").toString(), QString("ciao"));
            QCOMPARE(result.property("1").isNull(), true);
            QCOMPARE(result.property("2").isBoolean(), true);
            QCOMPARE(result.property("2").toBoolean(), true);
            QCOMPARE(result.property("3").isUndefined(), true);
        }

        // arguments object returned from script
        {
            QScriptValue result = eng.evaluate("(function() { return arguments; })(123)");
            QCOMPARE(result.isArray(), false);
            QVERIFY(result.isObject());
            QCOMPARE(result.property("length").toUInt32(), quint32(1));
            QCOMPARE(result.property("0").isNumber(), true);
            QCOMPARE(result.property("0").toNumber(), 123.0);
        }

        {
            QScriptValue result = eng.evaluate("(function() { return arguments; })('ciao', null, true, undefined)");
            QCOMPARE(result.isArray(), false);
            QCOMPARE(result.property("length").toUInt32(), quint32(4));
            QCOMPARE(result.property("0").isString(), true);
            QCOMPARE(result.property("0").toString(), QString("ciao"));
            QCOMPARE(result.property("1").isNull(), true);
            QCOMPARE(result.property("2").isBoolean(), true);
            QCOMPARE(result.property("2").toBoolean(), true);
            QCOMPARE(result.property("3").isUndefined(), true);
        }
    }
}