# -*- 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_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 (SECTION_RE, SYMBOL_RE, PROPERTY_RE, SIGNAL_RE, PARAMETER_RE, TAG_RE, COMMENT_END_RE) from unittest import (TestCase, main) identifier_section_tests = [ (SECTION_RE, 'TSIEOCN', None), (SECTION_RE, 'section', None), (SECTION_RE, 'section:', None), (SECTION_RE, 'section:test', None), (SECTION_RE, 'SECTION', {'colon': '', 'section_name': None}), (SECTION_RE, 'SECTION \t ', {'colon': '', 'section_name': None}), (SECTION_RE, ' \t SECTION \t ', {'colon': '', 'section_name': None}), (SECTION_RE, 'SECTION: \t ', {'colon': ':', 'section_name': None}), (SECTION_RE, 'SECTION : ', {'colon': ':', 'section_name': None}), (SECTION_RE, ' SECTION : ', {'colon': ':', 'section_name': None}), (SECTION_RE, 'SECTION:gtkwidget', {'colon': ':', 'section_name': 'gtkwidget'}), (SECTION_RE, 'SECTION:gtkwidget ', {'colon': ':', 'section_name': 'gtkwidget'}), (SECTION_RE, ' SECTION:gtkwidget', {'colon': ':', 'section_name': 'gtkwidget'}), (SECTION_RE, ' SECTION:gtkwidget\t ', {'colon': ':', 'section_name': 'gtkwidget'}), (SECTION_RE, 'SECTION: gtkwidget ', {'colon': ':', 'section_name': 'gtkwidget'}), (SECTION_RE, 'SECTION : gtkwidget', {'colon': ':', 'section_name': 'gtkwidget'}), (SECTION_RE, 'SECTION gtkwidget \f ', {'colon': '', 'section_name': 'gtkwidget'})] identifier_symbol_tests = [ (SYMBOL_RE, 'GBaseFinalizeFunc:', {'colon': ':', 'symbol_name': 'GBaseFinalizeFunc', 'annotations': ''}), (SYMBOL_RE, 'gtk_widget_show ', {'colon': '', 'symbol_name': 'gtk_widget_show', 'annotations': ''}), (SYMBOL_RE, ' gtk_widget_show', {'colon': '', 'symbol_name': 'gtk_widget_show', 'annotations': ''}), (SYMBOL_RE, ' gtk_widget_show ', {'colon': '', 'symbol_name': 'gtk_widget_show', 'annotations': ''}), (SYMBOL_RE, 'gtk_widget_show:', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': ''}), (SYMBOL_RE, 'gtk_widget_show :', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': ''}), (SYMBOL_RE, 'gtk_widget_show: ', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': ''}), (SYMBOL_RE, 'gtk_widget_show : ', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': ''}), (SYMBOL_RE, ' gtk_widget_show:', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': ''}), (SYMBOL_RE, ' gtk_widget_show :', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': ''}), (SYMBOL_RE, ' gtk_widget_show: ', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': ''}), (SYMBOL_RE, ' gtk_widget_show : ', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': ''}), (SYMBOL_RE, 'gtk_widget_show (skip)', {'colon': '', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip)'}), (SYMBOL_RE, 'gtk_widget_show: (skip)', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip)'}), (SYMBOL_RE, 'gtk_widget_show : (skip)', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip)'}), (SYMBOL_RE, 'gtk_widget_show: (skip)', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip)'}), (SYMBOL_RE, 'gtk_widget_show : (skip)', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip)'}), (SYMBOL_RE, ' gtk_widget_show:(skip)', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip)'}), (SYMBOL_RE, ' gtk_widget_show :(skip)', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip)'}), (SYMBOL_RE, ' gtk_widget_show: (skip)', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip)'}), (SYMBOL_RE, ' gtk_widget_show : (skip) \t ', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip) \t '}), (SYMBOL_RE, ' gtk_widget_show : (skip) \t ', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip) \t '}), (SYMBOL_RE, 'gtk_widget_show:(skip)(test1)', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip)(test1)'}), (SYMBOL_RE, 'gtk_widget_show (skip)(test1)', {'colon': '', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip)(test1)'}), (SYMBOL_RE, 'gtk_widget_show: (skip) (test1)', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip) (test1)'}), (SYMBOL_RE, 'gtk_widget_show : (skip) (test1)', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip) (test1)'}), (SYMBOL_RE, 'gtk_widget_show: (skip) (test1)', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip) (test1)'}), (SYMBOL_RE, 'gtk_widget_show : (skip) (test1)', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip) (test1)'}), (SYMBOL_RE, ' gtk_widget_show:(skip) (test1)', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip) (test1)'}), (SYMBOL_RE, ' gtk_widget_show :(skip) (test1)', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip) (test1)'}), (SYMBOL_RE, ' gtk_widget_show: (skip) (test1)', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip) (test1)'}), (SYMBOL_RE, ' gtk_widget_show : (skip) (test1) ', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip) (test1) '}), (SYMBOL_RE, 'gtk_widget_show: (skip) (test1) (test-2)', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip) (test1) (test-2)'}), (SYMBOL_RE, 'gtk_widget_show : (skip) (test1) (test-2)', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip) (test1) (test-2)'}), (SYMBOL_RE, 'gtk_widget_show: (skip) (test1) (test-2)', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip) (test1) (test-2)'}), (SYMBOL_RE, 'gtk_widget_show : (skip) (test1) (test-2)', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip) (test1) (test-2)'}), (SYMBOL_RE, ' gtk_widget_show:(skip) (test1) (test-2)', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip) (test1) (test-2)'}), (SYMBOL_RE, ' gtk_widget_show :(skip) (test1) (test-2)', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip) (test1) (test-2)'}), (SYMBOL_RE, ' gtk_widget_show: (skip) (test1) (test-2)', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip) (test1) (test-2)'}), (SYMBOL_RE, ' gtk_widget_show : (skip) (test1) (test-2) ', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip) (test1) (test-2) '}), (SYMBOL_RE, ' gtk_widget_show : (skip) (test1) (test-2) ', {'colon': ':', 'symbol_name': 'gtk_widget_show', 'annotations': '(skip) (test1) (test-2) '}), # constants (SYMBOL_RE, 'MY_CONSTANT:', {'colon': ':', 'symbol_name': 'MY_CONSTANT', 'annotations': ''}), # structs (SYMBOL_RE, 'FooWidget:', {'colon': ':', 'symbol_name': 'FooWidget', 'annotations': ''}), # enums (SYMBOL_RE, 'Something:', {'colon': ':', 'symbol_name': 'Something', 'annotations': ''})] identifier_property_tests = [ # simple property name (PROPERTY_RE, 'GtkWidget:name (skip)', {'class_name': 'GtkWidget', 'property_name': 'name', 'colon': '', 'annotations': '(skip)'}), (PROPERTY_RE, 'GtkWidget:name', {'class_name': 'GtkWidget', 'property_name': 'name', 'colon': '', 'annotations': ''}), (PROPERTY_RE, ' GtkWidget :name', {'class_name': 'GtkWidget', 'property_name': 'name', 'colon': '', 'annotations': ''}), (PROPERTY_RE, 'GtkWidget: name ', {'class_name': 'GtkWidget', 'property_name': 'name', 'colon': '', 'annotations': ''}), (PROPERTY_RE, ' GtkWidget : name ', {'class_name': 'GtkWidget', 'property_name': 'name', 'colon': '', 'annotations': ''}), (PROPERTY_RE, 'GtkWidget:name:', {'class_name': 'GtkWidget', 'property_name': 'name', 'colon': ':', 'annotations': ''}), (PROPERTY_RE, 'GtkWidget:name: ', {'class_name': 'GtkWidget', 'property_name': 'name', 'colon': ':', 'annotations': ''}), (PROPERTY_RE, ' GtkWidget:name:', {'class_name': 'GtkWidget', 'property_name': 'name', 'colon': ':', 'annotations': ''}), (PROPERTY_RE, 'Something:name:', {'class_name': 'Something', 'property_name': 'name', 'colon': ':', 'annotations': ''}), (PROPERTY_RE, 'Something:name: ', {'class_name': 'Something', 'property_name': 'name', 'colon': ':', 'annotations': ''}), (PROPERTY_RE, ' Something:name:', {'class_name': 'Something', 'property_name': 'name', 'colon': ':', 'annotations': ''}), (PROPERTY_RE, 'Weird-thing:name:', None), (PROPERTY_RE, 'really-weird_thing:name:', None), (PROPERTY_RE, 'GWin32InputStream:handle:', {'class_name': 'GWin32InputStream', 'property_name': 'handle', 'colon': ':', 'annotations': ''}), # property name that contains a dash (PROPERTY_RE, 'GtkWidget:double-buffered (skip)', {'class_name': 'GtkWidget', 'property_name': 'double-buffered', 'colon': '', 'annotations': '(skip)'}), (PROPERTY_RE, 'GtkWidget:double-buffered', {'class_name': 'GtkWidget', 'property_name': 'double-buffered', 'colon': '', 'annotations': ''}), (PROPERTY_RE, ' GtkWidget :double-buffered', {'class_name': 'GtkWidget', 'property_name': 'double-buffered', 'colon': '', 'annotations': ''}), (PROPERTY_RE, 'GtkWidget: double-buffered ', {'class_name': 'GtkWidget', 'property_name': 'double-buffered', 'colon': '', 'annotations': ''}), (PROPERTY_RE, ' GtkWidget : double-buffered ', {'class_name': 'GtkWidget', 'property_name': 'double-buffered', 'colon': '', 'annotations': ''}), (PROPERTY_RE, 'GtkWidget:double-buffered:', {'class_name': 'GtkWidget', 'property_name': 'double-buffered', 'colon': ':', 'annotations': ''}), (PROPERTY_RE, 'GtkWidget:double-buffered: ', {'class_name': 'GtkWidget', 'property_name': 'double-buffered', 'colon': ':', 'annotations': ''}), (PROPERTY_RE, ' GtkWidget:double-buffered:', {'class_name': 'GtkWidget', 'property_name': 'double-buffered', 'colon': ':', 'annotations': ''}), (PROPERTY_RE, 'Something:double-buffered:', {'class_name': 'Something', 'property_name': 'double-buffered', 'colon': ':', 'annotations': ''}), (PROPERTY_RE, 'Something:double-buffered: ', {'class_name': 'Something', 'property_name': 'double-buffered', 'colon': ':', 'annotations': ''}), (PROPERTY_RE, ' Something:double-buffered:', {'class_name': 'Something', 'property_name': 'double-buffered', 'colon': ':', 'annotations': ''}), (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', 'colon': ':', 'annotations': '(skip)'})] identifier_signal_tests = [ # simple property name (SIGNAL_RE, 'GtkWidget::changed: (skip)', {'class_name': 'GtkWidget', 'signal_name': 'changed', 'colon': ':', 'annotations': '(skip)'}), (SIGNAL_RE, 'GtkWidget::changed:', {'class_name': 'GtkWidget', 'signal_name': 'changed', 'colon': ':', 'annotations': ''}), (SIGNAL_RE, 'Something::changed:', {'class_name': 'Something', 'signal_name': 'changed', 'colon': ':', 'annotations': ''}), (SIGNAL_RE, 'Weird-thing::changed:', None), (SIGNAL_RE, 'really-weird_thing::changed:', None), # signal name that contains a dash (SIGNAL_RE, 'GtkWidget::hierarchy-changed: (skip)', {'class_name': 'GtkWidget', 'signal_name': 'hierarchy-changed', 'colon': ':', 'annotations': '(skip)'}), (SIGNAL_RE, 'GtkWidget::hierarchy-changed:', {'class_name': 'GtkWidget', 'signal_name': 'hierarchy-changed', 'colon': ':', 'annotations': ''}), (SIGNAL_RE, 'Something::hierarchy-changed:', {'class_name': 'Something', 'signal_name': 'hierarchy-changed', 'colon': ':', 'annotations': ''}), (SIGNAL_RE, 'Weird-thing::hierarchy-changed:', None), (SIGNAL_RE, 'really-weird_thing::hierarchy-changed:', None)] parameter_tests = [ (PARAMETER_RE, '@Short_description: Base class for all widgets ', {'parameter_name': 'Short_description', 'annotations': '', 'colon': '', 'description': 'Base class for all widgets'}), (PARAMETER_RE, '@...: the value of the first property, followed optionally by more', {'parameter_name': '...', 'annotations': '', 'colon': '', 'description': 'the value of the first property, followed optionally by more'}), (PARAMETER_RE, '@widget: a #GtkWidget', {'parameter_name': 'widget', 'annotations': '', 'colon': '', 'description': 'a #GtkWidget'}), (PARAMETER_RE, '@widget_pointer: (inout) (transfer none): ' 'address of a variable that contains @widget', {'parameter_name': 'widget_pointer', 'annotations': '(inout) (transfer none)', 'colon': ':', 'description': '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', 'annotations': '(inout) (transfer none) (allow-none) (attribute) (destroy) ' '(foreign) (inout) (out) (transfer) (skip) (method)', 'colon': ':', 'description': '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', 'annotations': '', 'colon': '', 'description': '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', 'annotations': '', 'colon': '', 'description': 'a #GSequenceIter'}), (PARAMETER_RE, '@keys: (array length=n_keys) (element-type GQuark) (allow-none):', {'parameter_name': 'keys', 'annotations': '(array length=n_keys) (element-type GQuark) (allow-none)', 'colon': ':', 'description': ''})] tag_tests = [ (TAG_RE, 'Since 3.0', None), (TAG_RE, 'Since: 3.0', {'tag_name': 'Since', 'annotations': '', 'colon': '', 'description': '3.0'}), (TAG_RE, 'Attributes: (inout) (transfer none): some note about attributes', {'tag_name': 'Attributes', 'annotations': '(inout) (transfer none)', 'colon': ':', 'description': 'some note about attributes'}), (TAG_RE, 'Rename to: something_else', {'tag_name': 'Rename to', 'annotations': '', 'colon': '', 'description': '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', 'annotations': '', 'colon': '', 'description': 'a #GtkWidget'}), (TAG_RE, 'Return value: (transfer none): The binary data that @text responds. ' 'This pointer', {'tag_name': 'Return value', 'annotations': '(transfer none)', 'colon': ':', 'description': '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', 'annotations': '(transfer full) (array length=out_len) (element-type guint8)', 'colon': ':', 'description': ''}), (TAG_RE, 'Returns: A boolean value, but let me tell you a bit about this boolean. It', {'tag_name': 'Returns', 'annotations': '', 'colon': '', 'description': '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', 'annotations': '(transfer container) (element-type GObject.ParamSpec)', 'colon': ':', 'description': 'a'}), (TAG_RE, 'Return value: (type GLib.HashTable>) ' '(transfer full):', {'tag_name': 'Return value', 'annotations': '(type GLib.HashTable>) ' '(transfer full)', 'colon': ':', 'description': ''})] comment_end_tests = [ (COMMENT_END_RE, '*/', {'description': ''}), (COMMENT_END_RE, ' */', {'description': ''}), (COMMENT_END_RE, ' */ ', {'description': ''}), (COMMENT_END_RE, '**/', {'description': ''}), (COMMENT_END_RE, ' **/', {'description': ''}), (COMMENT_END_RE, ' **/ ', {'description': ''}), (COMMENT_END_RE, 'test */', {'description': 'test'}), (COMMENT_END_RE, ' test*/', {'description': 'test'}), (COMMENT_END_RE, 'test **/', {'description': 'test'}), (COMMENT_END_RE, ' test**/', {'description': 'test'}), (COMMENT_END_RE, 'test *****/', {'description': 'test'}), (COMMENT_END_RE, ' test*****/', {'description': 'test'})] def create_tests(tests_name, testcases): for (index, testcase) in enumerate(testcases): real_test_name = '%s_%03d' % (tests_name, index) test_method = TestProgram.__create_test__(testcase) test_method.__name__ = real_test_name setattr(TestProgram, real_test_name, test_method) class TestProgram(TestCase): @classmethod def __create_test__(cls, testcase): def do_test(self): (program, text, expected) = testcase match = program.match(text) 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 if __name__ == '__main__': # Create tests from data create_tests('test_identifier_section', identifier_section_tests) create_tests('test_identifier_symbol', identifier_symbol_tests) create_tests('test_identifier_property', identifier_property_tests) create_tests('test_identifier_signal', identifier_signal_tests) create_tests('test_parameter', parameter_tests) create_tests('test_tag', tag_tests) create_tests('test_comment_end', comment_end_tests) # Run test suite main()