From f2cb41a101900c170b033f5903adfa4a61adfd3b Mon Sep 17 00:00:00 2001 From: Stein Heselmans Date: Mon, 7 Aug 2017 15:43:16 +0200 Subject: [PATCH 01/18] Add trial for verbose flag Verbosity needs to summarize the found warnings to the terminal --- docs/design.rst | 12 +++++---- src/mlx/warnings.py | 63 ++++++++++++++++++++++++++++++++----------- tests/test_doxygen.py | 14 +++++++--- 3 files changed, 64 insertions(+), 25 deletions(-) diff --git a/docs/design.rst b/docs/design.rst index dd583a72..06c34b3d 100644 --- a/docs/design.rst +++ b/docs/design.rst @@ -15,39 +15,41 @@ Class diagram @startuml class WarningsPlugin { #checkerList : WarningsChecker + +__init__(sphinx=False, doxygen=False, junit=False, verbose=False) } class WarningsChecker { #min_count = 0 #max_count = 0 #count = 0 + #verbose = False - #{abstract} __init__(name) + #{abstract} __init__(name, verbose=False) +set_limits(min_count=0, max_count=0, +{abstract}check(content) +get_count() } class RegexChecker { - #{abstract} __init__(name, regex) + #{abstract} __init__(name, regex, verbose=False) +check(content) } class SphinxChecker { #{static} String name #{static} String regex - +__init__() + +__init__(verbose=False) } class DoxyChecker { #{static} String name #{static} String regex - +__init__() + +__init__(verbose=False) } class JUnitChecker { #{static} String name - +__init__() + +__init__(verbose=False) +check(content) } diff --git a/src/mlx/warnings.py b/src/mlx/warnings.py index e15dec01..d3ed3776 100644 --- a/src/mlx/warnings.py +++ b/src/mlx/warnings.py @@ -2,7 +2,7 @@ import re import sys import abc -from junitparser import JUnitXml +from junitparser import JUnitXml, Failure, Error DOXYGEN_WARNING_REGEX = r"(?:(?:((?:[/.]|[A-Za-z]:).+?):(-?\d+):\s*([Ww]arning|[Ee]rror)|<.+>:-?\d+(?::\s*([Ww]arning|[Ee]rror))?): (.+(?:\n(?!\s*(?:[Nn]otice|[Ww]arning|[Ee]rror): )[^/<\n][^:\n][^/\n].+)*)|\s*([Nn]otice|[Ww]arning|[Ee]rror): (.+))$" doxy_pattern = re.compile(DOXYGEN_WARNING_REGEX) @@ -13,13 +13,15 @@ class WarningsChecker(object): - def __init__(self, name): + def __init__(self, name, verbose=False): ''' Constructor Args: name (str): Name of the checker + verbose (bool): Enable/disable verbose logging ''' self.name = name + self.verbose = verbose self.reset() def reset(self): @@ -112,14 +114,14 @@ def return_check_limits(self): class RegexChecker(WarningsChecker): - def __init__(self, name, pattern): + def __init__(self, name, pattern, verbose=False): ''' Constructor Args: name (str): Name of the checker pattern (str): Regular expression used by the checker in order to find warnings ''' - super(RegexChecker, self).__init__(name=name) + super(RegexChecker, self).__init__(name=name, verbose=verbose) self.pattern = pattern def check(self, content): @@ -129,28 +131,47 @@ def check(self, content): Args: content (str): The content to parse ''' - self.count += len(re.findall(self.pattern, content)) + matches = re.findall(self.pattern, content, re.M) + if self.verbose: + for match in matches: + print(match) + self.count += len(matches) class SphinxChecker(RegexChecker): name = 'sphinx' - def __init__(self): - super(SphinxChecker, self).__init__(name=SphinxChecker.name, pattern=sphinx_pattern) + def __init__(self, verbose=False): + ''' Constructor + + Args: + verbose (bool): Enable/disable verbose logging + ''' + super(SphinxChecker, self).__init__(name=SphinxChecker.name, pattern=sphinx_pattern, verbose=verbose) class DoxyChecker(RegexChecker): name = 'doxygen' - def __init__(self): - super(DoxyChecker, self).__init__(name=DoxyChecker.name, pattern=doxy_pattern) + def __init__(self, verbose=False): + ''' Constructor + + Args: + verbose (bool): Enable/disable verbose logging + ''' + super(DoxyChecker, self).__init__(name=DoxyChecker.name, pattern=doxy_pattern, verbose=verbose) class JUnitChecker(WarningsChecker): name = 'junit' - def __init__(self): - super(JUnitChecker, self).__init__(name=JUnitChecker.name) + def __init__(self, verbose=False): + ''' Constructor + + Args: + verbose (bool): Enable/disable verbose logging + ''' + super(JUnitChecker, self).__init__(name=JUnitChecker.name, verbose=verbose) def check(self, content): ''' @@ -160,13 +181,18 @@ def check(self, content): content (str): The content to parse ''' result = JUnitXml.fromstring(content) + if self.verbose: + for suite in result: + for testcase in suite: + if isinstance(testcase.result, Failure) or isinstance(testcase.result, Error): + print(str(testcase.classname)) result.update_statistics() self.count += result.errors + result.failures class WarningsPlugin: - def __init__(self, sphinx = False, doxygen = False, junit = False): + def __init__(self, sphinx = False, doxygen = False, junit = False, verbose = False): ''' Function for initializing the parsers @@ -174,14 +200,18 @@ def __init__(self, sphinx = False, doxygen = False, junit = False): sphinx (bool, optional): enable sphinx parser doxygen (bool, optional): enable doxygen parser junit (bool, optional): enable junit parser + verbose (bool, optional): enable verbose logging ''' self.checkerList = {} + self.verbose = False + if verbose: + self.verbose = True if sphinx: - self.activate_checker(SphinxChecker()) + self.activate_checker(SphinxChecker(self.verbose)) if doxygen: - self.activate_checker(DoxyChecker()) + self.activate_checker(DoxyChecker(self.verbose)) if junit: - self.activate_checker(JUnitChecker()) + self.activate_checker(JUnitChecker(self.verbose)) self.warn_min = 0 self.warn_max = 0 @@ -289,6 +319,7 @@ def main(): group.add_argument('-d', '--doxygen', dest='doxygen', action='store_true') group.add_argument('-s', '--sphinx', dest='sphinx', action='store_true') group.add_argument('-j', '--junit', dest='junit', action='store_true') + parser.add_argument('-v', '--verbose', dest='verbose', action='store_true') parser.add_argument('-m', '--maxwarnings', type=int, required=False, default=0, help='Maximum amount of warnings accepted') parser.add_argument('--minwarnings', type=int, required=False, default=0, @@ -297,7 +328,7 @@ def main(): parser.add_argument('logfile', help='Logfile that might contain warnings') args = parser.parse_args() - warnings = WarningsPlugin(sphinx=args.sphinx, doxygen=args.doxygen, junit=args.junit) + warnings = WarningsPlugin(sphinx=args.sphinx, doxygen=args.doxygen, junit=args.junit, verbose=args.verbose) warnings.set_maximum(args.maxwarnings) warnings.set_minimum(args.minwarnings) diff --git a/tests/test_doxygen.py b/tests/test_doxygen.py index b1886489..dd157609 100644 --- a/tests/test_doxygen.py +++ b/tests/test_doxygen.py @@ -1,3 +1,6 @@ +import sys +from io import StringIO +from mock import patch from unittest import TestCase from mlx.warnings import WarningsPlugin @@ -5,16 +8,19 @@ class TestDoxygenWarnings(TestCase): def setUp(self): - self.warnings = WarningsPlugin(False, True, False) - print(str(self.warnings)) + self.warnings = WarningsPlugin(False, True, False, verbose=True) def test_no_warning(self): - self.warnings.check('This should not be treated as warning') + dut = 'This should not be treated as warning' + self.warnings.check(dut) self.assertEqual(self.warnings.return_count(), 0) def test_single_warning(self): - self.warnings.check('testfile.c:6: warning: group test: ignoring title "Some test functions" that does not match old title "Some freaky test functions"') + dut = 'testfile.c:6: warning: group test: ignoring title "Some test functions" that does not match old title "Some freaky test functions"' + with patch('sys.stdout', new=StringIO()) as fake_out: + self.warnings.check(dut) self.assertEqual(self.warnings.return_count(), 1) + self.assertEqual(dut, fake_out.getvalue()) def test_single_warning_mixed(self): self.warnings.check('This1 should not be treated as warning') From 776952ecfa07a8ae785b54d152eff5403669fc4d Mon Sep 17 00:00:00 2001 From: Stein Heselmans Date: Mon, 7 Aug 2017 15:53:27 +0200 Subject: [PATCH 02/18] Removed some debug code --- src/mlx/warnings.py | 4 ++-- tests/test_doxygen.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/mlx/warnings.py b/src/mlx/warnings.py index d3ed3776..9bb3f9ca 100644 --- a/src/mlx/warnings.py +++ b/src/mlx/warnings.py @@ -131,10 +131,10 @@ def check(self, content): Args: content (str): The content to parse ''' - matches = re.findall(self.pattern, content, re.M) + matches = re.findall(self.pattern, content) if self.verbose: for match in matches: - print(match) + print(str(match)) self.count += len(matches) diff --git a/tests/test_doxygen.py b/tests/test_doxygen.py index dd157609..ae52fcc1 100644 --- a/tests/test_doxygen.py +++ b/tests/test_doxygen.py @@ -1,4 +1,3 @@ -import sys from io import StringIO from mock import patch from unittest import TestCase From 0aabfbfe059eb5af3f221a909f4f01fed18cf9fa Mon Sep 17 00:00:00 2001 From: Stein Heselmans Date: Wed, 9 Aug 2017 10:07:17 +0200 Subject: [PATCH 03/18] Correct classname and testcase name in example junit files --- tests/junit_double_fail.xml | 8 ++++---- tests/junit_no_fail.xml | 6 +++--- tests/junit_single_fail.xml | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/junit_double_fail.xml b/tests/junit_double_fail.xml index 296868d3..cf3da140 100644 --- a/tests/junit_double_fail.xml +++ b/tests/junit_double_fail.xml @@ -1,15 +1,15 @@ - - + + - + This time there is more content to the failure - + diff --git a/tests/junit_no_fail.xml b/tests/junit_no_fail.xml index cd6c8269..60ff3306 100644 --- a/tests/junit_no_fail.xml +++ b/tests/junit_no_fail.xml @@ -1,7 +1,7 @@ - - - + + + diff --git a/tests/junit_single_fail.xml b/tests/junit_single_fail.xml index 492590c0..ad9ca0fd 100644 --- a/tests/junit_single_fail.xml +++ b/tests/junit_single_fail.xml @@ -1,12 +1,12 @@ - - + + - + From 690da54bbe5b90058d2df08b100bd1ab777660d2 Mon Sep 17 00:00:00 2001 From: Stein Heselmans Date: Wed, 9 Aug 2017 16:43:18 +0200 Subject: [PATCH 04/18] Add authors file --- docs/authors.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 docs/authors.rst diff --git a/docs/authors.rst b/docs/authors.rst new file mode 100644 index 00000000..74cbb19c --- /dev/null +++ b/docs/authors.rst @@ -0,0 +1,11 @@ +======= +Authors +======= + +Melexis Warnings plugin is mainly maintained by: + +- Bavo Van Achte +- Crt Mori +- Stein Heselmans + + From cd909341fd1029844ebbd1a3e5b4e35316c71feb Mon Sep 17 00:00:00 2001 From: Stein Heselmans Date: Wed, 9 Aug 2017 16:43:57 +0200 Subject: [PATCH 05/18] Adapt test cases for verbosity --- tests/junit_double_fail.xml | 8 ++++---- tests/junit_single_fail.xml | 6 +++--- tests/test_doxygen.py | 20 ++++++++++++++------ tests/test_junit.py | 24 +++++++++++++++++------- tests/test_sphinx.py | 37 +++++++++++++++++++++++++++---------- 5 files changed, 65 insertions(+), 30 deletions(-) diff --git a/tests/junit_double_fail.xml b/tests/junit_double_fail.xml index cf3da140..e1e2611a 100644 --- a/tests/junit_double_fail.xml +++ b/tests/junit_double_fail.xml @@ -1,15 +1,15 @@ - - + + - + This time there is more content to the failure - + diff --git a/tests/junit_single_fail.xml b/tests/junit_single_fail.xml index ad9ca0fd..0c67935f 100644 --- a/tests/junit_single_fail.xml +++ b/tests/junit_single_fail.xml @@ -1,12 +1,12 @@ - - + + - + diff --git a/tests/test_doxygen.py b/tests/test_doxygen.py index ae52fcc1..bc2839ef 100644 --- a/tests/test_doxygen.py +++ b/tests/test_doxygen.py @@ -1,4 +1,7 @@ -from io import StringIO +try: + from StringIO import StringIO +except ImportError: + from io import StringIO from mock import patch from unittest import TestCase @@ -7,7 +10,7 @@ class TestDoxygenWarnings(TestCase): def setUp(self): - self.warnings = WarningsPlugin(False, True, False, verbose=True) + self.warnings = WarningsPlugin(doxygen=True, verbose=True) def test_no_warning(self): dut = 'This should not be treated as warning' @@ -19,11 +22,16 @@ def test_single_warning(self): with patch('sys.stdout', new=StringIO()) as fake_out: self.warnings.check(dut) self.assertEqual(self.warnings.return_count(), 1) - self.assertEqual(dut, fake_out.getvalue()) + self.assertRegexpMatches(fake_out.getvalue(), dut) def test_single_warning_mixed(self): - self.warnings.check('This1 should not be treated as warning') - self.warnings.check('testfile.c:6: warning: group test: ignoring title "Some test functions" that does not match old title "Some freaky test functions"') - self.warnings.check('This should not be treated as warning2') + dut1 = 'This1 should not be treated as warning' + dut2 = 'testfile.c:6: warning: group test: ignoring title "Some test functions" that does not match old title "Some freaky test functions"' + dut3 = 'This should not be treated as warning2' + with patch('sys.stdout', new=StringIO()) as fake_out: + self.warnings.check(dut1) + self.warnings.check(dut2) + self.warnings.check(dut3) self.assertEqual(self.warnings.return_count(), 1) + self.assertRegexpMatches(fake_out.getvalue(), dut2) diff --git a/tests/test_junit.py b/tests/test_junit.py index 275a091c..2d14a233 100644 --- a/tests/test_junit.py +++ b/tests/test_junit.py @@ -1,3 +1,8 @@ +try: + from StringIO import StringIO +except ImportError: + from io import StringIO +from mock import patch from unittest import TestCase from mlx.warnings import WarningsPlugin @@ -6,22 +11,27 @@ class TestJUnitFailures(TestCase): def setUp(self): - self.warnings = WarningsPlugin(False, False, True) + self.warnings = WarningsPlugin(junit=True, verbose=True) def test_no_warning(self): - with open('tests/junit_no_fail.xml') as xmlfile: - self.warnings.check(xmlfile.read()) + with open('tests/junit_no_fail.xml', 'r') as xmlfile: + self.warnings.check(xmlfile.read().encode('utf-8')) self.assertEqual(self.warnings.return_count(), 0) def test_single_warning(self): - with open('tests/junit_single_fail.xml') as xmlfile: - self.warnings.check(xmlfile.read()) + with open('tests/junit_single_fail.xml', 'r') as xmlfile: + with patch('sys.stdout', new=StringIO()) as fake_out: + self.warnings.check(xmlfile.read().encode('utf-8')) self.assertEqual(self.warnings.return_count(), 1) + self.assertRegexpMatches(fake_out.getvalue(), 'myfirstfai1ure') def test_dual_warning(self): - with open('tests/junit_double_fail.xml') as xmlfile: - self.warnings.check(xmlfile.read()) + with open('tests/junit_double_fail.xml', 'r') as xmlfile: + with patch('sys.stdout', new=StringIO()) as fake_out: + self.warnings.check(xmlfile.read().encode('utf-8')) self.assertEqual(self.warnings.return_count(), 2) + self.assertRegexpMatches(fake_out.getvalue(), 'myfirstfai1ure') + self.assertRegexpMatches(fake_out.getvalue(), 'mysecondfai1ure') def test_invalid_xml(self): with self.assertRaises(ParseError): diff --git a/tests/test_sphinx.py b/tests/test_sphinx.py index b188474d..c6452a5d 100644 --- a/tests/test_sphinx.py +++ b/tests/test_sphinx.py @@ -1,3 +1,8 @@ +try: + from StringIO import StringIO +except ImportError: + from io import StringIO +from mock import patch from unittest import TestCase from mlx.warnings import WarningsPlugin @@ -5,25 +10,37 @@ class TestSphinxWarnings(TestCase): def setUp(self): - self.warnings = WarningsPlugin(True, False, False) + self.warnings = WarningsPlugin(sphinx=True, verbose=True) def test_no_warning(self): self.warnings.check('This should not be treated as warning') self.assertEqual(self.warnings.return_count(), 0) def test_single_warning(self): - self.warnings.check("/home/bljah/test/index.rst:5: WARNING: toctree contains reference to nonexisting document u'installation'") + dut = "/home/bljah/test/index.rst:5: WARNING: toctree contains reference to nonexisting document u'installation'" + with patch('sys.stdout', new=StringIO()) as fake_out: + self.warnings.check(dut) self.assertEqual(self.warnings.return_count(), 1) - - def test_single_warning_no_line_number(self): - self.warnings.check("/home/bljah/test/index.rst:5: WARNING: toctree contains reference to nonexisting document u'installation'") - self.warnings.check("/home/bljah/test/index.rst:None: WARNING: toctree contains reference to nonexisting document u'installation'") + self.assertRegexpMatches(fake_out.getvalue(), dut) + + def test_warning_no_line_number(self): + dut1 = "/home/bljah/test/index.rst:5: WARNING: toctree contains reference to nonexisting document u'installation'" + dut2 = "/home/bljah/test/index.rst:None: WARNING: toctree contains reference to nonexisting document u'installation'" + with patch('sys.stdout', new=StringIO()) as fake_out: + self.warnings.check(dut1) + self.warnings.check(dut2) self.assertEqual(self.warnings.return_count(), 2) + self.assertRegexpMatches(fake_out.getvalue(), dut1) + self.assertRegexpMatches(fake_out.getvalue(), dut2) def test_single_warning_mixed(self): - self.warnings.check('This1 should not be treated as warning') - self.warnings.check("/home/bljah/test/index.rst:5: WARNING: toctree contains reference to nonexisting document u'installation'") - self.warnings.check('This should not be treated as warning2') - + dut1 = 'This1 should not be treated as warning' + dut2 = "/home/bljah/test/index.rst:5: WARNING: toctree contains reference to nonexisting document u'installation'" + dut3 = 'This should not be treated as warning2' + with patch('sys.stdout', new=StringIO()) as fake_out: + self.warnings.check(dut1) + self.warnings.check(dut2) + self.warnings.check(dut3) self.assertEqual(self.warnings.return_count(), 1) + self.assertRegexpMatches(fake_out.getvalue(), dut2) From 3ed3f65da63d1bcda28e7d8c1a00b50cc2106101 Mon Sep 17 00:00:00 2001 From: Stein Heselmans Date: Wed, 9 Aug 2017 16:44:28 +0200 Subject: [PATCH 06/18] Verbosity for JUnitChecker class --- src/mlx/warnings.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mlx/warnings.py b/src/mlx/warnings.py index 6511651d..dd79e722 100644 --- a/src/mlx/warnings.py +++ b/src/mlx/warnings.py @@ -187,7 +187,8 @@ def check(self, content): for suite in result: for testcase in suite: if isinstance(testcase.result, Failure) or isinstance(testcase.result, Error): - print(str(testcase.classname)) + print('{classname}.{testname}'.format(classname=testcase.classname, + testname=testcase.name)) result.update_statistics() self.count += result.errors + result.failures From 9b49e38174cf44624952a3aa7f7189b6804f3cfa Mon Sep 17 00:00:00 2001 From: Stein Heselmans Date: Thu, 10 Aug 2017 10:20:32 +0200 Subject: [PATCH 07/18] Add test case for multiline regex matching --- tests/test_doxygen.py | 10 ++++++++++ tests/test_sphinx.py | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/tests/test_doxygen.py b/tests/test_doxygen.py index bc2839ef..aceacf3c 100644 --- a/tests/test_doxygen.py +++ b/tests/test_doxygen.py @@ -35,3 +35,13 @@ def test_single_warning_mixed(self): self.assertEqual(self.warnings.return_count(), 1) self.assertRegexpMatches(fake_out.getvalue(), dut2) + def test_multiline(self): + duterr = 'testfile.c:6: warning: group test: ignoring title "Some test functions" that does not match old title "Some freaky test functions"' + dut = 'This1 should not be treated as warning' + dut += duterr + dut += 'This should not be treated as warning2' + with patch('sys.stdout', new=StringIO()) as fake_out: + self.warnings.check(dut) + self.assertEqual(self.warnings.return_count(), 1) + self.assertRegexpMatches(fake_out.getvalue(), duterr) + diff --git a/tests/test_sphinx.py b/tests/test_sphinx.py index c6452a5d..44d4a825 100644 --- a/tests/test_sphinx.py +++ b/tests/test_sphinx.py @@ -44,3 +44,13 @@ def test_single_warning_mixed(self): self.assertEqual(self.warnings.return_count(), 1) self.assertRegexpMatches(fake_out.getvalue(), dut2) + def test_multiline(self): + duterr = "/home/bljah/test/index.rst:5: WARNING: toctree contains reference to nonexisting document u'installation'" + dut = 'This1 should not be treated as warning' + dut += duterr + dut += 'This should not be treated as warning2' + with patch('sys.stdout', new=StringIO()) as fake_out: + self.warnings.check(dut) + self.assertEqual(self.warnings.return_count(), 1) + self.assertRegexpMatches(fake_out.getvalue(), duterr) + From 7d205ebeb9311cc4e6ffe5bf9cf920273a21daa2 Mon Sep 17 00:00:00 2001 From: Stein Heselmans Date: Thu, 10 Aug 2017 10:38:13 +0200 Subject: [PATCH 08/18] Make multiline test have newlines :wink: --- tests/test_doxygen.py | 6 +++--- tests/test_sphinx.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test_doxygen.py b/tests/test_doxygen.py index aceacf3c..be7e0eb7 100644 --- a/tests/test_doxygen.py +++ b/tests/test_doxygen.py @@ -36,10 +36,10 @@ def test_single_warning_mixed(self): self.assertRegexpMatches(fake_out.getvalue(), dut2) def test_multiline(self): - duterr = 'testfile.c:6: warning: group test: ignoring title "Some test functions" that does not match old title "Some freaky test functions"' - dut = 'This1 should not be treated as warning' + duterr = 'testfile.c:6: warning: group test: ignoring title "Some test functions" that does not match old title "Some freaky test functions"\n' + dut = 'This1 should not be treated as warning\n' dut += duterr - dut += 'This should not be treated as warning2' + dut += 'This should not be treated as warning2\n' with patch('sys.stdout', new=StringIO()) as fake_out: self.warnings.check(dut) self.assertEqual(self.warnings.return_count(), 1) diff --git a/tests/test_sphinx.py b/tests/test_sphinx.py index 44d4a825..3cfc3df4 100644 --- a/tests/test_sphinx.py +++ b/tests/test_sphinx.py @@ -45,10 +45,10 @@ def test_single_warning_mixed(self): self.assertRegexpMatches(fake_out.getvalue(), dut2) def test_multiline(self): - duterr = "/home/bljah/test/index.rst:5: WARNING: toctree contains reference to nonexisting document u'installation'" - dut = 'This1 should not be treated as warning' + duterr = "/home/bljah/test/index.rst:5: WARNING: toctree contains reference to nonexisting document u'installation'\n" + dut = 'This1 should not be treated as warning\n' dut += duterr - dut += 'This should not be treated as warning2' + dut += 'This should not be treated as warning2\n' with patch('sys.stdout', new=StringIO()) as fake_out: self.warnings.check(dut) self.assertEqual(self.warnings.return_count(), 1) From 2a301de0ac8ccb88ac5c8ee05a3db61ad1fc4db9 Mon Sep 17 00:00:00 2001 From: Stein Heselmans Date: Thu, 10 Aug 2017 10:58:03 +0200 Subject: [PATCH 09/18] Multiple warnings in multiline test --- tests/test_doxygen.py | 15 +++++++++------ tests/test_sphinx.py | 15 +++++++++------ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/tests/test_doxygen.py b/tests/test_doxygen.py index be7e0eb7..ad731fdd 100644 --- a/tests/test_doxygen.py +++ b/tests/test_doxygen.py @@ -36,12 +36,15 @@ def test_single_warning_mixed(self): self.assertRegexpMatches(fake_out.getvalue(), dut2) def test_multiline(self): - duterr = 'testfile.c:6: warning: group test: ignoring title "Some test functions" that does not match old title "Some freaky test functions"\n' - dut = 'This1 should not be treated as warning\n' - dut += duterr - dut += 'This should not be treated as warning2\n' + duterr1 = "testfile.c:6: warning: group test: ignoring title \"Some test functions\" that does not match old title \"Some freaky test functions\"\n" + duterr2 = "testfile.c:8: warning: group test: ignoring title \"Some test functions\" that does not match old title \"Some freaky test functions\"\n" + dut = "This1 should not be treated as warning\n" + dut += duterr1 + dut += "This should not be treated as warning2\n" + dut += duterr2 with patch('sys.stdout', new=StringIO()) as fake_out: self.warnings.check(dut) - self.assertEqual(self.warnings.return_count(), 1) - self.assertRegexpMatches(fake_out.getvalue(), duterr) + self.assertEqual(self.warnings.return_count(), 2) + self.assertRegexpMatches(fake_out.getvalue(), duterr1) + self.assertRegexpMatches(fake_out.getvalue(), duterr2) diff --git a/tests/test_sphinx.py b/tests/test_sphinx.py index 3cfc3df4..72006527 100644 --- a/tests/test_sphinx.py +++ b/tests/test_sphinx.py @@ -45,12 +45,15 @@ def test_single_warning_mixed(self): self.assertRegexpMatches(fake_out.getvalue(), dut2) def test_multiline(self): - duterr = "/home/bljah/test/index.rst:5: WARNING: toctree contains reference to nonexisting document u'installation'\n" - dut = 'This1 should not be treated as warning\n' - dut += duterr - dut += 'This should not be treated as warning2\n' + duterr1 = "/home/bljah/test/index.rst:5: WARNING: toctree contains reference to nonexisting document u'installation'\n" + duterr2 = "/home/bljah/test/index.rst:None: WARNING: toctree contains reference to nonexisting document u'installation'\n" + dut = "This1 should not be treated as warning\n" + dut += duterr1 + dut += "This should not be treated as warning2\n" + dut += duterr2 with patch('sys.stdout', new=StringIO()) as fake_out: self.warnings.check(dut) - self.assertEqual(self.warnings.return_count(), 1) - self.assertRegexpMatches(fake_out.getvalue(), duterr) + self.assertEqual(self.warnings.return_count(), 2) + self.assertRegexpMatches(fake_out.getvalue(), duterr1) + self.assertRegexpMatches(fake_out.getvalue(), duterr2) From 3fd2f788bb952200c4981444e355381ecdc72140 Mon Sep 17 00:00:00 2001 From: Stein Heselmans Date: Thu, 10 Aug 2017 10:59:21 +0200 Subject: [PATCH 10/18] Fix verbosity for RegexChecker --- src/mlx/warnings.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mlx/warnings.py b/src/mlx/warnings.py index dd79e722..801a57f9 100644 --- a/src/mlx/warnings.py +++ b/src/mlx/warnings.py @@ -133,11 +133,11 @@ def check(self, content): Args: content (str): The content to parse ''' - matches = re.findall(self.pattern, content) - if self.verbose: - for match in matches: - print(str(match)) - self.count += len(matches) + matches = re.finditer(self.pattern, content) + for match in matches: + self.count += 1 + if self.verbose: + print(match.group(0).strip()) class SphinxChecker(RegexChecker): From f51013559b14ad99ec3d885a80740eb731f4226a Mon Sep 17 00:00:00 2001 From: Stein Heselmans Date: Thu, 10 Aug 2017 11:00:02 +0200 Subject: [PATCH 11/18] Fix multiline test for sphinx checker --- src/mlx/warnings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlx/warnings.py b/src/mlx/warnings.py index 801a57f9..66a72fc2 100644 --- a/src/mlx/warnings.py +++ b/src/mlx/warnings.py @@ -9,7 +9,7 @@ DOXYGEN_WARNING_REGEX = r"(?:(?:((?:[/.]|[A-Za-z]:).+?):(-?\d+):\s*([Ww]arning|[Ee]rror)|<.+>:-?\d+(?::\s*([Ww]arning|[Ee]rror))?): (.+(?:\n(?!\s*(?:[Nn]otice|[Ww]arning|[Ee]rror): )[^/<\n][^:\n][^/\n].+)*)|\s*([Nn]otice|[Ww]arning|[Ee]rror): (.+))$" doxy_pattern = re.compile(DOXYGEN_WARNING_REGEX) -SPHINX_WARNING_REGEX = r"^(.+?:(?:\d+|None)): (DEBUG|INFO|WARNING|ERROR|SEVERE): (.+)\n?$" +SPHINX_WARNING_REGEX = r"(.+?:(?:\d+|None)): (DEBUG|INFO|WARNING|ERROR|SEVERE): (.+)\n?" sphinx_pattern = re.compile(SPHINX_WARNING_REGEX) From 0192708b89e52ae954176070c1c9c9c80ce9448d Mon Sep 17 00:00:00 2001 From: Stein Heselmans Date: Thu, 10 Aug 2017 15:10:18 +0200 Subject: [PATCH 12/18] improve regex for sphinx whitespace can be repeated --- src/mlx/warnings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlx/warnings.py b/src/mlx/warnings.py index 66a72fc2..6d46e73d 100644 --- a/src/mlx/warnings.py +++ b/src/mlx/warnings.py @@ -9,7 +9,7 @@ DOXYGEN_WARNING_REGEX = r"(?:(?:((?:[/.]|[A-Za-z]:).+?):(-?\d+):\s*([Ww]arning|[Ee]rror)|<.+>:-?\d+(?::\s*([Ww]arning|[Ee]rror))?): (.+(?:\n(?!\s*(?:[Nn]otice|[Ww]arning|[Ee]rror): )[^/<\n][^:\n][^/\n].+)*)|\s*([Nn]otice|[Ww]arning|[Ee]rror): (.+))$" doxy_pattern = re.compile(DOXYGEN_WARNING_REGEX) -SPHINX_WARNING_REGEX = r"(.+?:(?:\d+|None)): (DEBUG|INFO|WARNING|ERROR|SEVERE): (.+)\n?" +SPHINX_WARNING_REGEX = r"(.+?:(?:\d+|None)):\s*(DEBUG|INFO|WARNING|ERROR|SEVERE):\s*(.+)\n?" sphinx_pattern = re.compile(SPHINX_WARNING_REGEX) From 94404a387c2e6e40897100929cf512db767f38b7 Mon Sep 17 00:00:00 2001 From: Stein Heselmans Date: Thu, 10 Aug 2017 16:00:42 +0200 Subject: [PATCH 13/18] doxygen regex: don't match till end of given content --- src/mlx/warnings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlx/warnings.py b/src/mlx/warnings.py index 6d46e73d..d5781a44 100644 --- a/src/mlx/warnings.py +++ b/src/mlx/warnings.py @@ -6,7 +6,7 @@ from junitparser import JUnitXml, Failure, Error import glob -DOXYGEN_WARNING_REGEX = r"(?:(?:((?:[/.]|[A-Za-z]:).+?):(-?\d+):\s*([Ww]arning|[Ee]rror)|<.+>:-?\d+(?::\s*([Ww]arning|[Ee]rror))?): (.+(?:\n(?!\s*(?:[Nn]otice|[Ww]arning|[Ee]rror): )[^/<\n][^:\n][^/\n].+)*)|\s*([Nn]otice|[Ww]arning|[Ee]rror): (.+))$" +DOXYGEN_WARNING_REGEX = r"(?:((?:[/.]|[A-Za-z]:).+?):(-?\d+):\s*([Ww]arning|[Ee]rror)|<.+>:-?\d+(?::\s*([Ww]arning|[Ee]rror))?): (.+(?:\n(?!\s*(?:[Nn]otice|[Ww]arning|[Ee]rror): )[^/<\n][^:\n][^/\n].+)*)|\s*([Nn]otice|[Ww]arning|[Ee]rror): (.+)\n?" doxy_pattern = re.compile(DOXYGEN_WARNING_REGEX) SPHINX_WARNING_REGEX = r"(.+?:(?:\d+|None)):\s*(DEBUG|INFO|WARNING|ERROR|SEVERE):\s*(.+)\n?" From 40a1b355ebe0f2496f41e1ef630785cedbd1623a Mon Sep 17 00:00:00 2001 From: Stein Heselmans Date: Thu, 10 Aug 2017 16:02:30 +0200 Subject: [PATCH 14/18] doxygen regex: include filename in match for verbose output --- src/mlx/warnings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlx/warnings.py b/src/mlx/warnings.py index d5781a44..07f67e51 100644 --- a/src/mlx/warnings.py +++ b/src/mlx/warnings.py @@ -6,7 +6,7 @@ from junitparser import JUnitXml, Failure, Error import glob -DOXYGEN_WARNING_REGEX = r"(?:((?:[/.]|[A-Za-z]:).+?):(-?\d+):\s*([Ww]arning|[Ee]rror)|<.+>:-?\d+(?::\s*([Ww]arning|[Ee]rror))?): (.+(?:\n(?!\s*(?:[Nn]otice|[Ww]arning|[Ee]rror): )[^/<\n][^:\n][^/\n].+)*)|\s*([Nn]otice|[Ww]arning|[Ee]rror): (.+)\n?" +DOXYGEN_WARNING_REGEX = r"(?:((?:[/.]|[A-Za-z]).+?):(-?\d+):\s*([Ww]arning|[Ee]rror)|<.+>:-?\d+(?::\s*([Ww]arning|[Ee]rror))?): (.+(?:\n(?!\s*(?:[Nn]otice|[Ww]arning|[Ee]rror): )[^/<\n][^:\n][^/\n].+)*)|\s*([Nn]otice|[Ww]arning|[Ee]rror): (.+)\n?" doxy_pattern = re.compile(DOXYGEN_WARNING_REGEX) SPHINX_WARNING_REGEX = r"(.+?:(?:\d+|None)):\s*(DEBUG|INFO|WARNING|ERROR|SEVERE):\s*(.+)\n?" From ffde834a590f57f8bb09d3e1daf1153850bf6042 Mon Sep 17 00:00:00 2001 From: Stein Heselmans Date: Thu, 10 Aug 2017 16:07:28 +0200 Subject: [PATCH 15/18] doxygen regex: don't match newline as it takes all content after a matched warning --- src/mlx/warnings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlx/warnings.py b/src/mlx/warnings.py index 07f67e51..b9d7d89b 100644 --- a/src/mlx/warnings.py +++ b/src/mlx/warnings.py @@ -6,7 +6,7 @@ from junitparser import JUnitXml, Failure, Error import glob -DOXYGEN_WARNING_REGEX = r"(?:((?:[/.]|[A-Za-z]).+?):(-?\d+):\s*([Ww]arning|[Ee]rror)|<.+>:-?\d+(?::\s*([Ww]arning|[Ee]rror))?): (.+(?:\n(?!\s*(?:[Nn]otice|[Ww]arning|[Ee]rror): )[^/<\n][^:\n][^/\n].+)*)|\s*([Nn]otice|[Ww]arning|[Ee]rror): (.+)\n?" +DOXYGEN_WARNING_REGEX = r"(?:((?:[/.]|[A-Za-z]).+?):(-?\d+):\s*([Ww]arning|[Ee]rror)|<.+>:-?\d+(?::\s*([Ww]arning|[Ee]rror))?): (.+(?:(?!\s*(?:[Nn]otice|[Ww]arning|[Ee]rror): )[^/<\n][^:\n][^/\n].+)*)|\s*([Nn]otice|[Ww]arning|[Ee]rror): (.+)\n?" doxy_pattern = re.compile(DOXYGEN_WARNING_REGEX) SPHINX_WARNING_REGEX = r"(.+?:(?:\d+|None)):\s*(DEBUG|INFO|WARNING|ERROR|SEVERE):\s*(.+)\n?" From fe4bf18c60ee714185162580449f1ce26ffc8e47 Mon Sep 17 00:00:00 2001 From: Stein Heselmans Date: Thu, 10 Aug 2017 16:20:53 +0200 Subject: [PATCH 16/18] Cleanup verbosity flag --- src/mlx/warnings.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/mlx/warnings.py b/src/mlx/warnings.py index b9d7d89b..1ad05a3f 100644 --- a/src/mlx/warnings.py +++ b/src/mlx/warnings.py @@ -206,9 +206,7 @@ def __init__(self, sphinx = False, doxygen = False, junit = False, verbose = Fal verbose (bool, optional): enable verbose logging ''' self.checkerList = {} - self.verbose = False - if verbose: - self.verbose = True + self.verbose = verbose if sphinx: self.activate_checker(SphinxChecker(self.verbose)) if doxygen: From 68e936e39bf411d2281e82520c4a1790abfcf6d2 Mon Sep 17 00:00:00 2001 From: Stein Heselmans Date: Thu, 10 Aug 2017 16:51:15 +0200 Subject: [PATCH 17/18] Reduce code complexity, use filter-lambda --- src/mlx/warnings.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/mlx/warnings.py b/src/mlx/warnings.py index 1ad05a3f..da43916f 100644 --- a/src/mlx/warnings.py +++ b/src/mlx/warnings.py @@ -185,10 +185,9 @@ def check(self, content): result = JUnitXml.fromstring(content) if self.verbose: for suite in result: - for testcase in suite: - if isinstance(testcase.result, Failure) or isinstance(testcase.result, Error): - print('{classname}.{testname}'.format(classname=testcase.classname, - testname=testcase.name)) + for testcase in filter(lambda testcase: isinstance(testcase.result, (Failure, Error)), suite): + print('{classname}.{testname}'.format(classname=testcase.classname, + testname=testcase.name)) result.update_statistics() self.count += result.errors + result.failures From 7d859cd3233e75acad9b3a4912070676fe193778 Mon Sep 17 00:00:00 2001 From: Stein Heselmans Date: Thu, 10 Aug 2017 17:12:39 +0200 Subject: [PATCH 18/18] Implicit members for name and pattern, can be overriden --- src/mlx/warnings.py | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/src/mlx/warnings.py b/src/mlx/warnings.py index da43916f..b5c89564 100644 --- a/src/mlx/warnings.py +++ b/src/mlx/warnings.py @@ -14,15 +14,15 @@ class WarningsChecker(object): + name = 'checker' - def __init__(self, name, verbose=False): + def __init__(self, verbose=False): ''' Constructor Args: name (str): Name of the checker verbose (bool): Enable/disable verbose logging ''' - self.name = name self.verbose = verbose self.reset() @@ -115,16 +115,17 @@ def return_check_limits(self): class RegexChecker(WarningsChecker): + name = 'regex' + pattern = None - def __init__(self, name, pattern, verbose=False): + def __init__(self, verbose=False): ''' Constructor Args: name (str): Name of the checker pattern (str): Regular expression used by the checker in order to find warnings ''' - super(RegexChecker, self).__init__(name=name, verbose=verbose) - self.pattern = pattern + super(RegexChecker, self).__init__(verbose=verbose) def check(self, content): ''' @@ -142,26 +143,12 @@ def check(self, content): class SphinxChecker(RegexChecker): name = 'sphinx' - - def __init__(self, verbose=False): - ''' Constructor - - Args: - verbose (bool): Enable/disable verbose logging - ''' - super(SphinxChecker, self).__init__(name=SphinxChecker.name, pattern=sphinx_pattern, verbose=verbose) + pattern = sphinx_pattern class DoxyChecker(RegexChecker): name = 'doxygen' - - def __init__(self, verbose=False): - ''' Constructor - - Args: - verbose (bool): Enable/disable verbose logging - ''' - super(DoxyChecker, self).__init__(name=DoxyChecker.name, pattern=doxy_pattern, verbose=verbose) + pattern = doxy_pattern class JUnitChecker(WarningsChecker): @@ -173,7 +160,7 @@ def __init__(self, verbose=False): Args: verbose (bool): Enable/disable verbose logging ''' - super(JUnitChecker, self).__init__(name=JUnitChecker.name, verbose=verbose) + super(JUnitChecker, self).__init__(verbose=verbose) def check(self, content): '''