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 "PhyMLTests.h"
23
24 #include <QDir>
25
26 #include <U2Algorithm/CreatePhyTreeSettings.h>
27 #include <U2Algorithm/PhyTreeGeneratorRegistry.h>
28
29 #include <U2Core/AppContext.h>
30 #include <U2Core/BaseDocumentFormats.h>
31 #include <U2Core/DNASequenceObject.h>
32 #include <U2Core/DocumentModel.h>
33 #include <U2Core/GObjectTypes.h>
34 #include <U2Core/IOAdapter.h>
35 #include <U2Core/Log.h>
36 #include <U2Core/MultipleSequenceAlignmentObject.h>
37 #include <U2Core/PhyTreeObject.h>
38 #include <U2Core/SaveDocumentTask.h>
39
40 #include "PhyMLSupport.h"
41 namespace U2 {
createTestFactories()42 QList<XMLTestFactory *> PhyMLToolTests::createTestFactories() {
43 QList<XMLTestFactory *> res;
44 res.append(GTest_PhyML::createFactory());
45 return res;
46 }
47
init(XMLTestFormat *,const QDomElement & el)48 void GTest_PhyML::init(XMLTestFormat *, const QDomElement &el) {
49 treeObjFromDoc = nullptr;
50 task = nullptr;
51 input = nullptr;
52 maDoc = nullptr;
53 treeDoc = nullptr;
54
55 inputDocCtxName = el.attribute("in");
56 if (inputDocCtxName.isEmpty()) {
57 failMissingValue("in");
58 return;
59 }
60 resultCtxName = el.attribute("sample");
61 negative = el.attribute("negative");
62
63 QString dataType = el.attribute("datatype");
64 if (!dataType.isEmpty()) {
65 settings.extToolArguments << "-d";
66 settings.extToolArguments << dataType;
67 }
68
69 QString bootstrapString = el.attribute("bootstrap");
70 if (!bootstrapString.isEmpty()) {
71 settings.extToolArguments << "-b";
72 settings.extToolArguments << bootstrapString;
73 }
74
75 QString subtitutionalModel = el.attribute("model");
76 if (!subtitutionalModel.isEmpty()) {
77 settings.extToolArguments << "-m";
78 settings.extToolArguments << subtitutionalModel;
79 }
80
81 QString ttRatioString = el.attribute("tt_ratio");
82 if (!ttRatioString.isEmpty()) {
83 settings.extToolArguments << "-t";
84 settings.extToolArguments << ttRatioString;
85 }
86
87 QString subRatesString = el.attribute("substitution_rates");
88 if (!subRatesString.isEmpty()) {
89 settings.extToolArguments << "-t";
90 settings.extToolArguments << subRatesString;
91 }
92
93 QString invSitesString = el.attribute("inv_sites");
94 if (!invSitesString.isEmpty()) {
95 settings.extToolArguments << "-v";
96 settings.extToolArguments << invSitesString;
97 }
98
99 QString gammaFactorString = el.attribute("gamma");
100 if (!gammaFactorString.isEmpty()) {
101 settings.extToolArguments << "-a";
102 settings.extToolArguments << gammaFactorString;
103 }
104 }
105
prepare()106 void GTest_PhyML::prepare() {
107 maDoc = getContext<Document>(this, inputDocCtxName);
108 if (maDoc == nullptr) {
109 stateInfo.setError(QString("context not found %1").arg(inputDocCtxName));
110 return;
111 }
112
113 QList<GObject *> list = maDoc->findGObjectByType(GObjectTypes::MULTIPLE_SEQUENCE_ALIGNMENT);
114 if (list.size() == 0) {
115 stateInfo.setError(QString("container of object with type \"%1\" is empty").arg(GObjectTypes::MULTIPLE_SEQUENCE_ALIGNMENT));
116 return;
117 }
118
119 GObject *obj = list.first();
120 if (obj == nullptr) {
121 stateInfo.setError(QString("object with type \"%1\" not found").arg(GObjectTypes::MULTIPLE_SEQUENCE_ALIGNMENT));
122 return;
123 }
124 assert(obj != nullptr);
125 MultipleSequenceAlignmentObject *ma = qobject_cast<MultipleSequenceAlignmentObject *>(obj);
126 if (ma == nullptr) {
127 stateInfo.setError(QString("error can't cast to multiple alignment from GObject"));
128 return;
129 }
130
131 input = ma;
132
133 treeDoc = getContext<Document>(this, resultCtxName);
134 if (treeDoc == nullptr) {
135 stateInfo.setError(QString("context not found %1").arg(resultCtxName));
136 return;
137 }
138
139 QList<GObject *> list2 = treeDoc->findGObjectByType(GObjectTypes::PHYLOGENETIC_TREE);
140 if (list2.size() == 0) {
141 stateInfo.setError(QString("container of object with type \"%1\" is empty").arg(GObjectTypes::MULTIPLE_SEQUENCE_ALIGNMENT));
142 return;
143 }
144
145 GObject *obj2 = list2.first();
146 if (obj2 == nullptr) {
147 stateInfo.setError(QString("object with type \"%1\" not found").arg(GObjectTypes::PHYLOGENETIC_TREE));
148 return;
149 }
150
151 treeObjFromDoc = qobject_cast<PhyTreeObject *>(obj2);
152
153 if (treeObjFromDoc == nullptr) {
154 stateInfo.setError(QString("error can't cast to phylogenetic tree from GObject"));
155 return;
156 }
157 assert(obj != nullptr);
158
159 settings.algorithm = PhyMLSupport::ET_PHYML_ALGORITHM_NAME_AND_KEY;
160
161 task = new PhyTreeGeneratorLauncherTask(input->getMultipleAlignment(), settings);
162 addSubTask(task);
163 }
164
report()165 Task::ReportResult GTest_PhyML::report() {
166 if (task == nullptr) {
167 if (!stateInfo.hasError()) {
168 stateInfo.setError("PhyTreeGeneratorLauncherTask is not created");
169 }
170 return ReportResult_Finished;
171 }
172 if (!task->hasError()) {
173 const PhyTree computedTree = task->getResult();
174 const PhyTree &treeFromDoc = treeObjFromDoc->getTree();
175 bool same = PhyTreeObject::treesAreAlike(computedTree, treeFromDoc);
176 if (!same) {
177 if (negative.isEmpty()) {
178 stateInfo.setError("Trees are not equal");
179 } else {
180 if (negative != "Trees are not equal") {
181 stateInfo.setError(QString("Negative test failed: error string is empty, expected error \"%1\", but current error is \"Trees are not equal\"").arg(negative));
182 }
183 }
184 }
185 } else if (!negative.isEmpty()) {
186 if (negative != task->getError()) {
187 stateInfo.setError(QString("Negative test failed: error string is empty, expected error \"%1\", but current error is \"%2\"").arg(negative).arg(task->getError()));
188 } else {
189 stateInfo.setError("");
190 }
191 }
192
193 return ReportResult_Finished;
194 }
195
196 } // namespace U2
197