summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDieter Verfaillie <dieterv@optionexplicit.be>2015-06-23 20:13:17 +0200
committerDieter Verfaillie <dieterv@optionexplicit.be>2015-06-24 22:03:56 +0200
commitc7144d0ccc4ddca73c4ff690e147d247aedb2def (patch)
tree6954ad2be9ebcb25f090d92344e0ab8b113f560e
parent5f72748c8f1e8313b7f6c4c296cffdae7095cfbe (diff)
downloadgobject-introspection-c7144d0ccc4ddca73c4ff690e147d247aedb2def.tar.gz
misc: add tool semi-automating the GTK-Doc test suite update procedure
Creates .xml.in files in tests/scanner/annotationparser/gtk-doc which then need to be carefully compared for changes (using your favorite diff tool) with the .xml files already contained in that same directory. https://bugzilla.gnome.org/show_bug.cgi?id=725685
-rw-r--r--misc/update-gtkdoc-tests.py234
1 files changed, 234 insertions, 0 deletions
diff --git a/misc/update-gtkdoc-tests.py b/misc/update-gtkdoc-tests.py
new file mode 100644
index 00000000..4c1ec138
--- /dev/null
+++ b/misc/update-gtkdoc-tests.py
@@ -0,0 +1,234 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# -*- Mode: Python -*-
+
+# GObject-Introspection - a framework for introspecting GObject libraries
+# Copyright (C) 2012-2015 Dieter Verfaillie <dieterv@optionexplicit.be>
+#
+# 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.
+#
+
+
+import os
+import sys
+import io
+
+sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
+from giscanner.annotationparser import (COMMENT_BLOCK_START_RE, COMMENT_BLOCK_END_RE,
+ GtkDocCommentBlockParser, GtkDocCommentBlockWriter)
+from giscanner.message import MessageLogger, ERROR, FATAL
+
+
+HEADER = '''<?xml version="1.0" encoding="UTF-8"?>
+
+<tests xmlns="http://schemas.gnome.org/gobject-introspection/2013/test">
+
+'''
+
+TEST = '''<test>
+ <input>%(docblock)s</input>
+ <parser>
+%(tree)s
+ </parser>
+ <output>%(serialized)s</output>
+</test>
+
+'''
+
+FOOTER = '''</tests>
+'''
+
+
+def parsed2tree(docblock):
+ parsed = ''
+
+ if docblock is not None:
+ parsed += ' <docblock>\n'
+
+ parsed += ' <identifier>\n'
+ parsed += ' <name>%s</name>\n' % (docblock.name, )
+ if docblock.annotations:
+ parsed += ' <annotations>\n'
+ for ann_name, ann_options in docblock.annotations.items():
+ parsed += ' <annotation>\n'
+ parsed += ' <name>%s</name>\n' % (ann_name, )
+ if ann_options:
+ parsed += ' <options>\n'
+ if isinstance(ann_options, list):
+ for option in ann_options:
+ parsed += ' <option>\n'
+ parsed += ' <name>%s</name>\n' % (option, )
+ parsed += ' </option>\n'
+ else:
+ for (option, value) in ann_options.items():
+ parsed += ' <option>\n'
+ parsed += ' <name>%s</name>\n' % (option, )
+ if value:
+ parsed += ' <value>%s</value>\n' % (value, )
+ parsed += ' </option>\n'
+ parsed += ' </options>\n'
+ parsed += ' </annotation>\n'
+ parsed += ' </annotations>\n'
+ parsed += ' </identifier>\n'
+
+ if docblock.params:
+ parsed += ' <parameters>\n'
+ for param_name in docblock.params:
+ param = docblock.params.get(param_name)
+ parsed += ' <parameter>\n'
+ parsed += ' <name>%s</name>\n' % (param_name, )
+ if param.annotations:
+ parsed += ' <annotations>\n'
+ for ann_name, ann_options in param.annotations.items():
+ parsed += ' <annotation>\n'
+ parsed += ' <name>%s</name>\n' % (ann_name, )
+ if ann_options:
+ parsed += ' <options>\n'
+ if isinstance(ann_options, list):
+ for option in ann_options:
+ parsed += ' <option>\n'
+ parsed += ' <name>%s</name>\n' % (option, )
+ parsed += ' </option>\n'
+ else:
+ for (option, value) in ann_options.items():
+ parsed += ' <option>\n'
+ parsed += ' <name>%s</name>\n' % (option, )
+ if value:
+ parsed += ' <value>%s</value>\n' % (value, )
+ parsed += ' </option>\n'
+ parsed += ' </options>\n'
+ parsed += ' </annotation>\n'
+ parsed += ' </annotations>\n'
+ if param.description:
+ parsed += ' <description>%s</description>\n' % (param.description, )
+ parsed += ' </parameter>\n'
+ parsed += ' </parameters>\n'
+
+ if docblock.description:
+ parsed += ' <description>%s</description>\n' % (docblock.description, )
+
+ if docblock.tags:
+ parsed += ' <tags>\n'
+ for tag_name in docblock.tags:
+ tag = docblock.tags.get(tag_name)
+ parsed += ' <tag>\n'
+ parsed += ' <name>%s</name>\n' % (tag_name, )
+ if tag.annotations:
+ parsed += ' <annotations>\n'
+ for ann_name, ann_options in tag.annotations.items():
+ parsed += ' <annotation>\n'
+ parsed += ' <name>%s</name>\n' % (ann_name, )
+ if ann_options:
+ parsed += ' <options>\n'
+ if isinstance(ann_options, list):
+ for option in ann_options:
+ parsed += ' <option>\n'
+ parsed += ' <name>%s</name>\n' % (option, )
+ parsed += ' </option>\n'
+ else:
+ for (option, value) in ann_options.items():
+ parsed += ' <option>\n'
+ parsed += ' <name>%s</name>\n' % (option, )
+ if value:
+ parsed += ' <value>%s</value>\n' % (value, )
+ parsed += ' </option>\n'
+ parsed += ' </options>\n'
+ parsed += ' </annotation>\n'
+ parsed += ' </annotations>\n'
+ if tag.value:
+ parsed += ' <value>%s</value>\n' % (tag.value, )
+ if tag.description:
+ parsed += ' <description>%s</description>\n' % (tag.description, )
+ parsed += ' </tag>\n'
+ parsed += ' </tags>\n'
+
+ parsed += ' </docblock>'
+
+ return parsed
+
+
+if __name__ == '__main__':
+ if sys.version_info < (3, 0):
+ print('Sorry, update-gtkdoc-tests.py requires Python 3.x')
+ sys.exit(1)
+
+ gi_tests = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'tests', 'scanner', 'annotationparser', 'gtkdoc'))
+
+ gtkdoc_tests = None
+ if len(sys.argv) == 2:
+ gtkdoc_tests = sys.argv[1]
+ else:
+ # Fall back to default jhbuild checkoutroot directory layout
+ gtkdoc_tests = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'gtk-doc', 'tests'))
+
+ if not gtkdoc_tests or not os.path.isdir(gtkdoc_tests):
+ print('GTK-Doc source directory "%s" not found' % gtkdoc_tests)
+ sys.exit(1)
+ else:
+ print('Using GTK-Doc source directory "%s"' % gtkdoc_tests)
+
+ for root, dirs, files in os.walk(gtkdoc_tests):
+ for inputfile in files:
+ ext = os.path.splitext(inputfile)[-1].lower()
+ if 'src' in root and ext in ['.c', '.h']:
+ path = os.path.join(root, inputfile)
+ print('Reading "%s"' % path)
+
+ relpath = os.path.relpath(path, gtkdoc_tests).split(os.sep)
+ relpath = os.path.join(relpath[0], relpath[len(relpath) - 1])
+
+ logger = MessageLogger.get(namespace=None)
+ parser = GtkDocCommentBlockParser()
+ writer = GtkDocCommentBlockWriter(indent=True)
+ logger.enable_warnings((ERROR, FATAL))
+
+ with io.open(path, 'rU') as f:
+ lines = f.readlines()
+
+ chunks = []
+ in_comment = False
+ chunk_start = 0
+ chunk_end = 0
+
+ for line_index, line in enumerate(lines):
+ if not in_comment:
+ if COMMENT_BLOCK_START_RE.match(line):
+ # We are at a line that starts a GTK-Doc comment block
+ in_comment = True
+ # Store where this GTK-Doc comment block starts
+ chunk_start = line_index
+ else:
+ if COMMENT_BLOCK_END_RE.match(line):
+ # We are at a line that closes a GTK-Doc comment block
+ in_comment = False
+ # Store the GTK-Doc comment block
+ chunks.append([''.join(lines[chunk_start:line_index + 1]), relpath, chunk_start + 1])
+ # Data chunk after the GTK-Doc comment block starts at the next line
+ chunk_start = line_index + 1
+ # Store where the GTK-Doc comment block ends
+ chunk_end = line_index
+
+ outputfile = os.path.join(gi_tests, '%s.xml.in' % relpath)
+ print('Writing "%s"' % outputfile)
+ with io.open(outputfile, 'w', newline='', encoding='utf-8') as f:
+ f.write(HEADER)
+ for chunk in chunks:
+ docblock = parser.parse_comment_block(chunk[0].rstrip(), chunk[1], chunk[2])
+ if docblock:
+ f.write(TEST % {'docblock': chunk[0].rstrip(),
+ 'tree': parsed2tree(docblock),
+ 'serialized': writer.write(docblock).rstrip()})
+ f.write(FOOTER)