GCC Code Coverage Report


source/XpertMassCore/src/
File: source/XpertMassCore/src/FragmentationRule.cpp
Date: 2025-11-20 01:41:33
Lines:
241/282
85.5%
Functions:
24/28
85.7%
Branches:
211/456
46.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 /////////////////////// Local includes
35 #include "MsXpS/libXpertMassCore/FragmentationRule.hpp"
36 #include "MsXpS/libXpertMassCore/PolChemDef.hpp"
37
38
39 namespace MsXpS
40 {
41
42 namespace libXpertMassCore
43 {
44
45
46 /*!
47 \class MsXpS::libXpertMassCore::FragmentationRule
48 \inmodule libXpertMassCore
49 \ingroup PolChemDefGasPhaseChemicalReactions
50 \inheaderfile FragmentationRule.hpp
51
52 \brief The FragmentationRule class provides a model for specifying gas phase
53 fragmentation rules for refining fragmentation pathway specifications (\l
54 FragmentationPathway) of \l{Oligomer} \l{Sequence}s.
55
56 Fragmentation rules characterize in more detail the chemical reaction that
57 governs the fragmentation of the polymer in the gas-phase. The rule is a
58 conditional rule. Its logic is based on the presence of specified monomers
59 right at the place of the fragmentation and before or after that precise
60 location.
61
62 In saccharide chemistry, fragmentations are a very complex topic. This is
63 because a given monomer will fragment according to a given chemistry if it is
64 preceded in the sequence by a monomer of a given identity and according to
65 another chemistry if its direct environment is different.
66
67 This paradigm is implemented using a sequence environment logic based on
68 conditions that can be formulated thanks to three monomer codes:
69
70 \list
71 \li The monomer at which the fragmentation takes place (current code);
72 \li The monomer preceeding the current code (previous code);
73 \li The monomer following the current code (next code);
74 \endlist
75
76 The use of these codes is typically according to this kind of logic:
77
78 \e{If current monomer is Glu and previous monomer is Gly and
79 next monomer is Arg, then fragmentation should occur according
80 to this formula : "-H2O"}.
81
82 \sa FragmentationPathway
83 */
84
85
86 /*!
87 \variable MsXpS::libXpertMassCore::FragmentationRule::mcsp_polChemDef
88
89 \brief The PolChemDef (polymer chemistry definition) that is the context in
90 which the Oligomer being fragmented exists.
91 */
92
93 /*!
94 \variable MsXpS::libXpertMassCore::FragmentationRule::m_name
95
96 \brief The name of the FragmentationRule.
97 */
98
99 /*!
100 \variable MsXpS::libXpertMassCore::FragmentationRule::m_prevCode
101
102 \brief The \l Monomer code of the Monomer located before the actual
103 fragmentation site.
104 */
105
106
107 /*!
108 \variable MsXpS::libXpertMassCore::FragmentationRule::m_currCode
109
110 \brief The \l Monomer code of the Monomer at the actual fragmentation site.
111 */
112
113
114 /*!
115 \variable MsXpS::libXpertMassCore::FragmentationRule::m_nextCode
116
117 \brief The \l Monomer code of the Monomer located after the actual fragmentation
118 site.
119 */
120
121
122 /*!
123 \variable MsXpS::libXpertMassCore::FragmentationRule::m_comment
124
125 \brief A comment associated to the FragmentationRule.
126 */
127
128 /*!
129 \variable MsXpS::libXpertMassCore::FragmentationRule::m_formula
130
131 \brief A \l{Formula} instance describing the fragmentation reaction occurring on
132 the Monomer at which the fragmentation occurs.
133 */
134
135 /*!
136 \variable MsXpS::libXpertMassCore::FragmentationRule::m_isValid
137
138 \brief The validity status of this FragmentationRule instance.
139 */
140
141
142 /*!
143 \brief Constructs a fragmentation rule with a number of parameters.
144
145 \list
146 \li \a pol_chem_def_csp Polymer chemistry definition. Cannot be nullptr.
147
148 \li \a name Name. Cannot be empty.
149
150 \li \a prev_code Previous monomer code. Defaults to the null string.
151
152 \li \a current_code Current monomer code. Defaults to the null string.
153
154 \li \a next_code Next monomer code. Defaults to the null string.
155
156 \li \a comment Comment. Defaults to the null string.
157
158 \li \a formula_string Formula. Defaults to the null string.
159 \endlist
160
161 Upon setting all the member data, this instance is validated and the member
162 m_isValid is set to the result.
163 */
164 29 FragmentationRule::FragmentationRule(PolChemDefCstSPtr pol_chem_def_csp,
165 const QString &name,
166 const QString &prev_code,
167 const QString &current_code,
168 const QString &next_code,
169 const QString &comment,
170 29 const QString &formula_string)
171 58 : mcsp_polChemDef(pol_chem_def_csp),
172
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 4 times.
29 m_name(name),
173
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 4 times.
29 m_prevCode(prev_code),
174
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 4 times.
29 m_currCode(current_code),
175
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 4 times.
29 m_nextCode(next_code),
176
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 4 times.
29 m_comment(comment),
177
1/2
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
58 m_formula(formula_string)
178 {
179 29 ErrorList error_list;
180
1/2
✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
29 m_isValid = validate(&error_list);
181
182
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 25 times.
29 if(!m_isValid)
183
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 qCritical()
184 << "Upon construction of FragmentationRule, the instance failed to "
185
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 "validate with errors:"
186
3/6
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
8 << Utils::joinErrorList(error_list, ", ");
187
0/2
✗ Branch 6 not taken.
✗ Branch 7 not taken.
29 }
188
189
190 /*!
191 \brief Constructs a FragmentationRule instance starting from an XML <fgr> \a
192 element according to \a version and using the reference \a pol_chem_def_csp
193 polymer chemistry definition.
194
195 This is the current format (FAKE fgr):
196 \code
197
198 <fgr>
199 <name>a-fgr-2</name>
200 <formula>+H100</formula>
201 <prev-mnm-code>F</prev-mnm-code>
202 <curr-mnm-code>D</curr-mnm-code>
203 <next-mnm-code>E</next-mnm-code>
204 <comment>comment here!</comment>
205 </fgr>
206
207 \endcode
208
209 The rendering of the CleavageRule instances requires that the PolChemDef be
210 available.
211
212 \sa renderXmlFgrElement()
213 */
214 5 FragmentationRule::FragmentationRule(PolChemDefCstSPtr pol_chem_def_csp,
215 const QDomElement &element,
216 5 [[maybe_unused]] int version)
217
1/2
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 : mcsp_polChemDef(pol_chem_def_csp)
218 {
219
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if(mcsp_polChemDef == nullptr || mcsp_polChemDef.get() == nullptr)
220 qCritical() << "Constructing FragmentationRule with no PolChemDef.";
221
222
2/4
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
5 if(!renderXmlFgrElement(element))
223 qCritical()
224 << "Failed to fully render or validate the FragmentationRule XML element "
225 "for construction of FragmentationRule instance.";
226
0/2
✗ Branch 6 not taken.
✗ Branch 7 not taken.
5 }
227
228 /*!
229 \brief Constructs a FragmentationRule instance as a copy of \a other.
230
231 Upon setting all the member data, this instance is validated and the member
232 m_isValid is set to the result.
233 */
234 1 FragmentationRule::FragmentationRule(const FragmentationRule &other)
235 2 : mcsp_polChemDef(other.mcsp_polChemDef),
236
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 m_name(other.m_name),
237
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 m_prevCode(other.m_prevCode),
238
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 m_currCode(other.m_currCode),
239
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 m_nextCode(other.m_nextCode),
240
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 m_comment(other.m_comment),
241
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 m_formula(other.m_formula)
242 {
243 1 ErrorList error_list;
244
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 m_isValid = validate(&error_list);
245
246
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(!m_isValid)
247 qCritical()
248 << "Upon construction of FragmentationRule, the instance failed to "
249 "validate with errors:"
250 << Utils::joinErrorList(error_list, ", ");
251
0/2
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1 }
252
253
254 /*!
255 \brief Destructs the fragmentation rule.
256 */
257 70 FragmentationRule::~FragmentationRule()
258 {
259
2/2
✓ Branch 6 taken 34 times.
✓ Branch 7 taken 1 times.
70 }
260
261 /*!
262 \brief Sets the PolChemDef to \a pol_chem_def_csp.
263 */
264 void
265 1 FragmentationRule::setPolchemDefCstSPtr(PolChemDefCstSPtr pol_chem_def_csp)
266 {
267 1 mcsp_polChemDef = pol_chem_def_csp;
268
269 1 ErrorList error_list;
270
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 m_isValid = validate(&error_list);
271
272
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(!m_isValid)
273
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 qCritical()
274 << "Upon setting PolChemDef of FragmentationRule, the instance failed to "
275
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 "validate with errors:"
276
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 << Utils::joinErrorList(error_list, ", ");
277 1 }
278
279 /*!
280 \brief Returns the PolChemDef.
281 */
282 PolChemDefCstSPtr
283 FragmentationRule::getPolchemDefCstSPtr() const
284 {
285 return mcsp_polChemDef;
286 }
287
288 /*!
289 \brief Sets the name to \a name.
290 */
291 void
292 1 FragmentationRule::setName(const QString &name)
293 {
294 1 m_name = name;
295
296 1 ErrorList error_list;
297
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 m_isValid = validate(&error_list);
298
299
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(!m_isValid)
300
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 qCritical()
301 << "Upon setting name of FragmentationRule, the instance failed to "
302
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 "validate with errors:"
303
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 << Utils::joinErrorList(error_list, ", ");
304 1 }
305
306 /*!
307 \brief Returns the name.
308 */
309 const QString &
310 23 FragmentationRule::getName()
311 {
312 23 return m_name;
313 }
314
315 /*!
316 \brief Sets the previous monomer \a code.
317
318 Upon setting the member data, this instance is validated and the member
319 m_isValid is set to the result.
320 */
321 void
322 1 FragmentationRule::setPrevCode(const QString &code)
323 {
324 1 m_prevCode = code;
325
326 1 ErrorList error_list;
327
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 m_isValid = validate(&error_list);
328
329
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(!m_isValid)
330
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 qCritical() << "Upon setting previous code of FragmentationRule, the "
331 "instance failed to "
332
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 "validate with errors:"
333
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 << Utils::joinErrorList(error_list, ", ");
334 1 }
335
336
337 /*!
338 \brief Returns the previous monomer code.
339 */
340 const QString &
341 8 FragmentationRule::getPrevCode() const
342 {
343 8 return m_prevCode;
344 }
345
346
347 /*!
348 \brief Sets the current monomer \a code.
349
350 Upon setting the member data, this instance is validated and the member
351 m_isValid is set to the result.
352 */
353 void
354 1 FragmentationRule::setCurrCode(const QString &code)
355 {
356 1 m_currCode = code;
357
358 1 ErrorList error_list;
359
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 m_isValid = validate(&error_list);
360
361
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(!m_isValid)
362
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 qCritical() << "Upon setting current code of FragmentationRule, the "
363 "instance failed to "
364
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 "validate with errors:"
365
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 << Utils::joinErrorList(error_list, ", ");
366 1 }
367
368
369 /*!
370 \brief Returns the current monomer code.
371 */
372 const QString &
373 8 FragmentationRule::getCurrCode() const
374 {
375 8 return m_currCode;
376 }
377
378
379 /*!
380 \brief Sets the next monomer \a code.
381
382 Upon setting the member data, this instance is validated and the member
383 m_isValid is set to the result.
384 */
385 void
386 1 FragmentationRule::setNextCode(const QString &code)
387 {
388 1 m_nextCode = code;
389
390 1 ErrorList error_list;
391
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 m_isValid = validate(&error_list);
392
393
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(!m_isValid)
394
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 qCritical()
395 << "Upon setting next code of FragmentationRule, the instance failed to "
396
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 "validate with errors:"
397
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 << Utils::joinErrorList(error_list, ", ");
398 1 }
399
400
401 /*!
402 \brief Returns the next monomer code.
403 */
404 const QString &
405 8 FragmentationRule::getNextCode() const
406 {
407 8 return m_nextCode;
408 }
409
410
411 /*!
412 \brief Sets the \a comment.
413 */
414 void
415 1 FragmentationRule::setComment(const QString &comment)
416 {
417 1 m_comment = comment;
418 1 }
419
420
421 /*!
422 \brief Returns the comment.
423 */
424 const QString &
425 8 FragmentationRule::getComment() const
426 {
427 8 return m_comment;
428 }
429
430 /*!
431 \brief Sets the \a formula.
432
433 Upon setting the member data, this instance is validated and the member
434 m_isValid is set to the result.
435 */
436 void
437 1 FragmentationRule::setFormula(const Formula &formula)
438 {
439 1 m_formula = formula;
440
441 1 ErrorList error_list;
442
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 m_isValid = validate(&error_list);
443
444
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(!m_isValid)
445 qCritical()
446 << "Upon setting Formula of FragmentationRule, the instance failed to "
447 "validate with errors:"
448 << Utils::joinErrorList(error_list, ", ");
449 1 }
450
451 /*!
452 \brief Sets the member Formula using \a formula_string.
453
454 Upon setting the member data, this instance is validated and the member
455 m_isValid is set to the result.
456 */
457 void
458 FragmentationRule::setFormula(const QString &formula_string)
459 {
460 m_formula = Formula(formula_string);
461
462 ErrorList error_list;
463 m_isValid = validate(&error_list);
464
465 if(!m_isValid)
466 qCritical()
467 << "Upon setting Formula of FragmentationRule, the instance failed to "
468 "validate with errors:"
469 << Utils::joinErrorList(error_list, ", ");
470 }
471
472 /*!
473 \brief Returns a const reference to the member \l Formula.
474 */
475 const Formula &
476 8 FragmentationRule::getFormulaCstRef() const
477 {
478 8 return m_formula;
479 }
480
481 /*!
482 \brief Returns a reference to the member \l Formula.
483 */
484 Formula &
485 FragmentationRule::getFormulaRef()
486 {
487 return m_formula;
488 }
489
490 //////////////// OPERATORS /////////////////////
491 /*!
492 \brief Assigns \a other to this FragmentationRule instance.
493
494 Upon setting the member data, this instance is validated and the member
495 m_isValid is set to the result.
496
497 Returns a reference to this fragmentation rule.
498 */
499 FragmentationRule &
500 1 FragmentationRule::operator=(const FragmentationRule &other)
501 {
502
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(&other == this)
503 return *this;
504
505 1 mcsp_polChemDef = other.mcsp_polChemDef;
506 1 m_name = other.m_name;
507 1 m_prevCode = other.m_prevCode;
508 1 m_currCode = other.m_currCode;
509 1 m_nextCode = other.m_nextCode;
510 1 m_comment = other.m_comment;
511 1 m_formula = other.m_formula;
512
513 1 ErrorList error_list;
514
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 m_isValid = validate(&error_list);
515
516
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(!m_isValid)
517 qCritical()
518 << "Upon assignment of FragmentationRule, the instance failed to "
519 "validate with errors:"
520 << Utils::joinErrorList(error_list, ", ");
521
522 1 return *this;
523 1 }
524
525 /*!
526 \brief Returns true if \c this instance and \a other are identical.
527 */
528 bool
529 4 FragmentationRule::operator==(const FragmentationRule &other) const
530 {
531
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if(&other == this)
532 return true;
533
534
3/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
4 return mcsp_polChemDef == other.mcsp_polChemDef && m_name == other.m_name &&
535
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
4 m_prevCode == other.m_prevCode && m_currCode == other.m_currCode &&
536
4/8
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 4 times.
12 m_nextCode == other.m_nextCode && m_comment == other.m_comment &&
537 4 m_formula == other.m_formula;
538 }
539
540 /*!
541 \brief Returns true if \c this and \a other are different.
542
543 Returns the negated result of operator==().
544 */
545 bool
546 9 FragmentationRule::operator!=(const FragmentationRule &other) const
547 {
548
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 7 times.
9 if(&other == this)
549 return false;
550
551 2 return !operator==(other);
552 }
553
554
555 //////////////// VALIDATIONS /////////////////////
556 /*!
557 \brief Validates the FragmentationRule, recording any error as a message in \a error_list_p.
558
559 The validation involves checking that:
560
561 \list
562 \li The member PolChemDef cannot be nullptr.
563
564 \li The name is not empty.
565
566 \li The previous code is valid if non empty.
567
568 \li The current code is valid if non empty.
569
570 \li The next code is valid if non empty.
571
572 \li The formula validates successfully if non empty.
573 \endlist
574
575 The m_isValid member is set to true upon success, false otherwise and returned.
576 */
577 bool
578 102 FragmentationRule::validate(ErrorList *error_list_p) const
579 {
580
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 98 times.
102 qsizetype error_count = error_list_p->size();
581
582
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 98 times.
102 if(mcsp_polChemDef == nullptr || mcsp_polChemDef.get() == nullptr)
583 {
584 8 qCritical() << "A FragmentationRule with no PolChemDef available cannot "
585
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 "validate successfully.";
586 8 error_list_p->push_back(
587 "A FragmentationRule with no PolChemDef available cannot validate "
588 "successfully");
589 }
590
591
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 95 times.
102 if(m_name.isEmpty())
592 {
593 14 qCritical()
594
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 << "A FragmentationRule with no name cannot validate successfully.";
595 14 error_list_p->push_back(
596 "A FragmentationRule with no name cannot validate successfully");
597 }
598
599
4/6
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 94 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
102 if(m_prevCode.isEmpty() && m_currCode.isEmpty() && m_nextCode.isEmpty())
600 {
601 16 qCritical() << "A FragmentationRule with not a single Monomer code "
602
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 "cannot validate successfully.";
603 16 error_list_p->push_back(
604 "A FragmentationRule with not a single Monomer code cannot validate "
605 "successfully");
606 }
607
608
2/2
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 4 times.
102 if(mcsp_polChemDef != nullptr && mcsp_polChemDef.get() != nullptr &&
609
2/2
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 4 times.
98 !m_prevCode.isEmpty())
610 {
611
2/4
✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 94 times.
188 if(mcsp_polChemDef->getMonomerCstSPtrByCode(m_prevCode) == nullptr)
612 {
613 qCritical()
614 << "A FragmentationRule with an unknown previous monomer code "
615 "cannot validate successfully.";
616 error_list_p->push_back(
617 "A FragmentationRule with an unknown previous monomer code cannot "
618 "validate "
619 "successfully");
620 }
621 }
622
623
2/2
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 4 times.
102 if(mcsp_polChemDef != nullptr && mcsp_polChemDef.get() != nullptr &&
624
2/2
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 5 times.
98 !m_currCode.isEmpty())
625 {
626
2/4
✓ Branch 1 taken 93 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 93 times.
186 if(mcsp_polChemDef->getMonomerCstSPtrByCode(m_currCode) == nullptr)
627 {
628 qCritical()
629 << "A FragmentationRule with an unknown current monomer code "
630 "cannot validate successfully.";
631 error_list_p->push_back(
632 "A FragmentationRule with an unknown current monomer code cannot "
633 "validate "
634 "successfully");
635 }
636 }
637
638
2/2
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 4 times.
102 if(mcsp_polChemDef != nullptr && mcsp_polChemDef.get() != nullptr &&
639
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 6 times.
98 !m_nextCode.isEmpty())
640 {
641
2/4
✓ Branch 1 taken 92 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 92 times.
184 if(mcsp_polChemDef->getMonomerCstSPtrByCode(m_nextCode) == nullptr)
642 {
643 qCritical()
644 << "A FragmentationRule with an unknown next monomer code "
645 "cannot validate successfully.";
646 error_list_p->push_back(
647 "A FragmentationRule with an unknown next monomer code cannot "
648 "validate "
649 "successfully");
650 }
651 }
652
653
2/2
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 91 times.
102 if(m_formula.getActionFormula().isEmpty())
654 {
655 22 qCritical()
656 << "A FragmentationRule with no Formula does not make sense and "
657
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 "cannot validate successfully.";
658 22 error_list_p->push_back(
659 "A FragmentationRule with no Formula does not make sense and cannot "
660 "validate "
661 "successfully");
662 }
663
664
4/4
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 91 times.
200 if(mcsp_polChemDef != nullptr && mcsp_polChemDef.get() != nullptr &&
665
3/4
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 95 times.
200 !m_formula.validate(mcsp_polChemDef->getIsotopicDataCstSPtr(), error_list_p))
666 {
667 14 qCritical() << "A FragmentationRule with a non-empty invalid Formula "
668
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 "cannot validate successfully.";
669 14 error_list_p->push_back(
670 "A FragmentationRule with a non-empty invalid Formula cannot validate "
671 "successfully");
672 }
673
674 102 m_isValid = error_list_p->size() > error_count ? false : true;
675
676 102 return m_isValid;
677 }
678
679
680 /*!
681 \brief Returns the validity status of this FragmentationRule.
682 */
683 bool
684 11 FragmentationRule::isValid() const
685 {
686 11 return m_isValid;
687 }
688
689 //////////////// UTILITIES /////////////////////
690 /*!
691 \brief Returns a string with the textual representation of this
692 FragmentationRule instance.
693 */
694 QString
695 FragmentationRule::toString() const
696 {
697 QString text = "Fragmentation rule:\n";
698
699 text += QString("name: %1 - prev code: %2 - curr code: %3 - next code: %4 - formula: %5 - comment: %6 - is valid? %7\n").arg(m_name).arg(m_prevCode).arg(m_currCode).arg(m_nextCode).arg(m_formula.getActionFormula(/*with_title*/ true)).arg(m_comment).arg(m_isValid ? "true" : "false");
700
701 return text;
702 }
703
704
705 /*!
706 \brief Parses the FragmentationRule XML \a element.
707
708 Upon parsing and validation of the parsed data, the member data are updated,
709 thus essentially initializing this FragmentationRule instance.
710
711 Returns true if parsing and formula validation were successful, false otherwise.
712 */
713 bool
714 6 FragmentationRule::renderXmlFgrElement(const QDomElement &element)
715 {
716 6 QDomElement child;
717
718 6 bool prevSet = false;
719 6 bool currSet = false;
720 6 bool nextSet = false;
721 6 bool commentSet = false;
722
723 /* The xml node we are in is structured this way:
724 *
725 * <fgr>
726 * <name>one_rule</name>
727 * <formula>+H2O</formula>
728 * <prev-mnm-code>M</prev-mnm-code>
729 * <this-mnm-code>Y</this-mnm-code>
730 * <next-mnm-code>T</next-mnm-code>
731 * <comment>opt_comment</comment>
732 * </fgr>
733 *
734 * And the element parameter points to the
735 *
736 * <fgr> element tag:
737 * ^
738 * |
739 * +----- here we are right now.
740 *
741 * Which means that element.tagName() == "fgr" and that
742 * we'll have to go one step down to the first child of the
743 * current node in order to get to the <name> element.
744 *
745 * The DTD:
746 * <!ELEMENT fgr(name, formula, prev-mnm-code?,
747 * this-mnm-code?, next-mnm-code?, comment?)>
748 */
749
750
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
12 if(element.tagName() != "fgr")
751 return false;
752
753
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
12 child = element.firstChildElement();
754
755
5/10
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 6 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 6 times.
12 if(child.isNull() || child.tagName() != "name")
756 return false;
757
758
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 m_name = child.text();
759
760
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
12 child = child.nextSiblingElement();
761
762
5/10
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 6 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 6 times.
12 if(child.isNull() || child.tagName() != "formula")
763 return false;
764
765
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
6 if(!m_formula.renderXmlFormulaElement(child))
766 return false;
767
768 // Since the following items are not obligatory, we have to while()
769 // until we have no more items...
770
771
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
12 child = child.nextSiblingElement();
772
773
3/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 6 times.
30 while(!child.isNull())
774 {
775
3/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 18 times.
48 if(child.tagName() == "prev-mnm-code")
776 {
777
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if(prevSet)
778 return false;
779 else
780 {
781
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 m_prevCode = child.text();
782 6 prevSet = true;
783 }
784 }
785
3/4
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 12 times.
36 else if(child.tagName() == "curr-mnm-code")
786 {
787
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if(currSet)
788 return false;
789 else
790 {
791
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 m_currCode = child.text();
792 6 currSet = true;
793 }
794 }
795
3/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 6 times.
24 else if(child.tagName() == "next-mnm-code")
796 {
797
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if(nextSet)
798 return false;
799 else
800 {
801
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 m_nextCode = child.text();
802 6 nextSet = true;
803 }
804 }
805
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
12 else if(child.tagName() == "comment")
806 {
807
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if(commentSet)
808 return false;
809 else
810 {
811
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 m_comment = child.text();
812 6 commentSet = true;
813 }
814 }
815
816
2/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
48 child = child.nextSiblingElement();
817 }
818
819 6 ErrorList error_list;
820
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 m_isValid = validate(&error_list);
821
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if(!m_isValid)
822 {
823 qCritical()
824 << "The FragmentationRule rendered from <clr> element is invalid.";
825 }
826
827 6 return m_isValid;
828 12 }
829
830
831 /*!
832 \brief Formats a string suitable to use as an XML element.
833
834
835 The string is suitable to be used as an XML element in a polymer chemistry
836 definition file. The typical fragmentation rule element that is generated in
837 this function looks like this:
838
839 \code
840 <fgr>
841 <name>a-fgr-2</name>
842 <formula>+H100</formula>
843 <prev-mnm-code>F</prev-mnm-code>
844 <curr-mnm-code>D</curr-mnm-code>
845 <next-mnm-code>E</next-mnm-code>
846 <comment>comment here!</comment>
847 </fgr>
848 \endcode
849
850 The formatting of the XML element takes into account \a offset and \a
851 indent by prepending the string with \a offset * \a indent character substring.
852
853 \a indent defaults to two spaces.
854
855 Returns a dynamically allocated string that needs to be freed after use.
856 */
857 QString
858 2 FragmentationRule::formatXmlFgrElement(int offset, const QString &indent)
859 {
860
861 2 int newOffset;
862 2 int iter = 0;
863
864 2 QString lead("");
865 2 QString text;
866
867
868 // Prepare the lead.
869 2 newOffset = offset;
870
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 while(iter < newOffset)
871 {
872
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 lead += indent;
873 3 ++iter;
874 }
875
876
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
4 text += QString("%1<fgr>\n").arg(lead);
877
878 // Prepare the lead.
879 2 ++newOffset;
880 2 lead.clear();
881 2 iter = 0;
882
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 2 times.
9 while(iter < newOffset)
883 {
884
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 lead += indent;
885 5 ++iter;
886 }
887
888 // Continue with indented elements.
889
890
3/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
4 text += QString("%1<name>%2</name>\n").arg(lead).arg(m_name);
891
892
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 text += QString("%1<formula>%2</formula>\n")
893
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 .arg(lead)
894
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
4 .arg(m_formula.getActionFormula());
895
896
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if(!m_prevCode.isEmpty())
897
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 text += QString("%1<prev-mnm-code>%2</prev-mnm-code>\n")
898
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 .arg(lead)
899
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
6 .arg(m_prevCode);
900
901
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if(!m_currCode.isEmpty())
902
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 text += QString("%1<curr-mnm-code>%2</curr-mnm-code>\n")
903
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 .arg(lead)
904
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
6 .arg(m_currCode);
905
906
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if(!m_nextCode.isEmpty())
907
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 text += QString("%1<next-mnm-code>%2</next-mnm-code>\n")
908
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 .arg(lead)
909
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
6 .arg(m_nextCode);
910
911
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if(!m_comment.isEmpty())
912
3/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
4 text += QString("%1<comment>%2</comment>\n").arg(lead).arg(m_comment);
913
914 // Prepare the lead.
915 2 --newOffset;
916 2 lead.clear();
917 2 iter = 0;
918
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
7 while(iter < newOffset)
919 {
920
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 lead += indent;
921 3 ++iter;
922 }
923
924
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
4 text += QString("%1</fgr>\n").arg(lead);
925
926 2 return text;
927 2 }
928
929 } // namespace libXpertMassCore
930
931 } // namespace MsXpS
932