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