diff options
Diffstat (limited to 'tests/scanner/annotationparser/test_patterns.py')
-rw-r--r-- | tests/scanner/annotationparser/test_patterns.py | 943 |
1 files changed, 943 insertions, 0 deletions
diff --git a/tests/scanner/annotationparser/test_patterns.py b/tests/scanner/annotationparser/test_patterns.py new file mode 100644 index 00000000..774d674c --- /dev/null +++ b/tests/scanner/annotationparser/test_patterns.py @@ -0,0 +1,943 @@ +# -*- Mode: Python -*- +# GObject-Introspection - a framework for introspecting GObject libraries +# Copyright (C) 2012 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. +# + + +''' +test_patterns.py + +Tests ensuring the regular expression programs used +in annotationparser.py continue to function correctly. +Each regular expression program is tested on input that +should not match and input that should match. When input +should match, resulting symbolic groups are verified +against the expected output. +''' + + +from giscanner.annotationparser import (COMMENT_BLOCK_START_RE, COMMENT_BLOCK_END_RE, + COMMENT_ASTERISK_RE, INDENTATION_RE, EMPTY_LINE_RE, + SECTION_RE, SYMBOL_RE, PROPERTY_RE, + SIGNAL_RE, PARAMETER_RE, TAG_RE, + TAG_VALUE_VERSION_RE, TAG_VALUE_STABILITY_RE) +import unittest + + +comment_start_tests = [ + (COMMENT_BLOCK_START_RE, '/**', + {'code': '', + 'token': '/**', + 'comment': ''}), + (COMMENT_BLOCK_START_RE, ' /**', + {'code': '', + 'token': '/**', + 'comment': ''}), + (COMMENT_BLOCK_START_RE, ' /** ', + {'code': '', + 'token': '/**', + 'comment': ''}), + (COMMENT_BLOCK_START_RE, 'xyz /** ', + {'code': 'xyz', + 'token': '/**', + 'comment': ''}), + (COMMENT_BLOCK_START_RE, ' xyz /** ', + {'code': ' xyz', + 'token': '/**', + 'comment': ''}), + (COMMENT_BLOCK_START_RE, '/** xyz', + {'code': '', + 'token': '/**', + 'comment': 'xyz'}), + (COMMENT_BLOCK_START_RE, ' /**xyz', + {'code': '', + 'token': '/**', + 'comment': 'xyz'}), + (COMMENT_BLOCK_START_RE, ' /** xyz', + {'code': '', + 'token': '/**', + 'comment': 'xyz'}), + (COMMENT_BLOCK_START_RE, '/***', + None), + (COMMENT_BLOCK_START_RE, ' /***', + None), + (COMMENT_BLOCK_START_RE, ' /*** ', + None), + (COMMENT_BLOCK_START_RE, '/*** xyz', + None), + (COMMENT_BLOCK_START_RE, '/***** xyz', + None), + (COMMENT_BLOCK_START_RE, ' /*****xyz', + None), + (COMMENT_BLOCK_START_RE, ' /**/', + None), +] + + +comment_end_tests = [ + (COMMENT_BLOCK_END_RE, '*/', + {'comment': '', + 'token': '*/', + 'code': ''}), + (COMMENT_BLOCK_END_RE, ' */', + {'comment': '', + 'token': '*/', + 'code': ''}), + (COMMENT_BLOCK_END_RE, ' */ ', + {'comment': '', + 'token': '*/', + 'code': ''}), + (COMMENT_BLOCK_END_RE, '*/xyz', + {'comment': '', + 'token': '*/', + 'code': 'xyz'}), + (COMMENT_BLOCK_END_RE, ' */xyz', + {'comment': '', + 'token': '*/', + 'code': 'xyz'}), + (COMMENT_BLOCK_END_RE, ' */ xyz', + {'comment': '', + 'token': '*/', + 'code': ' xyz'}), + (COMMENT_BLOCK_END_RE, '**/', + {'comment': '', + 'token': '**/', + 'code': ''}), + (COMMENT_BLOCK_END_RE, ' **/', + {'comment': '', + 'token': '**/', + 'code': ''}), + (COMMENT_BLOCK_END_RE, ' **/ ', + {'comment': '', + 'token': '**/', + 'code': ''}), + (COMMENT_BLOCK_END_RE, 'test */', + {'comment': 'test', + 'token': '*/', + 'code': ''}), + (COMMENT_BLOCK_END_RE, ' test*/', + {'comment': 'test', + 'token': '*/', + 'code': ''}), + (COMMENT_BLOCK_END_RE, 'test */ xyz', + {'comment': 'test', + 'token': '*/', + 'code': ' xyz'}), + (COMMENT_BLOCK_END_RE, ' test*/ xyz ', + {'comment': 'test', + 'token': '*/', + 'code': ' xyz'}), + (COMMENT_BLOCK_END_RE, 'test **/', + {'comment': 'test', + 'token': '**/', + 'code': ''}), + (COMMENT_BLOCK_END_RE, ' test**/', + {'comment': 'test', + 'token': '**/', + 'code': ''}), + (COMMENT_BLOCK_END_RE, 'test *****/', + {'comment': 'test', + 'token': '*****/', + 'code': ''}), + (COMMENT_BLOCK_END_RE, ' test*****/', + {'comment': 'test', + 'token': '*****/', + 'code': ''})] + + +comment_asterisk_tests = [ + (COMMENT_ASTERISK_RE, '*', + {'comment': ''}), + (COMMENT_ASTERISK_RE, '* ', + {'comment': ''}), + (COMMENT_ASTERISK_RE, ' *', + {'comment': ''}), + (COMMENT_ASTERISK_RE, ' * ', + {'comment': ''}), + (COMMENT_ASTERISK_RE, ' * ', + {'comment': ''}), + (COMMENT_ASTERISK_RE, ' * test', + {'comment': ''}), + (COMMENT_ASTERISK_RE, 'test * ', + {'comment': 'test'})] + + +indentaton_tests = [ + (INDENTATION_RE, '', + {'indentation': ''}), + (INDENTATION_RE, ' ', + {'indentation': ' '}), + (INDENTATION_RE, ' ', + {'indentation': ' '}), + (INDENTATION_RE, ' x', + {'indentation': ' '}), + (INDENTATION_RE, ' *', + {'indentation': ' '})] + + +empty_line_tests = [ + (EMPTY_LINE_RE, '', + {}), + (EMPTY_LINE_RE, ' ', + {}), + (EMPTY_LINE_RE, ' .', + None)] + + +identifier_section_tests = [ + (SECTION_RE, 'TSIEOCN', + None), + (SECTION_RE, 'section', + None), + (SECTION_RE, 'section:', + None), + (SECTION_RE, 'section:test', + None), + (SECTION_RE, 'SECTION', + None), + (SECTION_RE, 'SECTION \t ', + None), + (SECTION_RE, ' \t SECTION \t ', + None), + (SECTION_RE, 'SECTION: \t ', + None), + (SECTION_RE, 'SECTION : ', + None), + (SECTION_RE, ' SECTION : ', + None), + (SECTION_RE, 'SECTION:gtkwidget', + {'delimiter': ':', + 'section_name': 'gtkwidget'}), + (SECTION_RE, 'SECTION:gtkwidget ', + {'delimiter': ':', + 'section_name': 'gtkwidget'}), + (SECTION_RE, ' SECTION:gtkwidget', + {'delimiter': ':', + 'section_name': 'gtkwidget'}), + (SECTION_RE, ' SECTION:gtkwidget\t ', + {'delimiter': ':', + 'section_name': 'gtkwidget'}), + (SECTION_RE, 'SECTION: gtkwidget ', + {'delimiter': ':', + 'section_name': 'gtkwidget'}), + (SECTION_RE, 'SECTION : gtkwidget', + {'delimiter': ':', + 'section_name': 'gtkwidget'}), + (SECTION_RE, 'SECTION gtkwidget \f ', + {'delimiter': '', + 'section_name': 'gtkwidget'})] + +identifier_symbol_tests = [ + (SYMBOL_RE, 'GBaseFinalizeFunc:', + {'delimiter': ':', + 'symbol_name': 'GBaseFinalizeFunc', + 'fields': ''}), + (SYMBOL_RE, 'gtk_widget_show ', + {'delimiter': '', + 'symbol_name': 'gtk_widget_show', + 'fields': ''}), + (SYMBOL_RE, ' gtk_widget_show', + {'delimiter': '', + 'symbol_name': 'gtk_widget_show', + 'fields': ''}), + (SYMBOL_RE, ' gtk_widget_show ', + {'delimiter': '', + 'symbol_name': 'gtk_widget_show', + 'fields': ''}), + (SYMBOL_RE, 'gtk_widget_show:', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': ''}), + (SYMBOL_RE, 'gtk_widget_show :', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': ''}), + (SYMBOL_RE, 'gtk_widget_show: ', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': ''}), + (SYMBOL_RE, 'gtk_widget_show : ', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': ''}), + (SYMBOL_RE, ' gtk_widget_show:', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': ''}), + (SYMBOL_RE, ' gtk_widget_show :', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': ''}), + (SYMBOL_RE, ' gtk_widget_show: ', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': ''}), + (SYMBOL_RE, ' gtk_widget_show : ', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': ''}), + (SYMBOL_RE, 'gtk_widget_show:(skip):', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip)'}), + (SYMBOL_RE, 'gtk_widget_show (skip)', + {'delimiter': '', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip)'}), + (SYMBOL_RE, 'gtk_widget_show: (skip)', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip)'}), + (SYMBOL_RE, 'gtk_widget_show : (skip)', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip)'}), + (SYMBOL_RE, 'gtk_widget_show: (skip)', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip)'}), + (SYMBOL_RE, 'gtk_widget_show : (skip)', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip)'}), + (SYMBOL_RE, ' gtk_widget_show:(skip)', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip)'}), + (SYMBOL_RE, ' gtk_widget_show :(skip)', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip)'}), + (SYMBOL_RE, ' gtk_widget_show: (skip)', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip)'}), + (SYMBOL_RE, ' gtk_widget_show : (skip) \t ', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip)'}), + (SYMBOL_RE, ' gtk_widget_show : (skip) \t ', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip)'}), + (SYMBOL_RE, 'gtk_widget_show:(skip)(test1)', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip)(test1)'}), + (SYMBOL_RE, 'gtk_widget_show (skip)(test1)', + {'delimiter': '', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip)(test1)'}), + (SYMBOL_RE, 'gtk_widget_show: (skip) (test1)', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip) (test1)'}), + (SYMBOL_RE, 'gtk_widget_show : (skip) (test1)', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip) (test1)'}), + (SYMBOL_RE, 'gtk_widget_show: (skip) (test1)', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip) (test1)'}), + (SYMBOL_RE, 'gtk_widget_show : (skip) (test1)', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip) (test1)'}), + (SYMBOL_RE, ' gtk_widget_show:(skip) (test1)', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip) (test1)'}), + (SYMBOL_RE, ' gtk_widget_show :(skip) (test1)', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip) (test1)'}), + (SYMBOL_RE, ' gtk_widget_show: (skip) (test1)', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip) (test1)'}), + (SYMBOL_RE, ' gtk_widget_show : (skip) (test1) ', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip) (test1)'}), + (SYMBOL_RE, 'gtk_widget_show: (skip) (test1) (test-2)', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip) (test1) (test-2)'}), + (SYMBOL_RE, 'gtk_widget_show : (skip) (test1) (test-2)', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip) (test1) (test-2)'}), + (SYMBOL_RE, 'gtk_widget_show: (skip) (test1) (test-2)', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip) (test1) (test-2)'}), + (SYMBOL_RE, 'gtk_widget_show : (skip) (test1) (test-2)', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip) (test1) (test-2)'}), + (SYMBOL_RE, ' gtk_widget_show:(skip) (test1) (test-2)', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip) (test1) (test-2)'}), + (SYMBOL_RE, ' gtk_widget_show :(skip) (test1) (test-2)', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip) (test1) (test-2)'}), + (SYMBOL_RE, ' gtk_widget_show: (skip) (test1) (test-2)', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip) (test1) (test-2)'}), + (SYMBOL_RE, ' gtk_widget_show : (skip) (test1) (test-2) ', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip) (test1) (test-2)'}), + (SYMBOL_RE, ' gtk_widget_show : (skip) (test1) (test-2) ', + {'delimiter': ':', + 'symbol_name': 'gtk_widget_show', + 'fields': '(skip) (test1) (test-2)'}), + # constants + (SYMBOL_RE, 'MY_CONSTANT:', + {'delimiter': ':', + 'symbol_name': 'MY_CONSTANT', + 'fields': ''}), + # structs + (SYMBOL_RE, 'FooWidget:', + {'delimiter': ':', + 'symbol_name': 'FooWidget', + 'fields': ''}), + # enums + (SYMBOL_RE, 'Something:', + {'delimiter': ':', + 'symbol_name': 'Something', + 'fields': ''}), + # annotations with multiple closing parentheses + (SYMBOL_RE, 'FooWidget: (transfer full) (type GLib.List(utf8))', + {'delimiter': ':', + 'symbol_name': 'FooWidget', + 'fields': '(transfer full) (type GLib.List(utf8))'}), + (SYMBOL_RE, 'FooWidget: (transfer full) (type GLib.List((utf8)))', + {'delimiter': ':', + 'symbol_name': 'FooWidget', + 'fields': '(transfer full) (type GLib.List((utf8)))'}), + (SYMBOL_RE, 'FooWidget: (transfer full) (type GLib.List(GLib.List(utf8)))', + {'delimiter': ':', + 'symbol_name': 'FooWidget', + 'fields': '(transfer full) (type GLib.List(GLib.List(utf8)))'}), + (SYMBOL_RE, 'FooWidget: (type GLib.List(GLib.List(utf8))) (transfer full)', + {'delimiter': ':', + 'symbol_name': 'FooWidget', + 'fields': '(type GLib.List(GLib.List(utf8))) (transfer full)'}), + (SYMBOL_RE, 'FooWidget: (type GLib.List(GLib.List(utf8)))(transfer full)(type GLib.List(GLib.List(utf8)))', + {'delimiter': ':', + 'symbol_name': 'FooWidget', + 'fields': '(type GLib.List(GLib.List(utf8)))(transfer full)(type GLib.List(GLib.List(utf8)))'})] + +identifier_property_tests = [ + # simple property name + (PROPERTY_RE, 'GtkWidget:name (skip)', + {'class_name': 'GtkWidget', + 'property_name': 'name', + 'delimiter': '', + 'fields': '(skip)'}), + (PROPERTY_RE, 'GtkWidget:name', + {'class_name': 'GtkWidget', + 'property_name': 'name', + 'delimiter': '', + 'fields': ''}), + (PROPERTY_RE, ' GtkWidget :name', + {'class_name': 'GtkWidget', + 'property_name': 'name', + 'delimiter': '', + 'fields': ''}), + (PROPERTY_RE, 'GtkWidget: name ', + {'class_name': 'GtkWidget', + 'property_name': 'name', + 'delimiter': '', + 'fields': ''}), + (PROPERTY_RE, ' GtkWidget : name ', + {'class_name': 'GtkWidget', + 'property_name': 'name', + 'delimiter': '', + 'fields': ''}), + (PROPERTY_RE, 'GtkWidget:name:', + {'class_name': 'GtkWidget', + 'property_name': 'name', + 'delimiter': ':', + 'fields': ''}), + (PROPERTY_RE, 'GtkWidget:name: ', + {'class_name': 'GtkWidget', + 'property_name': 'name', + 'delimiter': ':', + 'fields': ''}), + (PROPERTY_RE, ' GtkWidget:name:', + {'class_name': 'GtkWidget', + 'property_name': 'name', + 'delimiter': ':', + 'fields': ''}), + (PROPERTY_RE, 'Something:name:', + {'class_name': 'Something', + 'property_name': 'name', + 'delimiter': ':', + 'fields': ''}), + (PROPERTY_RE, 'Something:name: ', + {'class_name': 'Something', + 'property_name': 'name', + 'delimiter': ':', + 'fields': ''}), + (PROPERTY_RE, ' Something:name:', + {'class_name': 'Something', + 'property_name': 'name', + 'delimiter': ':', + 'fields': ''}), + (PROPERTY_RE, 'Weird-thing:name:', + None), + (PROPERTY_RE, 'really-weird_thing:name:', + None), + (PROPERTY_RE, 'GWin32InputStream:handle:', + {'class_name': 'GWin32InputStream', + 'property_name': 'handle', + 'delimiter': ':', + 'fields': ''}), + # properties: property name that contains a dash + (PROPERTY_RE, 'GtkWidget:double-buffered (skip)', + {'class_name': 'GtkWidget', + 'property_name': 'double-buffered', + 'delimiter': '', + 'fields': '(skip)'}), + (PROPERTY_RE, 'GtkWidget:double-buffered', + {'class_name': 'GtkWidget', + 'property_name': 'double-buffered', + 'delimiter': '', + 'fields': ''}), + (PROPERTY_RE, ' GtkWidget :double-buffered', + {'class_name': 'GtkWidget', + 'property_name': 'double-buffered', + 'delimiter': '', + 'fields': ''}), + (PROPERTY_RE, 'GtkWidget: double-buffered ', + {'class_name': 'GtkWidget', + 'property_name': 'double-buffered', + 'delimiter': '', + 'fields': ''}), + (PROPERTY_RE, ' GtkWidget : double-buffered ', + {'class_name': 'GtkWidget', + 'property_name': 'double-buffered', + 'delimiter': '', + 'fields': ''}), + (PROPERTY_RE, 'GtkWidget:double-buffered:', + {'class_name': 'GtkWidget', + 'property_name': 'double-buffered', + 'delimiter': ':', + 'fields': ''}), + (PROPERTY_RE, 'GtkWidget:double-buffered: ', + {'class_name': 'GtkWidget', + 'property_name': 'double-buffered', + 'delimiter': ':', + 'fields': ''}), + (PROPERTY_RE, ' GtkWidget:double-buffered:', + {'class_name': 'GtkWidget', + 'property_name': 'double-buffered', + 'delimiter': ':', + 'fields': ''}), + (PROPERTY_RE, 'Something:double-buffered:', + {'class_name': 'Something', + 'property_name': 'double-buffered', + 'delimiter': ':', + 'fields': ''}), + (PROPERTY_RE, 'Something:double-buffered: ', + {'class_name': 'Something', + 'property_name': 'double-buffered', + 'delimiter': ':', + 'fields': ''}), + (PROPERTY_RE, ' Something:double-buffered:', + {'class_name': 'Something', + 'property_name': 'double-buffered', + 'delimiter': ':', + 'fields': ''}), + (PROPERTY_RE, 'Weird-thing:double-buffered:', + None), + (PROPERTY_RE, 'really-weird_thing:double-buffered:', + None), + (PROPERTY_RE, ' GMemoryOutputStream:realloc-function: (skip)', + {'class_name': 'GMemoryOutputStream', + 'property_name': 'realloc-function', + 'delimiter': ':', + 'fields': '(skip)'}), + # properties: data with multiple closing parentheses + (PROPERTY_RE, 'GMemoryOutputStream:realloc-function: (transfer full) (type GLib.List(utf8))', + {'class_name': 'GMemoryOutputStream', + 'property_name': 'realloc-function', + 'delimiter': ':', + 'fields': '(transfer full) (type GLib.List(utf8))'}), + (PROPERTY_RE, 'GMemoryOutputStream:realloc-function: (transfer full) (type GLib.List((utf8)))', + {'class_name': 'GMemoryOutputStream', + 'property_name': 'realloc-function', + 'delimiter': ':', + 'fields': '(transfer full) (type GLib.List((utf8)))'}), + (PROPERTY_RE, 'GMemoryOutputStream:realloc-function: (transfer full) (type GLib.List(GLib.List(utf8)))', + {'class_name': 'GMemoryOutputStream', + 'property_name': 'realloc-function', + 'delimiter': ':', + 'fields': '(transfer full) (type GLib.List(GLib.List(utf8)))'}), + (PROPERTY_RE, 'GMemoryOutputStream:realloc-function: (type GLib.List(GLib.List(utf8))) (transfer full)', + {'class_name': 'GMemoryOutputStream', + 'property_name': 'realloc-function', + 'delimiter': ':', + 'fields': '(type GLib.List(GLib.List(utf8))) (transfer full)'})] + +identifier_signal_tests = [ + # simple signal name + (SIGNAL_RE, 'GtkWidget::changed: (skip)', + {'class_name': 'GtkWidget', + 'signal_name': 'changed', + 'delimiter': ':', + 'fields': '(skip)'}), + (SIGNAL_RE, 'GtkWidget::changed:', + {'class_name': 'GtkWidget', + 'signal_name': 'changed', + 'delimiter': ':', + 'fields': ''}), + (SIGNAL_RE, 'Something::changed:', + {'class_name': 'Something', + 'signal_name': 'changed', + 'delimiter': ':', + 'fields': ''}), + (SIGNAL_RE, 'Weird-thing::changed:', + None), + (SIGNAL_RE, 'really-weird_thing::changed:', + None), + # signals: signal name that contains a dash + (SIGNAL_RE, 'GtkWidget::hierarchy-changed: (skip)', + {'class_name': 'GtkWidget', + 'signal_name': 'hierarchy-changed', + 'delimiter': ':', + 'fields': '(skip)'}), + (SIGNAL_RE, 'GtkWidget::hierarchy-changed:', + {'class_name': 'GtkWidget', + 'signal_name': 'hierarchy-changed', + 'delimiter': ':', + 'fields': ''}), + (SIGNAL_RE, 'Something::hierarchy-changed:', + {'class_name': 'Something', + 'signal_name': 'hierarchy-changed', + 'delimiter': ':', + 'fields': ''}), + (SIGNAL_RE, 'Weird-thing::hierarchy-changed:', + None), + (SIGNAL_RE, 'really-weird_thing::hierarchy-changed:', + None), + # signals: data with multiple closing parentheses + (SIGNAL_RE, 'GtkWidget::hierarchy-changed: (transfer full) (type GLib.List(utf8))', + {'class_name': 'GtkWidget', + 'signal_name': 'hierarchy-changed', + 'delimiter': ':', + 'fields': '(transfer full) (type GLib.List(utf8))'}), + (SIGNAL_RE, 'GtkWidget::hierarchy-changed: (transfer full) (type GLib.List((utf8)))', + {'class_name': 'GtkWidget', + 'signal_name': 'hierarchy-changed', + 'delimiter': ':', + 'fields': '(transfer full) (type GLib.List((utf8)))'}), + (SIGNAL_RE, 'GtkWidget::hierarchy-changed: (transfer full) (type GLib.List(GLib.List(utf8)))', + {'class_name': 'GtkWidget', + 'signal_name': 'hierarchy-changed', + 'delimiter': ':', + 'fields': '(transfer full) (type GLib.List(GLib.List(utf8)))'}), + (SIGNAL_RE, 'GtkWidget::hierarchy-changed: (type GLib.List(GLib.List(utf8))) (transfer full)', + {'class_name': 'GtkWidget', + 'signal_name': 'hierarchy-changed', + 'delimiter': ':', + 'fields': '(type GLib.List(GLib.List(utf8))) (transfer full)'})] + +parameter_tests = [ + (PARAMETER_RE, '@Short_description: Base class for all widgets ', + {'parameter_name': 'Short_description', + 'fields': 'Base class for all widgets'}), + (PARAMETER_RE, '@...: the value of the first property, followed optionally by more', + {'parameter_name': '...', + 'fields': 'the value of the first property, followed optionally by more'}), + (PARAMETER_RE, '@args...: list of arguments', + {'parameter_name': 'args...', + 'fields': 'list of arguments'}), + (PARAMETER_RE, '@widget: a #GtkWidget', + {'parameter_name': 'widget', + 'fields': 'a #GtkWidget'}), + (PARAMETER_RE, '@widget_pointer: (inout) (transfer none): ' + 'address of a variable that contains @widget', + {'parameter_name': 'widget_pointer', + 'fields': '(inout) (transfer none): address of a variable that contains @widget'}), + (PARAMETER_RE, '@weird_thing: (inout) (transfer none) (allow-none) (attribute) (destroy) ' + '(foreign) (inout) (out) (transfer) (skip) (method): some weird @thing', + {'parameter_name': 'weird_thing', + 'fields': '(inout) (transfer none) (allow-none) (attribute) (destroy) ' + '(foreign) (inout) (out) (transfer) (skip) (method): ' + 'some weird @thing'}), + (PARAMETER_RE, '@data: a pointer to the element data. The data may be moved as elements ' + 'are added to the #GByteArray.', + {'parameter_name': 'data', + 'fields': 'a pointer to the element data. The data may be moved as elements ' + 'are added to the #GByteArray.'}), + (PARAMETER_RE, '@a: a #GSequenceIter', + {'parameter_name': 'a', + 'fields': 'a #GSequenceIter'}), + (PARAMETER_RE, '@keys: (array length=n_keys) (element-type GQuark) (allow-none):', + {'parameter_name': 'keys', + 'fields': '(array length=n_keys) (element-type GQuark) (allow-none):'}), + # parentheses in description + (PARAMETER_RE, '@foo: This is a foo (be careful using it)', + {'parameter_name': 'foo', + 'fields': 'This is a foo (be careful using it)'}), + (PARAMETER_RE, '@foo: This is a foo (be careful using it) and see also: bar', + {'parameter_name': 'foo', + 'fields': 'This is a foo (be careful using it) and see also: bar'}), + (PARAMETER_RE, '@foo: This is a foo (be careful using it) and see also: bar and baz', + {'parameter_name': 'foo', + 'fields': 'This is a foo (be careful using it) and see also: bar and baz'}), + # annotations with multiple closing parentheses, combined with parentheses in description + (PARAMETER_RE, '@foo: (transfer full) (element-type guint8): This is a foo (be careful using it) and see also: bar and baz', + {'parameter_name': 'foo', + 'fields': '(transfer full) (element-type guint8): This is a foo (be careful using it) and see also: bar and baz'}), + (PARAMETER_RE, '@foo: (transfer full) (element-type GLib.List(utf8)): This is a foo (be careful using it) and see also: bar and baz', + {'parameter_name': 'foo', + 'fields': '(transfer full) (element-type GLib.List(utf8)): This is a foo (be careful using it) and see also: bar and baz'}), + (PARAMETER_RE, '@foo: (transfer full) (element-type GLib.List((utf8))): This is a foo (be careful using it) and see also: bar and baz', + {'parameter_name': 'foo', + 'fields': '(transfer full) (element-type GLib.List((utf8))): This is a foo (be careful using it) and see also: bar and baz'}), + (PARAMETER_RE, '@foo: (transfer full) (element-type GLib.List(GLib.List(utf8))): This is a foo (be careful using it) and see also: bar and baz', + {'parameter_name': 'foo', + 'fields': '(transfer full) (element-type GLib.List(GLib.List(utf8))): This is a foo (be careful using it) and see also: bar and baz'}), + (PARAMETER_RE, '@foo: (element-type GLib.List(GLib.List(utf8))) (transfer full): This is a foo (be careful using it) and see also: bar and baz', + {'parameter_name': 'foo', + 'fields': '(element-type GLib.List(GLib.List(utf8))) (transfer full): This is a foo (be careful using it) and see also: bar and baz'})] + +tag_tests = [ + (TAG_RE, 'Since 3.0', + None), + (TAG_RE, 'Since: 3.0', + {'tag_name': 'Since', + 'fields': '3.0'}), + (TAG_RE, 'Attributes: (inout) (transfer none): some note about attributes', + {'tag_name': 'Attributes', + 'fields': '(inout) (transfer none): some note about attributes'}), + (TAG_RE, 'Rename to: something_else', + {'tag_name': 'Rename to', + 'fields': 'something_else'}), + (TAG_RE, '@Deprecated: Since 2.8, reference counting is done atomically', + None), + (TAG_RE, 'Returns %TRUE and does weird things', + None), + (TAG_RE, 'Returns: a #GtkWidget', + {'tag_name': 'Returns', + 'fields': 'a #GtkWidget'}), + (TAG_RE, 'Return value: (transfer none): The binary data that @text responds. ' + 'This pointer', + {'tag_name': 'Return value', + 'fields': '(transfer none): The binary data that @text responds. This pointer'}), + (TAG_RE, 'Return value: (transfer full) (array length=out_len) (element-type guint8):', + {'tag_name': 'Return value', + 'fields': '(transfer full) (array length=out_len) (element-type guint8):'}), + (TAG_RE, 'Returns: A boolean value, but let me tell you a bit about this boolean. It', + {'tag_name': 'Returns', + 'fields': 'A boolean value, but let me tell you a bit about this boolean. It'}), + (TAG_RE, 'Returns: (transfer container) (element-type GObject.ParamSpec): a', + {'tag_name': 'Returns', + 'fields': '(transfer container) (element-type GObject.ParamSpec): a'}), + (TAG_RE, 'Return value: (type GLib.HashTable<utf8,GLib.HashTable<utf8,utf8>>) ' + '(transfer full):', + {'tag_name': 'Return value', + 'fields': '(type GLib.HashTable<utf8,GLib.HashTable<utf8,utf8>>) (transfer full):'}), + # parentheses in description + (TAG_RE, 'Returns: Returns a foo (be careful using it)', + {'tag_name': 'Returns', + 'fields': 'Returns a foo (be careful using it)'}), + (TAG_RE, 'Returns: Returns a foo (be careful using it) and see also: bar', + {'tag_name': 'Returns', + 'fields': 'Returns a foo (be careful using it) and see also: bar'}), + (TAG_RE, 'Returns: Returns a foo (be careful using it) and see also: bar and baz', + {'tag_name': 'Returns', + 'fields': 'Returns a foo (be careful using it) and see also: bar and baz'}), + # annotations with multiple closing parentheses, combined with parentheses in description + (TAG_RE, 'Returns: (transfer full) (element-type guint8): Returns a foo (be careful using it) and see also: bar and baz', + {'tag_name': 'Returns', + 'fields': '(transfer full) (element-type guint8): Returns a foo (be careful using it) and see also: bar and baz'}), + (TAG_RE, 'Returns: (transfer full) (element-type GLib.List(utf8)): Returns a foo (be careful using it) and see also: bar and baz', + {'tag_name': 'Returns', + 'fields': '(transfer full) (element-type GLib.List(utf8)): Returns a foo (be careful using it) and see also: bar and baz'}), + (TAG_RE, 'Returns: (transfer full) (element-type GLib.List((utf8))): Returns a foo (be careful using it) and see also: bar and baz', + {'tag_name': 'Returns', + 'fields': '(transfer full) (element-type GLib.List((utf8))): Returns a foo (be careful using it) and see also: bar and baz'}), + (TAG_RE, 'Returns: (transfer full) (element-type GLib.List(GLib.List(utf8))): Returns a foo (be careful using it) and see also: bar and baz', + {'tag_name': 'Returns', + 'fields': '(transfer full) (element-type GLib.List(GLib.List(utf8))): Returns a foo (be careful using it) and see also: bar and baz'}), + (TAG_RE, 'Returns: (element-type GLib.List(GLib.List(utf8))) (transfer full): Returns a foo (be careful using it) and see also: bar and baz', + {'tag_name': 'Returns', + 'fields': '(element-type GLib.List(GLib.List(utf8))) (transfer full): Returns a foo (be careful using it) and see also: bar and baz'}), + (TAG_RE, 'Returns: (element-type utf8=invalid GLib.HashTable(utf8,utf8) invalid): returns %NULL.', + {'tag_name': 'Returns', + 'fields': '(element-type utf8=invalid GLib.HashTable(utf8,utf8) invalid): returns %NULL.'})] + + +tag_value_version_tests = [ + (TAG_VALUE_VERSION_RE, ' abc', + {'value': '', + 'delimiter': '', + 'description': 'abc'}), + (TAG_VALUE_VERSION_RE, '5 abc', + {'value': '5', + 'delimiter': '', + 'description': 'abc'}), + (TAG_VALUE_VERSION_RE, '5:abc', + {'value': '5', + 'delimiter': ':', + 'description': 'abc'}), + (TAG_VALUE_VERSION_RE, ' 0.1: abc', + {'value': '0.1', + 'delimiter': ':', + 'description': 'abc'}), + (TAG_VALUE_VERSION_RE, ' 12.10.3698: abc', + {'value': '12.10.3698', + 'delimiter': ':', + 'description': 'abc'})] + + +tag_value_stability_tests = [ + (TAG_VALUE_STABILITY_RE, ' abc', + {'value': '', + 'delimiter': '', + 'description': 'abc'}), + (TAG_VALUE_STABILITY_RE, 'stable abc', + {'value': 'stable', + 'delimiter': '', + 'description': 'abc'}), + (TAG_VALUE_STABILITY_RE, 'unstable abc', + {'value': 'unstable', + 'delimiter': '', + 'description': 'abc'}), + (TAG_VALUE_STABILITY_RE, 'private abc', + {'value': 'private', + 'delimiter': '', + 'description': 'abc'}), + (TAG_VALUE_STABILITY_RE, 'internal abc', + {'value': 'internal', + 'delimiter': '', + 'description': 'abc'}), + (TAG_VALUE_STABILITY_RE, 'StAbLe: abc', + {'value': 'StAbLe', + 'delimiter': ':', + 'description': 'abc'}), + (TAG_VALUE_STABILITY_RE, 'uNsTaBlE: abc', + {'value': 'uNsTaBlE', + 'delimiter': ':', + 'description': 'abc'}), + (TAG_VALUE_STABILITY_RE, 'PRIVATE: abc', + {'value': 'PRIVATE', + 'delimiter': ':', + 'description': 'abc'}), + (TAG_VALUE_STABILITY_RE, ' internal : abc', + {'value': 'internal', + 'delimiter': ':', + 'description': 'abc'}), + (TAG_VALUE_STABILITY_RE, 'xyz: abc', + {'value': '', + 'delimiter': '', + 'description': 'xyz: abc'})] + + +def create_test_method(testcase): + def do_test(self): + (program, text, expected) = testcase + + match = program.match(text) + + if match is not None: + msg = 'Test matched pattern but specifies no expected named groups.' + self.assertTrue(isinstance(expected, dict), msg) + + for group in match.groupdict().keys(): + msg = 'Test case is missing expected results for named group "%s".' % (group) + self.assertTrue(group in expected.keys(), msg) + + if expected is None: + msg = 'Program matched text but shouldn\'t:\n"%s"' + self.assertTrue(match is None, msg % (text, )) + else: + msg = 'Program should match text but didn\'t:\n"%s"' + self.assertTrue(match is not None, msg % (text, )) + + for key, value in expected.items(): + msg = 'expected "%s" for "%s" but match returned "%s"' + msg = msg % (value, key, match.group(key)) + self.assertEqual(match.group(key), value, msg) + + return do_test + + +def create_test_case(tests_class_name, testcases): + test_methods = {} + for (index, testcase) in enumerate(testcases): + test_method_name = 'test_%03d' % index + + test_method = create_test_method(testcase) + test_method.__name__ = test_method_name + test_methods[test_method_name] = test_method + + return type(tests_class_name, (unittest.TestCase,), test_methods) + + +def create_test_cases(): + test_cases = {} + for name, test_data in (('TestCommentStart', comment_start_tests), + ('TestCommentEnd', comment_end_tests), + ('TestCommentAsterisk', comment_asterisk_tests), + ('TestIndentaton', indentaton_tests), + ('TestEmptyLine', empty_line_tests), + ('TestIdentifierSection', identifier_section_tests), + ('TestIdentifierSymbol', identifier_symbol_tests), + ('TestIdentifierProperty', identifier_property_tests), + ('TestIdentifierSignal', identifier_signal_tests), + ('TestParameter', parameter_tests), + ('TestTag', tag_tests), + ('TestTagValueVersion', tag_value_version_tests), + ('TestTagValueStability', tag_value_stability_tests)): + test_cases[name] = create_test_case(name, test_data) + + 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) + + for name, test_case in _all_tests.iteritems(): + tests = loader.loadTestsFromTestCase(test_case) + suite.addTests(tests) + return suite + + +if __name__ == '__main__': + unittest.main() |