From df68368889bcd71d935b916681c70ce178280fef Mon Sep 17 00:00:00 2001 From: Warwick Allison Date: Thu, 24 Sep 2009 18:18:47 +1000 Subject: More tests for QmlSql, more WebKit-tested-validity. --- src/declarative/qml/qmlsqldatabase.cpp | 118 +++++++++++++++++++-- tests/auto/declarative/sql/data/1-creation.js | 20 ++++ tests/auto/declarative/sql/data/2-selection.js | 30 ++++++ .../sql/data/3-iteration-item-function.js | 27 +++++ .../declarative/sql/data/5-iteration-iterator.js | 27 +++++ .../declarative/sql/data/6-iteration-efficient.js | 28 +++++ tests/auto/declarative/sql/data/test1.js | 20 ---- tests/auto/declarative/sql/data/test2.js | 30 ------ tests/auto/declarative/sql/tst_sql.cpp | 15 ++- 9 files changed, 256 insertions(+), 59 deletions(-) create mode 100644 tests/auto/declarative/sql/data/1-creation.js create mode 100644 tests/auto/declarative/sql/data/2-selection.js create mode 100644 tests/auto/declarative/sql/data/3-iteration-item-function.js create mode 100644 tests/auto/declarative/sql/data/5-iteration-iterator.js create mode 100644 tests/auto/declarative/sql/data/6-iteration-efficient.js delete mode 100644 tests/auto/declarative/sql/data/test1.js delete mode 100644 tests/auto/declarative/sql/data/test2.js diff --git a/src/declarative/qml/qmlsqldatabase.cpp b/src/declarative/qml/qmlsqldatabase.cpp index 5869a56..b132c55 100644 --- a/src/declarative/qml/qmlsqldatabase.cpp +++ b/src/declarative/qml/qmlsqldatabase.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -62,12 +63,14 @@ Q_DECLARE_METATYPE(QSqlDatabase) Q_DECLARE_METATYPE(QSqlQuery) +class QmlSqlQueryScriptClassPropertyIterator; + class QmlSqlQueryScriptClass: public QScriptClass { public: QmlSqlQueryScriptClass(QScriptEngine *engine) : QScriptClass(engine) { str_length = engine->toStringHandle(QLatin1String("length")); - str_forwardOnly = engine->toStringHandle(QLatin1String("forwardOnly")); // not in HTML5 (optimization) + str_forwardOnly = engine->toStringHandle(QLatin1String("forwardOnly")); // not in HTML5 (an optimization) } QueryFlags queryProperty(const QScriptValue &object, @@ -112,12 +115,11 @@ public: } else if (name == str_forwardOnly) { return query.isForwardOnly(); } else { - if (query.at() == id || query.seek(id)) { // Qt 4.6 doesn't optimize at()==id + if ((uint)query.at() == id || query.seek(id)) { // Qt 4.6 doesn't optimize seek(at()) QSqlRecord r = query.record(); - QScriptValue row = engine()->newArray(r.count()); + QScriptValue row = engine()->newObject(); for (int j=0; j(object().data()); + return query.at() == m_index || query.seek(m_index); // Qt 4.6 doesn't optimize seek(at()) + } + + void next() + { + m_last = m_index; + ++m_index; + } + + bool hasPrevious() const + { + return (m_index > 0); + } + + void previous() + { + --m_index; + m_last = m_index; + } + + void toFront() + { + m_index = 0; + m_last = -1; + } + + void toBack() + { + QSqlQuery query = qscriptvalue_cast(object().data()); + m_index = query.size(); + m_last = -1; + } + + QScriptString name() const + { + return object().engine()->toStringHandle(QString::number(m_last)); + } + + uint id() const + { + return m_last; + } + +private: + int m_index; + int m_last; +}; + +QScriptClassPropertyIterator *QmlSqlQueryScriptClass::newIterator(const QScriptValue &object) +{ + return new QmlSqlQueryScriptClassPropertyIterator(object); +} + + + +static QScriptValue qmlsqldatabase_item(QScriptContext *context, QScriptEngine *engine) +{ + QSqlQuery query = qscriptvalue_cast(context->thisObject().data()); + int i = context->argument(0).toNumber(); + if (query.at() == i || query.seek(i)) { // Qt 4.6 doesn't optimize seek(at()) + QSqlRecord r = query.record(); + QScriptValue row = engine->newObject(); + for (int j=0; jundefinedValue(); +} + static QScriptValue qmlsqldatabase_executeSql(QScriptContext *context, QScriptEngine *engine) { QSqlDatabase db = qscriptvalue_cast(context->thisObject()); @@ -163,6 +262,7 @@ static QScriptValue qmlsqldatabase_executeSql(QScriptContext *context, QScriptEn QmlEnginePrivate::get(engine)->sqlQueryClass= new QmlSqlQueryScriptClass(engine); QScriptValue rows = engine->newObject(QmlEnginePrivate::get(engine)->sqlQueryClass); rows.setData(engine->newVariant(qVariantFromValue(query))); + rows.setProperty(QLatin1String("item"), engine->newFunction(qmlsqldatabase_item,1), QScriptValue::SkipInEnumeration); rs.setProperty(QLatin1String("rows"),rows); rs.setProperty(QLatin1String("rowsAffected"),query.numRowsAffected()); rs.setProperty(QLatin1String("insertId"),query.lastInsertId().toString()); // XXX only string @@ -234,7 +334,7 @@ static QScriptValue qmlsqldatabase_open(QScriptContext *context, QScriptEngine * database = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), dbid); } if (!database.isOpen()) { - QString basename = QmlEnginePrivate::get(engine)->offlineStoragePath + "/Databases/"; + QString basename = QmlEnginePrivate::get(engine)->offlineStoragePath + QLatin1String("/Databases/"); QDir().mkpath(basename); basename += dbid; database.setDatabaseName(basename+QLatin1String(".sqllite")); @@ -257,3 +357,9 @@ void qt_add_qmlsqldatabase(QScriptEngine *engine) engine->globalObject().setProperty(QLatin1String("openDatabase"), openDatabase); } +/* +HTML5 "spec" says "rs.rows[n]", but WebKit only impelments "rs.rows.item(n)". We do both (and property iterator). +We add a "forwardOnly" property that stops Qt caching results (code promises to only go forward +through the data. +*/ + diff --git a/tests/auto/declarative/sql/data/1-creation.js b/tests/auto/declarative/sql/data/1-creation.js new file mode 100644 index 0000000..95fa99e --- /dev/null +++ b/tests/auto/declarative/sql/data/1-creation.js @@ -0,0 +1,20 @@ +var db = openDatabase("QmlTestDB", "", "Test database from Qt autotests", 1000000); +var r="transaction_not_finished"; + +// Asynchronous in WebKit, so must wait before calling test() +db.transaction( + function(tx) { + tx.executeSql('CREATE TABLE IF NOT EXISTS Greeting(salutation TEXT, salutee TEXT)', [], + function(tx, rs) { }, function(tx, error) { r="CREATE FAILED: "+error.message }); + tx.executeSql('INSERT INTO Greeting VALUES(?, ?)', [ 'hello', 'world' ], + function(tx, rs) { }, function(tx, error) { r="INSERT FAILED: "+error.message }); + }, + function(tx, error) { r="TRANSACTION FAILED: "+error.message }, + function(tx, result) { if (r=="transaction_not_finished") r="passed" } +); + + +function test() +{ + return r; +} diff --git a/tests/auto/declarative/sql/data/2-selection.js b/tests/auto/declarative/sql/data/2-selection.js new file mode 100644 index 0000000..3acf686 --- /dev/null +++ b/tests/auto/declarative/sql/data/2-selection.js @@ -0,0 +1,30 @@ +var db = openDatabase("QmlTestDB", "", "Test database from Qt autotests", 1000000); +var r=0; + +db.transaction( + function(tx) { + tx.executeSql('INSERT INTO Greeting VALUES(?, ?)', [ 'hello', 'world' ], + function(tx, rs) { }, function(tx, error) { if (r==0) r="INSERT 1 FAILED: "+error.message }); + tx.executeSql('INSERT INTO Greeting VALUES(?, ?)', [ 'hello', 'world' ], + function(tx, rs) { }, function(tx, error) { if (r==0) r="INSERT 2 FAILED: "+error.message }); + tx.executeSql('INSERT INTO Greeting VALUES(?, ?)', [ 'hello', 'world' ], + function(tx, rs) { }, function(tx, error) { if (r==0) r="INSERT 3 FAILED: "+error.message }); + tx.executeSql('SELECT * FROM Greeting', [], + function(tx, rs) { + if ( rs.rows.length != 4 ) { // 1 from test1, 3 from this test. + if (r==0) r = "SELECT RETURNED WRONG VALUE "+rs.rows.length+rs.rows[0]+rs.rows[1] + } + }, + function(tx, error) { if (r==0) r="SELECT FAILED: "+error.message } + ); + }, + function(tx, error) { if (r==0) r="TRANSACTION FAILED: "+error.message }, + function(tx, result) { if (r==0) r="passed" } +); + + +function test() +{ + if (r == 0) r = "transaction_not_finished"; + return r; +} diff --git a/tests/auto/declarative/sql/data/3-iteration-item-function.js b/tests/auto/declarative/sql/data/3-iteration-item-function.js new file mode 100644 index 0000000..bad9b82 --- /dev/null +++ b/tests/auto/declarative/sql/data/3-iteration-item-function.js @@ -0,0 +1,27 @@ +var db = openDatabase("QmlTestDB", "", "Test database from Qt autotests", 1000000); +var r=0; + +db.transaction( + function(tx) { + tx.executeSql('SELECT * FROM Greeting', [], + function(tx, rs) { + var r1="" + for(var i = 0; i < rs.rows.length; i++) { + r1 += rs.rows.item(i).salutation + ", " + rs.rows.item(i).salutee + ";" + } + if (r1 != "hello, world;hello, world;hello, world;hello, world;") + r = "SELECTED DATA WRONG: "+r1; + }, + function(tx, error) { if (r==0) r="SELECT FAILED: "+error.message } + ); + }, + function(tx, error) { if (r==0) r="TRANSACTION FAILED: "+error.message }, + function(tx, result) { if (r==0) r="passed" } +); + + +function test() +{ + if (r == 0) r = "transaction_not_finished"; + return r; +} diff --git a/tests/auto/declarative/sql/data/5-iteration-iterator.js b/tests/auto/declarative/sql/data/5-iteration-iterator.js new file mode 100644 index 0000000..51f0504 --- /dev/null +++ b/tests/auto/declarative/sql/data/5-iteration-iterator.js @@ -0,0 +1,27 @@ +var db = openDatabase("QmlTestDB", "", "Test database from Qt autotests", 1000000); +var r=0; + +db.transaction( + function(tx) { + tx.executeSql('SELECT * FROM Greeting', [], + function(tx, rs) { + var r1="" + for(var i in rs.rows) { + r1 += rs.rows[i].salutation + ", " + rs.rows[i].salutee + ";" + } + if (r1 != "hello, world;hello, world;hello, world;hello, world;") + r = "SELECTED DATA WRONG: "+r1; + }, + function(tx, error) { if (r==0) r="SELECT FAILED: "+error.message } + ); + }, + function(tx, error) { if (r==0) r="TRANSACTION FAILED: "+error.message }, + function(tx, result) { if (r==0) r="passed" } +); + + +function test() +{ + if (r == 0) r = "transaction_not_finished"; + return r; +} diff --git a/tests/auto/declarative/sql/data/6-iteration-efficient.js b/tests/auto/declarative/sql/data/6-iteration-efficient.js new file mode 100644 index 0000000..2222b8a --- /dev/null +++ b/tests/auto/declarative/sql/data/6-iteration-efficient.js @@ -0,0 +1,28 @@ +var db = openDatabase("QmlTestDB", "", "Test database from Qt autotests", 1000000); +var r=0; + +db.transaction( + function(tx) { + tx.executeSql('SELECT * FROM Greeting', [], + function(tx, rs) { + var r1="" + rs.rows.forwardOnly = true; + for(var i=0; rs.rows[i]; ++i) { + r1 += rs.rows[i].salutation + ", " + rs.rows[i].salutee + ";" + } + if (r1 != "hello, world;hello, world;hello, world;hello, world;") + r = "SELECTED DATA WRONG: "+r1; + }, + function(tx, error) { if (r==0) r="SELECT FAILED: "+error.message } + ); + }, + function(tx, error) { if (r==0) r="TRANSACTION FAILED: "+error.message }, + function(tx, result) { if (r==0) r="passed" } +); + + +function test() +{ + if (r == 0) r = "transaction_not_finished"; + return r; +} diff --git a/tests/auto/declarative/sql/data/test1.js b/tests/auto/declarative/sql/data/test1.js deleted file mode 100644 index 95fa99e..0000000 --- a/tests/auto/declarative/sql/data/test1.js +++ /dev/null @@ -1,20 +0,0 @@ -var db = openDatabase("QmlTestDB", "", "Test database from Qt autotests", 1000000); -var r="transaction_not_finished"; - -// Asynchronous in WebKit, so must wait before calling test() -db.transaction( - function(tx) { - tx.executeSql('CREATE TABLE IF NOT EXISTS Greeting(salutation TEXT, salutee TEXT)', [], - function(tx, rs) { }, function(tx, error) { r="CREATE FAILED: "+error.message }); - tx.executeSql('INSERT INTO Greeting VALUES(?, ?)', [ 'hello', 'world' ], - function(tx, rs) { }, function(tx, error) { r="INSERT FAILED: "+error.message }); - }, - function(tx, error) { r="TRANSACTION FAILED: "+error.message }, - function(tx, result) { if (r=="transaction_not_finished") r="passed" } -); - - -function test() -{ - return r; -} diff --git a/tests/auto/declarative/sql/data/test2.js b/tests/auto/declarative/sql/data/test2.js deleted file mode 100644 index 3acf686..0000000 --- a/tests/auto/declarative/sql/data/test2.js +++ /dev/null @@ -1,30 +0,0 @@ -var db = openDatabase("QmlTestDB", "", "Test database from Qt autotests", 1000000); -var r=0; - -db.transaction( - function(tx) { - tx.executeSql('INSERT INTO Greeting VALUES(?, ?)', [ 'hello', 'world' ], - function(tx, rs) { }, function(tx, error) { if (r==0) r="INSERT 1 FAILED: "+error.message }); - tx.executeSql('INSERT INTO Greeting VALUES(?, ?)', [ 'hello', 'world' ], - function(tx, rs) { }, function(tx, error) { if (r==0) r="INSERT 2 FAILED: "+error.message }); - tx.executeSql('INSERT INTO Greeting VALUES(?, ?)', [ 'hello', 'world' ], - function(tx, rs) { }, function(tx, error) { if (r==0) r="INSERT 3 FAILED: "+error.message }); - tx.executeSql('SELECT * FROM Greeting', [], - function(tx, rs) { - if ( rs.rows.length != 4 ) { // 1 from test1, 3 from this test. - if (r==0) r = "SELECT RETURNED WRONG VALUE "+rs.rows.length+rs.rows[0]+rs.rows[1] - } - }, - function(tx, error) { if (r==0) r="SELECT FAILED: "+error.message } - ); - }, - function(tx, error) { if (r==0) r="TRANSACTION FAILED: "+error.message }, - function(tx, result) { if (r==0) r="passed" } -); - - -function test() -{ - if (r == 0) r = "transaction_not_finished"; - return r; -} diff --git a/tests/auto/declarative/sql/tst_sql.cpp b/tests/auto/declarative/sql/tst_sql.cpp index cb13427..10ce6d8 100644 --- a/tests/auto/declarative/sql/tst_sql.cpp +++ b/tests/auto/declarative/sql/tst_sql.cpp @@ -82,9 +82,14 @@ void tst_sql::testQml_data() QTest::addColumn("jsfile"); // The input file QTest::addColumn("result"); // The required output from the js test() function QTest::addColumn("databases"); // The number of databases that should have been created - - QTest::newRow("basic creation") << "data/test1.js" << "passed" << 1; - QTest::newRow("basic select") << "data/test2.js" << "passed" << 1; + QTest::addColumn("qmlextension"); // Things WebKit can't do + + QTest::newRow("creation") << "data/1-creation.js" << "passed" << 1 << false; + QTest::newRow("selection") << "data/2-selection.js" << "passed" << 1 << false; + QTest::newRow("iteration-item-function") << "data/3-iteration-item-function.js" << "passed" << 1 << false; + QTest::newRow("iteration-index") << "data/4-iteration-index.js" << "passed" << 1 << true; + QTest::newRow("iteration-iterator") << "data/5-iteration-iterator.js" << "passed" << 1 << true; + QTest::newRow("iteration-efficient") << "data/6-iteration-efficient.js" << "passed" << 1 << true; } void tst_sql::validateAgainstWebkit_data() @@ -102,6 +107,10 @@ void tst_sql::validateAgainstWebkit() QFETCH(QString, jsfile); QFETCH(QString, result); QFETCH(int, databases); + QFETCH(bool, qmlextension); + + if (qmlextension) // WebKit can't do it (yet?) + return; QFile f(jsfile); QVERIFY(f.open(QIODevice::ReadOnly)); -- cgit v0.12