1 /**
2 * UGENE - Integrated Bioinformatics Tools.
3 * Copyright (C) 2008-2021 UniPro <ugene@unipro.ru>
4 * http://ugene.net
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 */
21
22 #include "RepeatFinderTests.h"
23
24 #include <QFile>
25
26 #include <U2Algorithm/SArrayBasedFindTask.h>
27 #include <U2Algorithm/SArrayIndex.h>
28
29 #include <U2Core/AppContext.h>
30 #include <U2Core/BaseDocumentFormats.h>
31 #include <U2Core/DNAAlphabet.h>
32 #include <U2Core/DNASequenceObject.h>
33 #include <U2Core/DocumentModel.h>
34 #include <U2Core/U2OpStatusUtils.h>
35 #include <U2Core/U2SafePoints.h>
36
37 #include "FindRepeatsTask.h"
38 #include "RF_SArray_TandemFinder.h"
39
40 namespace U2 {
41
42 #define SEQ_ATTR "seq"
43 #define SEQ2_ATTR "seq2"
44 #define REG_ATTR "reg"
45 #define W_ATTR "w"
46 #define C_ATTR "c"
47 #define INV_ATTR "inverted"
48 #define MIND_ATTR "mind"
49 #define MAXD_ATTR "maxd"
50 #define RESULT_ATTR "expected_result"
51 #define REFL_ATTR "reflect"
52 #define EXCL_ATTR "exclude"
53 #define SEQUENCE "sequence"
54 #define QUERY "query"
55 #define USE_BITMASK "bit-mask"
56 #define MISMATCHES "mismatches"
57 #define ALG_ATTR "alg"
58
parseRegion(const QString & n,const QDomElement & el)59 U2Region GTest_FindSingleSequenceRepeatsTask::parseRegion(const QString &n, const QDomElement &el) {
60 U2Region res;
61 QString v = el.attribute(n);
62 if (v.isEmpty()) {
63 return res;
64 }
65 int idx = v.indexOf("..");
66 if (idx == -1 || idx + 2 >= v.length()) {
67 return res;
68 }
69 QString v1 = v.left(idx);
70 QString v2 = v.mid(idx + 2);
71 int startPos = v1.toInt();
72 int endPos = v2.toInt();
73 if (startPos >= 0 && endPos > startPos) {
74 res.startPos = startPos - 1;
75 res.length = endPos - startPos + 1;
76 }
77 return res;
78 }
79
init(XMLTestFormat *,const QDomElement & el)80 void GTest_FindSingleSequenceRepeatsTask::init(XMLTestFormat *, const QDomElement &el) {
81 seq = el.attribute(SEQ_ATTR);
82 if (seq.isEmpty()) {
83 stateInfo.setError(QString("Value not found '%1'").arg(SEQ_ATTR));
84 return;
85 }
86 seq2 = el.attribute(SEQ2_ATTR);
87 if (seq2.isEmpty()) {
88 seq2 = seq;
89 }
90 region = parseRegion(REG_ATTR, el);
91
92 QString algStr = el.attribute(ALG_ATTR);
93
94 if (algStr == "suffix") {
95 alg = RFAlgorithm_Suffix;
96 } else {
97 if (algStr == "diagonal") {
98 alg = RFAlgorithm_Diagonal;
99 } else {
100 alg = RFAlgorithm_Auto;
101 }
102 }
103
104 minD = el.attribute(MIND_ATTR, "-1").toInt();
105 maxD = el.attribute(MAXD_ATTR, "-1").toInt();
106
107 QString wStr = el.attribute(W_ATTR);
108 if (wStr.isEmpty()) {
109 stateInfo.setError(QString("Value not found '%1'").arg(W_ATTR));
110 return;
111 }
112 w = wStr.toInt();
113 if (w < 2) {
114 stateInfo.setError(QString("Illegal value for '%1': %2").arg(W_ATTR).arg(wStr));
115 return;
116 }
117
118 QString cStr = el.attribute(C_ATTR, "0");
119 c = cStr.toInt();
120 if (c < 0 || c >= w) {
121 stateInfo.setError(QString("Illegal value for '%1': %2").arg(C_ATTR).arg(cStr));
122 return;
123 }
124
125 inverted = el.attribute("invert") == "true";
126 reflect = el.attribute("reflect", "true") == "true";
127 filterNested = el.attribute("filterNested", "false") == "true";
128 filterUnique = el.attribute("filterUnique", "false") == "true";
129
130 if (filterNested && filterUnique) {
131 stateInfo.setError(QString("Filter unique and filter nested cannot go together"));
132 return;
133 }
134
135 resultFile = el.attribute(RESULT_ATTR);
136 if (resultFile.isEmpty()) {
137 stateInfo.setError(QString("Value not found '%1'").arg(RESULT_ATTR));
138 return;
139 }
140
141 excludeList = el.attribute(EXCL_ATTR).split(',', QString::SkipEmptyParts);
142 }
143
getAlgName(RFAlgorithm alg)144 static QString getAlgName(RFAlgorithm alg) {
145 QString res;
146 switch (alg) {
147 case RFAlgorithm_Diagonal:
148 res = "diagonal";
149 break;
150 case RFAlgorithm_Suffix:
151 res = "suffix";
152 break;
153 default:
154 res = "UNKNOWN";
155 break;
156 }
157 return res;
158 }
159
prepare()160 void GTest_FindSingleSequenceRepeatsTask::prepare() {
161 if (hasError() || isCanceled()) {
162 return;
163 }
164 U2SequenceObject *seq1IObj = getContext<U2SequenceObject>(this, seq);
165 if (seq1IObj == nullptr) {
166 stateInfo.setError("can't find sequence1");
167 return;
168 }
169
170 if (region.isEmpty()) {
171 region = U2Region(0, seq1IObj->getSequenceLength());
172 }
173
174 int maxLen = seq1IObj->getSequenceLength();
175 if (minD == -1) {
176 minD = -maxLen;
177 }
178 if (maxD == -1) {
179 maxD = maxLen;
180 }
181
182 QList<RFAlgorithm> algos;
183 if (alg == RFAlgorithm_Auto) {
184 algos << RFAlgorithm_Diagonal << RFAlgorithm_Suffix;
185 } else {
186 algos << alg;
187 }
188
189 FindRepeatsTaskSettings s;
190 s.minLen = w;
191 s.mismatches = c;
192 s.minDist = minD;
193 s.maxDist = maxD;
194 s.inverted = inverted;
195 s.seqRegion = region;
196 s.seq2Region = region;
197 s.reportReflected = reflect;
198 s.nThreads = 1; // todo: add to settings
199
200 if (filterNested == true) {
201 s.filter = DisjointRepeats;
202 } else if (filterUnique == true) {
203 s.filter = UniqueRepeats;
204 } else {
205 s.filter = NoFiltering;
206 }
207
208 U2OpStatusImpl os;
209 foreach (RFAlgorithm algo, algos) {
210 QString algName = getAlgName(algo);
211 if (excludeList.contains(algName)) {
212 continue;
213 }
214 s.algo = algo;
215 DNASequence seqData = seq1IObj->getWholeSequence(os);
216 CHECK_OP_EXT(os, setError(os.getError()), );
217 Task *sub = new FindRepeatsTask(s, seqData, seqData);
218 addSubTask(sub);
219 }
220 }
221
run()222 void GTest_FindSingleSequenceRepeatsTask::run() {
223 if (hasError() || isCanceled()) {
224 return;
225 }
226 QVector<RFResult> expectedResults;
227 // load file with results
228 QString fname = env->getVar("COMMON_DATA_DIR") + "/" + resultFile;
229 QFile file(fname);
230 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
231 stateInfo.setError(QString("Can't open results file %1").arg(fname));
232 return;
233 }
234
235 while (!file.atEnd()) {
236 QString line = file.readLine();
237 QStringList hit = line.split(' ', QString::SkipEmptyParts);
238 if (!(hit.size() == 3 || hit.size() == 4)) {
239 stateInfo.setError(QString("Can't parse results line: %1").arg(line));
240 return;
241 }
242 RFResult r;
243 r.x = hit[0].toInt() - 1;
244 r.y = hit[1].toInt() - 1;
245 r.l = hit[2].toInt();
246 r.c = hit.size() == 4 ? hit[3].toInt() : -1;
247 if (r.x < 0 || r.y < 0 || r.l < 0 || (hit.size() == 4 && r.c < 0)) {
248 stateInfo.setError(QString("Can't parse results line: %1").arg(line));
249 return;
250 }
251 expectedResults.append(r);
252 }
253 file.close();
254
255 std::sort(expectedResults.begin(), expectedResults.end());
256
257 // check all subtasks
258 FindRepeatsTask *sub = qobject_cast<FindRepeatsTask *>(getSubtasks()[0].data());
259 QVector<RFResult> calcResults = sub->getResults();
260 if (expectedResults.size() != calcResults.size()) {
261 stateInfo.setError(QString("Results count not matched, num = %1, expected = %2, alg = %3")
262 .arg(calcResults.size())
263 .arg(expectedResults.size())
264 .arg(getAlgName(sub->getSettings().algo)));
265 return;
266 }
267 std::sort(calcResults.begin(), calcResults.end());
268
269 for (int i = 0, n = expectedResults.size(); i < n; i++) {
270 RFResult re = expectedResults[i];
271 RFResult rc = calcResults[i];
272 if (re != rc || ((re.c >= 0) && (re.c != rc.c))) {
273 QString errorString = QString("Results not matched, expected(%1, %2, %3), computed(%4, %5, %6), algo = %7")
274 .arg(re.x)
275 .arg(re.y)
276 .arg(re.l)
277 .arg(rc.x)
278 .arg(rc.y)
279 .arg(rc.l)
280 .arg(getAlgName(sub->getSettings().algo));
281
282 if (re.c >= 0) {
283 errorString = QString("Results not matched, expected(%1, %2, %3, %4), computed(%5, %6, %7, %8), algo = %9")
284 .arg(re.x)
285 .arg(re.y)
286 .arg(re.l)
287 .arg(re.c)
288 .arg(rc.x)
289 .arg(rc.y)
290 .arg(rc.l)
291 .arg(rc.c)
292 .arg(getAlgName(sub->getSettings().algo));
293 }
294
295 stateInfo.setError(errorString);
296 return;
297 }
298 }
299 }
300
301 //---------------------------------------------------------------------------------------------------------
302 //---------------------------------------------------------------------------------------------------------
init(XMLTestFormat *,const QDomElement & el)303 void GTest_FindTandemRepeatsTask::init(XMLTestFormat *, const QDomElement &el) {
304 minD = el.attribute(MIND_ATTR, "-1").toInt();
305 maxD = el.attribute(MAXD_ATTR, "-1").toInt();
306
307 minSize = el.attribute("minSize", "3").toInt();
308 repeatCount = el.attribute("repeatCount", "3").toInt();
309
310 inverted = el.attribute("invert") == "true";
311 reflect = el.attribute("reflect", "true") == "true";
312 filterNested = el.attribute("filterNested", "false") == "true";
313 filterUnique = el.attribute("filterUnique", "false") == "true";
314
315 if (filterNested && filterUnique) {
316 stateInfo.setError(QString("Filter unique and filter nested cannot go together"));
317 return;
318 }
319
320 results = el.attribute(RESULT_ATTR);
321 sequence = el.attribute("sequence");
322 }
323
prepare()324 void GTest_FindTandemRepeatsTask::prepare() {
325 if (hasError() || isCanceled()) {
326 return;
327 }
328 // this->getContext(this,"")
329 // new DNAAlphabetRegistryImpl(
330 // TaskResourceUsage* tru = AppContext::getTaskScheduler()->getTaskResources(NULL).constData();
331 const DNAAlphabet *alph = AppContext::getDNAAlphabetRegistry()->findById(BaseDNAAlphabetIds::NUCL_DNA_DEFAULT());
332 seqObj = new DNASequence(QString("sequence"), sequence.toLatin1(), alph);
333 if (seqObj == nullptr) {
334 stateInfo.setError("can't find sequence1");
335 return;
336 }
337 string = (char *)(seqObj->constData());
338
339 int maxLen = sequence.length();
340 if (minD == -1) {
341 minD = -maxLen;
342 }
343 if (maxD == -1) {
344 maxD = maxLen;
345 }
346 if (maxSize == 0) {
347 maxSize = maxLen;
348 }
349
350 FindTandemsTaskSettings s;
351 s.minPeriod = minSize;
352 s.minRepeatCount = repeatCount;
353 s.seqRegion = region;
354 s.nThreads = 1; // todo: add to settings
355
356 addSubTask(new TandemFinder(s, *seqObj));
357 }
358
run()359 void GTest_FindTandemRepeatsTask::run() {
360 if (hasError() || isCanceled()) {
361 return;
362 }
363 QList<Tandem> expectedResults;
364 // load file with results
365 QStringList resList = results.split(';', QString::SkipEmptyParts);
366 foreach (const QString &result, resList) {
367 QStringList hit = result.split(',', QString::SkipEmptyParts);
368 if (hit.size() != 3) {
369 stateInfo.setError(QString("Can't parse results line: %1").arg(result));
370 return;
371 }
372 bool offsetConverted;
373 Tandem tnd(hit[0].toInt(&offsetConverted), hit[2].toInt(), hit[1].toInt());
374 if (!offsetConverted || tnd.size == 0 || tnd.repeatLen == 0) {
375 stateInfo.setError(QString("Can't parse results line: %1").arg(result));
376 return;
377 }
378 expectedResults.append(tnd);
379 }
380
381 // check all subtasks
382 TandemFinder *sub = qobject_cast<TandemFinder *>(this->getSubtasks()[0].data());
383 QList<Tandem> calcResults = sub->getResults();
384 if (expectedResults.size() != calcResults.size()) {
385 QString results("First results are:\n");
386 for (int i = 0, n = qMin(calcResults.size(), 3); i < n; i++) {
387 Tandem rc = calcResults[i];
388 results.append(QString("%1 %2 %3\n").arg(rc.offset).arg(rc.size).arg(rc.repeatLen));
389 }
390 stateInfo.setError(QString("Results count not matched, num = %1, expected = %2\n%3").arg(calcResults.size()).arg(expectedResults.size()).arg(results));
391 return;
392 }
393 std::sort(expectedResults.begin(), expectedResults.end());
394 std::sort(calcResults.begin(), calcResults.end());
395
396 for (int i = 0, n = expectedResults.size(); i < n; i++) {
397 Tandem re = expectedResults[i];
398 Tandem rc = calcResults[i];
399 if (re.offset != rc.offset || re.size != rc.size || re.repeatLen != rc.repeatLen) {
400 stateInfo.setError(QString("Results not matched, expected(%1, %2, %3), computed(%4, %5, %6)")
401 .arg(re.offset)
402 .arg(re.size)
403 .arg(re.repeatLen)
404 .arg(rc.offset)
405 .arg(rc.size)
406 .arg(rc.repeatLen));
407 return;
408 }
409 }
410
411 delete seqObj;
412 }
413
414 //---------------------------------------------------------------------------------------------------------
415 //---------------------------------------------------------------------------------------------------------
416
parseRegion(const QString & n,const QDomElement & el)417 U2Region GTest_FindRealTandemRepeatsTask::parseRegion(const QString &n, const QDomElement &el) {
418 U2Region res;
419 QString v = el.attribute(n);
420 if (v.isEmpty()) {
421 return res;
422 }
423 int idx = v.indexOf("..");
424 if (idx == -1 || idx + 2 >= v.length()) {
425 return res;
426 }
427 QString v1 = v.left(idx);
428 QString v2 = v.mid(idx + 2);
429 int startPos = v1.toInt();
430 int endPos = v2.toInt();
431 if (startPos >= 0 && endPos > startPos) {
432 res.startPos = startPos - 1;
433 res.length = endPos - startPos + 1;
434 }
435 return res;
436 }
437
init(XMLTestFormat *,const QDomElement & el)438 void GTest_FindRealTandemRepeatsTask::init(XMLTestFormat *, const QDomElement &el) {
439 minD = el.attribute(MIND_ATTR, "-1").toInt();
440 maxD = el.attribute(MAXD_ATTR, "-1").toInt();
441
442 minSize = el.attribute("minSize", "1").toInt();
443 repeatCount = el.attribute("repeatCount", "3").toInt();
444
445 inverted = el.attribute("invert") == "true";
446 reflect = el.attribute("reflect", "true") == "true";
447 filterNested = el.attribute("filterNested", "false") == "true";
448 filterUnique = el.attribute("filterUnique", "false") == "true";
449
450 if (filterNested && filterUnique) {
451 stateInfo.setError(QString("Filter unique and filter nested cannot go together"));
452 return;
453 }
454
455 results = el.attribute(RESULT_ATTR);
456 if (results.isEmpty()) {
457 stateInfo.setError(QString("Value not found '%1'").arg(RESULT_ATTR));
458 return;
459 }
460
461 sequence = el.attribute("sequence");
462 if (sequence.isEmpty()) {
463 stateInfo.setError(QString("Value not found '%1'").arg("sequence"));
464 return;
465 }
466 }
467
prepare()468 void GTest_FindRealTandemRepeatsTask::prepare() {
469 CHECK_OP(stateInfo, );
470 U2SequenceObject *seqObj = getContext<U2SequenceObject>(this, sequence);
471 if (seqObj == nullptr) {
472 stateInfo.setError("can't find sequence1");
473 return;
474 }
475 if (region.isEmpty()) {
476 region = U2Region(0, seqObj->getSequenceLength());
477 }
478
479 int maxLen = seqObj->getSequenceLength();
480 if (minD == -1) {
481 minD = -maxLen;
482 }
483 if (maxD == -1) {
484 maxD = maxLen;
485 }
486
487 FindTandemsTaskSettings s;
488 s.minPeriod = minSize;
489 s.minRepeatCount = repeatCount;
490 s.seqRegion = region;
491 s.nThreads = 1; // todo: add to settings
492
493 U2OpStatusImpl os;
494 DNASequence dna = seqObj->getWholeSequence(os);
495 CHECK_OP_EXT(os, setError(os.getError()), );
496 addSubTask(new TandemFinder(s, dna));
497 }
498
run()499 void GTest_FindRealTandemRepeatsTask::run() {
500 if (hasError() || isCanceled()) {
501 return;
502 }
503 QList<Tandem> expectedResults;
504 // load file with results
505 QString fname = env->getVar("COMMON_DATA_DIR") + "/" + results;
506 QFile file(fname);
507 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
508 stateInfo.setError(QString("Can't open results file %1").arg(fname));
509 return;
510 }
511
512 while (!file.atEnd()) {
513 QString line = file.readLine();
514 QStringList hit = line.split(' ', QString::SkipEmptyParts);
515 if (hit.size() != 5) {
516 stateInfo.setError(QString("Can't parse results line: %1").arg(line));
517 return;
518 }
519 bool h1ok, h2ok, h3ok;
520 Tandem t(hit[0].toInt(&h1ok) - 1, hit[3].toInt(&h2ok), hit[2].toInt(&h3ok));
521 if (!h1ok || !h2ok || !h3ok) {
522 stateInfo.setError(QString("Can't parse results line: %1").arg(line));
523 return;
524 }
525 expectedResults.append(t);
526 }
527 file.close();
528
529 std::sort(expectedResults.begin(), expectedResults.end());
530
531 // check all subtasks
532 TandemFinder *sub = qobject_cast<TandemFinder *>(this->getSubtasks()[0].data());
533 QList<Tandem> calcResults = sub->getResults();
534 QMutableListIterator<Tandem> cIt(calcResults);
535 QMutableListIterator<Tandem> eIt(expectedResults);
536 while (cIt.hasNext() && eIt.hasNext()) {
537 Tandem er = eIt.peekNext();
538 Tandem cr = cIt.peekNext();
539 if (er < cr) {
540 eIt.next();
541 // eIt.remove();
542 } else if (cr < er) {
543 cIt.next();
544 cIt.remove();
545 } else {
546 eIt.next();
547 eIt.remove();
548 cIt.next();
549 cIt.remove();
550 }
551 }
552 if (!expectedResults.isEmpty()) {
553 QString result("First of them:\n");
554 Tandem rc = expectedResults[0];
555 result.append(QString("%1 %2 %3\n").arg(rc.offset).arg(rc.size).arg(rc.repeatLen));
556 stateInfo.setError(QString("Not all expected tandems found: total %1\n%2").arg(expectedResults.size()).arg(result));
557 }
558 }
559
560 //---------------------------------------------------------------------------------------------------------
561 //---------------------------------------------------------------------------------------------------------
562
init(XMLTestFormat *,const QDomElement & el)563 void GTest_SArrayBasedFindTask::init(XMLTestFormat *, const QDomElement &el) {
564 QString buf = el.attribute(RESULT_ATTR);
565 if (buf.isEmpty()) {
566 stateInfo.setError(QString("Value not found: '%1'").arg(RESULT_ATTR));
567 return;
568 }
569
570 QStringList results = buf.split(",");
571 foreach (const QString &str, results) {
572 bool ok = false;
573 int pos = str.toInt(&ok);
574 if (!ok) {
575 stateInfo.setError("Can't parse expected results");
576 return;
577 } else {
578 expectedResults.append(pos);
579 }
580 }
581
582 seqObjName = el.attribute(SEQUENCE);
583 if (seqObjName.isEmpty()) {
584 stateInfo.setError(QString("Value not found: '%1'").arg(SEQUENCE));
585 return;
586 }
587
588 buf = el.attribute(MISMATCHES);
589 bool ok = false;
590 nMismatches = buf.toInt(&ok);
591 if (!ok) {
592 nMismatches = 0;
593 }
594
595 useBitMask = el.attribute(USE_BITMASK) == "true";
596
597 query = el.attribute(QUERY);
598 if (query.isEmpty()) {
599 stateInfo.setError(QString("Value not found: '%1'").arg(QUERY));
600 return;
601 }
602 }
603
cleanup()604 void GTest_SArrayBasedFindTask::cleanup() {
605 wholeSeq = QByteArray();
606
607 XmlTest::cleanup();
608 }
609
prepare()610 void GTest_SArrayBasedFindTask::prepare() {
611 CHECK_OP(stateInfo, );
612
613 U2SequenceObject *seqObj = getContext<U2SequenceObject>(this, seqObjName);
614 if (seqObj == nullptr) {
615 stateInfo.setError(QString("Can't find index sequence %1").arg(seqObjName));
616 return;
617 }
618 DNAAlphabetType seqType = seqObj->getAlphabet()->getType();
619 char unknownChar = seqType == DNAAlphabet_AMINO ? 'X' : seqType == DNAAlphabet_NUCL ? 'N'
620 : '\0';
621
622 const quint32 *bitMask = nullptr;
623 int bitCharLen = 0;
624
625 if (useBitMask) {
626 bitCharLen = bt.getBitMaskCharBitsNum(seqType);
627 bitMask = bt.getBitMaskCharBits(seqType);
628 }
629
630 int prefixSize = query.size();
631 if (nMismatches > 0) {
632 prefixSize = prefixSize / (nMismatches + 1);
633 }
634
635 wholeSeq = seqObj->getWholeSequenceData(stateInfo);
636 CHECK_OP(stateInfo, );
637 index = new SArrayIndex(wholeSeq.constData(), seqObj->getSequenceLength(), prefixSize, stateInfo, unknownChar, bitMask, bitCharLen);
638
639 if (hasError()) {
640 return;
641 }
642
643 SArrayBasedSearchSettings s;
644 s.query = query.toLatin1();
645 s.useBitMask = useBitMask;
646 s.bitMask = bitMask;
647 s.nMismatches = nMismatches;
648 s.bitMaskCharBitsNum = bitCharLen;
649 s.unknownChar = unknownChar;
650 findTask = new SArrayBasedFindTask(index, s);
651 addSubTask(findTask);
652 }
653
run()654 void GTest_SArrayBasedFindTask::run() {
655 if (hasError() || isCanceled()) {
656 return;
657 }
658
659 std::sort(expectedResults.begin(), expectedResults.end());
660
661 QList<int> calcResults = findTask->getResults();
662 if (expectedResults.size() != calcResults.size()) {
663 stateInfo.setError(QString("Results count do not match, num = %1, expected = %2")
664 .arg(calcResults.size())
665 .arg(expectedResults.size()));
666 return;
667 }
668
669 std::sort(calcResults.begin(), calcResults.end());
670 for (int i = 0, n = expectedResults.size(); i < n; i++) {
671 int re = expectedResults[i];
672 int rc = calcResults[i];
673 if (re != rc) {
674 stateInfo.setError(QString("Results not matched, expected %1, computed %2")
675 .arg(re)
676 .arg(rc));
677 return;
678 }
679 }
680 }
681
682 //---------------------------------------------------------------------------------------------------------
683 //---------------------------------------------------------------------------------------------------------
684
createTestFactories()685 QList<XMLTestFactory *> RepeatFinderTests::createTestFactories() {
686 QList<XMLTestFactory *> res;
687 res.append(GTest_FindSingleSequenceRepeatsTask::createFactory());
688 res.append(GTest_FindTandemRepeatsTask::createFactory());
689 res.append(GTest_FindRealTandemRepeatsTask::createFactory());
690 res.append(GTest_SArrayBasedFindTask::createFactory());
691 return res;
692 }
693
694 } // namespace U2
695