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
29 class tst_QWebHistory : public QObject
30 {
31 Q_OBJECT
32
33 public:
34 tst_QWebHistory();
35 virtual ~tst_QWebHistory();
36
37 protected :
loadPage(int nr)38 void loadPage(int nr)
39 {
40 frame->load(QUrl("qrc:/resources/page" + QString::number(nr) + ".html"));
41 waitForLoadFinished.exec();
42 }
43
44 public slots:
45 void init();
46 void cleanup();
47
48 private 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
67 private:
68 QWebPage* page;
69 QWebFrame* frame;
70 QWebHistory* hist;
71 QEventLoop waitForLoadFinished; //operation on history are asynchronous!
72 int histsize;
73 };
74
tst_QWebHistory()75 tst_QWebHistory::tst_QWebHistory()
76 {
77 }
78
~tst_QWebHistory()79 tst_QWebHistory::~tst_QWebHistory()
80 {
81 }
82
init()83 void 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
cleanup()96 void tst_QWebHistory::cleanup()
97 {
98 delete page;
99 }
100
101 /**
102 * Check QWebHistoryItem::title() method
103 */
title()104 void tst_QWebHistory::title()
105 {
106 QCOMPARE(hist->currentItem().title(), QString("page5"));
107 }
108
109 /**
110 * Check QWebHistory::count() method
111 */
count()112 void tst_QWebHistory::count()
113 {
114 QCOMPARE(hist->count(), histsize);
115 }
116
117 /**
118 * Check QWebHistory::back() method
119 */
back()120 void 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 */
forward()135 void 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 */
itemAt()156 void 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 */
goToItem()170 void 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 */
items()186 void 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 */
serialize_1()202 void 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 */
serialize_2()231 void 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 */
serialize_3()261 void 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
saveHistory(QWebHistory * history,QByteArray * in)298 static void saveHistory(QWebHistory* history, QByteArray* in)
299 {
300 in->clear();
301 QDataStream save(in, QIODevice::WriteOnly);
302 save << *history;
303 }
304
restoreHistory(QWebHistory * history,QByteArray * out)305 static void restoreHistory(QWebHistory* history, QByteArray* out)
306 {
307 QDataStream load(out, QIODevice::ReadOnly);
308 load >> *history;
309 }
310
311 /** The test shouldn't crash */
saveAndRestore_crash_1()312 void 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 */
saveAndRestore_crash_2()323 void 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 */
saveAndRestore_crash_3()337 void 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
popPushState_data()356 void 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) */
popPushState()367 void 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 */
clear()376 void 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
396 QTEST_MAIN(tst_QWebHistory)
397 #include "tst_qwebhistory.moc"
398