1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Charts module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 or (at your option) any later version
20** approved by the KDE Free Qt Foundation. The licenses are as published by
21** the Free Software Foundation and appearing in the file LICENSE.GPL3
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30#include "tst_qxyseries.h"
31
32Q_DECLARE_METATYPE(QList<QPointF>)
33
34void tst_QXYSeries::initTestCase()
35{
36}
37
38void tst_QXYSeries::cleanupTestCase()
39{
40 QTest::qWait(ms: 1); // Allow final deleteLaters to run
41}
42
43void tst_QXYSeries::init()
44{
45 m_view = new QChartView(newQChartOrQPolarChart());
46 m_view->resize(w: 200, h: 200);
47 m_chart = m_view->chart();
48}
49
50void tst_QXYSeries::cleanup()
51{
52 delete m_view;
53 m_view = 0;
54 m_chart = 0;
55 m_series = 0;
56}
57
58void tst_QXYSeries::seriesName()
59{
60 QSignalSpy nameSpy(m_series, SIGNAL(nameChanged()));
61 QCOMPARE(m_series->name(), QString());
62 m_series->setName("seriesname");
63 QCOMPARE(m_series->name(), QString("seriesname"));
64 TRY_COMPARE(nameSpy.count(), 1);
65}
66
67void tst_QXYSeries::seriesVisible()
68{
69 QSignalSpy visibleSpy(m_series, SIGNAL(visibleChanged()));
70 QCOMPARE(m_series->isVisible(), true);
71 m_series->setVisible(false);
72 QCOMPARE(m_series->isVisible(), false);
73 m_series->setVisible(true);
74 TRY_COMPARE(visibleSpy.count(), 2);
75}
76
77void tst_QXYSeries::seriesOpacity()
78{
79 QSignalSpy opacitySpy(m_series, SIGNAL(opacityChanged()));
80 QCOMPARE(m_series->opacity(), 1.0);
81
82 m_series->setOpacity(0.5);
83 QCOMPARE(m_series->opacity(), 0.5);
84 QCOMPARE(opacitySpy.count(), 1);
85
86 m_series->setOpacity(0.0);
87 QCOMPARE(m_series->opacity(), 0.0);
88 QCOMPARE(opacitySpy.count(), 2);
89
90 m_series->setOpacity(1.0);
91 QCOMPARE(m_series->opacity(), 1.0);
92 QCOMPARE(opacitySpy.count(), 3);
93}
94
95void tst_QXYSeries::pointLabelsFormat()
96{
97 QSignalSpy labelsFormatSpy(m_series, SIGNAL(pointLabelsFormatChanged(QString)));
98 QCOMPARE(m_series->pointLabelsFormat(), QLatin1String("@xPoint, @yPoint"));
99
100 QString format("@yPoint");
101 m_series->setPointLabelsFormat(format);
102 TRY_COMPARE(labelsFormatSpy.count(), 1);
103 QList<QVariant> arguments = labelsFormatSpy.takeFirst();
104 QVERIFY(arguments.at(0).toString() == format);
105
106 m_series->setPointLabelsFormat(QString());
107 TRY_COMPARE(labelsFormatSpy.count(), 1);
108 arguments = labelsFormatSpy.takeFirst();
109 QVERIFY(arguments.at(0).toString() == QString());
110
111}
112
113void tst_QXYSeries::pointLabelsVisible()
114{
115 QSignalSpy labelsVisibleSpy(m_series, SIGNAL(pointLabelsVisibilityChanged(bool)));
116 QCOMPARE(m_series->pointLabelsVisible(), false);
117
118 m_series->setPointLabelsVisible();
119 QCOMPARE(m_series->pointLabelsVisible(), true);
120 TRY_COMPARE(labelsVisibleSpy.count(), 1);
121 QList<QVariant> arguments = labelsVisibleSpy.takeFirst();
122 QVERIFY(arguments.at(0).toBool() == true);
123
124 m_series->setPointLabelsVisible(false);
125 QCOMPARE(m_series->pointLabelsVisible(), false);
126 TRY_COMPARE(labelsVisibleSpy.count(), 1);
127 arguments = labelsVisibleSpy.takeFirst();
128 QVERIFY(arguments.at(0).toBool() == false);
129}
130
131void tst_QXYSeries::pointLabelsFont()
132{
133 QFont defaultFont(m_series->pointLabelsFont());
134 QSignalSpy labelsFontSpy(m_series, SIGNAL(pointLabelsFontChanged(QFont)));
135
136 QFont font("Times", 10);
137 m_series->setPointLabelsFont(font);
138 TRY_COMPARE(labelsFontSpy.count(), 1);
139 QList<QVariant> arguments = labelsFontSpy.takeFirst();
140 QVERIFY(arguments.at(0).value<QFont>() == font);
141
142 m_series->setPointLabelsFont(defaultFont);
143 TRY_COMPARE(labelsFontSpy.count(), 1);
144 arguments = labelsFontSpy.takeFirst();
145 QVERIFY(arguments.at(0).value<QFont>() == defaultFont);
146
147}
148
149void tst_QXYSeries::pointLabelsColor()
150{
151 QColor defaultColor(QPen().color());
152 QSignalSpy labelsColorSpy(m_series, SIGNAL(pointLabelsColorChanged(QColor)));
153 QCOMPARE(m_series->pointLabelsColor(), defaultColor);
154
155 QColor color(Qt::blue);
156 m_series->setPointLabelsColor(color);
157 TRY_COMPARE(labelsColorSpy.count(), 1);
158 QList<QVariant> arguments = labelsColorSpy.takeFirst();
159 QVERIFY(arguments.at(0).value<QColor>() == color);
160
161 m_series->setPointLabelsColor(defaultColor);
162 TRY_COMPARE(labelsColorSpy.count(), 1);
163 arguments = labelsColorSpy.takeFirst();
164 QVERIFY(arguments.at(0).value<QColor>() == defaultColor);
165}
166
167void tst_QXYSeries::pointLabelsClipping()
168{
169 QSignalSpy labelsClippingSpy(m_series, SIGNAL(pointLabelsClippingChanged(bool)));
170 QCOMPARE(m_series->pointLabelsClipping(), true);
171
172 m_series->setPointLabelsClipping(false);
173 QCOMPARE(m_series->pointLabelsClipping(), false);
174 TRY_COMPARE(labelsClippingSpy.count(), 1);
175 QList<QVariant> arguments = labelsClippingSpy.takeFirst();
176 QVERIFY(arguments.at(0).toBool() == false);
177
178 m_series->setPointLabelsClipping();
179 QCOMPARE(m_series->pointLabelsClipping(), true);
180 TRY_COMPARE(labelsClippingSpy.count(), 1);
181 arguments = labelsClippingSpy.takeFirst();
182 QVERIFY(arguments.at(0).toBool() == true);
183}
184
185void tst_QXYSeries::append_data()
186{
187 QTest::addColumn< QList<QPointF> >(name: "points");
188 QTest::addColumn< QList<QPointF> >(name: "otherPoints");
189 QTest::newRow(dataTag: "0,0 1,1 2,2 3,3")
190 << (QList<QPointF>() << QPointF(0,0) << QPointF(1,1) << QPointF(2,2) << QPointF(3,3))
191 << (QList<QPointF>() << QPointF(4,4) << QPointF(5,5) << QPointF(6,6) << QPointF(7,7));
192 QTest::newRow(dataTag: "0,0 -1,-1 -2,-2 -3,-3")
193 << (QList<QPointF>() << QPointF(0,0) << QPointF(-1,-1) << QPointF(-2,-2) << QPointF(-3,-3))
194 << (QList<QPointF>() << QPointF(-4,-4) << QPointF(-5,-5) << QPointF(-6,-6) << QPointF(-7,-7));
195}
196
197
198void tst_QXYSeries::append_raw_data()
199{
200 append_data();
201}
202
203void tst_QXYSeries::append_raw()
204{
205 QFETCH(QList<QPointF>, points);
206 QFETCH(QList<QPointF>, otherPoints);
207 QSignalSpy spy0(m_series, SIGNAL(clicked(QPointF)));
208 QSignalSpy addedSpy(m_series, SIGNAL(pointAdded(int)));
209 m_series->append(points);
210 TRY_COMPARE(spy0.count(), 0);
211 TRY_COMPARE(addedSpy.count(), points.count());
212 QCOMPARE(m_series->points(), points);
213 QCOMPARE(m_series->pointsVector(), points.toVector());
214
215 // Process events between appends
216 foreach (const QPointF &point, otherPoints) {
217 m_series->append(point);
218 QApplication::processEvents();
219 }
220}
221
222void tst_QXYSeries::chart_append_data()
223{
224 append_data();
225}
226
227void tst_QXYSeries::chart_append()
228{
229 append_raw();
230 m_chart->addSeries(series: m_series);
231 m_view->show();
232 QVERIFY(QTest::qWaitForWindowExposed(m_view));
233}
234
235void tst_QXYSeries::append_chart_data()
236{
237 append_data();
238}
239
240void tst_QXYSeries::append_chart()
241{
242 m_view->show();
243 m_chart->addSeries(series: m_series);
244 QVERIFY(QTest::qWaitForWindowExposed(m_view));
245 append_raw();
246
247}
248
249void tst_QXYSeries::append_chart_animation_data()
250{
251 append_data();
252}
253
254void tst_QXYSeries::append_chart_animation()
255{
256 m_chart->setAnimationOptions(QChart::AllAnimations);
257 append_chart();
258}
259
260void tst_QXYSeries::count_data()
261{
262 QTest::addColumn<int>(name: "count");
263 QTest::newRow(dataTag: "0") << 0;
264 QTest::newRow(dataTag: "5") << 5;
265 QTest::newRow(dataTag: "10") << 5;
266}
267
268void tst_QXYSeries::count_raw_data()
269{
270 count_data();
271}
272
273void tst_QXYSeries::count_raw()
274{
275 QFETCH(int, count);
276
277 QSignalSpy spy0(m_series, SIGNAL(clicked(QPointF)));
278
279 for(int i=0 ; i< count; ++i)
280 m_series->append(x: i,y: i);
281
282 TRY_COMPARE(spy0.count(), 0);
283 QCOMPARE(m_series->count(), count);
284}
285
286void tst_QXYSeries::remove_raw_data()
287{
288 append_data();
289}
290
291void tst_QXYSeries::remove_raw()
292{
293 QFETCH(QList<QPointF>, points);
294 QSignalSpy spy0(m_series, SIGNAL(clicked(QPointF)));
295 m_series->append(points);
296 TRY_COMPARE(spy0.count(), 0);
297 QCOMPARE(m_series->points(), points);
298
299 foreach (const QPointF& point,points)
300 m_series->remove(point);
301
302 QCOMPARE(m_series->points().count(), 0);
303 TRY_COMPARE(spy0.count(), 0);
304
305 m_series->append(points);
306 QCOMPARE(m_series->points(), points);
307
308 //reverse order
309 for(int i = points.count()-1 ; i>=0; i--){
310 m_series->remove(point: points[i]);
311 }
312 QCOMPARE(m_series->points().count(), 0);
313
314 QApplication::processEvents();
315
316 // Process events between removes
317 m_series->append(points);
318 QCOMPARE(m_series->points(), points);
319 foreach (const QPointF &point, points) {
320 m_series->remove(point);
321 QApplication::processEvents();
322 }
323
324 // Actual meaningful delay between removes, but still shorter than animation duration
325 // (simulate e.g. spamming a hypothetical "remove last point"-button)
326 QList<QPointF> bunchOfPoints;
327 for (int i = 0; i < 10; i++)
328 bunchOfPoints.append(t: QPointF(i, QRandomGenerator::global()->generateDouble()));
329 m_series->replace(points: bunchOfPoints);
330 QCOMPARE(m_series->points(), bunchOfPoints);
331 QTest::qWait(ms: 1500); // Wait for append animations to be over
332 for (int i = bunchOfPoints.count() - 1; i >= 0; i--) {
333 m_series->remove(point: bunchOfPoints.at(i));
334 QTest::qWait(ms: 50);
335 }
336 QCOMPARE(m_series->points().count(), 0);
337
338 // Removal using index
339 for (int i = 0; i < 10; i++)
340 bunchOfPoints.append(t: QPointF(i, QRandomGenerator::global()->generateDouble()));
341 m_series->replace(points: bunchOfPoints);
342 m_series->remove(index: 5);
343 m_series->remove(index: 0);
344 QCOMPARE(m_series->points().count(), (bunchOfPoints.count() - 2));
345 for (int i = bunchOfPoints.count() - 3; i >= 0; i--) {
346 m_series->remove(index: i);
347 QCOMPARE(m_series->points().count(), i);
348 }
349 QCOMPARE(m_series->points().count(), 0);
350
351 // Multiple removal using index
352 for (int i = 0; i < 10; i++)
353 bunchOfPoints.append(t: QPointF(i, QRandomGenerator::global()->generateDouble()));
354 m_series->replace(points: bunchOfPoints);
355 m_series->removePoints(index: 5, count: 2);
356 m_series->removePoints(index: 0, count: 3);
357 QCOMPARE(m_series->points().count(), (bunchOfPoints.count() - 5));
358 m_series->removePoints(index: 0, count: (bunchOfPoints.count() - 5));
359 QCOMPARE(m_series->points().count(), 0);
360}
361
362void tst_QXYSeries::remove_chart_data()
363{
364 append_data();
365}
366
367void tst_QXYSeries::remove_chart()
368{
369 m_view->show();
370 m_chart->addSeries(series: m_series);
371 QVERIFY(QTest::qWaitForWindowExposed(m_view));
372 remove_raw();
373}
374
375void tst_QXYSeries::remove_chart_animation_data()
376{
377 append_data();
378}
379
380void tst_QXYSeries::remove_chart_animation()
381{
382 m_chart->setAnimationOptions(QChart::AllAnimations);
383 remove_chart();
384}
385
386
387void tst_QXYSeries::clear_raw_data()
388{
389 append_data();
390}
391
392void tst_QXYSeries::clear_raw()
393{
394 QFETCH(QList<QPointF>, points);
395 QSignalSpy spy0(m_series, SIGNAL(clicked(QPointF)));
396 m_series->append(points);
397 TRY_COMPARE(spy0.count(), 0);
398 QCOMPARE(m_series->points(), points);
399 m_series->clear();
400 TRY_COMPARE(spy0.count(), 0);
401 QCOMPARE(m_series->points().count(), 0);
402
403 QApplication::processEvents();
404}
405
406void tst_QXYSeries::clear_chart_data()
407{
408 append_data();
409}
410
411void tst_QXYSeries::clear_chart()
412{
413 m_view->show();
414 m_chart->addSeries(series: m_series);
415 QVERIFY(QTest::qWaitForWindowExposed(m_view));
416 clear_raw();
417}
418
419void tst_QXYSeries::clear_chart_animation_data()
420{
421 append_data();
422}
423
424void tst_QXYSeries::clear_chart_animation()
425{
426 m_chart->setAnimationOptions(QChart::AllAnimations);
427 clear_chart();
428}
429
430void tst_QXYSeries::replace_raw_data()
431{
432 append_data();
433}
434
435void tst_QXYSeries::replace_raw()
436{
437 QFETCH(QList<QPointF>, points);
438 QFETCH(QList<QPointF>, otherPoints);
439 QSignalSpy pointReplacedSpy(m_series, SIGNAL(pointReplaced(int)));
440 QSignalSpy pointsReplacedSpy(m_series, SIGNAL(pointsReplaced()));
441 m_series->append(points);
442 TRY_COMPARE(pointReplacedSpy.count(), 0);
443 TRY_COMPARE(pointsReplacedSpy.count(), 0);
444 QCOMPARE(m_series->points(), points);
445
446 foreach (const QPointF& point, points)
447 m_series->replace(oldX: point.x(),oldY: point.y(),newX: point.x(),newY: 0);
448 TRY_COMPARE(pointReplacedSpy.count(), points.count());
449 TRY_COMPARE(pointsReplacedSpy.count(), 0);
450
451 // Replace a point that does not exist
452 m_series->replace(oldX: -123, oldY: 999, newX: 0, newY: 0);
453 TRY_COMPARE(pointReplacedSpy.count(), points.count());
454 TRY_COMPARE(pointsReplacedSpy.count(), 0);
455
456 QList<QPointF> newPoints = m_series->points();
457 QCOMPARE(newPoints.count(), points.count());
458 for(int i =0 ; i<points.count() ; ++i) {
459 QCOMPARE(points[i].x(), newPoints[i].x());
460 QCOMPARE(newPoints[i].y(), 0.0);
461 }
462
463 // Replace all points
464 QList<QPointF> allPoints;
465 for (int i = 0; i < 10; i++)
466 allPoints.append(t: QPointF(i, QRandomGenerator::global()->generateDouble()));
467 m_series->replace(points: allPoints);
468 TRY_COMPARE(pointReplacedSpy.count(), points.count());
469 TRY_COMPARE(pointsReplacedSpy.count(), 1);
470
471 m_series->replace(points);
472 QApplication::processEvents();
473
474 // Process events between replaces
475 for (int i = 0; i < points.count(); ++i) {
476 m_series->replace(oldPoint: points.at(i), newPoint: otherPoints.at(i));
477 QApplication::processEvents();
478 }
479
480 newPoints = m_series->points();
481 QCOMPARE(newPoints.count(), points.count());
482 for (int i = 0; i < points.count(); ++i) {
483 QCOMPARE(otherPoints.at(i).x(), newPoints.at(i).x());
484 QCOMPARE(otherPoints.at(i).y(), newPoints.at(i).y());
485 }
486
487 // Append followed by a replace shouldn't crash
488 m_series->clear();
489 m_series->append(point: QPointF(22,22));
490 m_series->append(point: QPointF(23,23));
491 QApplication::processEvents();
492 m_series->replace(oldPoint: QPointF(23,23), newPoint: otherPoints.at(i: 1));
493 QCOMPARE(m_series->points().at(1).x(), otherPoints.at(1).x());
494 QCOMPARE(m_series->points().at(1).y(), otherPoints.at(1).y());
495
496 // Replace using index
497 m_series->append(points: otherPoints);
498 m_series->replace(index: 0, newPoint: QPointF(333, 333));
499 m_series->replace(index: 3, newX: 444, newY: 444);
500 m_series->replace(index: m_series->count() - 1, newPoint: QPointF(555, 555));
501 QCOMPARE(m_series->points().at(0), QPointF(333, 333));
502 QCOMPARE(m_series->points().at(3), QPointF(444, 444));
503 QCOMPARE(m_series->points().at(m_series->count() - 1), QPointF(555, 555));
504}
505
506
507void tst_QXYSeries::replace_chart_data()
508{
509 append_data();
510}
511
512void tst_QXYSeries::replace_chart()
513{
514 m_view->show();
515 m_chart->addSeries(series: m_series);
516 QVERIFY(QTest::qWaitForWindowExposed(m_view));
517 replace_raw();
518}
519
520void tst_QXYSeries::replace_chart_animation_data()
521{
522 append_data();
523}
524
525void tst_QXYSeries::replace_chart_animation()
526{
527 m_chart->setAnimationOptions(QChart::AllAnimations);
528 replace_chart();
529}
530
531void tst_QXYSeries::insert_data()
532{
533 append_data();
534}
535
536void tst_QXYSeries::insert()
537{
538 QFETCH(QList<QPointF>, points);
539 m_series->append(points);
540
541 QSignalSpy addedSpy(m_series, SIGNAL(pointAdded(int)));
542
543 m_series->insert(index: 0, point: QPointF(5, 5));
544 TRY_COMPARE(addedSpy.count(), 1);
545 QCOMPARE(m_series->points().count(), points.count() + 1);
546
547 m_series->insert(index: m_series->count(), point: QPointF(6, 6));
548 TRY_COMPARE(addedSpy.count(), 2);
549 QCOMPARE(m_series->points().count(), points.count() + 2);
550}
551
552void tst_QXYSeries::oper_data()
553{
554 append_data();
555}
556
557void tst_QXYSeries::oper()
558{
559 QFETCH(QList<QPointF>, points);
560
561 QSignalSpy spy0(m_series, SIGNAL(clicked(QPointF)));
562
563 foreach (const QPointF& point,points)
564 {
565 *m_series<<point;
566 }
567
568 QCOMPARE(m_series->points(), points);
569 TRY_COMPARE(spy0.count(), 0);
570}
571
572
573void tst_QXYSeries::pen_data()
574{
575 QTest::addColumn<QPen>(name: "pen");
576 QTest::newRow(dataTag: "null") << QPen();
577 QTest::newRow(dataTag: "blue") << QPen(Qt::blue);
578 QTest::newRow(dataTag: "black") << QPen(Qt::black);
579 QTest::newRow(dataTag: "red") << QPen(Qt::red);
580}
581
582void tst_QXYSeries::pen()
583{
584 QFETCH(QPen, pen);
585
586 QSignalSpy spy0(m_series, SIGNAL(clicked(QPointF)));
587 m_series->setPen(pen);
588
589 TRY_COMPARE(spy0.count(), 0);
590 QCOMPARE(m_series->pen(), pen);
591
592 m_chart->addSeries(series: m_series);
593
594 if (pen != QPen())
595 QCOMPARE(m_series->pen(), pen);
596
597 m_chart->setTheme(QChart::ChartThemeDark);
598
599 // setting a theme will overwrite all customizations
600 if (pen != QPen())
601 QVERIFY(m_series->pen() != pen);
602}
603
604void tst_QXYSeries::pointsVisible_data()
605{
606 QTest::addColumn<bool>(name: "pointsVisible");
607 QTest::newRow(dataTag: "true") << true;
608 QTest::newRow(dataTag: "false") << false;
609}
610
611void tst_QXYSeries::pointsVisible_raw_data()
612{
613 pointsVisible_data();
614}
615
616void tst_QXYSeries::pointsVisible_raw()
617{
618 QFETCH(bool, pointsVisible);
619 QSignalSpy spy0(m_series, SIGNAL(clicked(QPointF)));
620 m_series->setPointsVisible(pointsVisible);
621 TRY_COMPARE(spy0.count(), 0);
622 QCOMPARE(m_series->pointsVisible(), pointsVisible);
623}
624
625void tst_QXYSeries::changedSignals()
626{
627 QSignalSpy visibleSpy(m_series, SIGNAL(visibleChanged()));
628 QSignalSpy nameSpy(m_series, SIGNAL(nameChanged()));
629 QSignalSpy colorSpy(m_series, SIGNAL(colorChanged(QColor)));
630
631 // Visibility
632 m_series->setVisible(false);
633 m_series->setVisible(false);
634 TRY_COMPARE(visibleSpy.count(), 1);
635 m_series->setVisible(true);
636 TRY_COMPARE(visibleSpy.count(), 2);
637
638 // Color
639 m_series->setColor(QColor("aliceblue"));
640 TRY_COMPARE(colorSpy.count(), 1);
641
642 // Pen and Brush
643 QPen p = m_series->pen();
644 p.setColor("aquamarine");
645 m_series->setPen(p);
646 QBrush b = m_series->brush();
647 b.setColor("beige");
648 m_series->setBrush(b);
649 TRY_COMPARE(colorSpy.count(), 2);
650
651 // Verify all the signals again, to make sure no extra signals were emitted
652 TRY_COMPARE(visibleSpy.count(), 2);
653 TRY_COMPARE(nameSpy.count(), 0);
654 TRY_COMPARE(colorSpy.count(), 2);
655}
656

source code of qtcharts/tests/auto/qxyseries/tst_qxyseries.cpp