From 229a556c72fe44e3d557161c60e50d53efb80dbd Mon Sep 17 00:00:00 2001 From: Alexis Lee Date: Tue, 11 Nov 2014 11:09:19 +0000 Subject: [PATCH] Forklift nova-specs test_titles.py * Reports which sections are missing/extra * Checks line wrapping * Checks for literal carriage returns * Checks for trailing spaces * Handles per-release spec templates Change-Id: I5fdf2d42353dee737d0551013536adeaff6ed69a --- tests/test_titles.py | 105 +++++++++++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 39 deletions(-) diff --git a/tests/test_titles.py b/tests/test_titles.py index 14e59ca9..c65cce1c 100644 --- a/tests/test_titles.py +++ b/tests/test_titles.py @@ -11,32 +11,12 @@ # under the License. import glob +import re import docutils.core import testtools -TITLES = { - 'Problem Description': [], - 'Proposed Change': [ - 'Alternatives', - 'Security Impact', - 'Other End User Impact', - 'Performance Impact', - 'Other Deployer Impact', - 'Developer Impact', - ], - 'Implementation': [ - 'Assignee(s)', - 'Work Items', - ], - 'Dependencies': [], - 'Testing': [], - 'Documentation Impact': [], - 'References': [], -} - - class TestTitles(testtools.TestCase): def _get_title(self, section_tree): section = { @@ -46,7 +26,6 @@ class TestTitles(testtools.TestCase): if node.tagname == 'title': section['name'] = node.rawsource elif node.tagname == 'section': - # Note subsection subtitles are thrown away subsection = self._get_title(node) section['subtitles'].append(subsection['name']) return section @@ -55,27 +34,75 @@ class TestTitles(testtools.TestCase): titles = {} for node in spec: if node.tagname == 'section': + # Note subsection subtitles are thrown away section = self._get_title(node) titles[section['name']] = section['subtitles'] return titles - def _check_titles(self, titles): - self.assertEqual(TITLES, titles) + def _check_titles(self, filename, expect, actual): + missing_sections = [x for x in expect.keys() if x not in actual.keys()] + extra_sections = [x for x in actual.keys() if x not in expect.keys()] - def _run_template_tests(self, release_name): - files = ['specs/%s-template.rst' % release_name] + \ - glob.glob('specs/%s/*' % release_name) - for filename in files: - self.assertTrue(filename.endswith(".rst"), - "specs file must uses 'rst' extension.") - with open(filename) as f: - data = f.read() - spec = docutils.core.publish_doctree(data) - titles = self._get_titles(spec) - self._check_titles(titles) + msgs = [] + if len(missing_sections) > 0: + msgs.append("Missing sections: %s" % missing_sections) + if len(extra_sections) > 0: + msgs.append("Extra sections: %s" % extra_sections) - def test_juno_templates(self): - self._run_template_tests('juno') + for section in expect.keys(): + missing_subsections = [x for x in expect[section] + if x not in actual[section]] + # extra subsections are allowed + if len(missing_subsections) > 0: + msgs.append("Section '%s' is missing subsections: %s" + % (section, missing_subsections)) - def test_kilo_templates(self): - self._run_template_tests('kilo') + if len(msgs) > 0: + self.fail("While checking '%s':\n %s" + % (filename, "\n ".join(msgs))) + + def _check_lines_wrapping(self, tpl, raw): + for i, line in enumerate(raw.split("\n")): + if "http://" in line or "https://" in line: + continue + self.assertTrue( + len(line) < 80, + msg="%s:%d: Line limited to a maximum of 79 characters." % + (tpl, i+1)) + + def _check_no_cr(self, tpl, raw): + matches = re.findall('\r', raw) + self.assertEqual( + len(matches), 0, + "Found %s literal carriage returns in file %s" % + (len(matches), tpl)) + + + def _check_trailing_spaces(self, tpl, raw): + for i, line in enumerate(raw.split("\n")): + trailing_spaces = re.findall(" +$", line) + self.assertEqual(len(trailing_spaces),0, + "Found trailing spaces on line %s of %s" % (i+1, tpl)) + + + def test_template(self): + releases = [x.split('/')[1] for x in glob.glob('specs/*/')] + for release in releases: + with open("specs/%s-template.rst" % release) as f: + template = f.read() + spec = docutils.core.publish_doctree(template) + template_titles = self._get_titles(spec) + + files = glob.glob("specs/%s/*/*" % release) + for filename in files: + self.assertTrue(filename.endswith(".rst"), + "spec filenames must use 'rst' extension.") + with open(filename) as f: + data = f.read() + + spec = docutils.core.publish_doctree(data) + titles = self._get_titles(spec) + self._check_titles(filename, template_titles, titles) + self._check_lines_wrapping(filename, data) + self._check_no_cr(filename, data) + self._check_trailing_spaces(filename, data)