GCC Code Coverage Report


source/XpertMassCore/src/
File: source/XpertMassCore/src/CleavageAgent.cpp
Date: 2025-11-19 15:26:11
Lines:
280/384
72.9%
Functions:
30/31
96.8%
Branches:
263/686
38.3%

Line Branch Exec Source
1 /* BEGIN software license
2 *
3 * MsXpertSuite - mass spectrometry software suite
4 * -----------------------------------------------
5 * Copyright(C) 2009, ..., 2018 Filippo Rusconi
6 *
7 * http://www.msxpertsuite.org
8 *
9 * This file is part of the MsXpertSuite project.
10 *
11 * The MsXpertSuite project is the successor of the massXpert project. This
12 * project now includes various independent modules:
13 *
14 * - massXpert, model polymer chemistries and simulate mass spectrometric data;
15 * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner;
16 *
17 * This program is free software: you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation, either version 3 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29 *
30 * END software license
31 */
32
33
34 /////////////////////// Stdlib includes
35 #include <map>
36
37
38 /////////////////////// Local includes
39 #include "MsXpS/libXpertMassCore/CleavageAgent.hpp"
40
41 namespace MsXpS
42 {
43 namespace libXpertMassCore
44 {
45
46
47 /*!
48 \class MsXpS::libXpertMassCore::CleavageAgent
49 \inmodule libXpertMassCore
50 \ingroup PolChemDefAqueousChemicalReactions
51 \inheaderfile CleavageAgent.hpp
52
53 \brief The CleavageAgent class provides a model for specifying aqueous cleavage
54 specifications (patterns) of \l{Polymer} \l{Sequence}s.
55
56 Cleavage specifications determine the specificity of cleavage in a
57 polymer sequence using a simple syntax. For example, Trypsin is able
58 to cleave after lysyl and arginyl residues. Its cleavage pattern is
59 thus "Lys/;Arg/". However, it is known that Trypsin fails to cleave
60 after Lys if that monomer is followed by a Prolyl residue, thus the
61 complete cleavage agent specification for Trypsin comprises three cleavage
62 patterns: "Lys/;Arg/;-Lys/Pro".
63
64 A cleavage agent specification might not be enough information to
65 determine the manner in which a polymer is cleaved. Cleavage rules
66 might be required to refine the specification. A cleavage
67 agent specification might hold as many cleavage rules as required.
68
69 \sa CleavageMotif, CleavageRule
70 */
71
72
73 /*!
74 \variable MsXpS::libXpertMassCore::CleavageAgent::mcsp_polChemDef
75
76 \brief The \l PolChemDef polymer chemistry definition.
77 */
78
79 /*!
80 \variable MsXpS::libXpertMassCore::CleavageAgent::m_name
81
82 \brief The name of the CleavageAgent.
83 */
84
85 /*!
86 \variable MsXpS::libXpertMassCore::CleavageAgent::m_pattern
87
88 \brief The cleavage pattern, that might comprise more than one \l CleavageMotif.
89
90 \sa CleavageMotif, CleavageRule
91 */
92
93 /*!
94 \variable MsXpS::libXpertMassCore::CleavageAgent::m_motifs
95
96 \brief The container of \l{CleavageMotif}s that together make the CleavageAgent.
97
98 \sa CleavageMotif
99 */
100
101 /*!
102 \variable MsXpS::libXpertMassCore::CleavageAgent::m_rules
103
104 \brief The container of \l{CleavageRule}s that might be requied to refine the
105 CleavageAgent.
106
107 \sa CleavageRule
108 */
109
110
111 /*!
112 \variable MsXpS::libXpertMassCore::CleavageAgent::m_isValid
113
114 \brief The validity status of the instance.
115 */
116
117
118 /*!
119 \typedef MsXpS::libXpertMassCore::CleavageAgentSPtr
120 \relates MsXpS::libXpertMassCore::CleavageAgent.
121
122 Synonym for std::shared_ptr<CleavageAgent>.
123 */
124
125 /*!
126 \typedef MsXpS::libXpertMassCore::CleavageAgentCstSPtr
127 \relates MsXpS::libXpertMassCore::CleavageAgent.
128
129 Synonym for std::shared_ptr<const CleavageAgent>.
130 */
131
132
133 /*!
134 \brief Constructs a totally empty CleavageAgent instance
135 */
136
2/4
✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 63 times.
✗ Branch 6 not taken.
63 CleavageAgent::CleavageAgent(QObject *parent): QObject(parent)
137 {
138
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
63 }
139
140 /*!
141 \brief Constructs a CleavageAgent instance starting from an XML \a element
142 according to \a version and a \a pol_chem_def_csp PolChemDef.
143
144 The \a version indicates what version of the XML element is to be used.
145
146 Before version 2, the CleavageAgent class was named CleaveSpec and thus the
147 XML element was called <cls>:
148
149 This is the current format (FAKE cls):
150 \code
151 <cls>
152 <name>CyanogenBromide</name>
153 <pattern>M/A</pattern>
154 <clr>
155 <le-mnm-code>M</le-mnm-code>
156 <le-formula>-C1H2S1+O1</le-formula>
157 <re-mnm-code>A</re-mnm-code>
158 <re-formula>-CH3COOH</re-formula>
159 </clr>
160 </cls>
161
162 \endcode
163
164
165 After version 2, the CleaveSpec class has been named CleavageAgent and thus the
166 XML element is now called <cla>.The inner structure of the element has not
167 changed.
168
169 Depending on the \a version argument, one function (older) or the other
170 (current) is used to parse the XML element.
171
172 The rendering of the CleavageRule instances requires that the PolChemDef be
173 available.
174
175 \sa renderXmlClsElement(), renderXmlClaElement()
176 */
177 1632 CleavageAgent::CleavageAgent(PolChemDefCstSPtr pol_chem_def_csp,
178 const QDomElement &element,
179 int version,
180 1632 QObject *parent)
181
3/6
✓ Branch 3 taken 1632 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1632 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1632 times.
1632 : QObject(parent), mcsp_polChemDef(pol_chem_def_csp)
182 {
183
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1632 times.
1632 if(mcsp_polChemDef == nullptr || mcsp_polChemDef.get() == nullptr)
184 qCritical() << "Constructing CleavageAgent with no PolChemDef.";
185
186
2/2
✓ Branch 0 taken 1608 times.
✓ Branch 1 taken 24 times.
1632 if(version == 1)
187 {
188 1608 qDebug() << "Rendering XmlClsElement version" << version;
189
190
2/4
✓ Branch 1 taken 1608 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1608 times.
1608 if(!renderXmlClsElement(element, version))
191 qCritical()
192 << "Failed to fully render or validate the CleavageAgent XML element "
193 "for construction of CleavageAgent instance.";
194 }
195
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 else if(version == 2)
196 {
197 24 qDebug() << "Rendering XmlClaElement version" << version;
198
199
2/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
24 if(!renderXmlClaElement(element, version))
200 qCritical()
201 << "Failed to fully render or validate the CleavageAgent XML element "
202 "for construction of CleavageAgent instance.";
203 }
204 else
205 qFatalStream()
206 << "Programming error. The polymer chemistry definition version "
207 "is not correct.";
208
0/2
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1632 }
209
210 /*!
211 \brief Constructs a CleavageAgent instance.
212
213 \list
214 \li \a pol_chem_def_csp: The polymer chemistry definition.
215 \li \a name: The name of the CleavageAgent.
216 \li \a pattern: The pattern of the CleavageAgent, like ("Lys/;Arg/;-Lys/Pro").
217 \endlist
218
219 Upon setting all the member data, the \a pattern is parsed. After this, this
220 instance is validated and the member m_isValid is set to the result.
221 */
222 132 CleavageAgent::CleavageAgent(PolChemDefCstSPtr pol_chem_def_csp,
223 const QString &name,
224 const QString &pattern,
225 132 QObject *parent)
226 : QObject(parent),
227 264 mcsp_polChemDef(pol_chem_def_csp),
228
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 18 times.
132 m_name(name),
229
3/4
✓ Branch 2 taken 120 times.
✓ Branch 3 taken 12 times.
✓ Branch 5 taken 132 times.
✗ Branch 6 not taken.
384 m_pattern(pattern)
230 {
231
3/4
✓ Branch 1 taken 132 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 33 times.
✓ Branch 4 taken 99 times.
132 if(!parse())
232
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
66 qCritical()
233 << "Upon construction of the CleavageAgent, the pattern could not "
234
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 "be parsed.";
235
236 132 ErrorList error_list;
237
1/2
✓ Branch 1 taken 132 times.
✗ Branch 2 not taken.
132 m_isValid = validate(&error_list);
238
239
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 114 times.
132 if(!m_isValid)
240
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
36 qCritical()
241 << "Upon construction of the CleavageAgent, the instance failed to "
242
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 "validate with errors:"
243
3/6
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 18 times.
✗ Branch 8 not taken.
36 << Utils::joinErrorList(error_list, ", ");
244
0/2
✗ Branch 4 not taken.
✗ Branch 5 not taken.
132 }
245
246 /*!
247 \brief Constructs a CleavageAgent instance as a copy of \a other.
248
249 The copying of the member containers of CleavageMotif and CleavageRule instances
250 is shallow (only the shared pointers are copied).
251
252 Upon setting all the member data, this instance is validated and the member
253 m_isValid is set to the result.
254 */
255 93 CleavageAgent::CleavageAgent(const CleavageAgent &other, QObject *parent)
256 : QObject(parent),
257 186 mcsp_polChemDef(other.mcsp_polChemDef),
258
1/2
✓ Branch 0 taken 93 times.
✗ Branch 1 not taken.
93 m_name(other.m_name),
259
1/2
✓ Branch 0 taken 93 times.
✗ Branch 1 not taken.
93 m_pattern(other.m_pattern),
260
1/2
✓ Branch 1 taken 93 times.
✗ Branch 2 not taken.
93 m_motifs(other.m_motifs),
261
1/2
✓ Branch 3 taken 93 times.
✗ Branch 4 not taken.
186 m_rules(other.m_rules)
262 {
263 93 ErrorList error_list;
264
1/2
✓ Branch 1 taken 93 times.
✗ Branch 2 not taken.
93 m_isValid = validate(&error_list);
265
266
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 93 times.
93 if(!m_isValid)
267 qCritical()
268 << "Upon copy-construction of the CleavageAgent, the instance failed to "
269 "validate with errors:"
270 << Utils::joinErrorList(error_list, ", ");
271
0/2
✗ Branch 4 not taken.
✗ Branch 5 not taken.
93 }
272
273 /*!
274 \brief Destructs this CleavageAgent instance.
275 */
276 576 CleavageAgent::~CleavageAgent()
277 {
278
1/2
✓ Branch 4 taken 288 times.
✗ Branch 5 not taken.
1152 }
279
280 /*!
281 \brief Initialized this CleavageAgent using \a other.
282
283 After initialization, validity is checked, the result is set to m_isValid and is
284 returned.
285 */
286 bool
287 63 CleavageAgent::initialize(const CleavageAgent &other)
288 {
289 63 mcsp_polChemDef = other.mcsp_polChemDef;
290 63 m_name = other.m_name;
291 63 m_pattern = other.m_pattern;
292 63 m_motifs.assign(other.m_motifs.begin(), other.m_motifs.end());
293 63 m_rules.assign(other.m_rules.begin(), other.m_rules.end());
294
295 63 ErrorList error_list;
296
1/2
✓ Branch 1 taken 63 times.
✗ Branch 2 not taken.
63 m_isValid = validate(&error_list);
297
298
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63 times.
63 if(!m_isValid)
299 qCritical() << "Failed to initalize the CleavageAgent instance.";
300
301 63 return m_isValid;
302 63 }
303
304 //////////////// THE POLCHEMDEF /////////////////////
305 /*!
306 \brief Sets the PolChemDef to \a pol_chem_def_csp.
307
308 Upon setting the member data, this instance is validated and the member
309 m_isValid is set to the result.
310 */
311 void
312 9 CleavageAgent::setPolchemDefCstSPtr(PolChemDefCstSPtr pol_chem_def_csp)
313 {
314 9 mcsp_polChemDef = pol_chem_def_csp;
315
316 9 ErrorList error_list;
317
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 m_isValid = validate(&error_list);
318
319
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if(!m_isValid)
320
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
18 qCritical()
321 << "Upon setting PolChemDef of CleavageAgent, the instance failed to "
322
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 "validate with errors:"
323
3/6
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 9 times.
✗ Branch 8 not taken.
18 << Utils::joinErrorList(error_list, ", ");
324 9 }
325
326 /*!
327 \brief Returns the PolChemDef.
328 */
329 PolChemDefCstSPtr
330 3 CleavageAgent::getPolchemDefCstSPtr() const
331 {
332 3 return mcsp_polChemDef;
333 }
334
335 //////////////// THE NAME /////////////////////
336 /*!
337 \brief Sets the name to \a name.
338
339 Upon setting the member data, this instance is validated and the member
340 m_isValid is set to the result.
341 */
342 void
343 12 CleavageAgent::setName(const QString &name)
344 {
345 12 m_name = name;
346
347 12 ErrorList error_list;
348
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 m_isValid = validate(&error_list);
349
350
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if(!m_isValid)
351
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
12 qCritical() << "Upon setting name of CleavageAgent, the instance failed to "
352
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 "validate with errors:"
353
3/6
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 6 times.
✗ Branch 8 not taken.
12 << Utils::joinErrorList(error_list, ", ");
354 12 }
355
356 /*!
357 \brief Returns the name.
358 */
359 const QString &
360 1446 CleavageAgent::getName() const
361 {
362 1446 return m_name;
363 }
364
365 //////////////// THE PATTERN /////////////////////
366 /*!
367 \brief Sets the \a pattern.
368
369 Upon setting the member data, this instance is validated and the member
370 m_isValid is set to the result.
371 */
372 void
373 3 CleavageAgent::setPattern(const QString &pattern)
374 {
375 3 m_pattern = pattern;
376
377
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if(!parse())
378 qCritical() << "The pattern that was set could not be parsed.";
379
380 3 ErrorList error_list;
381
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 m_isValid = validate(&error_list);
382
383
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if(!m_isValid)
384 qCritical()
385 << "Upon setting pattern of CleavageAgent, the instance failed to "
386 "validate with errors:"
387 << Utils::joinErrorList(error_list, ", ");
388 3 }
389
390 /*!
391 \brief Returns the pattern.
392 */
393 const QString &
394 21 CleavageAgent::getPattern() const
395 {
396 21 return m_pattern;
397 }
398
399 /*!
400 \brief Returns a const reference to the container of CleavageMotif instances.
401 */
402 const std::vector<CleavageMotifSPtr> &
403 240 CleavageAgent::getMotifsCstRef() const
404 {
405 240 return m_motifs;
406 }
407
408 /*!
409 \brief Returns a reference to the container of CleavageMotif instances.
410 */
411 std::vector<CleavageMotifSPtr> &
412 15 CleavageAgent::getMotifsRef()
413 {
414 15 return m_motifs;
415 }
416
417 /*!
418 \brief Returns a const reference to the container of CleavageRule instances.
419 */
420 const std::vector<CleavageRuleSPtr> &
421 1239 CleavageAgent::getRulesCstRef() const
422 {
423 1239 return m_rules;
424 }
425
426 /*!
427 \brief Returns a reference to the container of CleavageRule instances.
428 */
429 std::vector<CleavageRuleSPtr> &
430 60 CleavageAgent::getRulesRef()
431 {
432 60 return m_rules;
433 }
434
435 /*!
436 \brief Returns the CleavageRule that has name \a name, or nullptr if not found.
437 */
438 CleavageRuleSPtr
439 9 CleavageAgent::getCleavageRuleSPtrByName(const QString &name) const
440 {
441
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 std::vector<CleavageRuleSPtr>::const_iterator the_iterator_cst =
442 18 std::find_if(m_rules.cbegin(),
443 m_rules.cend(),
444
6/12
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 9 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 9 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 9 times.
✗ Branch 13 not taken.
✓ Branch 20 taken 9 times.
✗ Branch 21 not taken.
81 [name](const CleavageRuleSPtr &cleavage_rule_sp) {
445
1/14
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 19 taken 9 times.
✗ Branch 20 not taken.
9 return cleavage_rule_sp->getName() == name;
446 });
447
448
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if(the_iterator_cst == m_rules.cend())
449 return nullptr;
450
451 9 return *the_iterator_cst;
452 }
453
454 //////////////// PARSING /////////////////////
455 /*!
456 \brief Parses this CleavageAgent instance.
457
458 The parsing involves separating the components found in the m_pattern string
459 and making CleavageMotif instances out of them.
460
461 Starting from a pattern "Lys/;Arg/;-Lys/Pro", the parsing would
462 first split it into three cleavage site strings:
463
464 \list
465 \li "Lys/";
466 \li "Arg/";
467 \li "-Lys/Pro"
468 \endlist
469
470 Each of these site strings will be deconstructed into motifs, stored
471 in CleavageMotif objects:
472
473 \list
474 \li First motif has a code container "[0] Lys", an offset of 1 and is for
475 cleavage;
476 \li Second motif has a code container "[0] Arg", an offset of 1 and is for
477 cleavage;
478 \li Third motif has a code container "[0] Lys, [1] Pro", an offset of 1
479 and is not for cleavage (mind the '-')
480 \endlist
481
482 If the pattern string is empty, m_isValid is set to false and false is
483 returned.
484
485 Returns true if parsing is successful, false otherwise.
486 */
487 bool
488 1779 CleavageAgent::parse()
489 {
490
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 1767 times.
1779 if(m_pattern.isEmpty())
491 {
492 12 m_isValid = false;
493 12 return false;
494 }
495
496 // The 'm_pattern' is a ';'-delimited string, in which each
497 // sub-string is a 'site'. Each site is in turn constituted by a
498 // motif and a '/' that indicates where the motif is actually
499 // cleaved.
500 //
501 // For example the "-Lys/Pro" site is actually a motif of sequence
502 // "LysPro" and the site holds two more informations with respect to
503 // the mere motif: it says that the motif should not be cleaved
504 //('-') and that if the '-' were not there, the cleavage would
505 // occur between the Lys and the Pro('/' symbolizes the cleavage).
506
507 // For example, if the cleavageagent had a "Lys/;Arg/;-Lys/Pro" string,
508 // it would be split into 3 strings: "Lys/" and "Arg/" and
509 // "-Lys/Pro"(these are 'site' strings). These three site string
510 // would further be deconstructed into motif string(removal of '-'
511 // and '/' characters). Where would these 3 motif strings be stored?
512 // They would be set into one cleavagemotif instance for each
513 // motif. Thus, for example, "-Lys/Pro" would yield a cleavagemotif of
514 // 'motif' LysPro, with a FALSE cleave member and a 1 offset member.
515
516 // Will return the number of cleavagemotif instances that were created.
517 // Upon error -1 is returned.
518
519
520 // "Lys/;Arg/;-Lys/Pro" --> [0] Lys/, [1] Arg/, [2] -Lys/Pro
521
1/2
✓ Branch 2 taken 1767 times.
✗ Branch 3 not taken.
1767 QStringList sites = m_pattern.split(";", Qt::SkipEmptyParts);
522
523 // for (int iter = 0; iter < sites.size() ; ++iter)
524 // qDebug() << __FILE__ << __LINE__
525 // << sites.at(iter);
526
527 1767 Enums::CleavageAction cleavage_action;
528
529
2/2
✓ Branch 0 taken 3399 times.
✓ Branch 1 taken 1746 times.
5145 for(int iter = 0; iter < sites.size(); ++iter)
530 {
531 3399 cleavage_action = Enums::CleavageAction::CLEAVE;
532
533
1/2
✓ Branch 0 taken 3399 times.
✗ Branch 1 not taken.
3399 QString iter_cleavage_site = sites.at(iter);
534
535
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3399 times.
3399 if(iter_cleavage_site.length() < 2)
536 {
537 qCritical() << iter_cleavage_site << "is an invalid cleavage site.";
538
539 m_isValid = false;
540 return false;
541 }
542
543
1/2
✓ Branch 1 taken 3399 times.
✗ Branch 2 not taken.
3399 int count = iter_cleavage_site.count(QChar('/'));
544
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 3378 times.
3399 if(count != 1)
545 {
546
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
42 qCritical()
547
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
21 << "The must be one and only one '/' in the cleavage site.";
548
549 21 m_isValid = false;
550 21 return false;
551 }
552
553 // Remove spaces.
554
3/6
✓ Branch 1 taken 3378 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3378 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3378 times.
✗ Branch 8 not taken.
3378 iter_cleavage_site.remove(QRegularExpression("\\s+"));
555
556 // Is there a '-' in the site string indicating that this site
557 // is NOT for cleavage? If so, there should be only one such
558 // sign and in position 0.
559
560
1/2
✓ Branch 1 taken 3378 times.
✗ Branch 2 not taken.
3378 count = iter_cleavage_site.count(QChar('-'));
561
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3378 times.
3378 if(count > 1)
562 {
563 qCritical() << "There must be at most one '-' in the cleavage site.";
564
565 m_isValid = false;
566 return false;
567 }
568
2/2
✓ Branch 0 taken 510 times.
✓ Branch 1 taken 2868 times.
3378 else if(count == 1)
569 {
570
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 510 times.
510 if(iter_cleavage_site.indexOf(QChar('-'), 0, Qt::CaseInsensitive) !=
571 0)
572 {
573 qCritical() << "The '-' in the cleavage site must be at the "
574 "beginning of the cleavage site.";
575
576 m_isValid = false;
577 return false;
578 }
579
580 510 cleavage_action = Enums::CleavageAction::NO_CLEAVE;
581
582 // We can remove the '-' character, as we now know
583 // that the site is NOT for cleavage.
584
1/2
✓ Branch 1 taken 510 times.
✗ Branch 2 not taken.
510 iter_cleavage_site.remove(0, 1);
585 }
586 // else: site is for cleavage: no '-' found.
587
588 // We can create a new cleavage motif.
589 3378 CleavageMotifSPtr cleavage_motif_sp =
590
1/2
✓ Branch 1 taken 3378 times.
✗ Branch 2 not taken.
3378 std::make_shared<CleavageMotif>(mcsp_polChemDef);
591
1/2
✓ Branch 1 taken 3378 times.
✗ Branch 2 not taken.
3378 cleavage_motif_sp->setCleavageAction(cleavage_action);
592
1/2
✓ Branch 1 taken 3378 times.
✗ Branch 2 not taken.
3378 cleavage_motif_sp->parseSite(iter_cleavage_site);
593
594
2/4
✓ Branch 1 taken 3378 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3378 times.
3378 if(!cleavage_motif_sp->isValid())
595 {
596 qCritical() << "Failed to create a valid CleavageMotif by parsing "
597 "cleavage site:"
598 << iter_cleavage_site;
599 cleavage_motif_sp.reset();
600 return false;
601 }
602
603
1/2
✓ Branch 1 taken 3378 times.
✗ Branch 2 not taken.
3378 m_motifs.push_back(cleavage_motif_sp);
604 3399 }
605
606 return true;
607 1767 }
608
609 //////////////// OPERATORS /////////////////////
610 /*!
611 \brief Returns true if \c this and \a other are identical.
612
613 Because the CleavageMotifSPtr in m_motifs and the CleavageRuleSPtr in m_rules do
614 not necessarily reference data from the PolChemDef, the comparison of the two
615 instances involves a deep comparison (not a comparison of the pointers
616 themselves).
617
618 */
619 bool
620 84 CleavageAgent::operator==(const CleavageAgent &other) const
621 {
622
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
84 if(&other == this)
623 return true;
624
625 // We cannot compare the PolChemDef, because that would cause
626 // an infinite loop: (each instance of this class in the PolChemDef would
627 // try to compare the PolChemDef...).
628
629
3/4
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 78 times.
84 if(m_name != other.m_name || m_pattern != other.m_pattern)
630 {
631 qDebug() << "Either the name or the pattern or both is/are different.";
632 return false;
633 }
634
635
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 72 times.
78 if(m_motifs.size() != other.m_motifs.size())
636 {
637 qDebug() << "The CleavageMotif containers have differing sizes.";
638 return false;
639 }
640
641
2/2
✓ Branch 0 taken 189 times.
✓ Branch 1 taken 72 times.
261 for(std::size_t iter = 0; iter < m_motifs.size(); ++iter)
642 {
643 // qDebug() << "Will compare two motifs:" << m_motifs.at(iter)->getMotif()
644 // << "versus" << other.m_motifs.at(iter)->getMotif();
645
646
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 189 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 189 times.
189 if(*m_motifs.at(iter).get() != *other.m_motifs.at(iter).get())
647 {
648 qDebug()
649 << "At least one CleavageMotif is different in both CleavageAgent "
650 "instances.";
651 return false;
652 }
653 }
654
655
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 66 times.
72 if(m_rules.size() != other.m_rules.size())
656 {
657 qDebug() << "The CleavageRule containers have differing sizes.";
658 return false;
659 }
660
661
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 57 times.
123 for(std::size_t iter = 0; iter < m_rules.size(); ++iter)
662 {
663
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 57 times.
57 if(*m_rules.at(iter).get() != *other.m_rules.at(iter).get())
664 {
665 qDebug()
666 << "At least one CleavageMotif is different in both CleavageAgent "
667 "instances.";
668 return false;
669 }
670 }
671
672 return true;
673 }
674
675 /*!
676 \brief Returns true if \c this and \a other are different.
677 */
678 bool
679 57 CleavageAgent::operator!=(const CleavageAgent &other) const
680 {
681
1/2
✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
57 if(&other == this)
682 return false;
683
684 57 return !operator==(other);
685 }
686
687 //////////////// VALIDATIONS /////////////////////
688 /*!
689 \brief Returns the CleavageAgent instance from the polymer chemistry definition
690 registered in this instance.
691
692 The key to search the CleavageAgent is this instance's member name.
693
694 If there is no PolChemDef available, nullptr is returned.
695
696 If no CleavageAgent instance is found by this instance's name, nullptr is
697 returned.
698 */
699 CleavageAgentCstSPtr
700 6 CleavageAgent::getFromPolChemDefByName() const
701 {
702
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if(mcsp_polChemDef == nullptr || mcsp_polChemDef.get() == nullptr)
703 return nullptr;
704
705
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if(m_name.isEmpty())
706 3 return nullptr;
707
708 3 return mcsp_polChemDef->getCleavageAgentCstSPtrByName(m_name);
709 }
710
711 /*!
712 \brief Returns the status of this CleavageAgent instance the polymer chemistry
713 definition registered in this instance.
714
715 The key to search the CleavageAgent is this instance's member name.
716
717 If there is no PolChemDef available,
718 Enums::PolChemDefEntityStatus::POL_CHEM_DEF_NOT_AVAILABLE is returned.
719
720 If no CleavageAgent instance is found by this instance's name,
721 Enums::PolChemDefEntityStatus::ENTITY_NOT_KNOWN is returned, otherwise
722 Enums::PolChemDefEntityStatus::ENTITY_KNOWN is returned.
723 */
724 Enums::PolChemDefEntityStatus
725 6 CleavageAgent::isKnownByNameInPolChemDef() const
726 {
727
728
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if(mcsp_polChemDef == nullptr || mcsp_polChemDef.get() == nullptr)
729 return Enums::PolChemDefEntityStatus::POL_CHEM_DEF_NOT_AVAILABLE;
730
731
4/4
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 3 times.
9 if(mcsp_polChemDef->getCleavageAgentCstSPtrByName(m_name) != nullptr)
732 3 return Enums::PolChemDefEntityStatus::ENTITY_KNOWN;
733
734 return Enums::PolChemDefEntityStatus::ENTITY_NOT_KNOWN;
735 }
736
737 /*!
738 \brief Returns the CleavageRule from the container that has \a name.
739
740 If no \l CleavageRule is found, nullptr is returned.
741 */
742 CleavageRuleCstSPtr
743 3 CleavageAgent::getCleavageRuleCstSPtrByName(const QString &name) const
744 {
745
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 std::vector<CleavageRuleSPtr>::const_iterator the_iterator_cst =
746 6 std::find_if(m_rules.cbegin(),
747 m_rules.cend(),
748
6/12
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 20 taken 3 times.
✗ Branch 21 not taken.
27 [name](const CleavageRuleSPtr &cleave_rule_sp) {
749
1/14
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 19 taken 3 times.
✗ Branch 20 not taken.
3 return cleave_rule_sp->getName() == name;
750 });
751
752
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if(the_iterator_cst == m_rules.cend())
753 return nullptr;
754
755 3 return *(the_iterator_cst);
756 }
757
758 /*!
759 \brief Returns the index of the CleavageRule instance named \a name in the
760 member container of CleavageRule intances. If no CleavageRule by name \a name is
761 found, -1 is returned.
762 */
763 int
764 3 CleavageAgent::getCleavageRuleIndexByName(const QString &name) const
765 {
766
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 std::vector<CleavageRuleSPtr>::const_iterator the_iterator_cst =
767 3 std::find_if(m_rules.cbegin(),
768 m_rules.cend(),
769
6/12
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 20 taken 3 times.
✗ Branch 21 not taken.
27 [name](const CleavageRuleSPtr &cleave_rule_sp) {
770
1/14
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 19 taken 3 times.
✗ Branch 20 not taken.
3 return cleave_rule_sp->getName() == name;
771 });
772
773
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if(the_iterator_cst == m_rules.cend())
774 return -1;
775
776 3 return std::distance(m_rules.cbegin(), the_iterator_cst);
777 }
778
779 /*!
780 \brief Validates this CleavageAgent instance setting error messages to \a
781 error_list_p.
782
783 The validation involves checking that:
784
785 \list
786 \li The PolChemDef must be available;
787 \li The name is not empty;
788 \li The pattern is nt empty;
789 \li The parsing of the pattern is successful.;
790 \li Each CleavageRule instance (if any) validates successfully.
791 \endlist
792
793 Returns true if the validation is successful, false otherwise.
794 */
795 bool
796 1986 CleavageAgent::validate(ErrorList *error_list_p) const
797 {
798
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1977 times.
1986 qsizetype error_count = error_list_p->size();
799
800
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1977 times.
1986 if(mcsp_polChemDef == nullptr || mcsp_polChemDef.get() == nullptr)
801 {
802 18 qCritical() << "A CleavageAgent with no PolChemDef available cannot "
803
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 "validate successfully.";
804 18 error_list_p->push_back(
805 "A CleavageAgent with no PolChemDef available cannot validate "
806 "successfully");
807 }
808
809
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 1947 times.
1986 if(m_name.isEmpty())
810 {
811 78 qCritical()
812
1/2
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
39 << "A CleavageAgent with no name cannot validate successfully.";
813 78 error_list_p->push_back(
814 "A CleavageAgent with no name cannot validate successfully");
815 }
816
817
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 1944 times.
1986 if(m_pattern.isEmpty())
818 {
819 84 qCritical()
820
1/2
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
42 << "A CleavageAgent with no pattern cannot validate successfully.";
821 84 error_list_p->push_back(
822 "A CleavageAgent with no pattern cannot validate successfully");
823 }
824
825 // If there are motifs, we have to check them all.
826
2/2
✓ Branch 0 taken 3819 times.
✓ Branch 1 taken 1986 times.
5805 for(const CleavageMotifSPtr &cleavage_motif_sp : m_motifs)
827 {
828
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3819 times.
3819 if(!cleavage_motif_sp->validate(error_list_p))
829 {
830 qCritical() << "A CleavageAgent with invalid CleavageMotif instances "
831 "cannot validate successfully.";
832 error_list_p->push_back(
833 "A CleavageAgent with invalid CleavageMotif instances cannot "
834 "validate "
835 "successfully");
836 break;
837 }
838 }
839
840 // If there are rules, we have to check them all.
841
2/2
✓ Branch 0 taken 324 times.
✓ Branch 1 taken 1986 times.
2310 for(const CleavageRuleSPtr &cleavage_rule_sp : m_rules)
842 {
843
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 324 times.
324 if(!cleavage_rule_sp->validate(error_list_p))
844 {
845 qCritical() << "A CleavageAgent with invalid CleavageRule instances "
846 "cannot validate successfully.";
847 error_list_p->push_back(
848 "A CleavageAgent with invalid CleavageRule instances cannot "
849 "validate "
850 "successfully");
851 break;
852 }
853 }
854
855 1986 m_isValid = error_list_p->size() > error_count ? false : true;
856
857 1986 return m_isValid;
858 }
859
860 /*!
861 \brief Returns the validity status of this instance.
862 */
863 bool
864 1668 CleavageAgent::isValid() const
865 {
866 1668 return m_isValid;
867 }
868
869 //////////////// XML DATA LOADING WRITING /////////////////////
870 /*!
871 \brief Parses a cleavage specification XML <cls> \a element using a
872 \a{version}ed function.
873
874 The data in the element are validated and if successful they are set to this
875 instance, thus initializing it.
876
877 After setting the member data, the instance is validated and the result is set
878 to m_isValid that is returned.
879 */
880 bool
881 1614 CleavageAgent::renderXmlClsElement(const QDomElement &element,
882 [[maybe_unused]] int version)
883 {
884 // For the time being the version is not necessary here. As of
885 // version up to 2, the current function works ok.
886
887 1614 QDomElement child;
888
1/2
✓ Branch 1 taken 1614 times.
✗ Branch 2 not taken.
1614 QDomElement childRule;
889
890 /* The xml node we are in is structured this way:
891 *
892 * <cls>
893 * <name>CyanogenBromide</name>
894 * <pattern>M/</pattern>
895 * <clr>
896 * <le-mnm-code>M</le-mnm-code>
897 * <le-formula>-C1H2S1+O1</le-formula>
898 * <re-mnm-code>M</re-mnm-code>
899 * <re-formula>-C1H2S1+O1</re-formula>
900 * </clr>
901 * </cls>
902 *
903 * And the element parameter points to the
904 *
905 * <cls> element tag:
906 * ^
907 * |
908 * +----- here we are right now.
909 *
910 * Which means that element.tagName() == "cls" and that
911 * we'll have to go one step down to the first child of the
912 * current node in order to get to the <name> element.
913 */
914
915
2/4
✓ Branch 1 taken 1614 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1614 times.
3228 if(element.tagName() != "cls")
916 {
917 qCritical() << "The expected <cls> element is not found.";
918 m_isValid = false;
919 return m_isValid;
920 }
921
922
3/6
✓ Branch 1 taken 1614 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1614 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1614 times.
✗ Branch 8 not taken.
3228 child = element.firstChildElement("name");
923
924
5/10
✓ Branch 1 taken 1614 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1614 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1614 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1614 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1614 times.
3228 if(child.isNull() || child.text().isEmpty())
925 {
926 qCritical()
927 << "The CleaveSpec did not render correctly: problem with the "
928 "<name> element.";
929 m_isValid = false;
930 return m_isValid;
931 }
932
1/2
✓ Branch 1 taken 1614 times.
✗ Branch 2 not taken.
1614 m_name = child.text();
933 // qDebug() << "The name:" << m_name;
934
935
3/6
✓ Branch 1 taken 1614 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1614 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1614 times.
✗ Branch 8 not taken.
3228 child = child.nextSiblingElement("pattern");
936
937
5/10
✓ Branch 1 taken 1614 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1614 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1614 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1614 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1614 times.
3228 if(child.isNull() || child.text().isEmpty())
938 {
939 qCritical()
940 << "The CleaveSpec did not render correctly: problem with the "
941 "<pattern> element.";
942 m_isValid = false;
943 return m_isValid;
944 }
945
1/2
✓ Branch 1 taken 1614 times.
✗ Branch 2 not taken.
1614 m_pattern = child.text();
946
947
2/4
✓ Branch 1 taken 1614 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1614 times.
1614 if(!parse())
948 {
949 qCritical() << "The CleaveSpec being initialized with a <cls> XML "
950 "element had an unparseable pattern.";
951 m_isValid = false;
952 return false;
953 }
954
955 // At this point there might be 0, 1 or more cleavage rules.
956
3/6
✓ Branch 1 taken 1614 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1614 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1614 times.
✗ Branch 8 not taken.
3228 child = child.nextSiblingElement("clr");
957
958
3/4
✓ Branch 1 taken 1821 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 207 times.
✓ Branch 4 taken 1614 times.
1821 while(!child.isNull())
959 {
960 207 CleavageRuleSPtr cleavage_rule_sp =
961
1/2
✓ Branch 1 taken 207 times.
✗ Branch 2 not taken.
207 std::make_shared<CleavageRule>(mcsp_polChemDef);
962
963
2/4
✓ Branch 1 taken 207 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 207 times.
207 if(!cleavage_rule_sp->renderXmlClrElement(child, version))
964 {
965 qCritical() << "Failed to render CleaveRule from <clr> XML element.";
966 m_isValid = false;
967 cleavage_rule_sp.reset();
968 return false;
969 }
970
971 207 ErrorList error_list;
972
2/4
✓ Branch 1 taken 207 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 207 times.
207 if(!cleavage_rule_sp->validate(&error_list))
973 {
974 qCritical() << "Failed to validate CleaveRule rendered from <clr> "
975 "XML element, with errors:";
976 Utils::joinErrorList(error_list, ", ");
977 cleavage_rule_sp.reset();
978 return false;
979 }
980
981
1/2
✓ Branch 1 taken 207 times.
✗ Branch 2 not taken.
207 m_rules.push_back(cleavage_rule_sp);
982
983
3/6
✓ Branch 1 taken 207 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 207 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 207 times.
✗ Branch 8 not taken.
414 child = child.nextSiblingElement("clr");
984
1/2
✓ Branch 0 taken 207 times.
✗ Branch 1 not taken.
414 }
985
986 1614 ErrorList error_list;
987
1/2
✓ Branch 1 taken 1614 times.
✗ Branch 2 not taken.
1614 m_isValid = validate(&error_list);
988
989
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1614 times.
1614 if(!m_isValid)
990 qCritical() << "Failed to validate CleaveSpec instance right after "
991 "rendering it from <cls> XML element, with errors:"
992 << Utils::joinErrorList(error_list, ", ");
993
994 1614 return m_isValid;
995 3228 }
996
997 /*!
998 \brief Parses a cleavage agent XML <cla> \a element using a \a{version}ed
999 function.
1000
1001 The data in the element are validated and if successful they are set to this
1002 instance, thus initializing it.
1003
1004 After setting the member data, the instance is validated and the result is set
1005 to m_isValid that is returned.
1006 */
1007 bool
1008 30 CleavageAgent::renderXmlClaElement(const QDomElement &element,
1009 [[maybe_unused]] int version)
1010 {
1011 // For the time being the version is not necessary here. As of
1012 // version up to 2, the current function works ok.
1013
1014 30 QDomElement child;
1015
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 QDomElement childRule;
1016
1017 /* The xml node we are in is structured this way:
1018 *
1019 * <cla>
1020 * <name>CyanogenBromide</name>
1021 * <pattern>M/</pattern>
1022 * <clr>
1023 * <le-mnm-code>M</le-mnm-code>
1024 * <le-formula>-C1H2S1+O1</le-formula>
1025 * <re-mnm-code>M</re-mnm-code>
1026 * <re-formula>-C1H2S1+O1</re-formula>
1027 * </clr>
1028 * </cla>
1029 *
1030 * And the element parameter points to the
1031 *
1032 * <cla> element tag:
1033 * ^
1034 * |
1035 * +----- here we are right now.
1036 *
1037 * Which means that element.tagName() == "cla" and that
1038 * we'll have to go one step down to the first child of the
1039 * current node in order to get to the <name> element.
1040 */
1041
1042
2/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 30 times.
60 if(element.tagName() != "cla")
1043 {
1044 qCritical() << "The expected <cla> element is not found.";
1045 m_isValid = false;
1046 return m_isValid;
1047 }
1048
1049
3/6
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 30 times.
✗ Branch 8 not taken.
60 child = element.firstChildElement("name");
1050
1051
5/10
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 30 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 30 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 30 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 30 times.
60 if(child.isNull() || child.text().isEmpty())
1052 {
1053 qCritical()
1054 << "The CleavageAgent did not render correctly: problem with the "
1055 "<name> element.";
1056 m_isValid = false;
1057 return m_isValid;
1058 }
1059
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 m_name = child.text();
1060 30 qDebug() << "The CleavageAgent has name:" << m_name;
1061
1062
3/6
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 30 times.
✗ Branch 8 not taken.
60 child = child.nextSiblingElement("pattern");
1063
1064
5/10
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 30 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 30 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 30 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 30 times.
60 if(child.isNull() || child.text().isEmpty())
1065 {
1066 qCritical()
1067 << "The CleavageAgent did not render correctly: problem with the "
1068 "<pattern> element.";
1069 m_isValid = false;
1070 return m_isValid;
1071 }
1072
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 m_pattern = child.text();
1073 30 qDebug() << "The CleavageAgent has pattern:" << m_pattern;
1074
1075
2/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 30 times.
30 if(!parse())
1076 {
1077 qCritical() << "The CleavageAgent being initialized with a <cls> XML "
1078 "element had an unparseable pattern.";
1079 m_isValid = false;
1080 return false;
1081 }
1082 30 qDebug() << "The CleavageAgent pattern was parsed successfully.";
1083
1084 // At this point there might be 0, 1 or more cleavage rules.
1085
3/6
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 30 times.
✗ Branch 8 not taken.
60 child = child.nextSiblingElement("clr");
1086
1087
3/4
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 30 times.
39 while(!child.isNull())
1088 {
1089 9 qDebug() << "Iterating in <clr> child element.";
1090
1091 9 CleavageRuleSPtr cleavage_rule_sp =
1092
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 std::make_shared<CleavageRule>(mcsp_polChemDef);
1093
1094 9 qDebug() << "Will now render the <clr> element.";
1095
1096
2/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
9 if(!cleavage_rule_sp->renderXmlClrElement(child, version))
1097 {
1098 qCritical()
1099 << "Failed to render CleavageRule from <clr> XML element.";
1100 m_isValid = false;
1101 cleavage_rule_sp.reset();
1102 return false;
1103 }
1104
1105 9 qDebug() << "The <clr> element was parsed successfully.";
1106
1107 9 ErrorList error_list;
1108
2/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
9 if(!cleavage_rule_sp->validate(&error_list))
1109 {
1110 qCritical() << "Failed to validate CleavageRule rendered from <clr> "
1111 "XML element, with errors:";
1112 Utils::joinErrorList(error_list, ", ");
1113 cleavage_rule_sp.reset();
1114 return false;
1115 }
1116
1117 9 qDebug() << "Now storing the CleavageRule in the container.";
1118
1119
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 m_rules.push_back(cleavage_rule_sp);
1120
1121
3/6
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 9 times.
✗ Branch 8 not taken.
18 child = child.nextSiblingElement("clr");
1122
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
18 }
1123
1124 30 ErrorList error_list;
1125
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 m_isValid = validate(&error_list);
1126
1127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if(!m_isValid)
1128 qCritical() << "Failed to validate CleavageAgent instance right after "
1129 "rendering it from <cls> XML element, with errors:"
1130 << Utils::joinErrorList(error_list, ", ");
1131 else
1132 30 qDebug() << "Successfully parsed the <cla> element.";
1133
1134 30 return m_isValid;
1135 60 }
1136
1137 /*!
1138 \brief Formats and returns a string describing this CleavageAgent instance in a
1139 format suitable to be used as an XML element.
1140
1141 The XML element is typically used in a polymer chemistry defintion and looks
1142 like this:
1143
1144 \code
1145 <cla>
1146 <name>CyanogenBromide</name>
1147 <pattern>M/</pattern>
1148 <clr>
1149 <re-mnm-code>M</re-mnm-code>
1150 <re-formula>-CH2S+O</re-formula>
1151 </clr>
1152 </cla>
1153 \endcode
1154
1155
1156 The formatting of the XML element takes into account \a offset and \a
1157 indent by prepending the string with \a offset * \a indent character
1158 substring.
1159
1160 \a indent defaults to two spaces.
1161
1162 Returns a string.
1163 */
1164 QString
1165 30 CleavageAgent::formatXmlClaElement(int offset, const QString &indent) const
1166 {
1167 30 int newOffset;
1168 30 int iter = 0;
1169
1170 30 QString lead("");
1171 30 QString text;
1172
1173
1174 // Prepare the lead.
1175 30 newOffset = offset;
1176
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 30 times.
108 while(iter < newOffset)
1177 {
1178
1/2
✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
78 lead += indent;
1179 78 ++iter;
1180 }
1181
1182
1183
2/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
60 text += QString("%1<cla>\n").arg(lead);
1184
1185 // Prepare the lead.
1186 30 ++newOffset;
1187 30 lead.clear();
1188 30 iter = 0;
1189
2/2
✓ Branch 1 taken 108 times.
✓ Branch 2 taken 30 times.
168 while(iter < newOffset)
1190 {
1191
1/2
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
108 lead += indent;
1192 108 ++iter;
1193 }
1194
1195 // Continue with indented elements.
1196
1197
3/6
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 30 times.
✗ Branch 8 not taken.
60 text += QString("%1<name>%2</name>\n").arg(lead).arg(m_name);
1198
3/6
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 30 times.
✗ Branch 8 not taken.
60 text += QString("%1<pattern>%2</pattern>\n").arg(lead).arg(m_pattern);
1199
1200
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 30 times.
39 for(const CleavageRuleSPtr &cleavage_rule_sp : m_rules)
1201
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
18 text += cleavage_rule_sp->formatXmlClrElement(newOffset);
1202
1203 // Prepare the lead for the closing element.
1204 30 --newOffset;
1205 30 lead.clear();
1206 30 iter = 0;
1207
2/2
✓ Branch 1 taken 78 times.
✓ Branch 2 taken 30 times.
138 while(iter < newOffset)
1208 {
1209
1/2
✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
78 lead += indent;
1210 78 ++iter;
1211 }
1212
1213
2/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
60 text += QString("%1</cla>\n").arg(lead);
1214
1215 30 return text;
1216 30 }
1217
1218 //////////////// UTILS /////////////////////
1219 /*!
1220 \brief Returns a string describing this CleavageAgent instance.
1221 */
1222 QString
1223 3 CleavageAgent::toString() const
1224 {
1225 3 return QString("%1 - %2 - %3 motifs - %4 rules")
1226
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 .arg(m_name)
1227
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 .arg(m_pattern)
1228
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
6 .arg(m_motifs.size())
1229
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 .arg(m_rules.size());
1230 }
1231
1232 void
1233
1234 CleavageAgent::registerJsConstructor(QJSEngine *engine)
1235
1236 {
1237 if(!engine)
1238 {
1239 qWarning() << "Cannot register CleavageAgent class: engine is null";
1240 return;
1241 }
1242
1243 // Register the meta object as a constructor
1244
1245 QJSValue jsMetaObject =
1246 engine->newQMetaObject(&CleavageAgent::staticMetaObject);
1247 engine->globalObject().setProperty("CleavageAgent", jsMetaObject);
1248 }
1249
1250
1251 } // namespace libXpertMassCore
1252 } // namespace MsXpS
1253