QGIS/tests/code_layout/test_qgsdoccoverage.py
2025-05-04 07:42:19 +10:00

194 lines
6.9 KiB
Python

"""QGIS Unit tests for API documentation coverage.
.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
__author__ = "Nyall Dawson"
__date__ = "01/02/2015"
__copyright__ = "Copyright 2016, The QGIS Project"
import json
import os
import sys
from pathlib import Path
try:
from qgis.static_testing import unittest
except ImportError:
import unittest
from doxygen_parser import DoxygenParser
from termcolor import colored
REGENERATE_LISTS = False
class TestQgsDocCoverage(unittest.TestCase):
def testCoverage(self):
print("CTEST_FULL_OUTPUT")
prefixPath = os.environ["QGIS_PREFIX_PATH"]
docPath = os.path.join(prefixPath, "..", "doc", "api", "xml")
doc_test_config_file = Path(__file__).parent / "doc_test.json"
with open(doc_test_config_file) as f:
doc_test_config = json.loads(f.read())
parser = DoxygenParser(
docPath,
doc_test_config["acceptable_missing_doc"],
doc_test_config["acceptable_missing_added_note"],
doc_test_config["acceptable_missing_brief"],
)
coverage = 100.0 * parser.documented_members / parser.documentable_members
missing = parser.documentable_members - parser.documented_members
if REGENERATE_LISTS:
with open(doc_test_config_file, "w") as f:
all_undocumented = {}
for c in sorted(list(parser.all_undocumented_members.keys())):
all_undocumented[c] = sorted(parser.all_undocumented_members[c])
f.write(
json.dumps(
{
"acceptable_missing_doc": all_undocumented,
"acceptable_missing_added_note": sorted(
parser.all_classes_missing_version_added
),
"acceptable_missing_brief": [],
},
indent=2,
)
)
print("---------------------------------")
print(f"{parser.documentable_members} total documentable members")
print(f"{parser.documented_members} total contain valid documentation")
print(f"Total documentation coverage {coverage}%")
print("---------------------------------")
print(f"{missing} members missing documentation")
print("---------------------------------")
print("Unacceptable missing documentation:")
if parser.undocumented_members:
for cls, props in list(parser.undocumented_members.items()):
print(
"\n\nClass {}, {}/{} members documented\n".format(
colored(cls, "yellow"), props["documented"], props["members"]
)
)
for mem in props["missing_members"]:
print(colored(' "' + mem + '"', "yellow", attrs=["bold"]))
if parser.noncompliant_members:
for cls, props in list(parser.noncompliant_members.items()):
print(
"\n\nClass {}, non-compliant members found\n".format(
colored(cls, "yellow")
)
)
for p in props:
for mem, error in p.items():
print(
colored(" " + mem + ": " + error, "yellow", attrs=["bold"])
)
if parser.broken_links:
for cls, props in list(parser.broken_links.items()):
print(
"\n\nClass {}, broken see also links found\n".format(
colored(cls, "yellow")
)
)
for member, links in props.items():
for l in links:
print(
colored(" " + member + ": " + l, "yellow", attrs=["bold"])
)
# self.assertEquals(len(parser.undocumented_string), 0, 'FAIL: new undocumented members have been introduced, please add documentation for these members')
if parser.classes_missing_group:
print("---------------------------------")
print("\n")
print(
colored(
f'{len(parser.classes_missing_group)} classes have been added without Doxygen group tag ("\\ingroup"):',
"yellow",
)
)
print("")
print(
" "
+ "\n ".join(
[
colored(cls, "yellow", attrs=["bold"])
for cls in parser.classes_missing_group
]
)
)
if parser.classes_missing_version_added:
print("---------------------------------")
print("\n")
print(
colored(
f'{len(parser.classes_missing_version_added)} classes have been added without a version added doxygen note ("\\since QGIS x.xx"):',
"yellow",
)
)
print("")
print(
" "
+ "\n ".join(
[
colored(cls, "yellow", attrs=["bold"])
for cls in parser.classes_missing_version_added
]
)
)
if parser.classes_missing_brief:
print("---------------------------------")
print("\n")
print(
colored(
f"{len(parser.classes_missing_brief)} classes have been added without at least a brief description:",
"yellow",
)
)
print("")
print(
" "
+ "\n ".join(
[
colored(cls, "yellow", attrs=["bold"])
for cls in parser.classes_missing_brief
]
)
)
sys.stdout.flush()
self.assertTrue(not parser.undocumented_members, "Undocumented members found")
self.assertTrue(
not parser.classes_missing_group, "Classes without \\group tag found"
)
self.assertTrue(
not parser.classes_missing_version_added,
"Classes without \\since version tag found",
)
self.assertTrue(
not parser.classes_missing_brief,
"Classes without \\brief description found",
)
self.assertTrue(not parser.noncompliant_members, "Non compliant members found")
self.assertTrue(not parser.broken_links, "Broken links found")
if __name__ == "__main__":
unittest.main()