From af2e146f5f24b93322ad0112d37a8e41222c3085 Mon Sep 17 00:00:00 2001 From: Dieter Verfaillie Date: Wed, 4 Jul 2012 11:58:13 +0200 Subject: giscanner: add AnnotationParser tests The tests in giscanner/annotationpatters.py only test the regular expression programs used when parsing GTK-Doc comment blocks but do not test the structure of the resulting "parse tree". This patch adds 193 GTK-Doc comment blocks and the expected results AnnotationParser should return (with it's current level of understanding of GTK-Doc comment block syntax). These are compared by tests/scanner/annotationparser/test_parser.py which complains with a diff on failure. https://bugzilla.gnome.org/show_bug.cgi?id=688897 --- tests/scanner/annotationparser/test_parser.py | 297 ++++++++++++++++++++++++++ 1 file changed, 297 insertions(+) create mode 100644 tests/scanner/annotationparser/test_parser.py (limited to 'tests/scanner/annotationparser/test_parser.py') diff --git a/tests/scanner/annotationparser/test_parser.py b/tests/scanner/annotationparser/test_parser.py new file mode 100644 index 00000000..86cd41a7 --- /dev/null +++ b/tests/scanner/annotationparser/test_parser.py @@ -0,0 +1,297 @@ +# -*- Mode: Python -*- +# GObject-Introspection - a framework for introspecting GObject libraries +# Copyright (C) 2012 Dieter Verfaillie +# +# 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. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. +# + + +''' +test_parser.py + +Tests ensuring the "parse tree" built by annotationparser.py +continues to function correctly. +''' + + +import difflib +import os +import xml.etree.ElementTree as etree +import unittest + +from giscanner.annotationparser import AnnotationParser +from giscanner.ast import Namespace +from giscanner.message import MessageLogger + + +def parsed2tree(docblock): + parsed = '' + + if docblock is not None: + parsed += '\n' + + parsed += ' \n' + # An identifier name is always required, but we can't trust our + # own parser to ensure this when testing so fall back to an empty + # string when no name has been parsed... + parsed += ' %s\n' % (docblock.name or '', ) + if docblock.options.values: + parsed += ' \n' + for key, value in docblock.options.values: + parsed += ' \n' + parsed += ' %s\n' % (key, ) + if value is not None: + options = value.all() + parsed += ' \n' + for option in options: + parsed += ' \n' + parsed += ' \n' + parsed += ' \n' + parsed += ' \n' + parsed += ' \n' + + if docblock.params: + parsed += ' \n' + for param_name in docblock.params: + param = docblock.params.get(param_name) + parsed += ' \n' + parsed += ' %s\n' % (param_name, ) + if param.options.values: + parsed += ' \n' + for key, value in param.options.values: + parsed += ' \n' + parsed += ' %s\n' % (key, ) + if value is not None: + options = value.all() + parsed += ' \n' + for option in options: + parsed += ' \n' + parsed += ' \n' + parsed += ' \n' + parsed += ' \n' + if param.comment or param.value: + parsed += ' %s\n' % (param.comment or param.value, ) + parsed += ' \n' + parsed += ' \n' + + if docblock.comment or docblock.value: + parsed += ' %s\n' % (docblock.comment or docblock.value, ) + + if docblock.tags: + parsed += ' \n' + for tag_name in docblock.tags: + tag = docblock.tags.get(tag_name) + parsed += ' \n' + parsed += ' %s\n' % (tag_name, ) + if tag.options.values: + parsed += ' \n' + for key, value in tag.options.values: + parsed += ' \n' + parsed += ' %s\n' %(key, ) + if value is not None: + options = value.all() + parsed += ' \n' + for option in options: + parsed += ' \n' + parsed += ' \n' + parsed += ' \n' + parsed += ' \n' + if tag.comment or tag.value: + parsed += ' %s\n' % (tag.comment or tag.value, ) + parsed += ' \n' + parsed += ' \n' + + parsed += '' + + return parsed + +def expected2tree(docblock): + # Note: this sucks, but we can't rely on etree.tostring() to generate useable output :( + + expected = '' + + if docblock is not None: + expected += '\n' + + if docblock.find('identifier') is not None: + expected += ' \n' + # Expecting an identifier name is required, don't bother checking if it's there or not + expected += ' %s\n' % (docblock.find('identifier/name').text, ) + annotations = docblock.find('identifier/annotations') + if annotations is not None: + expected += ' \n' + for annotation in annotations.iterfind('annotation'): + expected += ' \n' + expected += ' %s\n' % (annotation.find('name').text, ) + if annotation.find('options') is not None: + expected += ' \n' + for option in annotation.iterfind('options/option'): + expected += ' \n' + expected += ' \n' + expected += ' \n' + expected += ' \n' + expected += ' \n' + + parameters = docblock.find('parameters') + if parameters is not None: + expected += ' \n' + for parameter in parameters.iterfind('parameter'): + expected += ' \n' + expected += ' %s\n' % (parameter.find('name').text, ) + annotations = parameter.find('annotations') + if annotations is not None: + expected += ' \n' + for annotation in parameter.iterfind('annotations/annotation'): + expected += ' \n' + expected += ' %s\n' % (annotation.find('name').text, ) + if annotation.find('options') is not None: + expected += ' \n' + for option in annotation.iterfind('options/option'): + expected += ' \n' + expected += ' \n' + expected += ' \n' + expected += ' \n' + if parameter.find('description') is not None: + expected += ' %s\n' % (parameter.find('description').text, ) + expected += ' \n' + expected += ' \n' + + description = docblock.find('description') + if description is not None: + expected += ' %s\n' % (description.text, ) + + tags = docblock.find('tags') + if tags is not None: + expected += ' \n' + for tag in tags.iterfind('tag'): + expected += ' \n' + expected += ' %s\n' % (tag.find('name').text, ) + annotations = tag.find('annotations') + if annotations is not None: + expected += ' \n' + for annotation in tag.iterfind('annotations/annotation'): + expected += ' \n' + expected += ' %s\n' % (annotation.find('name').text, ) + if annotation.find('options') is not None: + expected += ' \n' + for option in annotation.iterfind('options/option'): + expected += ' \n' + expected += ' \n' + expected += ' \n' + expected += ' \n' + if tag.find('description') is not None: + expected += ' %s\n' % (tag.find('description').text, ) + expected += ' \n' + expected += ' \n' + + expected += '' + + return expected + + +def create_tests(tests_dir, tests_file): + tests_name = os.path.relpath(tests_file[:-4], tests_dir) + tests_name = tests_name.replace('/', '.').replace('\\', '.') + + tests_tree = etree.parse(tests_file).getroot() + + fix_cdata_elements = tests_tree.findall('test/commentblock') + fix_cdata_elements += tests_tree.findall('.//description') + + for element in fix_cdata_elements: + if element.text: + element.text = element.text.replace('{{?', '') + + for counter, test in enumerate(tests_tree.findall('test')): + test_name = 'test_%s.%03d' % (tests_name, counter + 1) + test_method = TestCommentBlock.__create_test__(test) + setattr(TestCommentBlock, test_name, test_method) + + +class TestCommentBlock(unittest.TestCase): + @classmethod + def __create_test__(cls, testcase): + def do_test(self): + # Parse GTK-Doc comment block + commentblock = testcase.find('commentblock').text + parsed_docblock = AnnotationParser().parse_comment_block((commentblock, 'test.c', 1)) + parsed_tree = parsed2tree(parsed_docblock).split('\n') + + # Get expected output + expected_docblock = testcase.find('docblock') + expected_tree = expected2tree(expected_docblock).split('\n') + + # Construct a meaningful message + msg = 'Parsed DocBlock object tree does not match expected output:\n\n' + msg += '%s\n\n' % (commentblock, ) + + diff = difflib.unified_diff(expected_tree, parsed_tree, + 'Expected DocBlock', 'Parsed DocBlock', + n=max(len(expected_tree), len(parsed_tree)), + lineterm='') + for line in diff: + msg += '%s\n' % (line, ) + + # Compare parsed with expected DocBlock tree + self.assertEqual(parsed_tree, expected_tree, msg) + + return do_test + + +if __name__ == '__main__': + # Initialize message logger + # TODO: at some point it might be a good idea to test warnings emitted + # by annotationparser here, instead of having them in tests/warn/annotationparser.h? + namespace = Namespace('Test', '1.0') + logger = MessageLogger.get(namespace=namespace) + logger.enable_warnings(False) + + # Load test cases from disc + tests_dir = os.path.dirname(os.path.abspath(__file__)) + + for dirpath, dirnames, filenames in os.walk(tests_dir): + for filename in filenames: + tests_file = os.path.join(dirpath, filename) + if os.path.basename(tests_file).endswith('.xml'): + create_tests(tests_dir, tests_file) + + # Run test suite + unittest.main() -- cgit v1.2.1 From 651ba3d400e9efd75e1618066cd1b485cccac1a2 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Mon, 17 Dec 2012 11:08:05 -0500 Subject: tests/annotationparser: Drop Python API usage down to 2.6, not 2.7 .iterfind() is new in 2.7, but we claim 2.6 support, as I use on RHEL6. --- tests/scanner/annotationparser/test_parser.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'tests/scanner/annotationparser/test_parser.py') diff --git a/tests/scanner/annotationparser/test_parser.py b/tests/scanner/annotationparser/test_parser.py index 86cd41a7..a1c5866c 100644 --- a/tests/scanner/annotationparser/test_parser.py +++ b/tests/scanner/annotationparser/test_parser.py @@ -145,12 +145,12 @@ def expected2tree(docblock): annotations = docblock.find('identifier/annotations') if annotations is not None: expected += ' \n' - for annotation in annotations.iterfind('annotation'): + for annotation in annotations.findall('annotation'): expected += ' \n' expected += ' %s\n' % (annotation.find('name').text, ) if annotation.find('options') is not None: expected += ' \n' - for option in annotation.iterfind('options/option'): + for option in annotation.findall('options/option'): expected += ' \n' parsed += ' \n' parsed += ' \n' - if tag.comment or tag.value: - parsed += ' %s\n' % (tag.comment or tag.value, ) + if tag.description or tag.value: + parsed += ' %s\n' % (tag.description or tag.value, ) parsed += ' \n' parsed += ' \n' -- cgit v1.2.1 From 30b17d39adc7a7284b926cac6ada566eb1b62292 Mon Sep 17 00:00:00 2001 From: Dieter Verfaillie Date: Tue, 14 May 2013 17:06:24 +0200 Subject: giscanner: rename AnnotationParser() to GtkDocCommentBlockParser() Clarify the purpose of what up until now was know as the AnnotationParser() class, as it does more than just extracting annotations, it parses the complete GTK-Doc comment block. --- tests/scanner/annotationparser/test_parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests/scanner/annotationparser/test_parser.py') diff --git a/tests/scanner/annotationparser/test_parser.py b/tests/scanner/annotationparser/test_parser.py index 82ca43ba..2c8cd6ed 100644 --- a/tests/scanner/annotationparser/test_parser.py +++ b/tests/scanner/annotationparser/test_parser.py @@ -33,7 +33,7 @@ import subprocess import unittest import xml.etree.ElementTree as etree -from giscanner.annotationparser import AnnotationParser +from giscanner.annotationparser import GtkDocCommentBlockParser from giscanner.ast import Namespace from giscanner.message import MessageLogger @@ -83,7 +83,7 @@ class TestCommentBlock(unittest.TestCase): # Parse GTK-Doc comment block commentblock = testcase.find(ns('{}input')).text - parsed_docblock = AnnotationParser().parse_comment_block((commentblock, 'test.c', 1)) + parsed_docblock = GtkDocCommentBlockParser().parse_comment_block((commentblock, 'test.c', 1)) parsed_tree = self.parsed2tree(parsed_docblock).split('\n') emitted_messages = [w[w.find(':') + 1:].strip() for w in output.getvalue()] -- cgit v1.2.1 From 8d9396f9b3253bff876456ec695bcea7cbbf7a69 Mon Sep 17 00:00:00 2001 From: Dieter Verfaillie Date: Wed, 15 May 2013 22:48:42 +0200 Subject: giscanner: expand parse_comment_block() parameters Makes it consistent with the parse_comment_blocks() and _parse_comment_block() methods. --- tests/scanner/annotationparser/test_parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests/scanner/annotationparser/test_parser.py') diff --git a/tests/scanner/annotationparser/test_parser.py b/tests/scanner/annotationparser/test_parser.py index 2c8cd6ed..adf4f657 100644 --- a/tests/scanner/annotationparser/test_parser.py +++ b/tests/scanner/annotationparser/test_parser.py @@ -83,7 +83,7 @@ class TestCommentBlock(unittest.TestCase): # Parse GTK-Doc comment block commentblock = testcase.find(ns('{}input')).text - parsed_docblock = GtkDocCommentBlockParser().parse_comment_block((commentblock, 'test.c', 1)) + parsed_docblock = GtkDocCommentBlockParser().parse_comment_block(commentblock, 'test.c', 1) parsed_tree = self.parsed2tree(parsed_docblock).split('\n') emitted_messages = [w[w.find(':') + 1:].strip() for w in output.getvalue()] -- cgit v1.2.1 From 6d9022311b5d3bfb48895466880c2a15235b63a6 Mon Sep 17 00:00:00 2001 From: Dieter Verfaillie Date: Wed, 24 Jul 2013 16:56:20 +0200 Subject: giscanner: give message.ERROR a purpose It's not yet being used but will be in the future by annotationparser.py to signal the difference between message.WARNING: something is wrong but the comment block can still be parsed and serialized back into a comment block without information being lost message.ERROR: something is wrong and the comment block can *not* be parsed and serialized back into a comment block without information being lost Different tools can then act accordingly. Nothing will change for g-ir-scanner but this will be important for the GTK-Doc comment block rewriting tool to prevent extremely broken input leading to even more broken output... --- tests/scanner/annotationparser/test_parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests/scanner/annotationparser/test_parser.py') diff --git a/tests/scanner/annotationparser/test_parser.py b/tests/scanner/annotationparser/test_parser.py index adf4f657..1b82625b 100644 --- a/tests/scanner/annotationparser/test_parser.py +++ b/tests/scanner/annotationparser/test_parser.py @@ -35,7 +35,7 @@ import xml.etree.ElementTree as etree from giscanner.annotationparser import GtkDocCommentBlockParser from giscanner.ast import Namespace -from giscanner.message import MessageLogger +from giscanner.message import MessageLogger, WARNING, ERROR, FATAL XML_NS = 'http://schemas.gnome.org/gobject-introspection/2013/test' @@ -358,7 +358,7 @@ if __name__ == '__main__': # Initialize message logger namespace = Namespace('Test', '1.0') logger = MessageLogger.get(namespace=namespace) - logger.enable_warnings(True) + logger.enable_warnings((WARNING, ERROR, FATAL)) # Load test cases from disc tests_dir = os.path.dirname(os.path.abspath(__file__)) -- cgit v1.2.1 From 873c828b21ab837bea751be823b04c10e68dd9ed Mon Sep 17 00:00:00 2001 From: Dieter Verfaillie Date: Wed, 29 May 2013 18:51:02 +0200 Subject: giscanner: rename DocBlock to GtkDocCommentBlock and move it downwards after DocTag, DocOptions etc for easier reading --- tests/scanner/annotationparser/test_parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests/scanner/annotationparser/test_parser.py') diff --git a/tests/scanner/annotationparser/test_parser.py b/tests/scanner/annotationparser/test_parser.py index 1b82625b..7141c7a3 100644 --- a/tests/scanner/annotationparser/test_parser.py +++ b/tests/scanner/annotationparser/test_parser.py @@ -96,11 +96,11 @@ class TestCommentBlock(unittest.TestCase): expected_messages.append(w.text.strip()) # Compare parsed with expected GtkDocCommentBlock - msg = 'Parsed DocBlock object tree does not match expected output:\n\n' + msg = 'Parsed GtkDocCommentBlock object tree does not match expected output:\n\n' msg += '%s\n\n' % (commentblock, ) diff = difflib.unified_diff(expected_tree, parsed_tree, - 'Expected DocBlock', 'Parsed DocBlock', + 'Expected GtkDocCommentBlock', 'Parsed GtkDocCommentBlock', n=max(len(expected_tree), len(parsed_tree)), lineterm='') for line in diff: -- cgit v1.2.1 From 5469415be4c237d7ea0125d214b7e73c441954f2 Mon Sep 17 00:00:00 2001 From: Dieter Verfaillie Date: Mon, 17 Jun 2013 17:05:11 +0200 Subject: giscanner: remove unused GtkDocCommentBlock.value --- tests/scanner/annotationparser/test_parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests/scanner/annotationparser/test_parser.py') diff --git a/tests/scanner/annotationparser/test_parser.py b/tests/scanner/annotationparser/test_parser.py index 7141c7a3..c88cc266 100644 --- a/tests/scanner/annotationparser/test_parser.py +++ b/tests/scanner/annotationparser/test_parser.py @@ -177,8 +177,8 @@ class TestCommentBlock(unittest.TestCase): parsed += ' \n' parsed += ' \n' - if docblock.description or docblock.value: - parsed += ' %s\n' % (docblock.description or docblock.value, ) + if docblock.description: + parsed += ' %s\n' % (docblock.description, ) if docblock.tags: parsed += ' \n' -- cgit v1.2.1 From 839e4f10a6b291a261c200484ff05ec44a31d93e Mon Sep 17 00:00:00 2001 From: Dieter Verfaillie Date: Thu, 25 Jul 2013 17:22:21 +0200 Subject: giscanner: extract tag values --- tests/scanner/annotationparser/test_parser.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'tests/scanner/annotationparser/test_parser.py') diff --git a/tests/scanner/annotationparser/test_parser.py b/tests/scanner/annotationparser/test_parser.py index c88cc266..98ae787e 100644 --- a/tests/scanner/annotationparser/test_parser.py +++ b/tests/scanner/annotationparser/test_parser.py @@ -203,8 +203,10 @@ class TestCommentBlock(unittest.TestCase): parsed += ' \n' parsed += ' \n' parsed += ' \n' - if tag.description or tag.value: - parsed += ' %s\n' % (tag.description or tag.value, ) + if tag.value: + parsed += ' %s\n' % (tag.value, ) + if tag.description: + parsed += ' %s\n' % (tag.description, ) parsed += ' \n' parsed += ' \n' @@ -297,6 +299,8 @@ class TestCommentBlock(unittest.TestCase): expected += ' \n' expected += ' \n' expected += ' \n' + if tag.find(ns('{}value')) is not None: + expected += ' %s\n' % (tag.find(ns('{}value')).text, ) if tag.find(ns('{}description')) is not None: expected += ' %s\n' % (tag.find(ns('{}description')).text, ) expected += ' \n' -- cgit v1.2.1 From a2b22ce75937d2d996ef90e0ab683d36031365d0 Mon Sep 17 00:00:00 2001 From: Dieter Verfaillie Date: Mon, 12 Aug 2013 16:54:11 +0200 Subject: giscanner: flesh out annotation parsing and storage - remove annotations regex, restore proper parens parsing - drop weird DocOption() storage class and use lists/dicts as appropriate - make GtkDocAnnotations a simple OrderedDict subclass instead of a weird hybrid dict/list storage class - Deprecate Attribute: tag, replace with (attributes) annotation on the identifier --- tests/scanner/annotationparser/test_parser.py | 92 ++++++++++++++++----------- 1 file changed, 55 insertions(+), 37 deletions(-) (limited to 'tests/scanner/annotationparser/test_parser.py') diff --git a/tests/scanner/annotationparser/test_parser.py b/tests/scanner/annotationparser/test_parser.py index 98ae787e..c7ff5321 100644 --- a/tests/scanner/annotationparser/test_parser.py +++ b/tests/scanner/annotationparser/test_parser.py @@ -130,20 +130,25 @@ class TestCommentBlock(unittest.TestCase): parsed += ' \n' parsed += ' %s\n' % (docblock.name, ) - if docblock.annotations.values: + if docblock.annotations: parsed += ' \n' - for key, value in docblock.annotations.values: + for ann_name, ann_options in docblock.annotations.items(): parsed += ' \n' - parsed += ' %s\n' % (key, ) - if value is not None: - options = value.all() + parsed += ' %s\n' % (ann_name, ) + if ann_options: parsed += ' \n' - for option in options: - parsed += ' \n' + if isinstance(ann_options, list): + for option in ann_options: + parsed += ' \n' + else: + for (option, value) in ann_options.items(): + parsed += ' \n' parsed += ' \n' parsed += ' \n' parsed += ' \n' @@ -155,20 +160,25 @@ class TestCommentBlock(unittest.TestCase): param = docblock.params.get(param_name) parsed += ' \n' parsed += ' %s\n' % (param_name, ) - if param.annotations.values: + if param.annotations: parsed += ' \n' - for key, value in param.annotations.values: + for ann_name, ann_options in param.annotations.items(): parsed += ' \n' - parsed += ' %s\n' % (key, ) - if value is not None: - options = value.all() + parsed += ' %s\n' % (ann_name, ) + if ann_options: parsed += ' \n' - for option in options: - parsed += ' \n' + if isinstance(ann_options, list): + for option in ann_options: + parsed += ' \n' + else: + for (option, value) in ann_options.items(): + parsed += ' \n' parsed += ' \n' parsed += ' \n' parsed += ' \n' @@ -186,20 +196,25 @@ class TestCommentBlock(unittest.TestCase): tag = docblock.tags.get(tag_name) parsed += ' \n' parsed += ' %s\n' % (tag_name, ) - if tag.annotations.values: + if tag.annotations: parsed += ' \n' - for key, value in tag.annotations.values: + for ann_name, ann_options in tag.annotations.items(): parsed += ' \n' - parsed += ' %s\n' % (key, ) - if value is not None: - options = value.all() + parsed += ' %s\n' % (ann_name, ) + if ann_options: parsed += ' \n' - for option in options: - parsed += ' \n' + if isinstance(ann_options, list): + for option in ann_options: + parsed += ' \n' + else: + for (option, value) in ann_options.items(): + parsed += ' \n' parsed += ' \n' parsed += ' \n' parsed += ' \n' @@ -235,8 +250,9 @@ class TestCommentBlock(unittest.TestCase): expected += ' \n' for option in annotation.findall(ns('{}options/{}option')): expected += ' \n' expected += ' \n' @@ -260,7 +276,8 @@ class TestCommentBlock(unittest.TestCase): expected += ' \n' for option in annotation.findall(ns('{}options/{}option')): expected += ' \n' @@ -292,7 +309,8 @@ class TestCommentBlock(unittest.TestCase): expected += ' \n' for option in annotation.findall(ns('{}options/{}option')): expected += ' \n' -- cgit v1.2.1 From 4ff3c660de64ba423659bd796fbd944b7af1913d Mon Sep 17 00:00:00 2001 From: Dieter Verfaillie Date: Thu, 25 Jul 2013 17:25:49 +0200 Subject: giscanner: give parameters their own storage class --- tests/scanner/annotationparser/test_parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests/scanner/annotationparser/test_parser.py') diff --git a/tests/scanner/annotationparser/test_parser.py b/tests/scanner/annotationparser/test_parser.py index c7ff5321..99ef2c21 100644 --- a/tests/scanner/annotationparser/test_parser.py +++ b/tests/scanner/annotationparser/test_parser.py @@ -182,8 +182,8 @@ class TestCommentBlock(unittest.TestCase): parsed += ' \n' parsed += ' \n' parsed += ' \n' - if param.description or param.value: - parsed += ' %s\n' % (param.description or param.value, ) + if param.description: + parsed += ' %s\n' % (param.description, ) parsed += ' \n' parsed += ' \n' -- cgit v1.2.1 From 6a874b86a1b9aae0c50a30b8cd3033870797eb1c Mon Sep 17 00:00:00 2001 From: Dieter Verfaillie Date: Tue, 23 Jul 2013 17:34:07 +0200 Subject: giscanner: refactor GTK-Doc comment block serialization --- tests/scanner/annotationparser/test_parser.py | 33 +++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 5 deletions(-) (limited to 'tests/scanner/annotationparser/test_parser.py') diff --git a/tests/scanner/annotationparser/test_parser.py b/tests/scanner/annotationparser/test_parser.py index 99ef2c21..ef4d7462 100644 --- a/tests/scanner/annotationparser/test_parser.py +++ b/tests/scanner/annotationparser/test_parser.py @@ -22,8 +22,7 @@ ''' test_parser.py -Tests ensuring the "parse tree" built by annotationparser.py -continues to function correctly. +Tests ensuring annotationparser.py continues to function correctly. ''' @@ -33,7 +32,7 @@ import subprocess import unittest import xml.etree.ElementTree as etree -from giscanner.annotationparser import GtkDocCommentBlockParser +from giscanner.annotationparser import GtkDocCommentBlockParser, GtkDocCommentBlockWriter from giscanner.ast import Namespace from giscanner.message import MessageLogger, WARNING, ERROR, FATAL @@ -120,6 +119,31 @@ class TestCommentBlock(unittest.TestCase): msg += self._diff_messages([expected_message], [emitted_message]) self.assertTrue(expected_message == emitted_message, msg) + # Compare serialized with expected comment block + expected_serialized = testcase.find(ns('{}output')) + indent = True + + if expected_serialized is None: + expected_serialized = '' + else: + if 'indent' in expected_serialized.attrib: + indent = expected_serialized.attrib['indent'] + if indent.lower() in ('false', '0'): + indent = False + elif indent.lower() in ('true', '1'): + indent = True + else: + self.assert_(False, 'Unknown value for "indent" attribute: %s' % (indent)) + + expected_serialized = expected_serialized.text + '\n' or None + + commentblockwriter = GtkDocCommentBlockWriter(indent=indent) + serialized = commentblockwriter.write(parsed_docblock) + + msg = 'Serialized comment block does not match expected output:\n\n' + msg += self._diff_messages(expected_serialized.split('\n'), serialized.split('\n')) + self.assertTrue(expected_serialized == serialized, msg) + return do_test def parsed2tree(self, docblock): @@ -230,8 +254,6 @@ class TestCommentBlock(unittest.TestCase): return parsed def expected2tree(self, docblock): - # Note: this sucks, but we can't rely on etree.tostring() to generate useable output :( - expected = '' if docblock is not None: @@ -364,6 +386,7 @@ def create_tests(logger, tests_dir, tests_file): fix_cdata_elements = tests_tree.findall(ns('{}test/{}input')) fix_cdata_elements += tests_tree.findall(ns('.//{}description')) + fix_cdata_elements += tests_tree.findall(ns('{}test/{}output')) for element in fix_cdata_elements: if element.text: -- cgit v1.2.1 From 42bb69a6a2f12165a9758b192e80da089e00ab5c Mon Sep 17 00:00:00 2001 From: Simon Feltman Date: Wed, 18 Dec 2013 18:21:55 -0800 Subject: tests: Refactor test_parser and test_patterns to use unittest.TestSuite Update both test_parser.py and test_patterns.py to dynamically generate TestCase sub-classes rather than modify a statically defined one. Use unittest.TestSuite to queue up the generated test cases via the "load_tests" hook. Use underscores instead of periods as a seperator for dynamically generated test cases and methods to match Python identifiers. Beyond general cleanup, these changes will help the ability to specify Python tests individually. https://bugzilla.gnome.org/show_bug.cgi?id=720713 --- tests/scanner/annotationparser/test_parser.py | 54 ++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 6 deletions(-) (limited to 'tests/scanner/annotationparser/test_parser.py') diff --git a/tests/scanner/annotationparser/test_parser.py b/tests/scanner/annotationparser/test_parser.py index ef4d7462..79cc8622 100644 --- a/tests/scanner/annotationparser/test_parser.py +++ b/tests/scanner/annotationparser/test_parser.py @@ -380,8 +380,7 @@ class TestCommentBlock(unittest.TestCase): return retval -def create_tests(logger, tests_dir, tests_file): - tests_name = os.path.relpath(tests_file[:-4], tests_dir).replace('/', '.').replace('\\', '.') +def create_test_case(logger, tests_dir, tests_file): tests_tree = etree.parse(tests_file).getroot() fix_cdata_elements = tests_tree.findall(ns('{}test/{}input')) @@ -393,17 +392,27 @@ def create_tests(logger, tests_dir, tests_file): element.text = element.text.replace('{{?', '') + test_methods = {} for counter, test in enumerate(tests_tree.findall(ns('{}test'))): - test_name = 'test_%s.%03d' % (tests_name, counter + 1) + test_name = 'test_%03d' % (counter + 1) test_method = TestCommentBlock.__create_test__(logger, test) - setattr(TestCommentBlock, test_name, test_method) + test_method.__name__ = test_name + test_methods[test_name] = test_method + # Dynamically generate a new subclass of TestCommentBlock in TitleCase + # with generated test methods. + test_class_name = os.path.relpath(tests_file[:-4], tests_dir) + test_class_name = test_class_name.replace('/', ' ').replace('\\', ' ').replace('.', ' ') + test_class_name = 'Test' + test_class_name.title().replace(' ', '') + return type(test_class_name, (TestCommentBlock,), test_methods) -if __name__ == '__main__': + +def create_test_cases(): # Initialize message logger namespace = Namespace('Test', '1.0') logger = MessageLogger.get(namespace=namespace) logger.enable_warnings((WARNING, ERROR, FATAL)) + test_cases = {} # Load test cases from disc tests_dir = os.path.dirname(os.path.abspath(__file__)) @@ -413,7 +422,40 @@ if __name__ == '__main__': tests_file = os.path.join(dirpath, filename) if os.path.basename(tests_file).endswith('.xml'): validate(tests_file) - create_tests(logger, tests_dir, tests_file) + test_case = create_test_case(logger, tests_dir, tests_file) + test_cases[test_case.__name__] = test_case + + return test_cases + + +# We currently need to push all the new test cases into the modules globals +# in order for parameterized tests to work. Ideally all that should be needed +# is the "load_tests" hook, but this does not work in the case were the tests +# are run in parameterized mode, e.g: python -m unittest test_parser.Test... +_all_tests = create_test_cases() +globals().update(_all_tests) + + +# Hook function for Python test loader. +def load_tests(loader, tests, pattern): + suite = unittest.TestSuite() + # add standard tests from module + suite.addTests(tests) + + # Initialize message logger + namespace = Namespace('Test', '1.0') + logger = MessageLogger.get(namespace=namespace) + logger.enable_warnings((WARNING, ERROR, FATAL)) + # Load test cases from disc + tests_dir = os.path.dirname(os.path.abspath(__file__)) + + for name, test_case in _all_tests.iteritems(): + tests = loader.loadTestsFromTestCase(test_case) + suite.addTests(tests) + return suite + + +if __name__ == '__main__': # Run test suite unittest.main() -- cgit v1.2.1