00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "kjsobject.h"
00023 #include "kjsprototype.h"
00024 #include "kjsarguments.h"
00025 #include "kjsinterpreter.h"
00026
00027 #include "qtest_kde.h"
00028
00029 class KJSApiTest : public QObject
00030 {
00031 Q_OBJECT
00032
00033 private Q_SLOTS:
00034 void objectConstruction();
00035 void interpreterEvaluate();
00036 void interpreterNormalizeCode();
00037 void objectProperties();
00038 void prototypeConstants();
00039 void prototypeProperties();
00040 void prototypeFunctions();
00041 void globalObject();
00042 };
00043
00044 void KJSApiTest::objectConstruction()
00045 {
00046 KJSInterpreter ip;
00047 KJSContext* ctx = ip.globalContext();
00048
00049
00050 QVERIFY2(KJSObject().isObject(), "Broken default object");
00051
00052
00053 QVERIFY2(KJSUndefined().isUndefined(),
00054 "Undefined object is not undefined");
00055
00056 QVERIFY2(KJSNull().isNull(),
00057 "Null object is not null");
00058
00059
00060 KJSBoolean boolObject(true);
00061 QVERIFY2(boolObject.isBoolean(), "Boolean object is not of boolean type");
00062 QVERIFY2(boolObject.toBoolean(ctx), "Boolean object has wrong value");
00063 QVERIFY2(!ctx->hasException(), "Boolean conversion threw exception");
00064
00065
00066 KJSNumber numObject(42.0);
00067 QVERIFY2(numObject.isNumber(), "Number object is not of number type");
00068 QCOMPARE(numObject.toNumber(ctx), 42.0);
00069 QCOMPARE(numObject.toInt32(ctx), 42);
00070 QVERIFY2(!ctx->hasException(), "Number conversion threw exception");
00071
00072
00073 KJSString stringObject("Trunk");
00074 QVERIFY2(stringObject.isString(), "String object is not of string type");
00075 QCOMPARE(stringObject.toString(ctx), QLatin1String("Trunk"));
00076 QVERIFY2(!ctx->hasException(), "String conversion threw exception");
00077
00078
00079 KJSArray arrayObject(ctx, 3);
00080 QVERIFY2(arrayObject.isObject(), "Array object is not of object type");
00081 QCOMPARE(arrayObject.property(ctx, "length").toNumber(ctx), 3.0);
00082 QCOMPARE(arrayObject.toString(ctx), QLatin1String(",,"));
00083 QVERIFY2(!ctx->hasException(), "Array conversion threw exception");
00084
00085
00086 KJSObject copy(stringObject);
00087 QCOMPARE(copy.toString(ctx), QLatin1String("Trunk"));
00088 copy = numObject;
00089 QCOMPARE(copy.toNumber(ctx), 42.0);
00090 }
00091
00092 void KJSApiTest::interpreterEvaluate()
00093 {
00094 KJSInterpreter ip;
00095 KJSContext* ctx = ip.globalContext();
00096 KJSResult res;
00097
00098
00099 res = ip.evaluate(")(");
00100 QVERIFY2(res.isException(), "Syntax error not caught");
00101
00102 res = ip.evaluate("11+22");
00103 QVERIFY2(!res.isException(), "Evaluation returned non-number object");
00104 QCOMPARE(res.value().toNumber(ctx), 33.0);
00105 }
00106
00107 void KJSApiTest::interpreterNormalizeCode()
00108 {
00109 int errLine = -1;
00110 QString errMsg;
00111 QString norm;
00112 bool ok;
00113
00114
00115 ok = KJSInterpreter::normalizeCode(")(", &norm, &errLine, &errMsg);
00116 QVERIFY(!ok);
00117 QVERIFY(!errMsg.isEmpty());
00118 QVERIFY(errLine >= 0 && errLine <= 2);
00119
00120
00121 ok = KJSInterpreter::normalizeCode("foo(); bar();", &norm);
00122 QVERIFY(ok);
00123 QVERIFY(!norm.isEmpty());
00124 QStringList lines = norm.split('\n');
00125 QVERIFY(lines.size() >= 2);
00126 int fooLine = lines.indexOf(QRegExp(" *foo\\(\\);"));
00127 int barLine = lines.indexOf(QRegExp(" *bar\\(\\);"));
00128 QVERIFY(fooLine >= 0);
00129 QVERIFY(barLine > fooLine);
00130 }
00131
00132 void KJSApiTest::objectProperties()
00133 {
00134 KJSInterpreter ip;
00135 KJSContext* ctx = ip.globalContext();
00136
00137 KJSObject global = ip.globalObject();
00138 KJSObject v;
00139
00140
00141 global.setProperty(ctx, "myprop", true);
00142 v = global.property(ctx, "myprop");
00143 QVERIFY(v.isBoolean());
00144 QCOMPARE(v.toBoolean(ctx), true);
00145
00146
00147 global.setProperty(ctx, "myprop", 21.0);
00148 v = global.property(ctx, "myprop");
00149 QVERIFY(v.isNumber());
00150 QCOMPARE(v.toNumber(ctx), 21.0);
00151
00152
00153 global.setProperty(ctx, "myprop", 22);
00154 v = global.property(ctx, "myprop");
00155 QVERIFY(v.isNumber());
00156 QCOMPARE(v.toNumber(ctx), 22.0);
00157
00158
00159 global.setProperty(ctx, "myprop", "myvalue8");
00160 v = global.property(ctx, "myprop");
00161 QVERIFY(v.isString());
00162 QCOMPARE(v.toString(ctx), QLatin1String("myvalue8"));
00163
00164
00165 global.setProperty(ctx, "myprop", QLatin1String("myvalue16"));
00166 v = global.property(ctx, "myprop");
00167 QVERIFY(v.isString());
00168 QCOMPARE(v.toString(ctx), QLatin1String("myvalue16"));
00169 }
00170
00171 void KJSApiTest::prototypeConstants()
00172 {
00173 KJSInterpreter ip;
00174 KJSContext* ctx = ip.globalContext();
00175
00176 KJSPrototype proto;
00177
00178 proto.defineConstant("d0", 44.4);
00179 proto.defineConstant("s0", QLatin1String("XYZ"));
00180
00181 KJSObject obj = proto.constructObject(ctx, 0);
00182
00183 QCOMPARE(obj.property(ctx, "d0").toNumber(ctx), 44.4);
00184 QCOMPARE(obj.property(ctx, "s0").toString(ctx), QLatin1String("XYZ"));
00185 }
00186
00187 static struct O { int x; } o0 = { 42 };
00188
00189 static KJSObject getX(KJSContext* , void* object)
00190 {
00191 O* o = reinterpret_cast<O*>(object);
00192 int x = o->x;
00193 return KJSNumber(x);
00194 }
00195
00196 static void setX(KJSContext* context, void* object, KJSObject value)
00197 {
00198 O* o = reinterpret_cast<O*>(object);
00199 double n = value.toNumber(context);
00200 o->x = n;
00201 }
00202
00203 void KJSApiTest::prototypeProperties()
00204 {
00205 KJSInterpreter ip;
00206 KJSContext* ctx = ip.globalContext();
00207
00208 KJSPrototype proto;
00209
00210 proto.defineProperty(ctx, "x", getX, setX);
00211 proto.defineProperty(ctx, "readOnlyX", getX);
00212
00213 KJSObject obj = proto.constructObject(ctx, &o0);
00214
00215
00216 QCOMPARE(obj.property(ctx, "x").toNumber(ctx), 42.0);
00217 obj.setProperty(ctx, "x", KJSNumber(43));
00218 QCOMPARE(obj.property(ctx, "x").toNumber(ctx), 43.0);
00219
00220 QCOMPARE(obj.property(ctx, "readOnlyX").toNumber(ctx), 43.0);
00221 obj.setProperty(ctx, "readOnlyX", KJSNumber(44));
00222 QVERIFY2(ctx->hasException(), "Write access caused no exception");
00223 QCOMPARE(obj.property(ctx, "readOnlyX").toNumber(ctx), 43.0);
00224 }
00225
00226 static KJSObject multiply(KJSContext* context, void* object,
00227 const KJSArguments& arguments)
00228 {
00229 double factor = *reinterpret_cast<double*>(object);
00230
00231
00232 if (arguments.count() != 1)
00233 return context->throwException("Missing argument");
00234
00235 KJSObject a0 = arguments.at(0);
00236 if (!a0.isNumber())
00237 return KJSNumber(-2);
00238
00239 double v0 = a0.toNumber(context);
00240
00241 return KJSNumber(factor * v0);
00242 }
00243
00244 void KJSApiTest::prototypeFunctions()
00245 {
00246 KJSInterpreter ip;
00247 KJSContext* ctx = ip.globalContext();
00248
00249 KJSPrototype proto;
00250
00251 proto.defineFunction(ctx, "multiply", multiply);
00252
00253 double factor = 3.0;
00254 KJSObject obj = proto.constructObject(ctx, &factor);
00255 ip.globalObject().setProperty(ctx, "obj", obj);
00256
00257 KJSResult res = ip.evaluate("obj.multiply(4)");
00258 QCOMPARE(res.value().toNumber(ctx), 12.0);
00259
00260
00261 res = ip.evaluate("obj.multiply()");
00262 QVERIFY2(res.isException(), "Exception did not work");
00263 }
00264
00265 void KJSApiTest::globalObject()
00266 {
00267 KJSPrototype proto;
00268 proto.defineConstant("g0", 55.5);
00269
00270 KJSGlobalObject glob = proto.constructGlobalObject(0);
00271
00272 KJSInterpreter ip(glob);
00273 KJSResult res = ip.evaluate("2 * g0");
00274 QCOMPARE(res.value().toNumber(ip.globalContext()), 111.0);
00275 }
00276
00277 QTEST_KDEMAIN_CORE(KJSApiTest)
00278
00279 #include "kjsapitest.moc"