##// END OF EJS Templates
Add impletation for displaying data that are already in cache when...
perrinel -
r539:575eda7156d0
parent child
Show More
@@ -1,211 +1,195
1 1 #include "Visualization/VisualizationGraphHelper.h"
2 2 #include "Visualization/qcustomplot.h"
3 3
4 4 #include <Data/ScalarSeries.h>
5 5
6 6 #include <Variable/Variable.h>
7 7
8 8 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
9 9
10 10 namespace {
11 11
12 12 class SqpDataContainer : public QCPGraphDataContainer {
13 13 public:
14 14 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
15 15 };
16 16
17 17
18 18 /// Format for datetimes on a axis
19 19 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
20 20
21 21 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
22 22 /// non-time data
23 23 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
24 24 {
25 25 if (isTimeAxis) {
26 26 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
27 27 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
28 28 dateTicker->setDateTimeSpec(Qt::UTC);
29 29
30 30 return dateTicker;
31 31 }
32 32 else {
33 33 // default ticker
34 34 return QSharedPointer<QCPAxisTicker>::create();
35 35 }
36 36 }
37 37
38 38 void updateScalarData(QCPAbstractPlottable *component, std::shared_ptr<ScalarSeries> scalarSeries,
39 const SqpRange &dateTime)
39 const SqpRange &range)
40 40 {
41 41 qCDebug(LOG_VisualizationGraphHelper()) << "TORM: updateScalarData"
42 42 << QThread::currentThread()->objectName();
43 43 if (auto qcpGraph = dynamic_cast<QCPGraph *>(component)) {
44 44 scalarSeries->lockRead();
45 45 {
46 // auto bounds = scalarSeries->subData(rang
47 // const auto &xData = scalarSeries->xAxisData()->cdata();
48 // const auto &valuesData = scalarSeries->valuesData()->cdata();
49
50 // auto xDataBegin = xData.cbegin();
51 // auto xDataEnd = xData.cend();
52
53 // qCInfo(LOG_VisualizationGraphHelper()) << "TODEBUG: Current points in cache"
54 // << xData.count();
55
56 // auto sqpDataContainer = QSharedPointer<SqpDataContainer>::create();
57 // qcpGraph->setData(sqpDataContainer);
58
59 // auto lowerIt = std::lower_bound(xDataBegin, xDataEnd, dateTime.m_TStart);
60 // auto upperIt = std::upper_bound(xDataBegin, xDataEnd, dateTime.m_TEnd);
61 // auto distance = std::distance(xDataBegin, lowerIt);
62
63 // auto valuesDataIt = valuesData.cbegin() + distance;
64 // for (auto xAxisDataIt = lowerIt; xAxisDataIt != upperIt;
65 // ++xAxisDataIt, ++valuesDataIt) {
66 // sqpDataContainer->appendGraphData(QCPGraphData(*xAxisDataIt, *valuesDataIt));
67 // }
46 auto sqpDataContainer = QSharedPointer<SqpDataContainer>::create();
47 qcpGraph->setData(sqpDataContainer);
48 auto bounds = scalarSeries->subData(range.m_TStart, range.m_TEnd);
49 for (auto it = bounds.first; it != bounds.second; ++it) {
50 sqpDataContainer->appendGraphData(QCPGraphData(it->x(), it->value()));
51 }
68 52
69 53 qCInfo(LOG_VisualizationGraphHelper()) << "TODEBUG: Current points displayed"
70 54 << sqpDataContainer->size();
71 55 }
72 56 scalarSeries->unlock();
73 57
74 58
75 59 // Display all data
76 60 component->parentPlot()->replot();
77 61 }
78 62 else {
79 63 /// @todo DEBUG
80 64 }
81 65 }
82 66
83 67 QCPAbstractPlottable *createScalarSeriesComponentV2(std::shared_ptr<ScalarSeries> scalarSeries,
84 68 QCustomPlot &plot)
85 69 {
86 70 auto component = plot.addGraph();
87 71
88 72 if (component) {
89 73 // Axes properties
90 74 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
91 75 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
92 76
93 77 auto setAxisProperties = [](auto axis, const auto &unit) {
94 78 // label (unit name)
95 79 axis->setLabel(unit.m_Name);
96 80
97 81 // ticker (depending on the type of unit)
98 82 axis->setTicker(axisTicker(unit.m_TimeUnit));
99 83 };
100 84 setAxisProperties(plot.xAxis, scalarSeries->xAxisUnit());
101 85 setAxisProperties(plot.yAxis, scalarSeries->valuesUnit());
102 86 }
103 87 return component;
104 88 }
105 89
106 90 QCPAbstractPlottable *createScalarSeriesComponent(std::shared_ptr<ScalarSeries> scalarSeries,
107 91 QCustomPlot &plot, const SqpRange &dateTime)
108 92 {
109 93 auto component = plot.addGraph();
110 94
111 95 if (component) {
112 96 // // Graph data
113 97 component->setData(scalarSeries->xAxisData()->data(), scalarSeries->valuesData()->data(),
114 98 true);
115 99
116 100 updateScalarData(component, scalarSeries, dateTime);
117 101
118 102 // Axes properties
119 103 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
120 104 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
121 105
122 106 auto setAxisProperties = [](auto axis, const auto &unit) {
123 107 // label (unit name)
124 108 axis->setLabel(unit.m_Name);
125 109
126 110 // ticker (depending on the type of unit)
127 111 axis->setTicker(axisTicker(unit.m_TimeUnit));
128 112 };
129 113 setAxisProperties(plot.xAxis, scalarSeries->xAxisUnit());
130 114 setAxisProperties(plot.yAxis, scalarSeries->valuesUnit());
131 115
132 116 // Display all data
133 117 component->rescaleAxes();
134 118 plot.replot();
135 119 }
136 120 else {
137 121 qCDebug(LOG_VisualizationGraphHelper())
138 122 << QObject::tr("Can't create graph for the scalar series");
139 123 }
140 124
141 125 return component;
142 126 }
143 127
144 128 } // namespace
145 129
146 130 QVector<QCPAbstractPlottable *>
147 131 VisualizationGraphHelper::createV2(std::shared_ptr<Variable> variable, QCustomPlot &plot) noexcept
148 132 {
149 133 auto result = QVector<QCPAbstractPlottable *>{};
150 134
151 135 if (variable) {
152 136 // Gets the data series of the variable to call the creation of the right components
153 137 // according to its type
154 138 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(variable->dataSeries())) {
155 139 result.append(createScalarSeriesComponentV2(scalarSeries, plot));
156 140 }
157 141 else {
158 142 qCDebug(LOG_VisualizationGraphHelper())
159 143 << QObject::tr("Can't create graph plottables : unmanaged data series type");
160 144 }
161 145 }
162 146 else {
163 147 qCDebug(LOG_VisualizationGraphHelper())
164 148 << QObject::tr("Can't create graph plottables : the variable is null");
165 149 }
166 150
167 151 return result;
168 152 }
169 153
170 154 QVector<QCPAbstractPlottable *> VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
171 155 QCustomPlot &plot) noexcept
172 156 {
173 157 auto result = QVector<QCPAbstractPlottable *>{};
174 158
175 159 if (variable) {
176 160 // Gets the data series of the variable to call the creation of the right components
177 161 // according to its type
178 162 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(variable->dataSeries())) {
179 163 result.append(createScalarSeriesComponent(scalarSeries, plot, variable->range()));
180 164 }
181 165 else {
182 166 qCDebug(LOG_VisualizationGraphHelper())
183 167 << QObject::tr("Can't create graph plottables : unmanaged data series type");
184 168 }
185 169 }
186 170 else {
187 171 qCDebug(LOG_VisualizationGraphHelper())
188 172 << QObject::tr("Can't create graph plottables : the variable is null");
189 173 }
190 174
191 175 return result;
192 176 }
193 177
194 178 void VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *> plotableVect,
195 179 std::shared_ptr<IDataSeries> dataSeries,
196 180 const SqpRange &dateTime)
197 181 {
198 182 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
199 183 if (plotableVect.size() == 1) {
200 184 updateScalarData(plotableVect.at(0), scalarSeries, dateTime);
201 185 }
202 186 else {
203 187 qCCritical(LOG_VisualizationGraphHelper()) << QObject::tr(
204 188 "Can't update Data of a scalarSeries because there is not only one component "
205 189 "associated");
206 190 }
207 191 }
208 192 else {
209 193 /// @todo DEBUG
210 194 }
211 195 }
@@ -1,310 +1,310
1 1 #include "AmdaResultParser.h"
2 2
3 3 #include <Data/ScalarSeries.h>
4 4 #include <Data/VectorSeries.h>
5 5
6 6 #include <QObject>
7 7 #include <QtTest>
8 8
9 9 namespace {
10 10
11 11 /// Path for the tests
12 12 const auto TESTS_RESOURCES_PATH
13 13 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaResultParser"}.absoluteFilePath();
14 14
15 15 QDateTime dateTime(int year, int month, int day, int hours, int minutes, int seconds)
16 16 {
17 17 return QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC};
18 18 }
19 19
20 20 /// Compares two vectors that can potentially contain NaN values
21 21 bool compareVectors(const QVector<double> &v1, const QVector<double> &v2)
22 22 {
23 23 if (v1.size() != v2.size()) {
24 24 return false;
25 25 }
26 26
27 27 auto result = true;
28 28 auto v2It = v2.cbegin();
29 29 for (auto v1It = v1.cbegin(), v1End = v1.cend(); v1It != v1End && result; ++v1It, ++v2It) {
30 30 auto v1Value = *v1It;
31 31 auto v2Value = *v2It;
32 32
33 33 // If v1 is NaN, v2 has to be NaN too
34 34 result = std::isnan(v1Value) ? std::isnan(v2Value) : (v1Value == v2Value);
35 35 }
36 36
37 37 return result;
38 38 }
39 39
40 40 bool compareVectors(const QVector<QVector<double> > &v1, const QVector<QVector<double> > &v2)
41 41 {
42 42 if (v1.size() != v2.size()) {
43 43 return false;
44 44 }
45 45
46 46 auto result = true;
47 47 for (auto i = 0; i < v1.size() && result; ++i) {
48 48 result &= compareVectors(v1.at(i), v2.at(i));
49 49 }
50 50
51 51 return result;
52 52 }
53 53
54 54 QVector<QVector<double> > valuesData(const ArrayData<1> &arrayData)
55 55 {
56 56 return QVector<QVector<double> >{arrayData.data()};
57 57 }
58 58
59 59 QVector<QVector<double> > valuesData(const ArrayData<2> &arrayData)
60 60 {
61 61 return arrayData.data();
62 62 }
63 63
64 64
65 65 QString inputFilePath(const QString &inputFileName)
66 66 {
67 67 return QFileInfo{TESTS_RESOURCES_PATH, inputFileName}.absoluteFilePath();
68 68 }
69 69
70 70 template <typename T>
71 71 struct ExpectedResults {
72 72 explicit ExpectedResults() = default;
73 73
74 74 explicit ExpectedResults(Unit xAxisUnit, Unit valuesUnit, const QVector<QDateTime> &xAxisData,
75 75 QVector<double> valuesData)
76 76 : ExpectedResults(xAxisUnit, valuesUnit, xAxisData,
77 77 QVector<QVector<double> >{std::move(valuesData)})
78 78 {
79 79 }
80 80
81 81 /// Ctor with QVector<QDateTime> as x-axis data. Datetimes are converted to doubles
82 82 explicit ExpectedResults(Unit xAxisUnit, Unit valuesUnit, const QVector<QDateTime> &xAxisData,
83 83 QVector<QVector<double> > valuesData)
84 84 : m_ParsingOK{true},
85 85 m_XAxisUnit{xAxisUnit},
86 86 m_ValuesUnit{valuesUnit},
87 87 m_XAxisData{},
88 88 m_ValuesData{std::move(valuesData)}
89 89 {
90 90 // Converts QVector<QDateTime> to QVector<double>
91 91 std::transform(xAxisData.cbegin(), xAxisData.cend(), std::back_inserter(m_XAxisData),
92 92 [](const auto &dateTime) { return dateTime.toMSecsSinceEpoch() / 1000.; });
93 93 }
94 94
95 95 /**
96 96 * Validates a DataSeries compared to the expected results
97 97 * @param results the DataSeries to validate
98 98 */
99 99 void validate(std::shared_ptr<IDataSeries> results)
100 100 {
101 101 if (m_ParsingOK) {
102 102 auto dataSeries = dynamic_cast<T *>(results.get());
103 103 QVERIFY(dataSeries != nullptr);
104 104
105 105 // Checks units
106 106 QVERIFY(dataSeries->xAxisUnit() == m_XAxisUnit);
107 107 QVERIFY(dataSeries->valuesUnit() == m_ValuesUnit);
108 108
109 109 // Checks values : as the vectors can potentially contain NaN values, we must use a
110 110 // custom vector comparison method
111 111 QVERIFY(compareVectors(dataSeries->xAxisData()->data(), m_XAxisData));
112 112 QVERIFY(compareVectors(valuesData(*dataSeries->valuesData()), m_ValuesData));
113 113 }
114 114 else {
115 115 QVERIFY(results == nullptr);
116 116 }
117 117 }
118 118
119 119 // Parsing was successfully completed
120 120 bool m_ParsingOK{false};
121 121 // Expected x-axis unit
122 122 Unit m_XAxisUnit{};
123 123 // Expected values unit
124 124 Unit m_ValuesUnit{};
125 125 // Expected x-axis data
126 126 QVector<double> m_XAxisData{};
127 127 // Expected values data
128 128 QVector<QVector<double> > m_ValuesData{};
129 129 };
130 130
131 131 } // namespace
132 132
133 133 Q_DECLARE_METATYPE(ExpectedResults<ScalarSeries>)
134 134 Q_DECLARE_METATYPE(ExpectedResults<VectorSeries>)
135 135
136 136 class TestAmdaResultParser : public QObject {
137 137 Q_OBJECT
138 138 private:
139 139 template <typename T>
140 140 void testReadDataStructure()
141 141 {
142 142 // ////////////// //
143 143 // Test structure //
144 144 // ////////////// //
145 145
146 146 // Name of TXT file to read
147 147 QTest::addColumn<QString>("inputFileName");
148 148 // Expected results
149 149 QTest::addColumn<ExpectedResults<T> >("expectedResults");
150 150 }
151 151
152 152 template <typename T>
153 153 void testRead(AmdaResultParser::ValueType valueType)
154 154 {
155 155 QFETCH(QString, inputFileName);
156 156 QFETCH(ExpectedResults<T>, expectedResults);
157 157
158 158 // Parses file
159 159 auto filePath = inputFilePath(inputFileName);
160 160 auto results = AmdaResultParser::readTxt(filePath, valueType);
161 161
162 162 // ///////////////// //
163 163 // Validates results //
164 164 // ///////////////// //
165 165 expectedResults.validate(results);
166 166 }
167 167
168 168 private slots:
169 169 /// Input test data
170 170 /// @sa testReadScalarTxt()
171 171 void testReadScalarTxt_data();
172 172
173 173 /// Tests parsing scalar series of a TXT file
174 174 void testReadScalarTxt();
175 175
176 176 /// Input test data
177 177 /// @sa testReadVectorTxt()
178 178 void testReadVectorTxt_data();
179 179
180 180 /// Tests parsing vector series of a TXT file
181 181 void testReadVectorTxt();
182 182 };
183 183
184 184 void TestAmdaResultParser::testReadScalarTxt_data()
185 185 {
186 186 testReadDataStructure<ScalarSeries>();
187 187
188 188 // ////////// //
189 189 // Test cases //
190 190 // ////////// //
191 191
192 192 // Valid files
193 193 QTest::newRow("Valid file")
194 194 << QStringLiteral("ValidScalar1.txt")
195 195 << ExpectedResults<ScalarSeries>{
196 196 Unit{QStringLiteral("nT"), true}, Unit{},
197 197 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
198 198 dateTime(2013, 9, 23, 9, 2, 30), dateTime(2013, 9, 23, 9, 3, 30),
199 199 dateTime(2013, 9, 23, 9, 4, 30), dateTime(2013, 9, 23, 9, 5, 30),
200 200 dateTime(2013, 9, 23, 9, 6, 30), dateTime(2013, 9, 23, 9, 7, 30),
201 201 dateTime(2013, 9, 23, 9, 8, 30), dateTime(2013, 9, 23, 9, 9, 30)},
202 202 QVector<double>{-2.83950, -2.71850, -2.52150, -2.57633, -2.58050, -2.48325, -2.63025,
203 203 -2.55800, -2.43250, -2.42200}};
204 204
205 205 QTest::newRow("Valid file (value of first line is invalid but it is converted to NaN")
206 206 << QStringLiteral("WrongValue.txt")
207 207 << ExpectedResults<ScalarSeries>{
208 208 Unit{QStringLiteral("nT"), true}, Unit{},
209 209 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
210 210 dateTime(2013, 9, 23, 9, 2, 30)},
211 211 QVector<double>{std::numeric_limits<double>::quiet_NaN(), -2.71850, -2.52150}};
212 212
213 213 QTest::newRow("Valid file that contains NaN values")
214 214 << QStringLiteral("NaNValue.txt")
215 215 << ExpectedResults<ScalarSeries>{
216 216 Unit{QStringLiteral("nT"), true}, Unit{},
217 217 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
218 218 dateTime(2013, 9, 23, 9, 2, 30)},
219 219 QVector<double>{std::numeric_limits<double>::quiet_NaN(), -2.71850, -2.52150}};
220 220
221 221 // Valid files but with some invalid lines (wrong unit, wrong values, etc.)
222 222 QTest::newRow("No unit file") << QStringLiteral("NoUnit.txt")
223 223 << ExpectedResults<ScalarSeries>{Unit{QStringLiteral(""), true},
224 224 Unit{}, QVector<QDateTime>{},
225 225 QVector<double>{}};
226 226 QTest::newRow("Wrong unit file")
227 227 << QStringLiteral("WrongUnit.txt")
228 228 << ExpectedResults<ScalarSeries>{Unit{QStringLiteral(""), true}, Unit{},
229 229 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30),
230 230 dateTime(2013, 9, 23, 9, 1, 30),
231 231 dateTime(2013, 9, 23, 9, 2, 30)},
232 232 QVector<double>{-2.83950, -2.71850, -2.52150}};
233 233
234 234 QTest::newRow("Wrong results file (date of first line is invalid")
235 235 << QStringLiteral("WrongDate.txt")
236 236 << ExpectedResults<ScalarSeries>{
237 237 Unit{QStringLiteral("nT"), true}, Unit{},
238 238 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
239 239 QVector<double>{-2.71850, -2.52150}};
240 240
241 241 QTest::newRow("Wrong results file (too many values for first line")
242 242 << QStringLiteral("TooManyValues.txt")
243 243 << ExpectedResults<ScalarSeries>{
244 244 Unit{QStringLiteral("nT"), true}, Unit{},
245 245 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
246 246 QVector<double>{-2.71850, -2.52150}};
247 247
248 248 QTest::newRow("Wrong results file (x of first line is NaN")
249 249 << QStringLiteral("NaNX.txt")
250 250 << ExpectedResults<ScalarSeries>{
251 251 Unit{QStringLiteral("nT"), true}, Unit{},
252 252 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
253 253 QVector<double>{-2.71850, -2.52150}};
254 254
255 255 QTest::newRow("Invalid file type (vector)")
256 256 << QStringLiteral("ValidVector1.txt")
257 257 << ExpectedResults<ScalarSeries>{Unit{QStringLiteral("nT"), true}, Unit{},
258 258 QVector<QDateTime>{}, QVector<double>{}};
259 259
260 260 // Invalid files
261 QTest::newRow("Invalid file (unexisting file)")
262 << QStringLiteral("UnexistingFile.txt") << ExpectedResults<ScalarSeries>{};
261 QTest::newRow("Invalid file (unexisting file)") << QStringLiteral("UnexistingFile.txt")
262 << ExpectedResults<ScalarSeries>{};
263 263
264 QTest::newRow("Invalid file (file not found on server)")
265 << QStringLiteral("FileNotFound.txt") << ExpectedResults<ScalarSeries>{};
264 QTest::newRow("Invalid file (file not found on server)") << QStringLiteral("FileNotFound.txt")
265 << ExpectedResults<ScalarSeries>{};
266 266 }
267 267
268 268 void TestAmdaResultParser::testReadScalarTxt()
269 269 {
270 270 testRead<ScalarSeries>(AmdaResultParser::ValueType::SCALAR);
271 271 }
272 272
273 273 void TestAmdaResultParser::testReadVectorTxt_data()
274 274 {
275 275 testReadDataStructure<VectorSeries>();
276 276
277 277 // ////////// //
278 278 // Test cases //
279 279 // ////////// //
280 280
281 281 // Valid files
282 282 QTest::newRow("Valid file")
283 283 << QStringLiteral("ValidVector1.txt")
284 284 << ExpectedResults<VectorSeries>{
285 285 Unit{QStringLiteral("nT"), true}, Unit{},
286 286 QVector<QDateTime>{dateTime(2013, 7, 2, 9, 13, 50), dateTime(2013, 7, 2, 9, 14, 6),
287 287 dateTime(2013, 7, 2, 9, 14, 22), dateTime(2013, 7, 2, 9, 14, 38),
288 288 dateTime(2013, 7, 2, 9, 14, 54), dateTime(2013, 7, 2, 9, 15, 10),
289 289 dateTime(2013, 7, 2, 9, 15, 26), dateTime(2013, 7, 2, 9, 15, 42),
290 290 dateTime(2013, 7, 2, 9, 15, 58), dateTime(2013, 7, 2, 9, 16, 14)},
291 291 QVector<QVector<double> >{
292 292 {-0.332, -1.011, -1.457, -1.293, -1.217, -1.443, -1.278, -1.202, -1.22, -1.259},
293 293 {3.206, 2.999, 2.785, 2.736, 2.612, 2.564, 2.892, 2.862, 2.859, 2.764},
294 294 {0.058, 0.496, 1.018, 1.485, 1.662, 1.505, 1.168, 1.244, 1.15, 1.358}}};
295 295
296 296 // Valid files but with some invalid lines (wrong unit, wrong values, etc.)
297 297 QTest::newRow("Invalid file type (scalar)")
298 298 << QStringLiteral("ValidScalar1.txt")
299 299 << ExpectedResults<VectorSeries>{Unit{QStringLiteral("nT"), true}, Unit{},
300 300 QVector<QDateTime>{},
301 301 QVector<QVector<double> >{{}, {}, {}}};
302 302 }
303 303
304 304 void TestAmdaResultParser::testReadVectorTxt()
305 305 {
306 306 testRead<VectorSeries>(AmdaResultParser::ValueType::VECTOR);
307 307 }
308 308
309 309 QTEST_MAIN(TestAmdaResultParser)
310 310 #include "TestAmdaResultParser.moc"
General Comments 1
Under Review
author

Auto status change to "Under Review"

You need to be logged in to leave comments. Login now