GCC Code Coverage Report


source/XpertMassCore/src/
File: source/XpertMassCore/src/CleavageRule.cpp
Date: 2025-11-20 01:41:33
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 75 CleavageRule::CleavageRule(PolChemDefCstSPtr pol_chem_def_csp)
120
5/10
✓ Branch 2 taken 75 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 75 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 75 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 75 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 75 times.
✗ Branch 15 not taken.
75 : mcsp_polChemDef(pol_chem_def_csp)
121 {
122
0/2
✗ Branch 4 not taken.
✗ Branch 5 not taken.
75 }
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 30 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 30 const QString &right_formula)
146 30 : mcsp_polChemDef(pol_chem_def_csp),
147
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 m_name(name),
148
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 m_leftCode(left_code),
149
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 m_leftFormula(left_formula),
150
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 m_rightCode(right_code),
151
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 m_rightFormula(right_formula)
152 {
153 30 ErrorList error_list;
154
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 m_isValid = validate(&error_list);
155
156
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 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.
30 }
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 2 CleavageRule::CleavageRule(const CleavageRule &other)
169 2 : mcsp_polChemDef(other.mcsp_polChemDef),
170
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 m_name(other.m_name),
171
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 m_leftCode(other.m_leftCode),
172
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 m_leftFormula(other.m_leftFormula),
173
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 m_rightCode(other.m_rightCode),
174
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 m_rightFormula(other.m_rightFormula)
175 {
176 2 ErrorList error_list;
177
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 m_isValid = validate(&error_list);
178
179
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 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.
2 }
185
186 /*!
187 \brief Destructs this CleavageRule instance
188 */
189 39 CleavageRule::~CleavageRule()
190 {
191
1/2
✓ Branch 5 taken 39 times.
✗ Branch 6 not taken.
39 }
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 5 CleavageRule::getPolchemDefCstSPtr() const
219 {
220 5 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 3 CleavageRule::setName(const QString &name)
231 {
232 3 m_name = name;
233
234 3 ErrorList error_list;
235
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 m_isValid = validate(&error_list);
236
237
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if(!m_isValid)
238
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 qCritical() << "Upon setting name of CleavageRule, the instance failed to "
239
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 "validate with errors:"
240
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, ", ");
241 3 }
242
243 /*!
244 \brief Returns the name.
245 */
246 const QString &
247 17 CleavageRule::getName() const
248 {
249 17 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 6 CleavageRule::setLeftCode(const QString &code)
260 {
261 6 m_leftCode = code;
262
263 6 ErrorList error_list;
264
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 m_isValid = validate(&error_list);
265
266
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if(!m_isValid)
267
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 qCritical()
268 << "Upon setting left code of CleavageRule, the instance failed to "
269
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 "validate with errors:"
270
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, ", ");
271 6 }
272
273 /*!
274 \brief Returns the left code.
275 */
276 const QString &
277 23 CleavageRule::getLeftCode() const
278 {
279 23 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 5 CleavageRule::setRightCode(const QString &code)
290 {
291 5 m_rightCode = code;
292
293 5 ErrorList error_list;
294
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 m_isValid = validate(&error_list);
295
296
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 if(!m_isValid)
297
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 qCritical()
298 << "Upon setting right code of CleavageRule, the instance failed to "
299
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 "validate with errors:"
300
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, ", ");
301 5 }
302
303 /*!
304 \brief Returns the right code.
305 */
306 const QString &
307 35 CleavageRule::getRightCode() const
308 {
309 35 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 3 CleavageRule::setLeftFormula(const Formula &formula)
320 {
321 3 m_leftFormula = formula;
322
323 3 ErrorList error_list;
324
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 m_isValid = validate(&error_list);
325
326
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if(!m_isValid)
327
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 qCritical()
328 << "Upon setting left formula of CleavageRule, the instance failed to "
329
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 "validate with errors:"
330
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, ", ");
331 3 }
332
333 /*!
334 \brief Returns the left formula.
335 */
336 const Formula &
337 10 CleavageRule::getLeftFormula() const
338 {
339 10 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 3 CleavageRule::setRightFormula(const Formula &formula)
350 {
351 3 m_rightFormula = formula;
352
353 3 ErrorList error_list;
354
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 m_isValid = validate(&error_list);
355
356
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if(!m_isValid)
357
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 qCritical()
358 << "Upon setting right formula of CleavageRule, the instance failed to "
359
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 "validate with errors:"
360
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, ", ");
361 3 }
362
363 /*!
364 \brief Returns the right formula.
365 */
366 const Formula &
367 23 CleavageRule::getRightFormula() const
368 {
369 23 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 5 CleavageRule::operator==(const CleavageRule &other) const
412 {
413
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 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 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
10 return m_name == other.m_name && m_leftCode == other.m_leftCode &&
421
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
10 m_leftFormula == other.m_leftFormula &&
422
3/6
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
15 m_rightCode == other.m_rightCode &&
423 5 m_rightFormula == other.m_rightFormula;
424 }
425
426 /*!
427 \brief Returns true if \c this and \a other are different.
428 */
429 bool
430 21 CleavageRule::operator!=(const CleavageRule &other) const
431 {
432
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 18 times.
21 if(this == &other)
433 return false;
434
435 3 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 324 CleavageRule::validate(ErrorList *error_list_p) const
464 {
465 324 m_isValid = true;
466
467
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 324 times.
324 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 4 times.
✓ Branch 1 taken 320 times.
324 if(m_name.isEmpty())
481 {
482 8 qCritical()
483
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 << "A CleavageRule with no name cannot validate successfully.";
484
485 4 m_isValid = false;
486
487
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if(error_list_p)
488 8 error_list_p->push_back(
489 "A CleavageRule with no name cannot validate successfully");
490 }
491
492
6/6
✓ Branch 0 taken 215 times.
✓ Branch 1 taken 109 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 213 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 322 times.
539 if(m_leftCode.isEmpty() && !m_leftFormula.getActionFormula().isEmpty())
493 {
494 4 qCritical()
495 << "A CleavageRule without a left monomer code but with a left formula"
496
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 "cannot validate successfully.";
497
498 2 m_isValid = false;
499
500
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if(error_list_p)
501 4 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 109 times.
✓ Branch 1 taken 215 times.
324 if(!m_leftCode.isEmpty())
508 {
509
3/4
✓ Branch 0 taken 109 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 107 times.
218 if(mcsp_polChemDef != nullptr && mcsp_polChemDef.get() != nullptr &&
510
4/4
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 107 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 107 times.
218 mcsp_polChemDef->getMonomerCstSPtrByCode(m_leftCode) == nullptr)
511 {
512 4 qCritical() << "A CleavageRule with an unknown left monomer code "
513
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 "cannot validate successfully.";
514
515 2 m_isValid = false;
516
517
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if(error_list_p)
518 4 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 1 times.
✓ Branch 3 taken 108 times.
109 if(m_leftFormula.getActionFormula().isEmpty())
525 {
526 2 qCritical() << "A CleavageRule with an empty left formula cannot "
527
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 "validate successfully.";
528
529 1 m_isValid = false;
530
531
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(error_list_p)
532 2 error_list_p->push_back(
533 "A CleavageRule with an empty left formula cannot validate "
534 "successfully");
535 }
536
3/4
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 106 times.
216 else if(mcsp_polChemDef != nullptr && mcsp_polChemDef.get() != nullptr &&
537
3/4
✓ Branch 2 taken 108 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 106 times.
216 !m_leftFormula.validate(mcsp_polChemDef->getIsotopicDataCstSPtr(),
538 error_list_p))
539 {
540 4 qCritical() << "A CleavageRule with an invalid left formula cannot "
541
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 "validate successfully.";
542
543 2 m_isValid = false;
544
545
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if(error_list_p)
546 4 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 7 times.
✓ Branch 1 taken 317 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 322 times.
331 if(m_rightCode.isEmpty() && !m_rightFormula.getActionFormula().isEmpty())
553 {
554 4 qCritical() << "A CleavageRule without a right monomer code but with a "
555 "right formula"
556
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 "cannot validate successfully.";
557
558 2 m_isValid = false;
559
560
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if(error_list_p)
561 4 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 317 times.
✓ Branch 1 taken 7 times.
324 if(!m_rightCode.isEmpty())
569 {
570
3/4
✓ Branch 0 taken 317 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 315 times.
634 if(mcsp_polChemDef != nullptr && mcsp_polChemDef.get() != nullptr &&
571
4/4
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 315 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 315 times.
634 mcsp_polChemDef->getMonomerCstSPtrByCode(m_rightCode) == nullptr)
572 {
573 4 qCritical() << "A CleavageRule with an unknown right monomer code "
574
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 "cannot validate successfully.";
575
576 2 m_isValid = false;
577
578
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if(error_list_p)
579 4 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 1 times.
✓ Branch 3 taken 316 times.
317 if(m_rightFormula.getActionFormula().isEmpty())
586 {
587 2 qCritical() << "A CleavageRule with an empty right formula cannot "
588
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 "validate successfully.";
589
590 1 m_isValid = false;
591
592
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(error_list_p)
593 2 error_list_p->push_back(
594 "A CleavageRule with an empty right formula cannot validate "
595 "successfully");
596 }
597
3/4
✓ Branch 0 taken 316 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 314 times.
632 else if(mcsp_polChemDef != nullptr && mcsp_polChemDef.get() != nullptr &&
598
1/2
✓ Branch 1 taken 316 times.
✗ Branch 2 not taken.
316 !m_rightFormula.validate(
599
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 314 times.
632 mcsp_polChemDef->getIsotopicDataCstSPtr(), error_list_p))
600 {
601 4 qCritical() << "A CleavageRule with an invalid right formula cannot "
602
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 "validate successfully.";
603
604 2 m_isValid = false;
605
606
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if(error_list_p)
607 4 error_list_p->push_back(
608 "A CleavageRule with an invalid right formula cannot validate "
609 "successfully");
610 }
611 }
612
613 324 return m_isValid;
614 }
615
616 /*!
617 \brief Returns the validity status of this CleavageRule.
618 */
619 bool
620 16 CleavageRule::isValid() const
621 {
622 16 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 73 CleavageRule::renderXmlClrElement(const QDomElement &element,
636 [[maybe_unused]] int version)
637 {
638 73 QDomElement child;
639
640 73 bool leftCodeSet = false;
641 73 bool leftFormulaSet = false;
642 73 bool rightCodeSet = false;
643 73 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 73 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 73 times.
146 if(element.tagName() != "clr")
675 return false;
676
677
2/4
✓ Branch 1 taken 73 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 73 times.
✗ Branch 5 not taken.
146 child = element.firstChildElement();
678
679 73 if(version == 1)
680 {
681 // no-op
682
683 73 version = 1;
684 }
685
686
2/4
✓ Branch 1 taken 73 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 73 times.
146 if(child.tagName() != "name")
687 return false;
688
689
1/2
✓ Branch 1 taken 73 times.
✗ Branch 2 not taken.
73 m_name = child.text();
690
691
2/4
✓ Branch 1 taken 73 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 73 times.
✗ Branch 5 not taken.
146 child = child.nextSiblingElement();
692
693
3/4
✓ Branch 1 taken 229 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 156 times.
✓ Branch 4 taken 73 times.
229 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 156 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 151 times.
312 if(child.tagName() == "le-mnm-code")
699 {
700
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 m_leftCode = child.text();
701 5 leftCodeSet = true;
702 }
703
3/4
✓ Branch 1 taken 151 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 146 times.
302 else if(child.tagName() == "le-formula")
704 {
705
2/4
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
5 m_leftFormula.setActionFormula(child.text());
706 5 leftFormulaSet = true;
707 }
708
3/4
✓ Branch 1 taken 146 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 73 times.
✓ Branch 5 taken 73 times.
292 else if(child.tagName() == "re-mnm-code")
709 {
710
1/2
✓ Branch 1 taken 73 times.
✗ Branch 2 not taken.
73 m_rightCode = child.text();
711 73 rightCodeSet = true;
712 }
713
2/4
✓ Branch 1 taken 73 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 73 times.
✗ Branch 5 not taken.
146 else if(child.tagName() == "re-formula")
714 {
715
2/4
✓ Branch 1 taken 73 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 73 times.
✗ Branch 5 not taken.
73 m_rightFormula.setActionFormula(child.text());
716 73 rightFormulaSet = true;
717 }
718
719
2/4
✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 156 times.
✗ Branch 5 not taken.
312 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 5 times.
✓ Branch 1 taken 68 times.
73 if(leftCodeSet)
726 {
727
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if(!leftFormulaSet)
728 return false;
729 }
730
731
1/2
✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
73 if(rightCodeSet)
732 {
733
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 73 times.
73 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 73 times.
73 if(!leftCodeSet && !rightCodeSet)
739 return false;
740
741 73 ErrorList error_list;
742
1/2
✓ Branch 1 taken 73 times.
✗ Branch 2 not taken.
73 m_isValid = validate(&error_list);
743
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 73 times.
73 if(!m_isValid)
744 {
745 qCritical() << "The CleavageRule rendered from <clr> element is invalid.";
746 }
747
748 73 qDebug() << "The <clr> element was rendered successfully.";
749
750 73 return m_isValid;
751 146 }
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 4 CleavageRule::formatXmlClrElement(int offset, const QString &indent)
776 {
777 4 int newOffset;
778 4 int iter = 0;
779
780 4 QString lead("");
781 4 QString text;
782
783
784 // Prepare the lead.
785 4 newOffset = offset;
786
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 4 times.
13 while(iter < newOffset)
787 {
788
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 lead += indent;
789 9 ++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 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
8 text += QString("%1<clr>\n").arg(lead);
800
801 // Prepare the lead.
802 4 ++newOffset;
803 4 lead.clear();
804 4 iter = 0;
805
2/2
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 4 times.
21 while(iter < newOffset)
806 {
807
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 lead += indent;
808 13 ++iter;
809 }
810
811 // Continue with indented elements.
812
813
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 text += QString("%1<name>%2</name>\n").arg(lead).arg(m_name);
814
815
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if(!m_leftCode.isEmpty())
816 {
817 3 Q_ASSERT(!m_leftFormula.getActionFormula().isEmpty());
818
819 3 text +=
820
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 QString("%1<le-mnm-code>%2</le-mnm-code>\n").arg(lead).arg(m_leftCode);
821
822
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 text += QString("%1<le-formula>%2</le-formula>\n")
823
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 .arg(lead)
824
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
9 .arg(m_leftFormula.getActionFormula());
825 }
826
827
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if(!m_rightCode.isEmpty())
828 {
829 4 Q_ASSERT(!m_rightFormula.getActionFormula().isEmpty());
830
831 4 text +=
832
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 QString("%1<re-mnm-code>%2</re-mnm-code>\n").arg(lead).arg(m_rightCode);
833
834
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 text += QString("%1<re-formula>%2</re-formula>\n")
835
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 .arg(lead)
836
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
12 .arg(m_rightFormula.getActionFormula());
837 }
838
839 // Prepare the lead for the closing element.
840 4 --newOffset;
841 4 lead.clear();
842 4 iter = 0;
843
2/2
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 4 times.
17 while(iter < newOffset)
844 {
845
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 lead += indent;
846 9 ++iter;
847 }
848
849
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
8 text += QString("%1</clr>\n").arg(lead);
850
851 4 return text;
852 4 }
853
854
855 } // namespace libXpertMassCore
856 } // namespace MsXpS
857