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 <QtTest/QtTest>
31#include <QtCharts/qabstractaxis.h>
32#include <QtCharts/qvalueaxis.h>
33#include <QtCharts/qlogvalueaxis.h>
34#include <QtCharts/qbarcategoryaxis.h>
35#include <QtCharts/qcategoryaxis.h>
36#ifndef QT_QREAL_IS_FLOAT
37#include <QtCharts/qdatetimeaxis.h>
38#endif
39#include <QtCharts/qlineseries.h>
40#include <QtCharts/qareaseries.h>
41#include <QtCharts/qscatterseries.h>
42#include <QtCharts/qsplineseries.h>
43#include <QtCharts/qpieseries.h>
44#include <QtCharts/qbarseries.h>
45#include <QtCharts/qpercentbarseries.h>
46#include <QtCharts/qstackedbarseries.h>
47#include <private/chartdataset_p.h>
48#include <private/abstractdomain_p.h>
49#include <tst_definitions.h>
50
51QT_CHARTS_USE_NAMESPACE
52
53Q_DECLARE_METATYPE(AbstractDomain *)
54Q_DECLARE_METATYPE(QAbstractAxis *)
55Q_DECLARE_METATYPE(QAbstractSeries *)
56Q_DECLARE_METATYPE(QList<QAbstractSeries *>)
57Q_DECLARE_METATYPE(QList<QAbstractAxis *>)
58Q_DECLARE_METATYPE(Qt::Alignment)
59Q_DECLARE_METATYPE(QList<Qt::Alignment>)
60Q_DECLARE_METATYPE(QLineSeries *)
61
62class tst_ChartDataSet: public QObject {
63
64 Q_OBJECT
65public:
66 tst_ChartDataSet():m_dataset(0){};
67
68public Q_SLOTS:
69 void initTestCase();
70 void cleanupTestCase();
71 void init();
72 void cleanup();
73
74private Q_SLOTS:
75 void chartdataset_data();
76 void chartdataset();
77 void addSeries_data();
78 void addSeries();
79 void removeSeries_data();
80 void removeSeries();
81 void addAxis_data();
82 void addAxis();
83 void removeAxis_data();
84 void removeAxis();
85 void attachAxis_data();
86 void attachAxis();
87 void detachAxis_data();
88 void detachAxis();
89 void domainChangePreservesRanges();
90
91private:
92 void compareDomain(QAbstractSeries *series, qreal minX, qreal maxX,
93 qreal minY, qreal maxY) const;
94 ChartDataSet* m_dataset;
95};
96
97void tst_ChartDataSet::initTestCase()
98{
99 qRegisterMetaType<AbstractDomain*>();
100 qRegisterMetaType<QAbstractAxis*>();
101 qRegisterMetaType<QAbstractSeries*>();
102}
103
104void tst_ChartDataSet::cleanupTestCase()
105{
106 QTest::qWait(ms: 1); // Allow final deleteLaters to run
107}
108
109void tst_ChartDataSet::init()
110{
111 Q_ASSERT(!m_dataset);
112 m_dataset = new ChartDataSet(0);
113}
114
115
116void tst_ChartDataSet::cleanup()
117{
118 delete m_dataset;
119 m_dataset = 0;
120}
121
122void tst_ChartDataSet::chartdataset_data()
123{
124}
125
126void tst_ChartDataSet::chartdataset()
127{
128 QVERIFY(m_dataset->axes().isEmpty());
129 QVERIFY(m_dataset->series().isEmpty());
130 m_dataset->createDefaultAxes();
131}
132
133
134void tst_ChartDataSet::addSeries_data()
135{
136 QTest::addColumn<QAbstractSeries*>(name: "series");
137
138 QAbstractSeries* line = new QLineSeries(this);
139 QTest::newRow(dataTag: "line") << line;
140
141 QAbstractSeries* area = new QAreaSeries(static_cast<QLineSeries*>(new QLineSeries(this)));
142 QTest::newRow(dataTag: "area") << area;
143
144 QAbstractSeries* scatter = new QScatterSeries(this);
145 QTest::newRow(dataTag: "scatter") << scatter;
146
147 QAbstractSeries* spline = new QSplineSeries(this);
148 QTest::newRow(dataTag: "spline") << spline;
149
150 QAbstractSeries* pie = new QPieSeries(this);
151 QTest::newRow(dataTag: "pie") << pie;
152
153 QAbstractSeries* bar = new QBarSeries(this);
154 QTest::newRow(dataTag: "bar") << bar;
155
156 QAbstractSeries* percent = new QPercentBarSeries(this);
157 QTest::newRow(dataTag: "percent") << percent;
158
159 QAbstractSeries* stacked = new QStackedBarSeries(this);
160 QTest::newRow(dataTag: "stacked") << stacked;
161}
162
163void tst_ChartDataSet::addSeries()
164{
165 QFETCH(QAbstractSeries*, series);
166 QVERIFY(m_dataset->series().isEmpty());
167
168 QSignalSpy spy0(m_dataset, SIGNAL(axisAdded(QAbstractAxis*)));
169 QSignalSpy spy1(m_dataset, SIGNAL(axisRemoved(QAbstractAxis*)));
170 QSignalSpy spy2(m_dataset, SIGNAL(seriesAdded(QAbstractSeries*)));
171 QSignalSpy spy3(m_dataset, SIGNAL(seriesRemoved(QAbstractSeries*)));
172
173 m_dataset->addSeries(series);
174
175 QCOMPARE(m_dataset->series().count(),1);
176 TRY_COMPARE(spy0.count(), 0);
177 TRY_COMPARE(spy1.count(), 0);
178 TRY_COMPARE(spy2.count(), 1);
179 TRY_COMPARE(spy3.count(), 0);
180}
181
182void tst_ChartDataSet::removeSeries_data()
183{
184 addSeries_data();
185}
186
187void tst_ChartDataSet::removeSeries()
188{
189 QFETCH(QAbstractSeries*, series);
190 QVERIFY(m_dataset->series().isEmpty());
191 m_dataset->addSeries(series);
192
193 QSignalSpy spy0(m_dataset, SIGNAL(axisAdded(QAbstractAxis*)));
194 QSignalSpy spy1(m_dataset, SIGNAL(axisRemoved(QAbstractAxis*)));
195 QSignalSpy spy2(m_dataset, SIGNAL(seriesAdded(QAbstractSeries*)));
196 QSignalSpy spy3(m_dataset, SIGNAL(seriesRemoved(QAbstractSeries*)));
197
198 m_dataset->removeSeries(series);
199
200 QCOMPARE(m_dataset->series().count(),0);
201 TRY_COMPARE(spy0.count(), 0);
202 TRY_COMPARE(spy1.count(), 0);
203 TRY_COMPARE(spy2.count(), 0);
204 TRY_COMPARE(spy3.count(), 1);
205
206 delete series;
207}
208
209void tst_ChartDataSet::addAxis_data()
210{
211 QTest::addColumn<QAbstractAxis*>(name: "axis");
212 QAbstractAxis* value = new QValueAxis(this);
213 QAbstractAxis* logvalue = new QLogValueAxis(this);
214 QAbstractAxis* category = new QCategoryAxis(this);
215 QAbstractAxis* barcategory = new QBarCategoryAxis(this);
216#ifndef QT_QREAL_IS_FLOAT
217 QAbstractAxis* datetime = new QDateTimeAxis(this);
218#endif
219
220 QTest::newRow(dataTag: "value") << value;
221 QTest::newRow(dataTag: "logvalue") << logvalue;
222 QTest::newRow(dataTag: "category") << category;
223 QTest::newRow(dataTag: "barcategory") << barcategory;
224#ifndef QT_QREAL_IS_FLOAT
225 QTest::newRow(dataTag: "datetime") << datetime;
226#endif
227}
228
229void tst_ChartDataSet::addAxis()
230{
231 QFETCH(QAbstractAxis*, axis);
232 QVERIFY(m_dataset->axes().isEmpty());
233
234 QSignalSpy spy0(m_dataset, SIGNAL(axisAdded(QAbstractAxis*)));
235 QSignalSpy spy1(m_dataset, SIGNAL(axisRemoved(QAbstractAxis*)));
236 QSignalSpy spy2(m_dataset, SIGNAL(seriesAdded(QAbstractSeries*)));
237 QSignalSpy spy3(m_dataset, SIGNAL(seriesRemoved(QAbstractSeries*)));
238
239 m_dataset->addAxis(axis,aligment: Qt::AlignBottom);
240
241 QCOMPARE(m_dataset->axes().count(),1);
242 TRY_COMPARE(spy0.count(), 1);
243 TRY_COMPARE(spy1.count(), 0);
244 TRY_COMPARE(spy2.count(), 0);
245 TRY_COMPARE(spy3.count(), 0);
246}
247
248void tst_ChartDataSet::removeAxis_data()
249{
250 addAxis_data();
251}
252
253void tst_ChartDataSet::removeAxis()
254{
255 QFETCH(QAbstractAxis*, axis);
256 QVERIFY(m_dataset->series().isEmpty());
257 m_dataset->addAxis(axis,aligment: Qt::AlignBottom);
258
259 QSignalSpy spy0(m_dataset, SIGNAL(axisAdded(QAbstractAxis*)));
260 QSignalSpy spy1(m_dataset, SIGNAL(axisRemoved(QAbstractAxis*)));
261 QSignalSpy spy2(m_dataset, SIGNAL(seriesAdded(QAbstractSeries*)));
262 QSignalSpy spy3(m_dataset, SIGNAL(seriesRemoved(QAbstractSeries*)));
263
264 m_dataset->removeAxis(axis);
265
266 QCOMPARE(m_dataset->axes().count(),0);
267 QCOMPARE(m_dataset->series().count(),0);
268 TRY_COMPARE(spy0.count(), 0);
269 TRY_COMPARE(spy1.count(), 1);
270 TRY_COMPARE(spy2.count(), 0);
271 TRY_COMPARE(spy3.count(), 0);
272
273 delete axis;
274}
275
276void tst_ChartDataSet::attachAxis_data()
277{
278
279 QTest::addColumn<QList<QAbstractSeries*> >(name: "series");
280 QTest::addColumn<QList<QAbstractAxis*> >(name: "axis");
281 QTest::addColumn<QList<Qt::Alignment> >(name: "alignment");
282 QTest::addColumn<QAbstractSeries*>(name: "attachSeries");
283 QTest::addColumn<QAbstractAxis*>(name: "attachAxis");
284 QTest::addColumn<bool>(name: "success");
285
286 {
287 QList<QAbstractSeries*> series;
288 QList<QAbstractAxis*> axes;
289 QList<Qt::Alignment> alignment;
290 QAbstractSeries* line = new QLineSeries(this);
291 QAbstractAxis* value1 = new QValueAxis(this);
292 QAbstractAxis* value2 = new QValueAxis(this);
293 series << line << 0;
294 axes << value1 << value2;
295 alignment << Qt::AlignBottom << Qt::AlignLeft;
296 QTest::newRow(dataTag: "first") << series << axes << alignment << line << value2 << true ;
297 }
298
299 {
300 QList<QAbstractSeries*> series;
301 QList<QAbstractAxis*> axes;
302 QList<Qt::Alignment> alignment;
303 QAbstractSeries* line = new QLineSeries(this);
304 QAbstractAxis* value1 = new QValueAxis(this);
305 QAbstractAxis* value2 = new QValueAxis(this);
306 series << 0 << line;
307 axes << value1 << value2;
308 alignment << Qt::AlignBottom << Qt::AlignLeft;
309 QTest::newRow(dataTag: "second") << series << axes << alignment << line << value1 << true;
310 }
311
312}
313
314void tst_ChartDataSet::attachAxis()
315{
316 QFETCH(QList<QAbstractSeries*>, series);
317 QFETCH(QList<QAbstractAxis*>, axis);
318 QFETCH(QList<Qt::Alignment>, alignment);
319 QFETCH(QAbstractSeries*, attachSeries);
320 QFETCH(QAbstractAxis*, attachAxis);
321 QFETCH(bool, success);
322
323 Q_ASSERT(series.count() == axis.count());
324 Q_ASSERT(series.count() == alignment.count());
325
326 QVERIFY(m_dataset->series().isEmpty());
327 QVERIFY(m_dataset->axes().isEmpty());
328
329 for(int i = 0 ; i < series.count() ; i++){
330 if(series[i]) m_dataset->addSeries(series: series[i]);
331 if(axis[i]) m_dataset->addAxis(axis: axis[i],aligment: alignment[i]);
332 if(series[i] && axis[i]) m_dataset->attachAxis(series: series[i],axis: axis[i]);
333 }
334
335 QSignalSpy spy0(m_dataset, SIGNAL(axisAdded(QAbstractAxis*)));
336 QSignalSpy spy1(m_dataset, SIGNAL(axisRemoved(QAbstractAxis*)));
337 QSignalSpy spy2(m_dataset, SIGNAL(seriesAdded(QAbstractSeries*)));
338 QSignalSpy spy3(m_dataset, SIGNAL(seriesRemoved(QAbstractSeries*)));
339
340 QCOMPARE(m_dataset->attachAxis(attachSeries,attachAxis),success);
341
342}
343
344void tst_ChartDataSet::detachAxis_data()
345{
346 QTest::addColumn<QList<QAbstractSeries*> >(name: "series");
347 QTest::addColumn<QList<QAbstractAxis*> >(name: "axis");
348 QTest::addColumn<QAbstractSeries*>(name: "detachSeries");
349 QTest::addColumn<QAbstractAxis*>(name: "detachAxis");
350 QTest::addColumn<bool>(name: "success");
351
352 {
353 QList<QAbstractSeries*> series;
354 QList<QAbstractAxis*> axes;
355 QAbstractSeries* line = new QLineSeries(this);
356 QAbstractAxis* value = new QValueAxis(this);
357 series << line;
358 axes << value;
359 QTest::newRow(dataTag: "first") << series << axes << line << value << true;
360 }
361}
362
363void tst_ChartDataSet::detachAxis()
364{
365 QFETCH(QList<QAbstractSeries*>, series);
366 QFETCH(QList<QAbstractAxis*>, axis);
367 QFETCH(QAbstractSeries*, detachSeries);
368 QFETCH(QAbstractAxis*, detachAxis);
369 QFETCH(bool, success);
370
371 Q_ASSERT(series.count() == axis.count());
372
373 QVERIFY(m_dataset->series().isEmpty());
374 QVERIFY(m_dataset->axes().isEmpty());
375
376 for(int i = 0; i < series.count(); i++) {
377 if(series[i]) m_dataset->addSeries(series: series[i]);
378 if(axis[i]) m_dataset->addAxis(axis: axis[i],aligment: Qt::AlignBottom);
379 if(series[i] && axis[i]) m_dataset->attachAxis(series: series[i],axis: axis[i]);
380 }
381
382 QSignalSpy spy0(m_dataset, SIGNAL(axisAdded(QAbstractAxis*)));
383 QSignalSpy spy1(m_dataset, SIGNAL(axisRemoved(QAbstractAxis*)));
384 QSignalSpy spy2(m_dataset, SIGNAL(seriesAdded(QAbstractSeries*)));
385 QSignalSpy spy3(m_dataset, SIGNAL(seriesRemoved(QAbstractSeries*)));
386
387 QCOMPARE(m_dataset->detachAxis(detachSeries,detachAxis),success);
388}
389
390void tst_ChartDataSet::domainChangePreservesRanges()
391{
392 // This test checks that domain ranges stay correct after an axis attachment causes domain
393 // to be recreated.
394 QVERIFY(m_dataset->series().isEmpty());
395 QVERIFY(m_dataset->axes().isEmpty());
396
397 QLineSeries* line = new QLineSeries(this);
398 QValueAxis* value1 = new QValueAxis(this);
399 QValueAxis* value2 = new QValueAxis(this);
400 QLogValueAxis* logValue1 = new QLogValueAxis(this);
401 QLogValueAxis* logValue2 = new QLogValueAxis(this);
402 (*line) << QPointF(1.0, 2.0) << QPointF(10.0, 20.0);
403
404 value1->setRange(min: 2.0, max: 6.0);
405 value2->setRange(min: 3.0, max: 7.0);
406 logValue1->setRange(min: 4.0, max: 8.0);
407 logValue2->setRange(min: 5.0, max: 9.0);
408
409 m_dataset->addSeries(series: line);
410 compareDomain(series: line, minX: 1.0, maxX: 10.0, minY: 2.0, maxY: 20.0);
411 m_dataset->addAxis(axis: value1, aligment: Qt::AlignBottom);
412 m_dataset->addAxis(axis: value2, aligment: Qt::AlignLeft);
413 m_dataset->addAxis(axis: logValue1, aligment: Qt::AlignBottom);
414 m_dataset->addAxis(axis: logValue2, aligment: Qt::AlignLeft);
415 compareDomain(series: line, minX: 1.0, maxX: 10.0, minY: 2.0, maxY: 20.0);
416
417 // Start with two value axes
418 m_dataset->attachAxis(series: line, axis: value1);
419 compareDomain(series: line, minX: 2.0, maxX: 6.0, minY: 2.0, maxY: 20.0);
420 m_dataset->attachAxis(series: line, axis: value2);
421 compareDomain(series: line, minX: 2.0, maxX: 6.0, minY: 3.0, maxY: 7.0);
422
423 // Detach y value and attach y logvalue
424 m_dataset->detachAxis(series: line, axis: value2);
425 compareDomain(series: line, minX: 2.0, maxX: 6.0, minY: 3.0, maxY: 7.0); // Detach doesn't change domain ranges
426 m_dataset->attachAxis(series: line, axis: logValue2);
427 compareDomain(series: line, minX: 2.0, maxX: 6.0, minY: 5.0, maxY: 9.0);
428
429 // Detach x value and attach x logvalue
430 m_dataset->detachAxis(series: line, axis: value1);
431 compareDomain(series: line, minX: 2.0, maxX: 6.0, minY: 5.0, maxY: 9.0); // Detach doesn't change domain ranges
432 m_dataset->attachAxis(series: line, axis: logValue1);
433 compareDomain(series: line, minX: 4.0, maxX: 8.0, minY: 5.0, maxY: 9.0);
434
435 // Detach y logvalue and attach y value
436 m_dataset->detachAxis(series: line, axis: logValue2);
437 compareDomain(series: line, minX: 4.0, maxX: 8.0, minY: 5.0, maxY: 9.0); // Detach doesn't change domain ranges
438 m_dataset->attachAxis(series: line, axis: value2);
439 compareDomain(series: line, minX: 4.0, maxX: 8.0, minY: 3.0, maxY: 7.0);
440}
441
442void tst_ChartDataSet::compareDomain(QAbstractSeries *series, qreal minX, qreal maxX,
443 qreal minY, qreal maxY) const
444{
445 AbstractDomain *domain = m_dataset->domainForSeries(series);
446 QCOMPARE(domain->minX(), minX);
447 QCOMPARE(domain->maxX(), maxX);
448 QCOMPARE(domain->minY(), minY);
449 QCOMPARE(domain->maxY(), maxY);
450}
451
452QTEST_MAIN(tst_ChartDataSet)
453#include "tst_chartdataset.moc"
454

source code of qtcharts/tests/auto/chartdataset/tst_chartdataset.cpp