1/* 2 Copyright (C) 2008 Holger Hans Peter Freyther 3 4 This library is free software; you can redistribute it and/or 5 modify it under the terms of the GNU Library General Public 6 License as published by the Free Software Foundation; either 7 version 2 of the License, or (at your option) any later version. 8 9 This library is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Library General Public License for more details. 13 14 You should have received a copy of the GNU Library General Public License 15 along with this library; see the file COPYING.LIB. If not, write to 16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 Boston, MA 02110-1301, USA. 18*/ 19 20#include <QtTest/QtTest> 21#include <QAction> 22 23#include "qwebpage.h" 24#include "qwebview.h" 25#include "qwebframe.h" 26#include "qwebhistory.h" 27#include "qdebug.h" 28 29class tst_QWebHistory : public QObject 30{ 31 Q_OBJECT 32 33public: 34 tst_QWebHistory(); 35 virtual ~tst_QWebHistory(); 36 37protected : 38 void loadPage(int nr) 39 { 40 frame->load(QUrl("qrc:/resources/page" + QString::number(nr) + ".html")); 41 waitForLoadFinished.exec(); 42 } 43 44public slots: 45 void init(); 46 void cleanup(); 47 48private slots: 49 void title(); 50 void count(); 51 void back(); 52 void forward(); 53 void itemAt(); 54 void goToItem(); 55 void items(); 56 void serialize_1(); //QWebHistory countity 57 void serialize_2(); //QWebHistory index 58 void serialize_3(); //QWebHistoryItem 59 void saveAndRestore_crash_1(); 60 void saveAndRestore_crash_2(); 61 void saveAndRestore_crash_3(); 62 void popPushState_data(); 63 void popPushState(); 64 void clear(); 65 66 67private: 68 QWebPage* page; 69 QWebFrame* frame; 70 QWebHistory* hist; 71 QEventLoop waitForLoadFinished; //operation on history are asynchronous! 72 int histsize; 73}; 74 75tst_QWebHistory::tst_QWebHistory() 76{ 77} 78 79tst_QWebHistory::~tst_QWebHistory() 80{ 81} 82 83void tst_QWebHistory::init() 84{ 85 page = new QWebPage(this); 86 frame = page->mainFrame(); 87 connect(page, SIGNAL(loadFinished(bool)), &waitForLoadFinished, SLOT(quit()), Qt::QueuedConnection); 88 89 for (int i = 1;i < 6;i++) { 90 loadPage(i); 91 } 92 hist = page->history(); 93 histsize = 5; 94} 95 96void tst_QWebHistory::cleanup() 97{ 98 delete page; 99} 100 101/** 102 * Check QWebHistoryItem::title() method 103 */ 104void tst_QWebHistory::title() 105{ 106 QCOMPARE(hist->currentItem().title(), QString("page5")); 107} 108 109/** 110 * Check QWebHistory::count() method 111 */ 112void tst_QWebHistory::count() 113{ 114 QCOMPARE(hist->count(), histsize); 115} 116 117/** 118 * Check QWebHistory::back() method 119 */ 120void tst_QWebHistory::back() 121{ 122 for (int i = histsize;i > 1;i--) { 123 QCOMPARE(page->mainFrame()->toPlainText(), QString("page") + QString::number(i)); 124 hist->back(); 125 waitForLoadFinished.exec(); 126 } 127 //try one more time (too many). crash test 128 hist->back(); 129 QCOMPARE(page->mainFrame()->toPlainText(), QString("page1")); 130} 131 132/** 133 * Check QWebHistory::forward() method 134 */ 135void tst_QWebHistory::forward() 136{ 137 //rewind history :-) 138 while (hist->canGoBack()) { 139 hist->back(); 140 waitForLoadFinished.exec(); 141 } 142 143 for (int i = 1;i < histsize;i++) { 144 QCOMPARE(page->mainFrame()->toPlainText(), QString("page") + QString::number(i)); 145 hist->forward(); 146 waitForLoadFinished.exec(); 147 } 148 //try one more time (too many). crash test 149 hist->forward(); 150 QCOMPARE(page->mainFrame()->toPlainText(), QString("page") + QString::number(histsize)); 151} 152 153/** 154 * Check QWebHistory::itemAt() method 155 */ 156void tst_QWebHistory::itemAt() 157{ 158 for (int i = 1;i < histsize;i++) { 159 QCOMPARE(hist->itemAt(i - 1).title(), QString("page") + QString::number(i)); 160 QVERIFY(hist->itemAt(i - 1).isValid()); 161 } 162 //check out of range values 163 QVERIFY(!hist->itemAt(-1).isValid()); 164 QVERIFY(!hist->itemAt(histsize).isValid()); 165} 166 167/** 168 * Check QWebHistory::goToItem() method 169 */ 170void tst_QWebHistory::goToItem() 171{ 172 QWebHistoryItem current = hist->currentItem(); 173 hist->back(); 174 waitForLoadFinished.exec(); 175 hist->back(); 176 waitForLoadFinished.exec(); 177 QVERIFY(hist->currentItem().title() != current.title()); 178 hist->goToItem(current); 179 waitForLoadFinished.exec(); 180 QCOMPARE(hist->currentItem().title(), current.title()); 181} 182 183/** 184 * Check QWebHistory::items() method 185 */ 186void tst_QWebHistory::items() 187{ 188 QList<QWebHistoryItem> items = hist->items(); 189 //check count 190 QCOMPARE(histsize, items.count()); 191 192 //check order 193 for (int i = 1;i <= histsize;i++) { 194 QCOMPARE(items.at(i - 1).title(), QString("page") + QString::number(i)); 195 } 196} 197 198/** 199 * Check history state after serialization (pickle, persistent..) method 200 * Checks history size, history order 201 */ 202void tst_QWebHistory::serialize_1() 203{ 204 QByteArray tmp; //buffer 205 QDataStream save(&tmp, QIODevice::WriteOnly); //here data will be saved 206 QDataStream load(&tmp, QIODevice::ReadOnly); //from here data will be loaded 207 208 save << *hist; 209 QVERIFY(save.status() == QDataStream::Ok); 210 QCOMPARE(hist->count(), histsize); 211 212 //check size of history 213 //load next page to find differences 214 loadPage(6); 215 QCOMPARE(hist->count(), histsize + 1); 216 load >> *hist; 217 QVERIFY(load.status() == QDataStream::Ok); 218 QCOMPARE(hist->count(), histsize); 219 220 //check order of historyItems 221 QList<QWebHistoryItem> items = hist->items(); 222 for (int i = 1;i <= histsize;i++) { 223 QCOMPARE(items.at(i - 1).title(), QString("page") + QString::number(i)); 224 } 225} 226 227/** 228 * Check history state after serialization (pickle, persistent..) method 229 * Checks history currentIndex value 230 */ 231void tst_QWebHistory::serialize_2() 232{ 233 QByteArray tmp; //buffer 234 QDataStream save(&tmp, QIODevice::WriteOnly); //here data will be saved 235 QDataStream load(&tmp, QIODevice::ReadOnly); //from here data will be loaded 236 237 int oldCurrentIndex = hist->currentItemIndex(); 238 239 hist->back(); 240 waitForLoadFinished.exec(); 241 hist->back(); 242 waitForLoadFinished.exec(); 243 //check if current index was changed (make sure that it is not last item) 244 QVERIFY(hist->currentItemIndex() != oldCurrentIndex); 245 //save current index 246 oldCurrentIndex = hist->currentItemIndex(); 247 248 save << *hist; 249 QVERIFY(save.status() == QDataStream::Ok); 250 load >> *hist; 251 QVERIFY(load.status() == QDataStream::Ok); 252 253 //check current index 254 QCOMPARE(hist->currentItemIndex(), oldCurrentIndex); 255} 256 257/** 258 * Check history state after serialization (pickle, persistent..) method 259 * Checks QWebHistoryItem public property after serialization 260 */ 261void tst_QWebHistory::serialize_3() 262{ 263 QByteArray tmp; //buffer 264 QDataStream save(&tmp, QIODevice::WriteOnly); //here data will be saved 265 QDataStream load(&tmp, QIODevice::ReadOnly); //from here data will be loaded 266 267 //prepare two different history items 268 QWebHistoryItem a = hist->currentItem(); 269 a.setUserData("A - user data"); 270 271 //check properties BEFORE serialization 272 QString title(a.title()); 273 QDateTime lastVisited(a.lastVisited()); 274 QUrl originalUrl(a.originalUrl()); 275 QUrl url(a.url()); 276 QVariant userData(a.userData()); 277 278 save << *hist; 279 QVERIFY(save.status() == QDataStream::Ok); 280 QVERIFY(!load.atEnd()); 281 hist->clear(); 282 QVERIFY(hist->count() == 1); 283 load >> *hist; 284 QVERIFY(load.status() == QDataStream::Ok); 285 QWebHistoryItem b = hist->currentItem(); 286 287 //check properties AFTER serialization 288 QCOMPARE(b.title(), title); 289 QCOMPARE(b.lastVisited(), lastVisited); 290 QCOMPARE(b.originalUrl(), originalUrl); 291 QCOMPARE(b.url(), url); 292 QCOMPARE(b.userData(), userData); 293 294 //Check if all data was read 295 QVERIFY(load.atEnd()); 296} 297 298static void saveHistory(QWebHistory* history, QByteArray* in) 299{ 300 in->clear(); 301 QDataStream save(in, QIODevice::WriteOnly); 302 save << *history; 303} 304 305static void restoreHistory(QWebHistory* history, QByteArray* out) 306{ 307 QDataStream load(out, QIODevice::ReadOnly); 308 load >> *history; 309} 310 311/** The test shouldn't crash */ 312void tst_QWebHistory::saveAndRestore_crash_1() 313{ 314 QByteArray buffer; 315 saveHistory(hist, &buffer); 316 for (unsigned i = 0; i < 5; i++) { 317 restoreHistory(hist, &buffer); 318 saveHistory(hist, &buffer); 319 } 320} 321 322/** The test shouldn't crash */ 323void tst_QWebHistory::saveAndRestore_crash_2() 324{ 325 QByteArray buffer; 326 saveHistory(hist, &buffer); 327 QWebPage* page2 = new QWebPage(this); 328 QWebHistory* hist2 = page2->history(); 329 for (unsigned i = 0; i < 5; i++) { 330 restoreHistory(hist2, &buffer); 331 saveHistory(hist2, &buffer); 332 } 333 delete page2; 334} 335 336/** The test shouldn't crash */ 337void tst_QWebHistory::saveAndRestore_crash_3() 338{ 339 QByteArray buffer; 340 saveHistory(hist, &buffer); 341 QWebPage* page2 = new QWebPage(this); 342 QWebHistory* hist1 = hist; 343 QWebHistory* hist2 = page2->history(); 344 for (unsigned i = 0; i < 5; i++) { 345 restoreHistory(hist1, &buffer); 346 restoreHistory(hist2, &buffer); 347 QVERIFY(hist1->count() == hist2->count()); 348 QVERIFY(hist1->count() == histsize); 349 hist2->back(); 350 saveHistory(hist2, &buffer); 351 hist2->clear(); 352 } 353 delete page2; 354} 355 356void tst_QWebHistory::popPushState_data() 357{ 358 QTest::addColumn<QString>("script"); 359 QTest::newRow("pushState") << "history.pushState(123, \"foo\");"; 360 QTest::newRow("replaceState") << "history.replaceState(\"a\", \"b\");"; 361 QTest::newRow("back") << "history.back();"; 362 QTest::newRow("forward") << "history.forward();"; 363 QTest::newRow("clearState") << "history.clearState();"; 364} 365 366/** Crash test, WebKit bug 38840 (https://bugs.webkit.org/show_bug.cgi?id=38840) */ 367void tst_QWebHistory::popPushState() 368{ 369 QFETCH(QString, script); 370 QWebPage page; 371 page.mainFrame()->setHtml("<html><body>long live Qt!</body></html>"); 372 page.mainFrame()->evaluateJavaScript(script); 373} 374 375/** ::clear */ 376void tst_QWebHistory::clear() 377{ 378 QByteArray buffer; 379 380 QAction* actionBack = page->action(QWebPage::Back); 381 QVERIFY(actionBack->isEnabled()); 382 saveHistory(hist, &buffer); 383 QVERIFY(hist->count() > 1); 384 hist->clear(); 385 QVERIFY(hist->count() == 1); // Leave current item. 386 QVERIFY(!actionBack->isEnabled()); 387 388 QWebPage* page2 = new QWebPage(this); 389 QWebHistory* hist2 = page2->history(); 390 QVERIFY(hist2->count() == 0); 391 hist2->clear(); 392 QVERIFY(hist2->count() == 0); // Do not change anything. 393 delete page2; 394} 395 396QTEST_MAIN(tst_QWebHistory) 397#include "tst_qwebhistory.moc" 398