GCC Code Coverage Report


source/XpertMassCore/src/
File: source/XpertMassCore/src/CleavageRule.cpp
Date: 2025-11-19 15:26:11
Lines:
239/276
86.6%
Functions:
21/23
91.3%
Branches:
209/410
51.0%

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/CleavageRule.hpp"
36 #include "MsXpS/libXpertMassCore/PolChemDef.hpp"
37
38 namespace MsXpS
39 {
40 namespace libXpertMassCore
41 {
42
43
44 /*!
45 \class MsXpS::libXpertMassCore::CleavageRule
46 \inmodule libXpertMassCore
47 \ingroup PolChemDefAqueousChemicalReactions
48 \inheaderfile CleavageRule.hpp
49
50 \brief The CleavageRule class provides a model for specifying aqueous cleavage
51 rules for refining cleavage agent specifications (\l CleavageAgent) of
52 \l{Polymer} \l{Sequence}s.
53
54 Cleavage rules help refine the description of the chemical reaction that is the
55 basis of a cleavage (either enzymatic or chemical).
56
57 While a number of cleavage agents (like a number of enzymes) do not make
58 unexpected reactions upon the cleavage (enzymes usually hydrolyze their
59 substrates), there are chemical agents that during the process of cleaving their
60 polymer sequence substrate also chemically modify the ends of the generated
61 oligomers. One notorious example is the case of cyanogen bromide, that cleaves
62 proteins right (that is, C-terminal) of methionyl residues. Upon such cleavage,
63 the monomer at the right side of the generated oligomer (methionyl residue) gets
64 modified according to this actionformula: "-CH2S+O". This reaction is modelled
65 using a CleavageRule.
66
67 \sa CleavageMotif, CleavageAgent
68 */
69
70
71 /*!
72 \variable MsXpS::libXpertMassCore::CleavageRule::mcsp_polChemDef
73
74 \brief The \l PolChemDef polymer chemistry definition.
75 */
76
77 /*!
78 \variable MsXpS::libXpertMassCore::CleavageRule::m_name
79
80 \brief The name of the CleavageRule.
81 */
82
83 /*!
84 \variable MsXpS::libXpertMassCore::CleavageRule::m_leftCode
85
86 \brief The \l Monomer code at the left of the cleavage site.
87 */
88
89 /*!
90 \variable MsXpS::libXpertMassCore::CleavageRule::m_leftFormula
91
92 \brief The \l Formula to be applied onto the left monomer code.
93 */
94
95 /*!
96 \variable MsXpS::libXpertMassCore::CleavageRule::m_rightCode
97
98 \brief The \l Monomer code at the right of the cleavage site.
99 */
100
101 /*!
102 \variable MsXpS::libXpertMassCore::CleavageRule::m_rightFormula
103
104 \brief The \l Formula to be applied onto the right monomer code.
105 */
106
107 /*!
108 \variable MsXpS::libXpertMassCore::CleavageRule::m_isValid
109
110 \brief The validity status of the CleavageRule instance.
111 */
112
113
114 /*!
115 \brief Constructs a CleavageRule instance with \a pol_chem_def_csp as the polymer chemistry definition.
116
117 The validiy status (m_isValid) of this install will be set to false.
118 */
119 225 CleavageRule::CleavageRule(PolChemDefCstSPtr pol_chem_def_csp)
120
5/10
✓ Branch 2 taken 225 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 225 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 225 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 225 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 225 times.
✗ Branch 15 not taken.
225 : mcsp_polChemDef(pol_chem_def_csp)
121 {
122
0/2
✗ Branch 4 not taken.
✗ Branch 5 not taken.
225 }
123
124
125 /*!
126 \brief Constructs a CleavageRule instance
127
128 \list
129 \li \a pol_chem_def_csp: Polymer chemistry definition.
130 \li \a name: the name.
131 \li \a left_code: The \l Monomer code at the left of the cleavage site.
132 \li \a left_formula: .The \l Formula to be applied onto the left monomer code.
133 \li \a right_code: .The \l Monomer code at the right of the cleavage site.
134 \li \a right_formula: .The \l Formula to be applied onto the right monomer code.
135 \endlist
136
137 After setting the member data, the instance is validated and the result is set
138 to m_isValid.
139 */
140 90 CleavageRule::CleavageRule(PolChemDefCstSPtr pol_chem_def_csp,
141 const QString &name,
142 const QString &left_code,
143 const QString &left_formula,
144 const QString &right_code,
145 90 const QString &right_formula)
146 90 : mcsp_polChemDef(pol_chem_def_csp),
147
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
90 m_name(name),
148
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
90 m_leftCode(left_code),
149
1/2
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
90 m_leftFormula(left_formula),
150
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
90 m_rightCode(right_code),
151
1/2
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
90 m_rightFormula(right_formula)
152 {
153 90 ErrorList error_list;
154
1/2
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
90 m_isValid = validate(&error_list);
155
156
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
90 if(!m_isValid)
157 qCritical() << "Upon construction of CleavageRule, the instance failed to "
158 "validate with errors:"
159 << Utils::joinErrorList(error_list, ", ");
160
0/2
✗ Branch 5 not taken.
✗ Branch 6 not taken.
90 }
161
162 /*!
163 \brief Constructs a CleavageRule instance as a copy of \a other.
164
165 After setting the member data, the instance is validated and the result is set
166 to m_isValid.
167 */
168 6 CleavageRule::CleavageRule(const CleavageRule &other)
169 6 : mcsp_polChemDef(other.mcsp_polChemDef),
170
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 m_name(other.m_name),
171
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 m_leftCode(other.m_leftCode),
172
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 m_leftFormula(other.m_leftFormula),
173
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 m_rightCode(other.m_rightCode),
174
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 m_rightFormula(other.m_rightFormula)
175 {
176 6 ErrorList error_list;
177
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 m_isValid = validate(&error_list);
178
179
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if(!m_isValid)
180 qCritical()
181 << "Upon copy-construction of CleavageRule, the instance failed to "
182 "validate with errors:"
183 << Utils::joinErrorList(error_list, ", ");
184
0/2
✗ Branch 5 not taken.
✗ Branch 6 not taken.
6 }
185
186 /*!
187 \brief Destructs this CleavageRule instance
188 */
189 117 CleavageRule::~CleavageRule()
190 {
191
1/2
✓ Branch 5 taken 117 times.
✗ Branch 6 not taken.
117 }
192
193 /*!
194 \brief Sets the PolChemDef to \a pol_chem_def_csp.
195
196 After setting the member data, the instance is validated and the result is set
197 to m_isValid.
198 */
199 void
200 CleavageRule::setPolchemDefCstSPtr(PolChemDefCstSPtr pol_chem_def_csp)
201 {
202 mcsp_polChemDef = pol_chem_def_csp;
203
204 ErrorList error_list;
205 m_isValid = validate(&error_list);
206
207 if(!m_isValid)
208 qCritical()
209 << "Upon setting PolChemDef of CleavageRule, the instance failed to "
210 "validate with errors:"
211 << Utils::joinErrorList(error_list, ", ");
212 }
213
214 /*!
215 \brief Returns the PolChemDef.
216 */
217 PolChemDefCstSPtr
218 15 CleavageRule::getPolchemDefCstSPtr() const
219 {
220 15 return mcsp_polChemDef;
221 }
222
223 /*!
224 \brief Sets the name to \a name.
225
226 After setting the member data, the instance is validated and the result is set
227 to m_isValid.
228 */
229 void
230 9 CleavageRule::setName(const QString &name)
231 {
232 9 m_name = name;
233
234 9 ErrorList error_list;
235
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 m_isValid = validate(&error_list);
236
237
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
9 if(!m_isValid)
238
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 qCritical() << "Upon setting name of CleavageRule, the instance failed to "
239
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 "validate with errors:"
240
3/6
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
6 << Utils::joinErrorList(error_list, ", ");
241 9 }
242
243 /*!
244 \brief Returns the name.
245 */
246 const QString &
247 51 CleavageRule::getName() const
248 {
249 51 return m_name;
250 }
251
252 /*!
253 \brief Sets the left \a code.
254
255 After setting the member data, the instance is validated and the result is set
256 to m_isValid.
257 */
258 void
259 18 CleavageRule::setLeftCode(const QString &code)
260 {
261 18 m_leftCode = code;
262
263 18 ErrorList error_list;
264
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 m_isValid = validate(&error_list);
265
266
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
18 if(!m_isValid)
267
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
18 qCritical()
268 << "Upon setting left code of CleavageRule, the instance failed to "
269
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 "validate with errors:"
270
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, ", ");
271 18 }
272
273 /*!
274 \brief Returns the left code.
275 */
276 const QString &
277 69 CleavageRule::getLeftCode() const
278 {
279 69 return m_leftCode;
280 }
281
282 /*!
283 \brief Sets the right \a code.
284
285 After setting the member data, the instance is validated and the result is set
286 to m_isValid.
287 */
288 void
289 15 CleavageRule::setRightCode(const QString &code)
290 {
291 15 m_rightCode = code;
292
293 15 ErrorList error_list;
294
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 m_isValid = validate(&error_list);
295
296
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 6 times.
15 if(!m_isValid)
297
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
18 qCritical()
298 << "Upon setting right code of CleavageRule, the instance failed to "
299
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 "validate with errors:"
300
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, ", ");
301 15 }
302
303 /*!
304 \brief Returns the right code.
305 */
306 const QString &
307 105 CleavageRule::getRightCode() const
308 {
309 105 return m_rightCode;
310 }
311
312 /*!
313 \brief Sets the left \a formula.
314
315 After setting the member data, the instance is validated and the result is set
316 to m_isValid.
317 */
318 void
319 9 CleavageRule::setLeftFormula(const Formula &formula)
320 {
321 9 m_leftFormula = formula;
322
323 9 ErrorList error_list;
324
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 m_isValid = validate(&error_list);
325
326
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
9 if(!m_isValid)
327
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 qCritical()
328 << "Upon setting left formula of CleavageRule, the instance failed to "
329
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 "validate with errors:"
330
3/6
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
6 << Utils::joinErrorList(error_list, ", ");
331 9 }
332
333 /*!
334 \brief Returns the left formula.
335 */
336 const Formula &
337 30 CleavageRule::getLeftFormula() const
338 {
339 30 return m_leftFormula;
340 }
341
342 /*!
343 \brief Sets the right \a formula.
344
345 After setting the member data, the instance is validated and the result is set
346 to m_isValid.
347 */
348 void
349 9 CleavageRule::setRightFormula(const Formula &formula)
350 {
351 9 m_rightFormula = formula;
352
353 9 ErrorList error_list;
354
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 m_isValid = validate(&error_list);
355
356
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
9 if(!m_isValid)
357
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 qCritical()
358 << "Upon setting right formula of CleavageRule, the instance failed to "
359
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 "validate with errors:"
360
3/6
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
6 << Utils::joinErrorList(error_list, ", ");
361 9 }
362
363 /*!
364 \brief Returns the right formula.
365 */
366 const Formula &
367 69 CleavageRule::getRightFormula() const
368 {
369 69 return m_rightFormula;
370 }
371
372 //////////////// OPERATORS /////////////////////
373 /*!
374 \brief Assigns to \a other to this CleavageRule instance.
375
376 After setting the member data, the instance is validated and the result is set
377 to m_isValid.
378
379 Returns a reference to this CleavageRule instance.
380 */
381 CleavageRule &
382 CleavageRule::operator=(const CleavageRule &other)
383 {
384 if(&other == this)
385 return *this;
386
387 mcsp_polChemDef = other.mcsp_polChemDef;
388 m_name = other.m_name;
389
390 m_leftCode = other.m_leftCode;
391 m_leftFormula = other.m_leftFormula;
392
393 m_rightCode = other.m_rightCode;
394 m_rightFormula = other.m_rightFormula;
395
396 ErrorList error_list;
397 m_isValid = validate(&error_list);
398
399 if(!m_isValid)
400 qCritical() << "Upon assignment of CleavageRule, the instance failed to "
401 "validate with errors:"
402 << Utils::joinErrorList(error_list, ", ");
403
404 return *this;
405 }
406
407 /*!
408 \brief Returns true if \c this and \a other are identical.
409 */
410 bool
411 15 CleavageRule::operator==(const CleavageRule &other) const
412 {
413
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if(this == &other)
414 return true;
415
416 // We cannot compare the PolChemDef, because that would cause
417 // an infinite loop: (each instance of this class in the PolChemDef would
418 // try to compare the PolChemDef...).
419
420
3/6
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
30 return m_name == other.m_name && m_leftCode == other.m_leftCode &&
421
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
30 m_leftFormula == other.m_leftFormula &&
422
3/6
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
45 m_rightCode == other.m_rightCode &&
423 15 m_rightFormula == other.m_rightFormula;
424 }
425
426 /*!
427 \brief Returns true if \c this and \a other are different.
428 */
429 bool
430 63 CleavageRule::operator!=(const CleavageRule &other) const
431 {
432
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 54 times.
63 if(this == &other)
433 return false;
434
435 9 return !operator==(other);
436 }
437
438 //////////////// VALIDATIONS /////////////////////
439 /*!
440 \brief Validates this CleavageRule instance and stores error messages to \a
441 error_list_p.
442
443 Validation entails the following:
444
445 \list
446
447 \li The member PolChemDef cannot be nullptr;
448
449 \li The member name cannot be empty;
450
451 \li If the left monomer code is not empty, it must be known to the polymer
452 chemistry definition. In that case, if the left formula is not empty, it needs
453 to validate successfully.
454
455 \li The same logic is applied to the monomer at the right hand side of the
456 cleavage site.
457 \endlist
458
459 Sets m_isValid to true if the validation is successful, false otherwise.
460 Returns m_isValid.
461 */
462 bool
463 972 CleavageRule::validate(ErrorList *error_list_p) const
464 {
465 972 m_isValid = true;
466
467
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 972 times.
972 if(mcsp_polChemDef == nullptr || mcsp_polChemDef.get() == nullptr)
468 {
469 qCritical() << "A CleavageRule with no PolChemDef available cannot "
470 "validate successfully.";
471
472 m_isValid = false;
473
474 if(error_list_p)
475 error_list_p->push_back(
476 "A CleavageRule with no PolChemDef available cannot validate "
477 "successfully");
478 }
479
480
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 960 times.
972 if(m_name.isEmpty())
481 {
482 24 qCritical()
483
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 << "A CleavageRule with no name cannot validate successfully.";
484
485 12 m_isValid = false;
486
487
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if(error_list_p)
488 24 error_list_p->push_back(
489 "A CleavageRule with no name cannot validate successfully");
490 }
491
492
6/6
✓ Branch 0 taken 645 times.
✓ Branch 1 taken 327 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 639 times.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 966 times.
1617 if(m_leftCode.isEmpty() && !m_leftFormula.getActionFormula().isEmpty())
493 {
494 12 qCritical()
495 << "A CleavageRule without a left monomer code but with a left formula"
496
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 "cannot validate successfully.";
497
498 6 m_isValid = false;
499
500
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if(error_list_p)
501 12 error_list_p->push_back(
502 "A CleavageRule without a left monomer code but with a left formula "
503 "cannot validate "
504 "successfully");
505 }
506
507
2/2
✓ Branch 0 taken 327 times.
✓ Branch 1 taken 645 times.
972 if(!m_leftCode.isEmpty())
508 {
509
3/4
✓ Branch 0 taken 327 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 321 times.
654 if(mcsp_polChemDef != nullptr && mcsp_polChemDef.get() != nullptr &&
510
4/4
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 321 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 321 times.
654 mcsp_polChemDef->getMonomerCstSPtrByCode(m_leftCode) == nullptr)
511 {
512 12 qCritical() << "A CleavageRule with an unknown left monomer code "
513
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 "cannot validate successfully.";
514
515 6 m_isValid = false;
516
517
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if(error_list_p)
518 12 error_list_p->push_back(
519 "A CleavageRule with an unknown left monomer code cannot "
520 "validate "
521 "successfully");
522 }
523
524
2/2
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 324 times.
327 if(m_leftFormula.getActionFormula().isEmpty())
525 {
526 6 qCritical() << "A CleavageRule with an empty left formula cannot "
527
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 "validate successfully.";
528
529 3 m_isValid = false;
530
531
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if(error_list_p)
532 6 error_list_p->push_back(
533 "A CleavageRule with an empty left formula cannot validate "
534 "successfully");
535 }
536
3/4
✓ Branch 0 taken 324 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 318 times.
648 else if(mcsp_polChemDef != nullptr && mcsp_polChemDef.get() != nullptr &&
537
3/4
✓ Branch 2 taken 324 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 318 times.
648 !m_leftFormula.validate(mcsp_polChemDef->getIsotopicDataCstSPtr(),
538 error_list_p))
539 {
540 12 qCritical() << "A CleavageRule with an invalid left formula cannot "
541
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 "validate successfully.";
542
543 6 m_isValid = false;
544
545
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if(error_list_p)
546 12 error_list_p->push_back(
547 "A CleavageRule with an invalid left formula cannot validate "
548 "successfully");
549 }
550 }
551
552
6/6
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 951 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 966 times.
993 if(m_rightCode.isEmpty() && !m_rightFormula.getActionFormula().isEmpty())
553 {
554 12 qCritical() << "A CleavageRule without a right monomer code but with a "
555 "right formula"
556
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 "cannot validate successfully.";
557
558 6 m_isValid = false;
559
560
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if(error_list_p)
561 12 error_list_p->push_back(
562 "A CleavageRule without a right monomer code but with a right "
563 "formula "
564 "cannot validate "
565 "successfully");
566 }
567
568
2/2
✓ Branch 0 taken 951 times.
✓ Branch 1 taken 21 times.
972 if(!m_rightCode.isEmpty())
569 {
570
3/4
✓ Branch 0 taken 951 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 945 times.
1902 if(mcsp_polChemDef != nullptr && mcsp_polChemDef.get() != nullptr &&
571
4/4
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 945 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 945 times.
1902 mcsp_polChemDef->getMonomerCstSPtrByCode(m_rightCode) == nullptr)
572 {
573 12 qCritical() << "A CleavageRule with an unknown right monomer code "
574
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 "cannot validate successfully.";
575
576 6 m_isValid = false;
577
578
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if(error_list_p)
579 12 error_list_p->push_back(
580 "A CleavageRule with an unknown right monomer code cannot "
581 "validate "
582 "successfully");
583 }
584
585
2/2
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 948 times.
951 if(m_rightFormula.getActionFormula().isEmpty())
586 {
587 6 qCritical() << "A CleavageRule with an empty right formula cannot "
588
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 "validate successfully.";
589
590 3 m_isValid = false;
591
592
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if(error_list_p)
593 6 error_list_p->push_back(
594 "A CleavageRule with an empty right formula cannot validate "
595 "successfully");
596 }
597
3/4
✓ Branch 0 taken 948 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 942 times.
1896 else if(mcsp_polChemDef != nullptr && mcsp_polChemDef.get() != nullptr &&
598
1/2
✓ Branch 1 taken 948 times.
✗ Branch 2 not taken.
948 !m_rightFormula.validate(
599
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 942 times.
1896 mcsp_polChemDef->getIsotopicDataCstSPtr(), error_list_p))
600 {
601 12 qCritical() << "A CleavageRule with an invalid right formula cannot "
602
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 "validate successfully.";
603
604 6 m_isValid = false;
605
606
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if(error_list_p)
607 12 error_list_p->push_back(
608 "A CleavageRule with an invalid right formula cannot validate "
609 "successfully");
610 }
611 }
612
613 972 return m_isValid;
614 }
615
616 /*!
617 \brief Returns the validity status of this CleavageRule.
618 */
619 bool
620 48 CleavageRule::isValid() const
621 {
622 48 return m_isValid;
623 }
624
625 //////////////// XML DATA LOADING WRITING /////////////////////
626 /*!
627 \brief Parses the CleavageRule XML \a element using a \a{version}ed function.
628
629 Upon parsing of the \a element, its data are validated and set to this
630 CleavageRule instance, thus essentially initializing it.
631
632 Returns true if parsing and validation were successful, false otherwise.
633 */
634 bool
635 219 CleavageRule::renderXmlClrElement(const QDomElement &element,
636 [[maybe_unused]] int version)
637 {
638 219 QDomElement child;
639
640 219 bool leftCodeSet = false;
641 219 bool leftFormulaSet = false;
642 219 bool rightCodeSet = false;
643 219 bool rightFormulaSet = false;
644
645 /* The xml node we are in is structured this way:
646 *
647 * <clr>
648 * <name>Homeseryl</name>
649 * <le-mnm-code>M</le-mnm-code>
650 * <le-formula>-C1H2S1+O1</le-formula>
651 * <re-mnm-code>M</re-mnm-code>
652 * <re-formula>-C1H2S1+O1</re-formula>
653 * </clr>
654 *
655 * And the element parameter points to the
656 *
657 * <clr> element tag:
658 * ^
659 * |
660 * +----- here we are right now.
661 *
662 * Which means that xml_node->name == "clr" and that
663 * we'll have to go one step down to the first child of the
664 * current node in order to get to the <code> element.
665 *
666 * Note that the DTD stipulates that there can be no or one at most
667 * of each left end and/or right end set of data. So be careful
668 * with the assertions !
669 * This is the DTD material:
670 * <!ELEMENT clr((le-mnm-code,le-formula)?,
671 *(re-mnm-code,re-formula)?)>
672 */
673
674
2/4
✓ Branch 1 taken 219 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 219 times.
438 if(element.tagName() != "clr")
675 return false;
676
677
2/4
✓ Branch 1 taken 219 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 219 times.
✗ Branch 5 not taken.
438 child = element.firstChildElement();
678
679 219 if(version == 1)
680 {
681 // no-op
682
683 219 version = 1;
684 }
685
686
2/4
✓ Branch 1 taken 219 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 219 times.
438 if(child.tagName() != "name")
687 return false;
688
689
1/2
✓ Branch 1 taken 219 times.
✗ Branch 2 not taken.
219 m_name = child.text();
690
691
2/4
✓ Branch 1 taken 219 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 219 times.
✗ Branch 5 not taken.
438 child = child.nextSiblingElement();
692
693
3/4
✓ Branch 1 taken 687 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 468 times.
✓ Branch 4 taken 219 times.
687 while(!child.isNull())
694 {
695 // OK, apparently there is a child element, so let's try to see
696 // what's going on. It can either be "le-mnm-code" or "re-mnm-code".
697
698
3/4
✓ Branch 1 taken 468 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 453 times.
936 if(child.tagName() == "le-mnm-code")
699 {
700
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 m_leftCode = child.text();
701 15 leftCodeSet = true;
702 }
703
3/4
✓ Branch 1 taken 453 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 438 times.
906 else if(child.tagName() == "le-formula")
704 {
705
2/4
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
15 m_leftFormula.setActionFormula(child.text());
706 15 leftFormulaSet = true;
707 }
708
3/4
✓ Branch 1 taken 438 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 219 times.
✓ Branch 5 taken 219 times.
876 else if(child.tagName() == "re-mnm-code")
709 {
710
1/2
✓ Branch 1 taken 219 times.
✗ Branch 2 not taken.
219 m_rightCode = child.text();
711 219 rightCodeSet = true;
712 }
713
2/4
✓ Branch 1 taken 219 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 219 times.
✗ Branch 5 not taken.
438 else if(child.tagName() == "re-formula")
714 {
715
2/4
✓ Branch 1 taken 219 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 219 times.
✗ Branch 5 not taken.
219 m_rightFormula.setActionFormula(child.text());
716 219 rightFormulaSet = true;
717 }
718
719
2/4
✓ Branch 1 taken 468 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 468 times.
✗ Branch 5 not taken.
936 child = child.nextSiblingElement();
720 }
721
722 // OK, we just finished parsing this <clr> element. Check what we
723 // got.
724
725
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 204 times.
219 if(leftCodeSet)
726 {
727
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if(!leftFormulaSet)
728 return false;
729 }
730
731
1/2
✓ Branch 0 taken 219 times.
✗ Branch 1 not taken.
219 if(rightCodeSet)
732 {
733
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 219 times.
219 if(!rightFormulaSet)
734 return false;
735 }
736
737 // It cannot be that no single code could be set.
738
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 219 times.
219 if(!leftCodeSet && !rightCodeSet)
739 return false;
740
741 219 ErrorList error_list;
742
1/2
✓ Branch 1 taken 219 times.
✗ Branch 2 not taken.
219 m_isValid = validate(&error_list);
743
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 219 times.
219 if(!m_isValid)
744 {
745 qCritical() << "The CleavageRule rendered from <clr> element is invalid.";
746 }
747
748 219 qDebug() << "The <clr> element was rendered successfully.";
749
750 219 return m_isValid;
751 438 }
752
753 /*!
754 \brief Formats a string representing this CleavageRule instance suitable to use
755 as an XML element.
756
757 The typical cleavage rule element that is generated in this function looks like
758 this:
759
760 \code
761 <clr>
762 <re-mnm-code>M</re-mnm-code>
763 <re-formula>-CH2S+O</re-formula>
764 </clr>
765 \endcode
766
767 The formatting of the XML element takes into account \a offset and \a
768 indent by prepending the string with \a offset * \a indent character substring.
769
770 \a indent defaults to two spaces.
771
772 Returns a string.
773 */
774 QString
775 12 CleavageRule::formatXmlClrElement(int offset, const QString &indent)
776 {
777 12 int newOffset;
778 12 int iter = 0;
779
780 12 QString lead("");
781 12 QString text;
782
783
784 // Prepare the lead.
785 12 newOffset = offset;
786
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 12 times.
39 while(iter < newOffset)
787 {
788
1/2
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
27 lead += indent;
789 27 ++iter;
790 }
791
792 /*
793 <clr>
794 <re-mnm-code>M</re-mnm-code>
795 <re-formula>-CH2S+O</re-formula>
796 </clr>
797 */
798
799
2/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
24 text += QString("%1<clr>\n").arg(lead);
800
801 // Prepare the lead.
802 12 ++newOffset;
803 12 lead.clear();
804 12 iter = 0;
805
2/2
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 12 times.
63 while(iter < newOffset)
806 {
807
1/2
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
39 lead += indent;
808 39 ++iter;
809 }
810
811 // Continue with indented elements.
812
813
3/6
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 8 not taken.
24 text += QString("%1<name>%2</name>\n").arg(lead).arg(m_name);
814
815
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 3 times.
12 if(!m_leftCode.isEmpty())
816 {
817 9 Q_ASSERT(!m_leftFormula.getActionFormula().isEmpty());
818
819 9 text +=
820
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 QString("%1<le-mnm-code>%2</le-mnm-code>\n").arg(lead).arg(m_leftCode);
821
822
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 text += QString("%1<le-formula>%2</le-formula>\n")
823
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
18 .arg(lead)
824
2/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
27 .arg(m_leftFormula.getActionFormula());
825 }
826
827
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if(!m_rightCode.isEmpty())
828 {
829 12 Q_ASSERT(!m_rightFormula.getActionFormula().isEmpty());
830
831 12 text +=
832
3/6
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 8 not taken.
24 QString("%1<re-mnm-code>%2</re-mnm-code>\n").arg(lead).arg(m_rightCode);
833
834
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 text += QString("%1<re-formula>%2</re-formula>\n")
835
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
24 .arg(lead)
836
2/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
36 .arg(m_rightFormula.getActionFormula());
837 }
838
839 // Prepare the lead for the closing element.
840 12 --newOffset;
841 12 lead.clear();
842 12 iter = 0;
843
2/2
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 12 times.
51 while(iter < newOffset)
844 {
845
1/2
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
27 lead += indent;
846 27 ++iter;
847 }
848
849
2/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
24 text += QString("%1</clr>\n").arg(lead);
850
851 12 return text;
852 12 }
853
854
855 } // namespace libXpertMassCore
856 } // namespace MsXpS
857