GCC Code Coverage Report


source/XpertMassCore/src/
File: source/XpertMassCore/src/ChemicalGroupRule.cpp
Date: 2025-11-20 01:41:33
Lines:
67/98
68.4%
Functions:
12/13
92.3%
Branches:
45/124
36.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/ChemicalGroupRule.hpp"
36
37
38 namespace MsXpS
39 {
40
41 namespace libXpertMassCore
42 {
43
44
45 /*!
46 \class MsXpS::libXpertMassCore::ChemicalGroupRule
47 \inmodule libXpertMassCore
48 \ingroup PolChemDefBuildingdBlocks
49 \inheaderfile ChemicalGroupRule.hpp
50
51 \brief The ChemicalGroupRule class provides a model for refining the
52 acido-basic behaviour of a chemical group of either a \l Monomer object or of a
53 \l Modif object.
54
55 In an pkaphpidata definition file, the following xml structure
56 is encountered:
57
58 \code
59 <pkaphpidata>
60 <monomers>
61 <monomer>
62 <code>A</code>
63 <mnmchemgroup>
64 <name>N-term NH2</name>
65 <pka>9.6</pka>
66 <acidcharged>TRUE</acidcharged>
67 <polrule>left_trapped</polrule>
68 <chemgrouprule>
69 <entity>LE_PLM_MODIF</entity>
70 <name>Acetylation</name>
71 <outcome>LOST</outcome>
72 </chemgrouprule>
73 </mnmchemgroup>
74 <mnmchemgroup>
75 <name>C-term COOH</name>
76 <pka>2.35</pka>
77 <acidcharged>FALSE</acidcharged>
78 <polrule>right_trapped</polrule>
79 </mnmchemgroup>
80 </monomer>
81 <monomer>
82 <code>C</code>
83 <mnmchemgroup>
84 <name>N-term NH2</name>
85 <pka>9.6</pka>
86 <acidcharged>TRUE</acidcharged>
87 <polrule>left_trapped</polrule>
88 <chemgrouprule>
89 <entity>LE_PLM_MODIF</entity>
90 <name>Acetylation</name>
91 <outcome>LOST</outcome>
92 </chemgrouprule>
93 </mnmchemgroup>
94 <mnmchemgroup>
95 <name>C-term COOH</name>
96 <pka>2.35</pka>
97 <acidcharged>FALSE</acidcharged>
98 <polrule>right_trapped</polrule>
99 </mnmchemgroup>
100 <mnmchemgroup>
101 <name>Lateral SH2</name>
102 <pka>8.3</pka>
103 <acidcharged>FALSE</acidcharged>
104 <polrule>never_trapped</polrule>
105 </mnmchemgroup>
106 </monomer>
107 .....
108 <modifs>
109 <modif>
110 <name>Phosphorylation</name>
111 <mdfchemgroup>
112 <name>none_set</name>
113 <pka>1.2</pka>
114 <acidcharged>FALSE</acidcharged>
115 </mdfchemgroup>
116 <mdfchemgroup>
117 <name>none_set</name>
118 <pka>6.5</pka>
119 <acidcharged>FALSE</acidcharged>
120 </mdfchemgroup>
121 </modif>
122 </modifs>
123 </pkaphpidata>
124 \endcode
125
126 \sa ChemicalGroup,
127 */
128
129
130 /*!
131 \variable MsXpS::libXpertMassCore::ChemicalGroupRule::m_name
132
133 \brief The name of the ChemicalGroupRule instance.
134 */
135
136 /*!
137 \variable MsXpS::libXpertMassCore::ChemicalGroupRule::m_entity
138
139 \brief The entity of the ChemicalGroupRule instance, like LE_PLM_MODIF for
140 \e{left end polymer modification}.
141 */
142
143 /*!
144 \variable MsXpS::libXpertMassCore::ChemicalGroupRule::m_chemicalGroupFate
145
146 \brief The fate of the ChemicalGroupRule instance.
147
148 \sa MsXpS::libXpertMassCore::Enums::ChemicalGroupFate
149 */
150
151 /*!
152 \brief Constructs a ChemicalGroupRule instance.
153
154 \list
155 \li \a name: The name of this ChemicalGroupRule instance.
156 \li \a entity: The entity of this ChemicalGroupRule instance.
157 \li \a fate: The fate of this ChemicalGroupRule instance.
158 \endlist
159 */
160 7 ChemicalGroupRule::ChemicalGroupRule(const QString &name,
161 const QString &entity,
162 7 Enums::ChemicalGroupFate fate)
163
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
7 : m_name(name), m_entity(entity), m_chemicalGroupFate(fate)
164 {
165 7 Q_ASSERT(m_chemicalGroupFate == Enums::ChemicalGroupFate::LOST ||
166 m_chemicalGroupFate == Enums::ChemicalGroupFate::PRESERVED);
167 7 }
168
169 /*!
170 \brief Constructs a ChemicalGroupRule instance as a copy of \a other.
171 */
172 8 ChemicalGroupRule::ChemicalGroupRule(const ChemicalGroupRule &other)
173
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 : m_name(other.m_name),
174
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 m_entity(other.m_entity),
175 8 m_chemicalGroupFate(other.m_chemicalGroupFate),
176 8 m_isValid(other.m_isValid)
177 {
178 8 }
179
180 /*!
181 \ brief Constructs this ChemicalGroupRule
182 */
183 15 ChemicalGroupRule::~ChemicalGroupRule()
184 {
185 15 }
186
187 /*!
188 \brief Sets the \a name.
189 */
190 void
191 5 ChemicalGroupRule::setName(const QString &name)
192 {
193 5 m_name = name;
194
195 5 ErrorList error_list;
196
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 m_isValid = validate(&error_list);
197
198
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if(!m_isValid)
199 {
200
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
10 qCritical()
201
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 << "After setting name, the object did not validate successfully.";
202 }
203 5 }
204
205
206 /*!
207 \brief Returns the name.
208 */
209 QString
210 23 ChemicalGroupRule::getName()
211 {
212
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 return m_name;
213 }
214
215
216 /*!
217 \brief Sets the \a entity.
218 */
219 void
220 5 ChemicalGroupRule::setEntity(const QString &entity)
221 {
222 5 m_entity = entity;
223
224 5 ErrorList error_list;
225
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 m_isValid = validate(&error_list);
226
227
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if(!m_isValid)
228 {
229 qCritical()
230 << "After setting entity, the object did not validate successfully.";
231 }
232 5 }
233
234 /*!
235 \brief Returns the entity.
236 */
237 QString
238 27 ChemicalGroupRule::getEntity()
239 {
240
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 return m_entity;
241 }
242
243 /*!
244 \brief Sets the \a fate.
245 */
246 void
247 5 ChemicalGroupRule::setFate(Enums::ChemicalGroupFate fate)
248 {
249 5 m_chemicalGroupFate = fate;
250
251 5 ErrorList error_list;
252
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 m_isValid = validate(&error_list);
253
254
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if(!m_isValid)
255 {
256 qCritical()
257 << "After setting fate, the object did not validate successfully.";
258 }
259 5 }
260
261 /*!
262 \brief Returns the fate.
263 */
264 Enums::ChemicalGroupFate
265 1 ChemicalGroupRule::getFate()
266 {
267 1 return m_chemicalGroupFate;
268 }
269
270 /*!
271 \brief Assigns \a other to this instance.
272 */
273 ChemicalGroupRule &
274 ChemicalGroupRule::operator=(const ChemicalGroupRule &other)
275 {
276 if(&other == this)
277 return *this;
278
279 m_name = other.m_name;
280 m_entity = other.m_entity;
281 m_chemicalGroupFate = other.m_chemicalGroupFate;
282 m_isValid = other.m_isValid;
283
284 return *this;
285 }
286
287 /*!
288 \brief Validates this instance, setting eventual error messages to \a
289 error_list_p.
290
291 \note \a error_list_p is not cleared.
292
293 Following a successful validation, m_isValid is set to true, to false
294 otherwise and that result is returned.
295 */
296 bool
297 16 ChemicalGroupRule::validate(ErrorList *error_list_p) const
298 {
299
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 qsizetype error_count = error_list_p->size();
300
301
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if(m_name.isEmpty())
302 {
303 qCritical()
304 << "The ChemicalGroupRule cannot validate with an empty name.";
305 error_list_p->push_back(
306 "The ChemicalGroupRule cannot validate with an empty name");
307 }
308
309
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 11 times.
16 if(m_entity.isEmpty())
310 {
311 10 qCritical()
312
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 << "The ChemicalGroupRule cannot validate with an empty entity.";
313 10 error_list_p->push_back(
314 "The ChemicalGroupRule cannot validate with an empty entity");
315 }
316
317 16 m_isValid = error_list_p->size() > error_count ? false : true;
318
319 16 return m_isValid;
320 }
321
322 /*!
323 \brief Returns the validity status of this instance.
324 */
325 bool
326 2 ChemicalGroupRule::isValid() const
327 {
328 2 return m_isValid;
329 }
330
331 /*!
332 \brief Parses the ChemicalGroupRule XML \a element.
333
334 Upon parsing of the \a element, its data are validated and set to this
335 ChemicalGroupRule instance, thus essentially initializing it.
336
337 Returns true if parsing and validation were successful, false otherwise.
338 */
339 bool
340 1 ChemicalGroupRule::renderXmlElement(const QDomElement &element)
341 {
342 1 QDomElement child;
343
344 // In an acidobasic definition file, the following xml structure
345 // is encountered:
346
347 // <monomer>
348 // <code>C</code>
349 // <mnmchemgroup>
350 // <name>N-term NH2</name>
351 // <pka>9.6</pka>
352 // <acidcharged>TRUE</acidcharged>
353 // <polrule>left_trapped</polrule>
354 // <chemgrouprule>
355 // <entity>LE_PLM_MODIF</entity>
356 // <name>Acetylation</name>
357 // <outcome>LOST</outcome>
358 // </chemgrouprule>
359 // </mnmchemgroup>
360
361 // The relevant DTD line is:
362 // <!ELEMENT chemgrouprule(entity,name,outcome)>
363
364 // And the element the parameter points to is:
365
366 // <chemgrouprule>
367
368 // Which means that element.tagName() == "chemgrouprule" and that we'll
369 // have to go one step down to the first child of the current node
370 // in order to get to the <entity> element.
371
372
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
2 if(element.tagName() != "chemgrouprule")
373 {
374 qCritical() << "Failed to render <chemgrouprule> element: "
375 "<chemgrouprule> element not found.";
376 return false;
377 }
378
379
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 child = element.firstChildElement("entity");
380
381
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 if(child.isNull())
382 {
383 qCritical() << "Failed to render <chemgrouprule> element: <entity> "
384 "element not found.";
385 return false;
386 }
387
388
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 m_entity = child.text();
389
390
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 child = child.nextSiblingElement();
391
392
5/10
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
2 if(child.isNull() || child.tagName() != "name")
393 {
394 qCritical() << "Failed to render <chemgrouprule> element: <name> element "
395 "not found.";
396 return false;
397 }
398
399
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 m_name = child.text();
400
401
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 child = child.nextSiblingElement();
402
403
5/10
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
2 if(child.isNull() || child.tagName() != "outcome")
404 {
405 qCritical() << "Failed to render <chemgrouprule> element: <outcome> "
406 "element not found.";
407 return false;
408 }
409
410
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 if(child.text() == "LOST")
411 1 m_chemicalGroupFate = Enums::ChemicalGroupFate::LOST;
412 else if(child.text() == "PRESERVED")
413 m_chemicalGroupFate = Enums::ChemicalGroupFate::PRESERVED;
414 else
415 {
416 qCritical() << "Failed to render <chemgrouprule> element: <outcome> "
417 "element had bad value.";
418 return false;
419 }
420
421 1 ErrorList error_list;
422
423
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 m_isValid = validate(&error_list);
424
425 1 return m_isValid;
426 2 }
427
428
429 } // namespace libXpertMassCore
430 } // namespace MsXpS
431