htmlreport: Add HTML validation and fix syntax errors (#2317)

Add HTML validation with HTML Tidy for the resulting files index.html
and stats.html.
Fix syntax errors found by the validator.
Fix that the links in the footer are not clickable by removing the
"height: 75%;" style for the classes "menu" and "menu_index".
Add some line breaks to the HTML output for better readability and for
easier debugging.
This commit is contained in:
Sebastian 2019-11-01 15:06:44 +01:00 committed by GitHub
parent 91a4bcd71e
commit 4f927ea6c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 51 additions and 17 deletions

View File

@ -20,7 +20,7 @@ env:
before_install: before_install:
# install needed deps # install needed deps
- travis_retry sudo apt-get update -qq - travis_retry sudo apt-get update -qq
- travis_retry sudo apt-get install -qq python3-pip qt5-default qt5-qmake qtbase5-dev qtcreator libxml2-utils libpcre3 gdb unzip wx-common xmlstarlet python3-dev liblua5.3-dev libcurl3 libcairo2-dev libsigc++-2.0-dev - travis_retry sudo apt-get install -qq python3-pip qt5-default qt5-qmake qtbase5-dev qtcreator libxml2-utils libpcre3 gdb unzip wx-common xmlstarlet python3-dev liblua5.3-dev libcurl3 libcairo2-dev libsigc++-2.0-dev tidy
# Python 2 modules # Python 2 modules
- travis_retry python2 -m pip install --user pytest==4.6.4 - travis_retry python2 -m pip install --user pytest==4.6.4
- travis_retry python2 -m pip install --user pylint - travis_retry python2 -m pip install --user pylint

View File

@ -1,24 +1,54 @@
#!/bin/bash -ex #!/bin/bash -ex
# Command for checking HTML syntax with HTML Tidy, see http://www.html-tidy.org/
# newer tidy (5.6.0) command, if using this it is not necessary to ignore warnings:
#tidy_cmd='tidy -o /dev/null -eq --drop-empty-elements no'
# older tidy from 2009 (Ubuntu 16.04 Xenial comes with this old version):
tidy_cmd='tidy -o /dev/null -eq'
function validate_html {
set +e
${tidy_cmd} $1
tidy_status=$?
set -e
if [ $tidy_status -eq 2 ]; then
echo "HTML does not validate!"
exit 1
fi
}
./cppcheck-htmlreport --file ../gui/test/data/xmlfiles/xmlreport_v2.xml --title "xml2 test" --report-dir . --source-dir ../test/ ./cppcheck-htmlreport --file ../gui/test/data/xmlfiles/xmlreport_v2.xml --title "xml2 test" --report-dir . --source-dir ../test/
echo -e "\n" echo -e "\n"
# Check HTML syntax
validate_html index.html
validate_html stats.html
../cppcheck ../gui/test --enable=all --inconclusive --xml-version=2 2> gui_test.xml ../cppcheck ../gui/test --enable=all --inconclusive --xml-version=2 2> gui_test.xml
xmllint --noout gui_test.xml xmllint --noout gui_test.xml
./cppcheck-htmlreport --file ./gui_test.xml --title "xml2 + inconclusive test" --report-dir . ./cppcheck-htmlreport --file ./gui_test.xml --title "xml2 + inconclusive test" --report-dir .
echo "" echo ""
# Check HTML syntax
validate_html index.html
validate_html stats.html
../cppcheck ../gui/test --enable=all --inconclusive --verbose --xml-version=2 2> gui_test.xml ../cppcheck ../gui/test --enable=all --inconclusive --verbose --xml-version=2 2> gui_test.xml
xmllint --noout gui_test.xml xmllint --noout gui_test.xml
./cppcheck-htmlreport --file ./gui_test.xml --title "xml2 + inconclusive + verbose test" --report-dir . ./cppcheck-htmlreport --file ./gui_test.xml --title "xml2 + inconclusive + verbose test" --report-dir .
echo -e "\n" echo -e "\n"
# Check HTML syntax
validate_html index.html
validate_html stats.html
../cppcheck --errorlist --inconclusive --xml-version=2 > errorlist.xml ../cppcheck --errorlist --inconclusive --xml-version=2 > errorlist.xml
xmllint --noout errorlist.xml xmllint --noout errorlist.xml
./cppcheck-htmlreport --file ./errorlist.xml --title "errorlist" --report-dir . ./cppcheck-htmlreport --file ./errorlist.xml --title "errorlist" --report-dir .
# Check HTML syntax
validate_html index.html
validate_html stats.html
../cppcheck ../samples/memleak/good.c ../samples/resourceLeak/good.c --xml-version=2 --enable=information --suppressions-list=test_suppressions.txt --xml 2> unmatchedSuppr.xml ../cppcheck ../samples/memleak/good.c ../samples/resourceLeak/good.c --xml-version=2 --enable=information --suppressions-list=test_suppressions.txt --xml 2> unmatchedSuppr.xml
xmllint --noout unmatchedSuppr.xml xmllint --noout unmatchedSuppr.xml
@ -27,3 +57,6 @@ grep "unmatchedSuppression<.*>information<.*>Unmatched suppression: variableScop
grep ">unmatchedSuppression</.*>information<.*>Unmatched suppression: uninitstring<" index.html grep ">unmatchedSuppression</.*>information<.*>Unmatched suppression: uninitstring<" index.html
grep "notexisting" index.html grep "notexisting" index.html
grep ">unmatchedSuppression<.*>information<.*>Unmatched suppression: \*<" index.html grep ">unmatchedSuppression<.*>information<.*>Unmatched suppression: \*<" index.html
# Check HTML syntax
validate_html index.html
validate_html stats.html

View File

@ -90,7 +90,7 @@ div.verbose div.content {
margin-top: 5px; margin-top: 5px;
text-align: left; text-align: left;
width: 150px; width: 150px;
height: 75%; /*height: 75%;*/
position: fixed; position: fixed;
overflow: auto; overflow: auto;
z-index: 1; z-index: 1;
@ -102,7 +102,7 @@ div.verbose div.content {
padding-left: 5px; padding-left: 5px;
text-align: left; text-align: left;
width: 300px; width: 300px;
height: 75%; /*height: 75%;*/
position: fixed; position: fixed;
overflow: auto; overflow: auto;
z-index: 1; z-index: 1;
@ -259,7 +259,7 @@ HTML_FOOTER = """
</br> </br>
Internet: <a href="http://cppcheck.net">http://cppcheck.net</a></br> Internet: <a href="http://cppcheck.net">http://cppcheck.net</a></br>
IRC: <a href="irc://irc.freenode.net/cppcheck">irc://irc.freenode.net/cppcheck</a></br> IRC: <a href="irc://irc.freenode.net/cppcheck">irc://irc.freenode.net/cppcheck</a></br>
<p> </p>
</div> </div>
</body> </body>
</html> </html>
@ -573,24 +573,23 @@ if __name__ == '__main__':
except IndexError: except IndexError:
cnt_min = 0 cnt_min = 0
stat_fmt = " <tr><td><input type='checkbox' onclick='toggle_class_visibility(this.id)' id='{}' name='{}' checked></td><td>{}</td><td>{}</td></tr>" stat_fmt = "\n <tr><td><input type='checkbox' onclick='toggle_class_visibility(this.id)' id='{}' name='{}' checked></td><td>{}</td><td>{}</td></tr>"
for occurrences in reversed(range(cnt_min, cnt_max + 1)): for occurrences in reversed(range(cnt_min, cnt_max + 1)):
for _id in [k for k, v in sorted(counter.items()) if v == occurrences]: for _id in [k for k, v in sorted(counter.items()) if v == occurrences]:
stat_html.append(stat_fmt.format(_id, _id, dict(counter.most_common())[_id], _id)) stat_html.append(stat_fmt.format(_id, _id, dict(counter.most_common())[_id], _id))
output_file.write(HTML_HEAD.replace('id="menu" dir="rtl"', 'id="menu_index"', 1).replace("Defects:", "Defect summary;", 1) % (options.title, '', options.title, '', '')) output_file.write(HTML_HEAD.replace('id="menu" dir="rtl"', 'id="menu_index"', 1).replace("Defects:", "Defect summary;", 1) % (options.title, '', options.title, '', ''))
output_file.write(' <table>') output_file.write('\n <label><input type="checkbox" onclick="toggle_all()" checked> Toggle all</label>')
output_file.write(' <tr><th>Show</th><th>#</th><th>Defect ID</th></tr>') output_file.write('\n <table>')
output_file.write('<label><input type="checkbox" onclick="toggle_all()" checked/> Toggle all</label>') output_file.write('\n <tr><th>Show</th><th>#</th><th>Defect ID</th></tr>')
output_file.write(''.join(stat_html)) output_file.write(''.join(stat_html))
output_file.write(' <tr><td></td><td>' + str(stats_count) + '</td><td>total</td></tr>') output_file.write('\n <tr><td></td><td>' + str(stats_count) + '</td><td>total</td></tr>')
output_file.write(' </table>') output_file.write('\n </table>')
output_file.write(' <a href="stats.html">Statistics</a></p>') output_file.write('\n <p><a href="stats.html">Statistics</a></p>')
output_file.write(HTML_HEAD_END.replace("content", "content_index", 1)) output_file.write(HTML_HEAD_END.replace("content", "content_index", 1))
output_file.write(' <table>\n')
output_file.write( output_file.write('\n <table>')
' <tr><th>Line</th><th>Id</th><th>CWE</th><th>Severity</th><th>Message</th></tr>') output_file.write('\n <tr><th>Line</th><th>Id</th><th>CWE</th><th>Severity</th><th>Message</th></tr>')
for filename, data in sorted(files.items()): for filename, data in sorted(files.items()):
if filename in decode_errors: # don't print a link but a note if filename in decode_errors: # don't print a link but a note
output_file.write("\n <tr><td colspan='5'>%s</td></tr>" % (filename)) output_file.write("\n <tr><td colspan='5'>%s</td></tr>" % (filename))
@ -625,18 +624,18 @@ if __name__ == '__main__':
if error['id'] == 'missingInclude': if error['id'] == 'missingInclude':
output_file.write( output_file.write(
'\n <tr class="%s"><td></td><td>%s</td><td></td><td>%s</td><td>%s</td></tr>' % '\n <tr class="%s"><td></td><td>%s</td><td></td><td>%s</td><td>%s</td></tr>' %
(error['id'], error['id'], error['severity'], error['msg'])) (error['id'], error['id'], error['severity'], html_escape(error['msg'])))
elif (error['id'] == 'unmatchedSuppression') and filename.endswith('*'): elif (error['id'] == 'unmatchedSuppression') and filename.endswith('*'):
output_file.write( output_file.write(
'\n <tr class="%s"><td></td><td>%s</td><td></td><td>%s</td><td %s>%s</td></tr>' % '\n <tr class="%s"><td></td><td>%s</td><td></td><td>%s</td><td %s>%s</td></tr>' %
(error['id'], error['id'], error['severity'], error_class, (error['id'], error['id'], error['severity'], error_class,
error['msg'])) html_escape(error['msg'])))
else: else:
output_file.write( output_file.write(
'\n <tr class="%s"><td><a href="%s#line-%d">%d</a></td><td>%s</td><td>%s</td><td>%s</td><td %s>%s</td></tr>' % '\n <tr class="%s"><td><a href="%s#line-%d">%d</a></td><td>%s</td><td>%s</td><td>%s</td><td %s>%s</td></tr>' %
(error['id'], data['htmlfile'], error['line'], error['line'], (error['id'], data['htmlfile'], error['line'], error['line'],
error['id'], cwe_url, error['severity'], error_class, error['id'], cwe_url, error['severity'], error_class,
error['msg'])) html_escape(error['msg'])))
output_file.write('\n </table>') output_file.write('\n </table>')
output_file.write(HTML_FOOTER % contentHandler.versionCppcheck) output_file.write(HTML_FOOTER % contentHandler.versionCppcheck)
@ -707,4 +706,6 @@ if __name__ == '__main__':
break break
stats_file.write("</p>\n") stats_file.write("</p>\n")
stats_file.write(HTML_FOOTER % contentHandler.versionCppcheck)
print("\nOpen '" + options.report_dir + "/index.html' to see the results.") print("\nOpen '" + options.report_dir + "/index.html' to see the results.")