##// END OF EJS Templates
Move the AMDA data type to a type accessible from core
Alexandre Leroux -
r1332:d3daab81283b
parent child
Show More
@@ -0,0 +1,26
1 #ifndef SCIQLOP_DATASERIESTYPE_H
2 #define SCIQLOP_DATASERIESTYPE_H
3
4 #include <QString>
5
6 enum class DataSeriesType { SCALAR, SPECTROGRAM, VECTOR, UNKNOWN };
7
8 struct DataSeriesTypeUtils {
9 static DataSeriesType fromString(const QString &type)
10 {
11 if (type == QStringLiteral("scalar")) {
12 return DataSeriesType::SCALAR;
13 }
14 else if (type == QStringLiteral("spectrogram")) {
15 return DataSeriesType::SPECTROGRAM;
16 }
17 else if (type == QStringLiteral("vector")) {
18 return DataSeriesType::VECTOR;
19 }
20 else {
21 return DataSeriesType::UNKNOWN;
22 }
23 }
24 };
25
26 #endif // SCIQLOP_DATASERIESTYPE_H
@@ -1,21 +1,21
1 1 #ifndef SCIQLOP_AMDARESULTPARSER_H
2 2 #define SCIQLOP_AMDARESULTPARSER_H
3 3
4 4 #include "AmdaGlobal.h"
5 5
6 #include <Data/DataSeriesType.h>
7
6 8 #include <QLoggingCategory>
7 9
8 10 #include <memory>
9 11
10 12 class IDataSeries;
11 13
12 14 Q_DECLARE_LOGGING_CATEGORY(LOG_AmdaResultParser)
13 15
14 16 struct SCIQLOP_AMDA_EXPORT AmdaResultParser {
15 enum class ValueType { SCALAR, SPECTROGRAM, VECTOR, UNKNOWN };
16
17 17 static std::shared_ptr<IDataSeries> readTxt(const QString &filePath,
18 ValueType valueType) noexcept;
18 DataSeriesType valueType) noexcept;
19 19 };
20 20
21 21 #endif // SCIQLOP_AMDARESULTPARSER_H
@@ -1,288 +1,274
1 1 #include "AmdaProvider.h"
2 2 #include "AmdaDefs.h"
3 3 #include "AmdaResultParser.h"
4 4 #include "AmdaServer.h"
5 5
6 6 #include <Common/DateUtils.h>
7 7 #include <Data/DataProviderParameters.h>
8 8 #include <Network/NetworkController.h>
9 9 #include <SqpApplication.h>
10 10 #include <Variable/Variable.h>
11 11
12 12 #include <QNetworkAccessManager>
13 13 #include <QNetworkReply>
14 14 #include <QTemporaryFile>
15 15 #include <QThread>
16 16
17 17 Q_LOGGING_CATEGORY(LOG_AmdaProvider, "AmdaProvider")
18 18
19 19 namespace {
20 20
21 21 /// URL format for a request on AMDA server. The parameters are as follows:
22 22 /// - %1: server URL
23 23 /// - %2: start date
24 24 /// - %3: end date
25 25 /// - %4: parameter id
26 26 /// AMDA V2: http://amdatest.irap.omp.eu/php/rest/
27 27 const auto AMDA_URL_FORMAT = QStringLiteral(
28 28 "http://%1/php/rest/"
29 29 "getParameter.php?startTime=%2&stopTime=%3&parameterID=%4&outputFormat=ASCII&"
30 30 "timeFormat=ISO8601&gzip=0");
31 31
32 32 /// Dates format passed in the URL (e.g 2013-09-23T09:00)
33 33 const auto AMDA_TIME_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss");
34 34
35 35 /// Formats a time to a date that can be passed in URL
36 36 QString dateFormat(double sqpRange) noexcept
37 37 {
38 38 auto dateTime = DateUtils::dateTime(sqpRange);
39 39 return dateTime.toString(AMDA_TIME_FORMAT);
40 40 }
41 41
42 AmdaResultParser::ValueType valueType(const QString &valueType)
43 {
44 if (valueType == QStringLiteral("scalar")) {
45 return AmdaResultParser::ValueType::SCALAR;
46 }
47 else if (valueType == QStringLiteral("spectrogram")) {
48 return AmdaResultParser::ValueType::SPECTROGRAM;
49 }
50 else if (valueType == QStringLiteral("vector")) {
51 return AmdaResultParser::ValueType::VECTOR;
52 }
53 else {
54 return AmdaResultParser::ValueType::UNKNOWN;
55 }
56 }
57 42
58 43 } // namespace
59 44
60 45 AmdaProvider::AmdaProvider()
61 46 {
62 47 qCDebug(LOG_AmdaProvider()) << tr("AmdaProvider::AmdaProvider") << QThread::currentThread();
63 48 if (auto app = sqpApp) {
64 49 auto &networkController = app->networkController();
65 50 connect(this, SIGNAL(requestConstructed(std::shared_ptr<QNetworkRequest>, QUuid,
66 51 std::function<void(QNetworkReply *, QUuid)>)),
67 52 &networkController,
68 53 SLOT(onProcessRequested(std::shared_ptr<QNetworkRequest>, QUuid,
69 54 std::function<void(QNetworkReply *, QUuid)>)));
70 55
71 56
72 57 connect(&sqpApp->networkController(),
73 58 SIGNAL(replyDownloadProgress(QUuid, std::shared_ptr<QNetworkRequest>, double)),
74 59 this,
75 60 SLOT(onReplyDownloadProgress(QUuid, std::shared_ptr<QNetworkRequest>, double)));
76 61 }
77 62 }
78 63
79 64 std::shared_ptr<IDataProvider> AmdaProvider::clone() const
80 65 {
81 66 // No copy is made in the clone
82 67 return std::make_shared<AmdaProvider>();
83 68 }
84 69
85 70 void AmdaProvider::requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters)
86 71 {
87 72 // NOTE: Try to use multithread if possible
88 73 const auto times = parameters.m_Times;
89 74 const auto data = parameters.m_Data;
90 75 for (const auto &dateTime : qAsConst(times)) {
91 76 qCDebug(LOG_AmdaProvider()) << tr("TORM AmdaProvider::requestDataLoading ") << acqIdentifier
92 77 << dateTime;
93 78 this->retrieveData(acqIdentifier, dateTime, data);
94 79
95 80
96 81 // TORM when AMDA will support quick asynchrone request
97 82 QThread::msleep(1000);
98 83 }
99 84 }
100 85
101 86 void AmdaProvider::requestDataAborting(QUuid acqIdentifier)
102 87 {
103 88 if (auto app = sqpApp) {
104 89 auto &networkController = app->networkController();
105 90 networkController.onReplyCanceled(acqIdentifier);
106 91 }
107 92 }
108 93
109 94 void AmdaProvider::onReplyDownloadProgress(QUuid acqIdentifier,
110 95 std::shared_ptr<QNetworkRequest> networkRequest,
111 96 double progress)
112 97 {
113 98 qCDebug(LOG_AmdaProvider()) << tr("onReplyDownloadProgress") << acqIdentifier
114 99 << networkRequest.get() << progress;
115 100 auto acqIdToRequestProgressMapIt = m_AcqIdToRequestProgressMap.find(acqIdentifier);
116 101 if (acqIdToRequestProgressMapIt != m_AcqIdToRequestProgressMap.end()) {
117 102
118 103 // Update the progression for the current request
119 104 auto requestPtr = networkRequest;
120 105 auto findRequest = [requestPtr](const auto &entry) { return requestPtr == entry.first; };
121 106
122 107 auto &requestProgressMap = acqIdToRequestProgressMapIt->second;
123 108 auto requestProgressMapEnd = requestProgressMap.end();
124 109 auto requestProgressMapIt
125 110 = std::find_if(requestProgressMap.begin(), requestProgressMapEnd, findRequest);
126 111
127 112 if (requestProgressMapIt != requestProgressMapEnd) {
128 113 requestProgressMapIt->second = progress;
129 114 }
130 115 else {
131 116 // This case can happened when a progression is send after the request has been
132 117 // finished.
133 118 // Generaly the case when aborting a request
134 119 qCDebug(LOG_AmdaProvider()) << tr("Can't retrieve Request in progress") << acqIdentifier
135 120 << networkRequest.get() << progress;
136 121 }
137 122
138 123 // Compute the current final progress and notify it
139 124 double finalProgress = 0.0;
140 125
141 126 auto fraq = requestProgressMap.size();
142 127
143 128 for (auto requestProgress : requestProgressMap) {
144 129 finalProgress += requestProgress.second;
145 130 qCDebug(LOG_AmdaProvider()) << tr("Current final progress without fraq:")
146 131 << finalProgress << requestProgress.second;
147 132 }
148 133
149 134 if (fraq > 0) {
150 135 finalProgress = finalProgress / fraq;
151 136 }
152 137
153 138 qCDebug(LOG_AmdaProvider()) << tr("Current final progress: ") << fraq << finalProgress;
154 139 emit dataProvidedProgress(acqIdentifier, finalProgress);
155 140 }
156 141 else {
157 142 // This case can happened when a progression is send after the request has been finished.
158 143 // Generaly the case when aborting a request
159 144 emit dataProvidedProgress(acqIdentifier, 100.0);
160 145 }
161 146 }
162 147
163 148 void AmdaProvider::retrieveData(QUuid token, const SqpRange &dateTime, const QVariantHash &data)
164 149 {
165 150 // Retrieves product ID from data: if the value is invalid, no request is made
166 151 auto productId = data.value(AMDA_XML_ID_KEY).toString();
167 152 if (productId.isNull()) {
168 153 qCCritical(LOG_AmdaProvider()) << tr("Can't retrieve data: unknown product id");
169 154 return;
170 155 }
171 156
172 157 // Retrieves the data type that determines whether the expected format for the result file is
173 158 // scalar, vector...
174 auto productValueType = valueType(data.value(AMDA_DATA_TYPE_KEY).toString());
159 auto productValueType
160 = DataSeriesTypeUtils::fromString(data.value(AMDA_DATA_TYPE_KEY).toString());
175 161
176 162 // /////////// //
177 163 // Creates URL //
178 164 // /////////// //
179 165
180 166 auto startDate = dateFormat(dateTime.m_TStart);
181 167 auto endDate = dateFormat(dateTime.m_TEnd);
182 168
183 169 QVariantHash urlProperties{{AMDA_SERVER_KEY, data.value(AMDA_SERVER_KEY)}};
184 170 auto url = QUrl{QString{AMDA_URL_FORMAT}.arg(AmdaServer::instance().url(urlProperties),
185 171 startDate, endDate, productId)};
186 172 qCInfo(LOG_AmdaProvider()) << tr("TORM AmdaProvider::retrieveData url:") << url;
187 173 auto tempFile = std::make_shared<QTemporaryFile>();
188 174
189 175 // LAMBDA
190 176 auto httpDownloadFinished = [this, dateTime, tempFile,
191 177 productValueType](QNetworkReply *reply, QUuid dataId) noexcept {
192 178
193 179 // Don't do anything if the reply was abort
194 180 if (reply->error() == QNetworkReply::NoError) {
195 181
196 182 if (tempFile) {
197 183 auto replyReadAll = reply->readAll();
198 184 if (!replyReadAll.isEmpty()) {
199 185 tempFile->write(replyReadAll);
200 186 }
201 187 tempFile->close();
202 188
203 189 // Parse results file
204 190 if (auto dataSeries
205 191 = AmdaResultParser::readTxt(tempFile->fileName(), productValueType)) {
206 192 emit dataProvided(dataId, dataSeries, dateTime);
207 193 }
208 194 else {
209 195 /// @todo ALX : debug
210 196 emit dataProvidedFailed(dataId);
211 197 }
212 198 }
213 199 m_AcqIdToRequestProgressMap.erase(dataId);
214 200 }
215 201 else {
216 202 qCCritical(LOG_AmdaProvider()) << tr("httpDownloadFinished ERROR");
217 203 emit dataProvidedFailed(dataId);
218 204 }
219 205
220 206 };
221 207 auto httpFinishedLambda
222 208 = [this, httpDownloadFinished, tempFile](QNetworkReply *reply, QUuid dataId) noexcept {
223 209
224 210 // Don't do anything if the reply was abort
225 211 if (reply->error() == QNetworkReply::NoError) {
226 212 auto downloadFileUrl = QUrl{QString{reply->readAll()}.trimmed()};
227 213
228 214 qCInfo(LOG_AmdaProvider())
229 215 << tr("TORM AmdaProvider::retrieveData downloadFileUrl:") << downloadFileUrl;
230 216 // Executes request for downloading file //
231 217
232 218 // Creates destination file
233 219 if (tempFile->open()) {
234 220 // Executes request and store the request for progression
235 221 auto request = std::make_shared<QNetworkRequest>(downloadFileUrl);
236 222 updateRequestProgress(dataId, request, 0.0);
237 223 emit requestConstructed(request, dataId, httpDownloadFinished);
238 224 }
239 225 else {
240 226 emit dataProvidedFailed(dataId);
241 227 }
242 228 }
243 229 else {
244 230 qCCritical(LOG_AmdaProvider()) << tr("httpFinishedLambda ERROR");
245 231 m_AcqIdToRequestProgressMap.erase(dataId);
246 232 emit dataProvidedFailed(dataId);
247 233 }
248 234 };
249 235
250 236 // //////////////// //
251 237 // Executes request //
252 238 // //////////////// //
253 239
254 240 auto request = std::make_shared<QNetworkRequest>(url);
255 241 qCDebug(LOG_AmdaProvider()) << tr("First Request creation") << request.get();
256 242 updateRequestProgress(token, request, 0.0);
257 243
258 244 emit requestConstructed(request, token, httpFinishedLambda);
259 245 }
260 246
261 247 void AmdaProvider::updateRequestProgress(QUuid acqIdentifier,
262 248 std::shared_ptr<QNetworkRequest> request, double progress)
263 249 {
264 250 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress request") << request.get();
265 251 auto acqIdToRequestProgressMapIt = m_AcqIdToRequestProgressMap.find(acqIdentifier);
266 252 if (acqIdToRequestProgressMapIt != m_AcqIdToRequestProgressMap.end()) {
267 253 auto &requestProgressMap = acqIdToRequestProgressMapIt->second;
268 254 auto requestProgressMapIt = requestProgressMap.find(request);
269 255 if (requestProgressMapIt != requestProgressMap.end()) {
270 256 requestProgressMapIt->second = progress;
271 257 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new progress for request")
272 258 << acqIdentifier << request.get() << progress;
273 259 }
274 260 else {
275 261 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new request") << acqIdentifier
276 262 << request.get() << progress;
277 263 acqIdToRequestProgressMapIt->second.insert(std::make_pair(request, progress));
278 264 }
279 265 }
280 266 else {
281 267 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new acqIdentifier")
282 268 << acqIdentifier << request.get() << progress;
283 269 auto requestProgressMap = std::map<std::shared_ptr<QNetworkRequest>, double>{};
284 270 requestProgressMap.insert(std::make_pair(request, progress));
285 271 m_AcqIdToRequestProgressMap.insert(
286 272 std::make_pair(acqIdentifier, std::move(requestProgressMap)));
287 273 }
288 274 }
@@ -1,133 +1,133
1 1 #include "AmdaResultParser.h"
2 2
3 3 #include "AmdaResultParserHelper.h"
4 4
5 5 #include <QFile>
6 6
7 7 #include <cmath>
8 8
9 9 Q_LOGGING_CATEGORY(LOG_AmdaResultParser, "AmdaResultParser")
10 10
11 11 namespace {
12 12
13 13 /// Message in result file when the file was not found on server
14 14 const auto FILE_NOT_FOUND_MESSAGE = QStringLiteral("Not Found");
15 15
16 16 /// Checks if a line is a comment line
17 17 bool isCommentLine(const QString &line)
18 18 {
19 19 return line.startsWith("#");
20 20 }
21 21
22 22 /**
23 23 * Creates helper that will be used to read AMDA file, according to the type passed as parameter
24 24 * @param valueType the type of values expected in the AMDA file (scalars, vectors, spectrograms...)
25 25 * @return the helper created
26 26 */
27 std::unique_ptr<IAmdaResultParserHelper> createHelper(AmdaResultParser::ValueType valueType)
27 std::unique_ptr<IAmdaResultParserHelper> createHelper(DataSeriesType valueType)
28 28 {
29 29 switch (valueType) {
30 case AmdaResultParser::ValueType::SCALAR:
30 case DataSeriesType::SCALAR:
31 31 return std::make_unique<ScalarParserHelper>();
32 case AmdaResultParser::ValueType::SPECTROGRAM:
32 case DataSeriesType::SPECTROGRAM:
33 33 return std::make_unique<SpectrogramParserHelper>();
34 case AmdaResultParser::ValueType::VECTOR:
34 case DataSeriesType::VECTOR:
35 35 return std::make_unique<VectorParserHelper>();
36 case AmdaResultParser::ValueType::UNKNOWN:
36 case DataSeriesType::UNKNOWN:
37 37 // Invalid case
38 38 break;
39 39 }
40 40
41 41 // Invalid cases
42 42 qCCritical(LOG_AmdaResultParser())
43 43 << QObject::tr("Can't create helper to read result file: unsupported type");
44 44 return nullptr;
45 45 }
46 46
47 47 /**
48 48 * Reads properties of the stream passed as parameter
49 49 * @param helper the helper used to read properties line by line
50 50 * @param stream the stream to read
51 51 */
52 52 void readProperties(IAmdaResultParserHelper &helper, QTextStream &stream)
53 53 {
54 54 // Searches properties in the comment lines (as long as the reading has not reached the data)
55 55 // AMDA V2: while (stream.readLineInto(&line) && !line.contains(DATA_HEADER_REGEX)) {
56 56 QString line{};
57 57 while (stream.readLineInto(&line) && isCommentLine(line)) {
58 58 helper.readPropertyLine(line);
59 59 }
60 60 }
61 61
62 62 /**
63 63 * Reads results of the stream passed as parameter
64 64 * @param helper the helper used to read results line by line
65 65 * @param stream the stream to read
66 66 */
67 67 void readResults(IAmdaResultParserHelper &helper, QTextStream &stream)
68 68 {
69 69 QString line{};
70 70
71 71 // Skip comment lines
72 72 while (stream.readLineInto(&line) && isCommentLine(line)) {
73 73 }
74 74
75 75 if (!stream.atEnd()) {
76 76 do {
77 77 helper.readResultLine(line);
78 78 } while (stream.readLineInto(&line));
79 79 }
80 80 }
81 81
82 82 } // namespace
83 83
84 84 std::shared_ptr<IDataSeries> AmdaResultParser::readTxt(const QString &filePath,
85 ValueType valueType) noexcept
85 DataSeriesType type) noexcept
86 86 {
87 if (valueType == ValueType::UNKNOWN) {
87 if (type == DataSeriesType::UNKNOWN) {
88 88 qCCritical(LOG_AmdaResultParser())
89 89 << QObject::tr("Can't retrieve AMDA data: the type of values to be read is unknown");
90 90 return nullptr;
91 91 }
92 92
93 93 QFile file{filePath};
94 94
95 95 if (!file.open(QFile::ReadOnly | QIODevice::Text)) {
96 96 qCCritical(LOG_AmdaResultParser())
97 97 << QObject::tr("Can't retrieve AMDA data from file %1: %2")
98 98 .arg(filePath, file.errorString());
99 99 return nullptr;
100 100 }
101 101
102 102 QTextStream stream{&file};
103 103
104 104 // Checks if the file was found on the server
105 105 auto firstLine = stream.readLine();
106 106 if (firstLine.compare(FILE_NOT_FOUND_MESSAGE) == 0) {
107 107 qCCritical(LOG_AmdaResultParser())
108 108 << QObject::tr("Can't retrieve AMDA data from file %1: file was not found on server")
109 109 .arg(filePath);
110 110 return nullptr;
111 111 }
112 112
113 auto helper = createHelper(valueType);
113 auto helper = createHelper(type);
114 114 Q_ASSERT(helper != nullptr);
115 115
116 116 // Reads header file to retrieve properties
117 117 stream.seek(0); // returns to the beginning of the file
118 118 readProperties(*helper, stream);
119 119
120 120 // Checks properties
121 121 if (helper->checkProperties()) {
122 122 // Reads results
123 123 // AMDA V2: remove line
124 124 stream.seek(0); // returns to the beginning of the file
125 125 readResults(*helper, stream);
126 126
127 127 // Creates data series
128 128 return helper->createSeries();
129 129 }
130 130 else {
131 131 return nullptr;
132 132 }
133 133 }
@@ -1,164 +1,164
1 1 #include "AmdaProvider.h"
2 2 #include "AmdaResultParser.h"
3 3
4 4 #include "SqpApplication.h"
5 5 #include <Data/DataSeries.h>
6 6 #include <Data/IDataSeries.h>
7 7 #include <Data/ScalarSeries.h>
8 8 #include <Time/TimeController.h>
9 9 #include <Variable/Variable.h>
10 10 #include <Variable/VariableController.h>
11 11
12 12 #include <QObject>
13 13 #include <QtTest>
14 14
15 15 #include <memory>
16 16
17 17 // TEST with REF:
18 18 // AmdaData-2012-01-01-12-00-00_2012-01-03-12-00-00
19 19 // imf(0) - Type : Local Parameter @ CDPP/AMDA -
20 20 // Name : bx_gse - Units : nT - Size : 1 -
21 21 // Frame : GSE - Mission : ACE -
22 22 // Instrument : MFI - Dataset : mfi_final-prelim
23 23 // REFERENCE DOWNLOAD FILE =
24 24 // http://amdatest.irap.omp.eu/php/rest/getParameter.php?startTime=2012-01-01T12:00:00&stopTime=2012-01-03T12:00:00&parameterID=imf(0)&outputFormat=ASCII&timeFormat=ISO8601&gzip=0
25 25
26 26 namespace {
27 27
28 28 /// Path for the tests
29 29 const auto TESTS_RESOURCES_PATH
30 30 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaAcquisition"}.absoluteFilePath();
31 31
32 32 /// Delay after each operation on the variable before validating it (in ms)
33 33 const auto OPERATION_DELAY = 10000;
34 34
35 35 template <typename T>
36 36 bool compareDataSeries(std::shared_ptr<IDataSeries> candidate, SqpRange candidateCacheRange,
37 37 std::shared_ptr<IDataSeries> reference)
38 38 {
39 39 auto compareLambda = [](const auto &it1, const auto &it2) {
40 40 return (it1.x() == it2.x()) && (it1.value() == it2.value());
41 41 };
42 42
43 43 auto candidateDS = std::dynamic_pointer_cast<T>(candidate);
44 44 auto referenceDS = std::dynamic_pointer_cast<T>(reference);
45 45
46 46 if (candidateDS && referenceDS) {
47 47
48 48 auto itRefs
49 49 = referenceDS->xAxisRange(candidateCacheRange.m_TStart, candidateCacheRange.m_TEnd);
50 50 qDebug() << " DISTANCE" << std::distance(candidateDS->cbegin(), candidateDS->cend())
51 51 << std::distance(itRefs.first, itRefs.second);
52 52
53 53 return std::equal(candidateDS->cbegin(), candidateDS->cend(), itRefs.first, itRefs.second,
54 54 compareLambda);
55 55 }
56 56 else {
57 57 return false;
58 58 }
59 59 }
60 60 }
61 61
62 62 class TestAmdaAcquisition : public QObject {
63 63 Q_OBJECT
64 64
65 65 private slots:
66 66 /// Input data for @sa testAcquisition()
67 67 void testAcquisition_data();
68 68 void testAcquisition();
69 69 };
70 70
71 71 void TestAmdaAcquisition::testAcquisition_data()
72 72 {
73 73 // ////////////// //
74 74 // Test structure //
75 75 // ////////////// //
76 76
77 77 QTest::addColumn<QString>("dataFilename"); // File containing expected data of acquisitions
78 78 QTest::addColumn<SqpRange>("initialRange"); // First acquisition
79 79 QTest::addColumn<std::vector<SqpRange> >("operations"); // Acquisitions to make
80 80
81 81 // ////////// //
82 82 // Test cases //
83 83 // ////////// //
84 84
85 85 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
86 86 return DateUtils::secondsSinceEpoch(
87 87 QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC});
88 88 };
89 89
90 90
91 91 QTest::newRow("amda")
92 92 << "AmdaData-2012-01-01-12-00-00_2012-01-03-12-00-00.txt"
93 93 << SqpRange{dateTime(2012, 1, 2, 2, 3, 0), dateTime(2012, 1, 2, 2, 4, 0)}
94 94 << std::vector<SqpRange>{
95 95 // 2 : pan (jump) left for two min
96 96 SqpRange{dateTime(2012, 1, 2, 2, 1, 0), dateTime(2012, 1, 2, 2, 2, 0)},
97 97 // 3 : pan (jump) right for four min
98 98 SqpRange{dateTime(2012, 1, 2, 2, 5, 0), dateTime(2012, 1, 2, 2, 6, 0)},
99 99 // 4 : pan (overlay) right for 30 sec
100 100 /*SqpRange{dateTime(2012, 1, 2, 2, 5, 30), dateTime(2012, 1, 2, 2, 6, 30)},
101 101 // 5 : pan (overlay) left for 30 sec
102 102 SqpRange{dateTime(2012, 1, 2, 2, 5, 0), dateTime(2012, 1, 2, 2, 6, 0)},
103 103 // 6 : pan (overlay) left for 30 sec - BIS
104 104 SqpRange{dateTime(2012, 1, 2, 2, 4, 30), dateTime(2012, 1, 2, 2, 5, 30)},
105 105 // 7 : Zoom in Inside 20 sec range
106 106 SqpRange{dateTime(2012, 1, 2, 2, 4, 50), dateTime(2012, 1, 2, 2, 5, 10)},
107 107 // 8 : Zoom out Inside 20 sec range
108 108 SqpRange{dateTime(2012, 1, 2, 2, 4, 30), dateTime(2012, 1, 2, 2, 5, 30)}*/};
109 109 }
110 110
111 111 void TestAmdaAcquisition::testAcquisition()
112 112 {
113 113 /// @todo: update test to be compatible with AMDA v2
114 114
115 115 // Retrieves data file
116 116 QFETCH(QString, dataFilename);
117 117 auto filePath = QFileInfo{TESTS_RESOURCES_PATH, dataFilename}.absoluteFilePath();
118 auto results = AmdaResultParser::readTxt(filePath, AmdaResultParser::ValueType::SCALAR);
118 auto results = AmdaResultParser::readTxt(filePath, DataSeriesType::SCALAR);
119 119
120 120 /// Lambda used to validate a variable at each step
121 121 auto validateVariable = [results](std::shared_ptr<Variable> variable, const SqpRange &range) {
122 122 // Checks that the variable's range has changed
123 123 qInfo() << tr("Compare var range vs range") << variable->range() << range;
124 124 QCOMPARE(variable->range(), range);
125 125
126 126 // Checks the variable's data series
127 127 QVERIFY(compareDataSeries<ScalarSeries>(variable->dataSeries(), variable->cacheRange(),
128 128 results));
129 129 qInfo() << "\n";
130 130 };
131 131
132 132 // Creates variable
133 133 QFETCH(SqpRange, initialRange);
134 134 sqpApp->timeController().onTimeToUpdate(initialRange);
135 135 auto provider = std::make_shared<AmdaProvider>();
136 136 auto variable = sqpApp->variableController().createVariable(
137 137 "bx_gse", {{"dataType", "scalar"}, {"xml:id", "imf(0)"}}, provider);
138 138
139 139 QTest::qWait(OPERATION_DELAY);
140 140 validateVariable(variable, initialRange);
141 141
142 142 // Makes operations on the variable
143 143 QFETCH(std::vector<SqpRange>, operations);
144 144 for (const auto &operation : operations) {
145 145 // Asks request on the variable and waits during its execution
146 146 sqpApp->variableController().onRequestDataLoading({variable}, operation, false);
147 147
148 148 QTest::qWait(OPERATION_DELAY);
149 149 validateVariable(variable, operation);
150 150 }
151 151 }
152 152
153 153 int main(int argc, char *argv[])
154 154 {
155 155 SqpApplication app(argc, argv);
156 156 app.setAttribute(Qt::AA_Use96Dpi, true);
157 157 TestAmdaAcquisition tc;
158 158 QTEST_SET_MAIN_SOURCE_PATH
159 159 return QTest::qExec(&tc, argc, argv);
160 160 }
161 161
162 162 // QTEST_MAIN(TestAmdaAcquisition)
163 163
164 164 #include "TestAmdaAcquisition.moc"
@@ -1,579 +1,579
1 1 #include "AmdaResultParser.h"
2 2
3 3 #include <Data/ScalarSeries.h>
4 4 #include <Data/SpectrogramSeries.h>
5 5 #include <Data/VectorSeries.h>
6 6
7 7 #include <QObject>
8 8 #include <QtTest>
9 9
10 10 namespace {
11 11
12 12 /// Path for the tests
13 13 const auto TESTS_RESOURCES_PATH
14 14 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaResultParser"}.absoluteFilePath();
15 15
16 16 QDateTime dateTime(int year, int month, int day, int hours, int minutes, int seconds)
17 17 {
18 18 return QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC};
19 19 }
20 20
21 21 QString inputFilePath(const QString &inputFileName)
22 22 {
23 23 return QFileInfo{TESTS_RESOURCES_PATH, inputFileName}.absoluteFilePath();
24 24 }
25 25
26 26 template <typename T>
27 27 struct ExpectedResults {
28 28
29 29 ExpectedResults &setParsingOK(bool parsingOK)
30 30 {
31 31 m_ParsingOK = parsingOK;
32 32 return *this;
33 33 }
34 34
35 35 ExpectedResults &setXAxisUnit(Unit xAxisUnit)
36 36 {
37 37 m_XAxisUnit = std::move(xAxisUnit);
38 38 return *this;
39 39 }
40 40
41 41 ExpectedResults &setXAxisData(const QVector<QDateTime> &xAxisData)
42 42 {
43 43 m_XAxisData.clear();
44 44
45 45 // Converts QVector<QDateTime> to QVector<double>
46 46 std::transform(xAxisData.cbegin(), xAxisData.cend(), std::back_inserter(m_XAxisData),
47 47 [](const auto &dateTime) { return dateTime.toMSecsSinceEpoch() / 1000.; });
48 48
49 49 return *this;
50 50 }
51 51
52 52 ExpectedResults &setValuesUnit(Unit valuesUnit)
53 53 {
54 54 m_ValuesUnit = std::move(valuesUnit);
55 55 return *this;
56 56 }
57 57
58 58 ExpectedResults &setValuesData(QVector<double> valuesData)
59 59 {
60 60 m_ValuesData.clear();
61 61 m_ValuesData.push_back(std::move(valuesData));
62 62 return *this;
63 63 }
64 64
65 65 ExpectedResults &setValuesData(QVector<QVector<double> > valuesData)
66 66 {
67 67 m_ValuesData = std::move(valuesData);
68 68 return *this;
69 69 }
70 70
71 71 ExpectedResults &setYAxisEnabled(bool yAxisEnabled)
72 72 {
73 73 m_YAxisEnabled = yAxisEnabled;
74 74 return *this;
75 75 }
76 76
77 77 ExpectedResults &setYAxisUnit(Unit yAxisUnit)
78 78 {
79 79 m_YAxisUnit = std::move(yAxisUnit);
80 80 return *this;
81 81 }
82 82
83 83 ExpectedResults &setYAxisData(QVector<double> yAxisData)
84 84 {
85 85 m_YAxisData = std::move(yAxisData);
86 86 return *this;
87 87 }
88 88
89 89 /**
90 90 * Validates a DataSeries compared to the expected results
91 91 * @param results the DataSeries to validate
92 92 */
93 93 void validate(std::shared_ptr<IDataSeries> results)
94 94 {
95 95 if (m_ParsingOK) {
96 96 auto dataSeries = dynamic_cast<T *>(results.get());
97 97 if (dataSeries == nullptr) {
98 98
99 99 // No unit detected, parsink ok but data is nullptr
100 100 // TODO, improve the test to verify that the data is null
101 101 return;
102 102 }
103 103
104 104 // Checks units
105 105 QVERIFY(dataSeries->xAxisUnit() == m_XAxisUnit);
106 106 QVERIFY(dataSeries->valuesUnit() == m_ValuesUnit);
107 107
108 108 auto verifyRange = [dataSeries](const auto &expectedData, const auto &equalFun) {
109 109 QVERIFY(std::equal(dataSeries->cbegin(), dataSeries->cend(), expectedData.cbegin(),
110 110 expectedData.cend(),
111 111 [&equalFun](const auto &dataSeriesIt, const auto &expectedX) {
112 112 return equalFun(dataSeriesIt, expectedX);
113 113 }));
114 114 };
115 115
116 116 // Checks x-axis data
117 117 verifyRange(m_XAxisData, [](const auto &seriesIt, const auto &value) {
118 118 return seriesIt.x() == value;
119 119 });
120 120
121 121 // Checks values data of each component
122 122 for (auto i = 0; i < m_ValuesData.size(); ++i) {
123 123 verifyRange(m_ValuesData.at(i), [i](const auto &seriesIt, const auto &value) {
124 124 auto itValue = seriesIt.value(i);
125 125 return (std::isnan(itValue) && std::isnan(value)) || seriesIt.value(i) == value;
126 126 });
127 127 }
128 128
129 129 // Checks y-axis (if defined)
130 130 auto yAxis = dataSeries->yAxis();
131 131 QCOMPARE(yAxis.isDefined(), m_YAxisEnabled);
132 132
133 133 if (m_YAxisEnabled) {
134 134 // Unit
135 135 QCOMPARE(yAxis.unit(), m_YAxisUnit);
136 136
137 137 // Data
138 138 QVERIFY(std::equal(yAxis.cbegin(), yAxis.cend(), m_YAxisData.cbegin(),
139 139 m_YAxisData.cend(), [](const auto &it, const auto &expectedVal) {
140 140 return it.first() == expectedVal;
141 141 }));
142 142 }
143 143 }
144 144 else {
145 145 QVERIFY(results == nullptr);
146 146 }
147 147 }
148 148
149 149 // Parsing was successfully completed
150 150 bool m_ParsingOK{false};
151 151 // Expected x-axis unit
152 152 Unit m_XAxisUnit{};
153 153 // Expected x-axis data
154 154 QVector<double> m_XAxisData{};
155 155 // Expected values unit
156 156 Unit m_ValuesUnit{};
157 157 // Expected values data
158 158 QVector<QVector<double> > m_ValuesData{};
159 159 // Expected data series has y-axis
160 160 bool m_YAxisEnabled{false};
161 161 // Expected y-axis unit (if axis defined)
162 162 Unit m_YAxisUnit{};
163 163 // Expected y-axis data (if axis defined)
164 164 QVector<double> m_YAxisData{};
165 165 };
166 166
167 167 } // namespace
168 168
169 169 Q_DECLARE_METATYPE(ExpectedResults<ScalarSeries>)
170 170 Q_DECLARE_METATYPE(ExpectedResults<SpectrogramSeries>)
171 171 Q_DECLARE_METATYPE(ExpectedResults<VectorSeries>)
172 172
173 173 class TestAmdaResultParser : public QObject {
174 174 Q_OBJECT
175 175 private:
176 176 template <typename T>
177 177 void testReadDataStructure()
178 178 {
179 179 // ////////////// //
180 180 // Test structure //
181 181 // ////////////// //
182 182
183 183 // Name of TXT file to read
184 184 QTest::addColumn<QString>("inputFileName");
185 185 // Expected results
186 186 QTest::addColumn<ExpectedResults<T> >("expectedResults");
187 187 }
188 188
189 189 template <typename T>
190 void testRead(AmdaResultParser::ValueType valueType)
190 void testRead(DataSeriesType valueType)
191 191 {
192 192 QFETCH(QString, inputFileName);
193 193 QFETCH(ExpectedResults<T>, expectedResults);
194 194
195 195 // Parses file
196 196 auto filePath = inputFilePath(inputFileName);
197 197 auto results = AmdaResultParser::readTxt(filePath, valueType);
198 198
199 199 // ///////////////// //
200 200 // Validates results //
201 201 // ///////////////// //
202 202 expectedResults.validate(results);
203 203 }
204 204
205 205 private slots:
206 206 /// Input test data
207 207 /// @sa testReadScalarTxt()
208 208 void testReadScalarTxt_data();
209 209
210 210 /// Tests parsing scalar series of a TXT file
211 211 void testReadScalarTxt();
212 212
213 213 /// Input test data
214 214 /// @sa testReadSpectrogramTxt()
215 215 void testReadSpectrogramTxt_data();
216 216
217 217 /// Tests parsing spectrogram series of a TXT file
218 218 void testReadSpectrogramTxt();
219 219
220 220 /// Input test data
221 221 /// @sa testReadVectorTxt()
222 222 void testReadVectorTxt_data();
223 223
224 224 /// Tests parsing vector series of a TXT file
225 225 void testReadVectorTxt();
226 226 };
227 227
228 228 void TestAmdaResultParser::testReadScalarTxt_data()
229 229 {
230 230 testReadDataStructure<ScalarSeries>();
231 231
232 232 // ////////// //
233 233 // Test cases //
234 234 // ////////// //
235 235
236 236 // Valid files
237 237 QTest::newRow("Valid file")
238 238 << QStringLiteral("ValidScalar1.txt")
239 239 << ExpectedResults<ScalarSeries>{}
240 240 .setParsingOK(true)
241 241 .setXAxisUnit(Unit{"nT", true})
242 242 .setXAxisData({dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
243 243 dateTime(2013, 9, 23, 9, 2, 30), dateTime(2013, 9, 23, 9, 3, 30),
244 244 dateTime(2013, 9, 23, 9, 4, 30), dateTime(2013, 9, 23, 9, 5, 30),
245 245 dateTime(2013, 9, 23, 9, 6, 30), dateTime(2013, 9, 23, 9, 7, 30),
246 246 dateTime(2013, 9, 23, 9, 8, 30), dateTime(2013, 9, 23, 9, 9, 30)})
247 247 .setValuesData({-2.83950, -2.71850, -2.52150, -2.57633, -2.58050, -2.48325, -2.63025,
248 248 -2.55800, -2.43250, -2.42200});
249 249
250 250 QTest::newRow("Valid file (value of first line is invalid but it is converted to NaN")
251 251 << QStringLiteral("WrongValue.txt")
252 252 << ExpectedResults<ScalarSeries>{}
253 253 .setParsingOK(true)
254 254 .setXAxisUnit(Unit{"nT", true})
255 255 .setXAxisData({dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
256 256 dateTime(2013, 9, 23, 9, 2, 30)})
257 257 .setValuesData({std::numeric_limits<double>::quiet_NaN(), -2.71850, -2.52150});
258 258
259 259 QTest::newRow("Valid file that contains NaN values")
260 260 << QStringLiteral("NaNValue.txt")
261 261 << ExpectedResults<ScalarSeries>{}
262 262 .setParsingOK(true)
263 263 .setXAxisUnit(Unit{("nT"), true})
264 264 .setXAxisData({dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
265 265 dateTime(2013, 9, 23, 9, 2, 30)})
266 266 .setValuesData({std::numeric_limits<double>::quiet_NaN(), -2.71850, -2.52150});
267 267
268 268 // Valid files but with some invalid lines (wrong unit, wrong values, etc.)
269 269 QTest::newRow("No unit file")
270 270 << QStringLiteral("NoUnit.txt")
271 271 << ExpectedResults<ScalarSeries>{}.setParsingOK(true).setXAxisUnit(Unit{"", true});
272 272
273 273 QTest::newRow("Wrong unit file")
274 274 << QStringLiteral("WrongUnit.txt")
275 275 << ExpectedResults<ScalarSeries>{}
276 276 .setParsingOK(true)
277 277 .setXAxisUnit(Unit{"", true})
278 278 .setXAxisData({dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
279 279 dateTime(2013, 9, 23, 9, 2, 30)})
280 280 .setValuesData({-2.83950, -2.71850, -2.52150});
281 281
282 282 QTest::newRow("Wrong results file (date of first line is invalid")
283 283 << QStringLiteral("WrongDate.txt")
284 284 << ExpectedResults<ScalarSeries>{}
285 285 .setParsingOK(true)
286 286 .setXAxisUnit(Unit{"nT", true})
287 287 .setXAxisData({dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)})
288 288 .setValuesData({-2.71850, -2.52150});
289 289
290 290 QTest::newRow("Wrong results file (too many values for first line")
291 291 << QStringLiteral("TooManyValues.txt")
292 292 << ExpectedResults<ScalarSeries>{}
293 293 .setParsingOK(true)
294 294 .setXAxisUnit(Unit{"nT", true})
295 295 .setXAxisData({dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)})
296 296 .setValuesData({-2.71850, -2.52150});
297 297
298 298 QTest::newRow("Wrong results file (x of first line is NaN")
299 299 << QStringLiteral("NaNX.txt")
300 300 << ExpectedResults<ScalarSeries>{}
301 301 .setParsingOK(true)
302 302 .setXAxisUnit(Unit{"nT", true})
303 303 .setXAxisData({dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)})
304 304 .setValuesData({-2.71850, -2.52150});
305 305
306 306 QTest::newRow("Invalid file type (vector)")
307 307 << QStringLiteral("ValidVector1.txt")
308 308 << ExpectedResults<ScalarSeries>{}.setParsingOK(true).setXAxisUnit(Unit{"nT", true});
309 309
310 310 // Invalid files
311 311 QTest::newRow("Invalid file (unexisting file)")
312 312 << QStringLiteral("UnexistingFile.txt")
313 313 << ExpectedResults<ScalarSeries>{}.setParsingOK(false);
314 314
315 315 QTest::newRow("Invalid file (file not found on server)")
316 316 << QStringLiteral("FileNotFound.txt")
317 317 << ExpectedResults<ScalarSeries>{}.setParsingOK(false);
318 318 }
319 319
320 320 void TestAmdaResultParser::testReadScalarTxt()
321 321 {
322 testRead<ScalarSeries>(AmdaResultParser::ValueType::SCALAR);
322 testRead<ScalarSeries>(DataSeriesType::SCALAR);
323 323 }
324 324
325 325 void TestAmdaResultParser::testReadSpectrogramTxt_data()
326 326 {
327 327 testReadDataStructure<SpectrogramSeries>();
328 328
329 329 // ////////// //
330 330 // Test cases //
331 331 // ////////// //
332 332
333 333 // Valid files
334 334 QTest::newRow("Valid file (three bands)")
335 335 << QStringLiteral("spectro/ValidSpectrogram1.txt")
336 336 << ExpectedResults<SpectrogramSeries>{}
337 337 .setParsingOK(true)
338 338 .setXAxisUnit(Unit{"t", true})
339 339 .setXAxisData({dateTime(2012, 11, 6, 9, 14, 35), dateTime(2012, 11, 6, 9, 16, 10),
340 340 dateTime(2012, 11, 6, 9, 17, 45), dateTime(2012, 11, 6, 9, 19, 20),
341 341 dateTime(2012, 11, 6, 9, 20, 55)})
342 342 .setYAxisEnabled(true)
343 343 .setYAxisUnit(Unit{"eV"})
344 344 .setYAxisData({5.75, 7.6, 10.05}) // middle of the intervals of each band
345 345 .setValuesUnit(Unit{"eV/(cm^2-s-sr-eV)"})
346 346 .setValuesData(QVector<QVector<double> >{
347 347 {16313.780, 12631.465, 8223.368, 27595.301, 12820.613},
348 348 {15405.838, 11957.925, 15026.249, 25617.533, 11179.109},
349 349 {8946.475, 18133.158, 10875.621, 24051.619, 19283.221}});
350 350
351 351 auto fourBandsResult
352 352 = ExpectedResults<SpectrogramSeries>{}
353 353 .setParsingOK(true)
354 354 .setXAxisUnit(Unit{"t", true})
355 355 .setXAxisData({dateTime(2012, 11, 6, 9, 14, 35), dateTime(2012, 11, 6, 9, 16, 10),
356 356 dateTime(2012, 11, 6, 9, 17, 45), dateTime(2012, 11, 6, 9, 19, 20),
357 357 dateTime(2012, 11, 6, 9, 20, 55)})
358 358 .setYAxisEnabled(true)
359 359 .setYAxisUnit(Unit{"eV"})
360 360 .setYAxisData({5.75, 7.6, 10.05, 13.}) // middle of the intervals of each band
361 361 .setValuesUnit(Unit{"eV/(cm^2-s-sr-eV)"})
362 362 .setValuesData(QVector<QVector<double> >{
363 363 {16313.780, 12631.465, 8223.368, 27595.301, 12820.613},
364 364 {15405.838, 11957.925, 15026.249, 25617.533, 11179.109},
365 365 {8946.475, 18133.158, 10875.621, 24051.619, 19283.221},
366 366 {20907.664, 32076.725, 13008.381, 13142.759, 23226.998}});
367 367
368 368 QTest::newRow("Valid file (four bands)") << QStringLiteral("spectro/ValidSpectrogram2.txt")
369 369 << fourBandsResult;
370 370 QTest::newRow("Valid file (four unsorted bands)")
371 371 << QStringLiteral("spectro/ValidSpectrogram3.txt")
372 372 << fourBandsResult; // Bands and values are sorted
373 373
374 374 auto nan = std::numeric_limits<double>::quiet_NaN();
375 375
376 376 auto nanValuesResult
377 377 = ExpectedResults<SpectrogramSeries>{}
378 378 .setParsingOK(true)
379 379 .setXAxisUnit(Unit{"t", true})
380 380 .setXAxisData({dateTime(2012, 11, 6, 9, 14, 35), dateTime(2012, 11, 6, 9, 16, 10),
381 381 dateTime(2012, 11, 6, 9, 17, 45), dateTime(2012, 11, 6, 9, 19, 20),
382 382 dateTime(2012, 11, 6, 9, 20, 55)})
383 383 .setYAxisEnabled(true)
384 384 .setYAxisUnit(Unit{"eV"})
385 385 .setYAxisData({5.75, 7.6, 10.05, 13.}) // middle of the intervals of each band
386 386 .setValuesUnit(Unit{"eV/(cm^2-s-sr-eV)"})
387 387 .setValuesData(
388 388 QVector<QVector<double> >{{nan, 12631.465, 8223.368, 27595.301, 12820.613},
389 389 {15405.838, nan, nan, 25617.533, 11179.109},
390 390 {8946.475, 18133.158, 10875.621, 24051.619, 19283.221},
391 391 {nan, nan, nan, nan, nan}});
392 392
393 393 QTest::newRow("Valid file (containing NaN values)")
394 394 << QStringLiteral("spectro/ValidSpectrogramNaNValues.txt") << nanValuesResult;
395 395 QTest::newRow("Valid file (containing fill values)")
396 396 << QStringLiteral("spectro/ValidSpectrogramFillValues.txt")
397 397 << nanValuesResult; // Fill values are replaced by NaN values in the data series
398 398
399 399 QTest::newRow("Valid file (containing data holes, resolution = 3 minutes)")
400 400 << QStringLiteral("spectro/ValidSpectrogramDataHoles.txt")
401 401 << ExpectedResults<SpectrogramSeries>{}
402 402 .setParsingOK(true)
403 403 .setXAxisUnit(Unit{"t", true})
404 404 .setXAxisData({dateTime(2011, 12, 10, 12, 10, 54), //
405 405 dateTime(2011, 12, 10, 12, 13, 54), // Data hole
406 406 dateTime(2011, 12, 10, 12, 16, 54), // Data hole
407 407 dateTime(2011, 12, 10, 12, 17, 23), //
408 408 dateTime(2011, 12, 10, 12, 20, 23), // Data hole
409 409 dateTime(2011, 12, 10, 12, 23, 23), // Data hole
410 410 dateTime(2011, 12, 10, 12, 23, 51), //
411 411 dateTime(2011, 12, 10, 12, 26, 51), // Data hole
412 412 dateTime(2011, 12, 10, 12, 29, 51), // Data hole
413 413 dateTime(2011, 12, 10, 12, 30, 19), //
414 414 dateTime(2011, 12, 10, 12, 33, 19), // Data hole
415 415 dateTime(2011, 12, 10, 12, 35, 04), //
416 416 dateTime(2011, 12, 10, 12, 36, 41), //
417 417 dateTime(2011, 12, 10, 12, 38, 18), //
418 418 dateTime(2011, 12, 10, 12, 39, 55)})
419 419 .setYAxisEnabled(true)
420 420 .setYAxisUnit(Unit{"eV"})
421 421 .setYAxisData({16485.85, 20996.1}) // middle of the intervals of each band
422 422 .setValuesUnit(Unit{"eV/(cm^2-s-sr-eV)"})
423 423 .setValuesData(QVector<QVector<double> >{{2577578.000, //
424 424 nan, // Data hole
425 425 nan, // Data hole
426 426 2314121.500, //
427 427 nan, // Data hole
428 428 nan, // Data hole
429 429 2063608.750, //
430 430 nan, // Data hole
431 431 nan, // Data hole
432 432 2234525.500, //
433 433 nan, // Data hole
434 434 1670215.250, //
435 435 1689243.250, //
436 436 1654617.125, //
437 437 1504983.750},
438 438 {2336016.000, //
439 439 nan, // Data hole
440 440 nan, // Data hole
441 441 1712093.125, //
442 442 nan, // Data hole
443 443 nan, // Data hole
444 444 1614491.625, //
445 445 nan, // Data hole
446 446 nan, // Data hole
447 447 1764516.500, //
448 448 nan, // Data hole
449 449 1688078.500, //
450 450 1743183.500, //
451 451 1733603.250, //
452 452 1708356.500}});
453 453
454 454 QTest::newRow(
455 455 "Valid file (containing data holes at the beginning and the end, resolution = 4 minutes)")
456 456 << QStringLiteral("spectro/ValidSpectrogramDataHoles2.txt")
457 457 << ExpectedResults<SpectrogramSeries>{}
458 458 .setParsingOK(true)
459 459 .setXAxisUnit(Unit{"t", true})
460 460 .setXAxisData({
461 461 dateTime(2011, 12, 10, 12, 2, 54), // Data hole
462 462 dateTime(2011, 12, 10, 12, 6, 54), // Data hole
463 463 dateTime(2011, 12, 10, 12, 10, 54), //
464 464 dateTime(2011, 12, 10, 12, 14, 54), // Data hole
465 465 dateTime(2011, 12, 10, 12, 17, 23), //
466 466 dateTime(2011, 12, 10, 12, 21, 23), // Data hole
467 467 dateTime(2011, 12, 10, 12, 23, 51), //
468 468 dateTime(2011, 12, 10, 12, 27, 51), // Data hole
469 469 dateTime(2011, 12, 10, 12, 30, 19), //
470 470 dateTime(2011, 12, 10, 12, 34, 19), // Data hole
471 471 dateTime(2011, 12, 10, 12, 35, 04), //
472 472 dateTime(2011, 12, 10, 12, 36, 41), //
473 473 dateTime(2011, 12, 10, 12, 38, 18), //
474 474 dateTime(2011, 12, 10, 12, 39, 55),
475 475 dateTime(2011, 12, 10, 12, 43, 55), // Data hole
476 476 dateTime(2011, 12, 10, 12, 47, 55), // Data hole
477 477 dateTime(2011, 12, 10, 12, 51, 55), // Data hole
478 478 dateTime(2011, 12, 10, 12, 55, 55), // Data hole
479 479 dateTime(2011, 12, 10, 12, 59, 55) // Data hole
480 480 })
481 481 .setYAxisEnabled(true)
482 482 .setYAxisUnit(Unit{"eV"})
483 483 .setYAxisData({16485.85, 20996.1}) // middle of the intervals of each band
484 484 .setValuesUnit(Unit{"eV/(cm^2-s-sr-eV)"})
485 485 .setValuesData(QVector<QVector<double> >{{
486 486 nan, // Data hole
487 487 nan, // Data hole
488 488 2577578.000, //
489 489 nan, // Data hole
490 490 2314121.500, //
491 491 nan, // Data hole
492 492 2063608.750, //
493 493 nan, // Data hole
494 494 2234525.500, //
495 495 nan, // Data hole
496 496 1670215.250, //
497 497 1689243.250, //
498 498 1654617.125, //
499 499 1504983.750, //
500 500 nan, // Data hole
501 501 nan, // Data hole
502 502 nan, // Data hole
503 503 nan, // Data hole
504 504 nan // Data hole
505 505 },
506 506 {
507 507 nan, // Data hole
508 508 nan, // Data hole
509 509 2336016.000, //
510 510 nan, // Data hole
511 511 1712093.125, //
512 512 nan, // Data hole
513 513 1614491.625, //
514 514 nan, // Data hole
515 515 1764516.500, //
516 516 nan, // Data hole
517 517 1688078.500, //
518 518 1743183.500, //
519 519 1733603.250, //
520 520 1708356.500, //
521 521 nan, // Data hole
522 522 nan, // Data hole
523 523 nan, // Data hole
524 524 nan, // Data hole
525 525 nan // Data hole
526 526 }});
527 527
528 528 // Invalid files
529 529 QTest::newRow("Invalid file (inconsistent bands)")
530 530 << QStringLiteral("spectro/InvalidSpectrogramWrongBands.txt")
531 531 << ExpectedResults<SpectrogramSeries>{}.setParsingOK(false);
532 532 }
533 533
534 534 void TestAmdaResultParser::testReadSpectrogramTxt()
535 535 {
536 testRead<SpectrogramSeries>(AmdaResultParser::ValueType::SPECTROGRAM);
536 testRead<SpectrogramSeries>(DataSeriesType::SPECTROGRAM);
537 537 }
538 538
539 539 void TestAmdaResultParser::testReadVectorTxt_data()
540 540 {
541 541 testReadDataStructure<VectorSeries>();
542 542
543 543 // ////////// //
544 544 // Test cases //
545 545 // ////////// //
546 546
547 547 // Valid files
548 548 QTest::newRow("Valid file")
549 549 << QStringLiteral("ValidVector1.txt")
550 550 << ExpectedResults<VectorSeries>{}
551 551 .setParsingOK(true)
552 552 .setXAxisUnit(Unit{"nT", true})
553 553 .setXAxisData({dateTime(2013, 7, 2, 9, 13, 50), dateTime(2013, 7, 2, 9, 14, 6),
554 554 dateTime(2013, 7, 2, 9, 14, 22), dateTime(2013, 7, 2, 9, 14, 38),
555 555 dateTime(2013, 7, 2, 9, 14, 54), dateTime(2013, 7, 2, 9, 15, 10),
556 556 dateTime(2013, 7, 2, 9, 15, 26), dateTime(2013, 7, 2, 9, 15, 42),
557 557 dateTime(2013, 7, 2, 9, 15, 58), dateTime(2013, 7, 2, 9, 16, 14)})
558 558 .setValuesData(
559 559 {{-0.332, -1.011, -1.457, -1.293, -1.217, -1.443, -1.278, -1.202, -1.22, -1.259},
560 560 {3.206, 2.999, 2.785, 2.736, 2.612, 2.564, 2.892, 2.862, 2.859, 2.764},
561 561 {0.058, 0.496, 1.018, 1.485, 1.662, 1.505, 1.168, 1.244, 1.15, 1.358}});
562 562
563 563 // Valid files but with some invalid lines (wrong unit, wrong values, etc.)
564 564 QTest::newRow("Invalid file type (scalar)")
565 565 << QStringLiteral("ValidScalar1.txt")
566 566 << ExpectedResults<VectorSeries>{}
567 567 .setParsingOK(true)
568 568 .setXAxisUnit(Unit{"nT", true})
569 569 .setXAxisData({})
570 570 .setValuesData(QVector<QVector<double> >{{}, {}, {}});
571 571 }
572 572
573 573 void TestAmdaResultParser::testReadVectorTxt()
574 574 {
575 testRead<VectorSeries>(AmdaResultParser::ValueType::VECTOR);
575 testRead<VectorSeries>(DataSeriesType::VECTOR);
576 576 }
577 577
578 578 QTEST_MAIN(TestAmdaResultParser)
579 579 #include "TestAmdaResultParser.moc"
General Comments 0
You need to be logged in to leave comments. Login now