• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pcolby / doxlee / 9041885859

11 May 2024 06:52AM UTC coverage: 74.501% (+0.2%) from 74.286%
9041885859

push

github

pcolby
Apply categories to all log output

11 of 46 new or added lines in 3 files covered. (23.91%)

6 existing lines in 3 files now uncovered.

336 of 451 relevant lines covered (74.5%)

1188.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.03
/src/doxml.cpp
1
// SPDX-FileCopyrightText: 2021-2024 Paul Colby <git@colby.id.au>
2
// SPDX-License-Identifier: LGPL-3.0-or-later
3

4
#include "doxml.h"
5

6
#include "variant.h"
7

8
#include <QCoreApplication>
9
#include <QDebug>
10
#include <QLoggingCategory>
11
#include <QXmlStreamReader>
12

13
/// Shorten the QStringLiteral macro for readability.
14
#define QSL(str) QStringLiteral(str)
15

16
/// Shorten QCoreApplication::translate calls for readability.
17
#define QTR(str) QCoreApplication::translate("doxml", str)
18

19
namespace doxlee {
20

21
namespace doxml {
22

23
static Q_LOGGING_CATEGORY(lc, "doxlee.doxml", QtInfoMsg);
96✔
24

25
QPair<QStringList,QStringList> kinds(const QDir &doxmlDir)
24✔
26
{
27
    return kinds(doxmlDir.absoluteFilePath(QSL("index.xsd")));
42✔
28
}
29

30
QPair<QStringList,QStringList> kinds(const QString &indexXsdPath)
24✔
31
{
32
    // Open the file for reading.
33
    QFile file(indexXsdPath);
24✔
34
    if (!file.open(QIODevice::ReadOnly|QIODevice::Text)) {
24✔
NEW
35
        qCWarning(lc).noquote() << QTR("Error opening file for reading: %1").arg(indexXsdPath);
×
36
        return { };
37
    }
38

39
    QStringList compoundKinds, memberKinds;
18✔
40

41
    // Parse the opening <schema> element.
42
    QXmlStreamReader xml(&file);
24✔
43
    if (!xml.readNextStartElement()) {
24✔
NEW
44
        qCWarning(lc).noquote() << QTR("Invalid XML file: %1 - %2").arg(indexXsdPath, xml.errorString());
×
45
        return { };
46
    }
47
    if (xml.name() != QSL("schema")) {
30✔
NEW
48
        qCWarning(lc).noquote() << QTR("File is not a Doxygen XML index schema: %1 - %2")
×
NEW
49
            .arg(indexXsdPath, xml.name().toString());
×
50
        return { };
51
    }
52

53
    // Parse the contained 'kind' elements.
54
    while ((!xml.atEnd()) && (xml.readNextStartElement())) {
192✔
55
        if (xml.name() == QSL("simpleType")) {
336✔
56
            const QString nameAttribute = xml.attributes().value(QSL("name")).toString();
84✔
57
            if ((nameAttribute == QSL("CompoundKind")) || (nameAttribute == QSL("MemberKind"))) {
84✔
58
                while ((!xml.atEnd()) && (xml.readNextStartElement())) {
96✔
59
                    if (xml.name() == QSL("restriction")) {
96✔
60
                        QStringList &kindsList = (nameAttribute == QLatin1String("CompoundKind"))
84✔
61
                            ? compoundKinds : memberKinds;
48✔
62
                        while ((!xml.atEnd()) && (xml.readNextStartElement())) {
696✔
63
                            if (xml.name() == QSL("enumeration")) {
1,296✔
64
                                kindsList.append(xml.attributes().value(QSL("value")).toString());
1,134✔
65
                            }
66
                            xml.skipCurrentElement();
648✔
67
                        }
68
                    } else xml.skipCurrentElement();
×
69
                }
70
            } else xml.skipCurrentElement();
×
71
        } else xml.skipCurrentElement();
132✔
72
    }
73
    qCInfo(lc).noquote() << QTR("Parsed %1 compound kind(s), and %2 member kind(s) from %3")
60✔
74
        .arg(compoundKinds.size()).arg(memberKinds.size()).arg(indexXsdPath);
42✔
75
    return { compoundKinds, memberKinds };
24✔
76
}
48✔
77

78
QVariantMap parseIndex(const QDir &doxmlDir, const bool extraIndexes)
24✔
79
{
80
    return parseIndex(doxmlDir.absoluteFilePath(QSL("index.xml")), extraIndexes);
42✔
81
}
82

83
QVariantMap parseIndex(const QString &indexXmlPath, const bool extraIndexes)
24✔
84
{
85
    // Open the file for reading.
86
    QFile file(indexXmlPath);
24✔
87
    if (!file.open(QIODevice::ReadOnly|QIODevice::Text)) {
24✔
NEW
88
        qCWarning(lc).noquote() << QTR("Error opening file for reading: %1").arg(indexXmlPath);
×
89
        return QVariantMap();
90
    }
91

92
    // Parse the opening <doxygenindex> element.
93
    QXmlStreamReader xml(&file);
24✔
94
    if (!xml.readNextStartElement()) {
24✔
NEW
95
        qCWarning(lc).noquote() << QTR("Invalid XML file: %1 - %2").arg(indexXmlPath, xml.errorString());
×
96
        return QVariantMap();
97
    }
98
    qCDebug(lc) << xml.name() << "version" << xml.attributes().value(QSL("version"))
30✔
UNCOV
99
             << xml.attributes().value(QSL("xml:lang")).toString();
×
100
    if (xml.name() != QSL("doxygenindex")) {
30✔
NEW
101
        qCWarning(lc).noquote() << QTR("File is not a Doxygen XML index: %1 - %2")
×
102
                                .arg(indexXmlPath, xml.name().toString());
×
103
        return QVariantMap();
104
    }
105
    QVariantMap indexMap;
18✔
106
    indexMap.insert(QSL("doxygenVersion"), xml.attributes().value(QSL("version")).toString());
60✔
107
    indexMap.insert(QSL("doxygenLanguage"), xml.attributes().value(QSL("xml:lang")).toString());
60✔
108

109
    // Parse the contained <compound> elements.
110
    QVariantList compounds;
18✔
111
    while ((!xml.atEnd()) && (xml.readNextStartElement())) {
192✔
112
        if (xml.name() == QSL("compound")) {
336✔
113
            QVariantMap compound;
126✔
114
            compound.insert(QSL("refid"), xml.attributes().value(QSL("refid")).toString());
420✔
115
            compound.insert(QSL("kind"), xml.attributes().value(QSL("kind")).toString());
420✔
116
            if ((!xml.readNextStartElement()) || (xml.name() != QSL("name"))) {
336✔
NEW
117
                qCWarning(lc).noquote() << QTR(" %1:%2:%3 <compound> does not begin with <name>")
×
118
                    .arg(indexXmlPath).arg(xml.lineNumber()).arg(xml.columnNumber());
×
119
                return QVariantMap();
120
            }
121
            compound.insert(QSL("name"), xml.readElementText());
294✔
122
            //qCDebug(lc) << __func__ << "compound" << compound;
123
            QVariantList members;
126✔
124
            while ((!xml.atEnd()) && (xml.readNextStartElement())) {
576✔
125
                if (xml.name() == QSL("member")) {
816✔
126
                    QVariantMap member;
306✔
127
                    member.insert(QSL("refid"), xml.attributes().value(QSL("refid")).toString());
1,020✔
128
                    member.insert(QSL("kind"), xml.attributes().value(QSL("kind")).toString());
1,020✔
129
                    if ((!xml.readNextStartElement()) || (xml.name() != QSL("name"))) {
816✔
NEW
130
                        qCWarning(lc).noquote() << QTR("%1:%2:%3 <member> does not begin with <name>")
×
131
                            .arg(indexXmlPath).arg(xml.lineNumber()).arg(xml.columnNumber());
×
132
                        return QVariantMap();
133
                    }
134
                    member.insert(QSL("name"), xml.readElementText());
714✔
135
                    //qCDebug(lc) << __func__ << "member" << member;
136
                    members.append(member);
714✔
137
                    xml.skipCurrentElement();
408✔
138
                } else {
102✔
NEW
139
                    qCWarning(lc).noquote() << QTR("Skipping unknown <%1> element at %2:%3:%4")
×
140
                        .arg(xml.name().toString(), indexXmlPath).arg(xml.lineNumber()).arg(xml.columnNumber());
×
141
                    xml.skipCurrentElement();
×
142
                }
143
            }
144
            compound.insert(QSL("members"), members);
294✔
145
            compounds.append(compound);
294✔
146
        } else {
42✔
NEW
147
            qCWarning(lc).noquote() << QTR("Skipping unknown <%1> element at %2:%3:%4")
×
148
                .arg(xml.name().toString(), indexXmlPath).arg(xml.lineNumber()).arg(xml.columnNumber());
×
149
            xml.skipCurrentElement();
×
150
        }
151
    }
152
    qCInfo(lc).noquote() << QTR("Parsed %1 compound(s) from %2").arg(compounds.size()).arg(indexXmlPath);
60✔
153
    indexMap.insert(QSL("compoundsList"), compounds);
42✔
154
    if (extraIndexes) {
24✔
155
        #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
156
        indexMap.insert(doxml::extraIndexes(compounds));
42✔
157
        #else
158
        const QVariantMap extra = doxml::extraIndexes(compounds);
159
        for (auto iter = extra.constBegin(); iter != extra.constEnd(); ++iter) {
160
            indexMap.insert(iter.key(), iter.value());
161
        }
162
        #endif
163
    }
164
    return indexMap;
165
}
24✔
166

167
QVariantMap extraIndexes(const QVariantList &compounds)
24✔
168
{
169
    QHash<QString,QVariantList> compoundsByKind, membersByKind;
18✔
170
    QVariantMap compoundsByRefId, membersByRefId;
18✔
171
    for (const QVariant &compound: compounds) {
192✔
172
        const QVariantMap compoundMap = compound.toMap();
168✔
173
        {
174
            const QString kind = compoundMap.value(QSL("kind")).toString();
336✔
175
            const QString refid = compoundMap.value(QSL("refid")).toString();
336✔
176
            compoundsByKind[kind].append(compound);
168✔
177
            compoundsByRefId.insert(refid, compound);
168✔
178
        }
42✔
179

180
        const QVariantList members = compoundMap.value(QSL("members")).toList();
336✔
181
        for (const QVariant &member: members) {
576✔
182
            const QVariantMap memberMap = member.toMap();
408✔
183
            const QString kind = memberMap.value(QSL("kind")).toString();
816✔
184
            const QString refid = memberMap.value(QSL("refid")).toString();
816✔
185
            membersByKind[kind].append(member);
408✔
186
            membersByRefId.insert(refid, member);
408✔
187
        }
102✔
188
    }
42✔
189
    for (QVariantList &compoundsList: compoundsByKind) sortBy(compoundsList, QSL("name"));
198✔
190
    for (QVariantList &membersList: membersByKind)     sortBy(membersList,   QSL("name"));
114✔
191
    return QVariantMap{
192
        { QSL("compoundsByKind" ), toVariant(compoundsByKind) },
48✔
193
        { QSL("compoundsByRefId"), compoundsByRefId           },
24✔
194
        { QSL("membersByKind"   ), toVariant(membersByKind)   },
48✔
195
        { QSL("membersByRefId"  ), membersByRefId             },
24✔
196
    };
186✔
197
}
24✔
198

199
QVariantMap parseCompound(const QDir &doxmlDir, const QString &refId)
72✔
200
{
201
    return parseCompound(doxmlDir.absoluteFilePath(QSL("%1.xml").arg(refId)));
126✔
202
}
203

204
QVariantMap parseCompound(const QString &compoundXmlPath)
72✔
205
{
206
    QFile file(compoundXmlPath);
72✔
207
    if (!file.open(QIODevice::ReadOnly|QIODevice::Text)) {
72✔
NEW
208
        qCWarning(lc).noquote() << QTR("Error opening file for reading: %1").arg(compoundXmlPath);
×
209
        return QVariantMap();
210
    }
211
    QXmlStreamReader xml(&file);
72✔
212

213
    /// \todo Transform map to our desired structure
214
    const QVariantMap map = toVariant(xml);
144✔
215

216
    const QVariantMap compoundDefinition = map.value(QSL("doxygen")).toMap()
144✔
217
        .value(QSL("compounddef")).toMap();
144✔
218
    if (compoundDefinition.isEmpty()) {
72✔
NEW
219
        qCWarning(lc).noquote() << QTR("Error reading compond defintion: %1").arg(compoundXmlPath);
×
220
        return QVariantMap();
221
    }
222

223
    return compoundDefinition;
18✔
224
}
72✔
225

226
} // namespace doxml
227

228
} // namespace doxlee
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc