diff options
author | alexv-smirnov <alex@ydb.tech> | 2023-06-13 11:05:01 +0300 |
---|---|---|
committer | alexv-smirnov <alex@ydb.tech> | 2023-06-13 11:05:01 +0300 |
commit | bf0f13dd39ee3e65092ba3572bb5b1fcd125dcd0 (patch) | |
tree | 1d1df72c0541a59a81439842f46d95396d3e7189 /contrib/tools/cython/Cython/Compiler/Tests | |
parent | 8bfdfa9a9bd19bddbc58d888e180fbd1218681be (diff) | |
download | ydb-bf0f13dd39ee3e65092ba3572bb5b1fcd125dcd0.tar.gz |
add ymake export to ydb
Diffstat (limited to 'contrib/tools/cython/Cython/Compiler/Tests')
14 files changed, 1289 insertions, 0 deletions
diff --git a/contrib/tools/cython/Cython/Compiler/Tests/TestBuffer.py b/contrib/tools/cython/Cython/Compiler/Tests/TestBuffer.py new file mode 100644 index 0000000000..1f69d96524 --- /dev/null +++ b/contrib/tools/cython/Cython/Compiler/Tests/TestBuffer.py @@ -0,0 +1,105 @@ +from Cython.TestUtils import CythonTest +import Cython.Compiler.Errors as Errors +from Cython.Compiler.Nodes import * +from Cython.Compiler.ParseTreeTransforms import * +from Cython.Compiler.Buffer import * + + +class TestBufferParsing(CythonTest): + # First, we only test the raw parser, i.e. + # the number and contents of arguments are NOT checked. + # However "dtype"/the first positional argument is special-cased + # to parse a type argument rather than an expression + + def parse(self, s): + return self.should_not_fail(lambda: self.fragment(s)).root + + def not_parseable(self, expected_error, s): + e = self.should_fail(lambda: self.fragment(s), Errors.CompileError) + self.assertEqual(expected_error, e.message_only) + + def test_basic(self): + t = self.parse(u"cdef object[float, 4, ndim=2, foo=foo] x") + bufnode = t.stats[0].base_type + self.assertTrue(isinstance(bufnode, TemplatedTypeNode)) + self.assertEqual(2, len(bufnode.positional_args)) +# print bufnode.dump() + # should put more here... + + def test_type_pos(self): + self.parse(u"cdef object[short unsigned int, 3] x") + + def test_type_keyword(self): + self.parse(u"cdef object[foo=foo, dtype=short unsigned int] x") + + def test_pos_after_key(self): + self.not_parseable("Non-keyword arg following keyword arg", + u"cdef object[foo=1, 2] x") + + +# See also tests/error/e_bufaccess.pyx and tets/run/bufaccess.pyx +# THESE TESTS ARE NOW DISABLED, the code they test was pretty much +# refactored away +class TestBufferOptions(CythonTest): + # Tests the full parsing of the options within the brackets + + def nonfatal_error(self, error): + # We're passing self as context to transform to trap this + self.error = error + self.assertTrue(self.expect_error) + + def parse_opts(self, opts, expect_error=False): + assert opts != "" + s = u"def f():\n cdef object[%s] x" % opts + self.expect_error = expect_error + root = self.fragment(s, pipeline=[NormalizeTree(self), PostParse(self)]).root + if not expect_error: + vardef = root.stats[0].body.stats[0] + assert isinstance(vardef, CVarDefNode) # use normal assert as this is to validate the test code + buftype = vardef.base_type + self.assertTrue(isinstance(buftype, TemplatedTypeNode)) + self.assertTrue(isinstance(buftype.base_type_node, CSimpleBaseTypeNode)) + self.assertEqual(u"object", buftype.base_type_node.name) + return buftype + else: + self.assertTrue(len(root.stats[0].body.stats) == 0) + + def non_parse(self, expected_err, opts): + self.parse_opts(opts, expect_error=True) +# e = self.should_fail(lambda: self.parse_opts(opts)) + self.assertEqual(expected_err, self.error.message_only) + + def __test_basic(self): + buf = self.parse_opts(u"unsigned short int, 3") + self.assertTrue(isinstance(buf.dtype_node, CSimpleBaseTypeNode)) + self.assertTrue(buf.dtype_node.signed == 0 and buf.dtype_node.longness == -1) + self.assertEqual(3, buf.ndim) + + def __test_dict(self): + buf = self.parse_opts(u"ndim=3, dtype=unsigned short int") + self.assertTrue(isinstance(buf.dtype_node, CSimpleBaseTypeNode)) + self.assertTrue(buf.dtype_node.signed == 0 and buf.dtype_node.longness == -1) + self.assertEqual(3, buf.ndim) + + def __test_ndim(self): + self.parse_opts(u"int, 2") + self.non_parse(ERR_BUF_NDIM, u"int, 'a'") + self.non_parse(ERR_BUF_NDIM, u"int, -34") + + def __test_use_DEF(self): + t = self.fragment(u""" + DEF ndim = 3 + def f(): + cdef object[int, ndim] x + cdef object[ndim=ndim, dtype=int] y + """, pipeline=[NormalizeTree(self), PostParse(self)]).root + stats = t.stats[0].body.stats + self.assertTrue(stats[0].base_type.ndim == 3) + self.assertTrue(stats[1].base_type.ndim == 3) + + # add exotic and impossible combinations as they come along... + +if __name__ == '__main__': + import unittest + unittest.main() + diff --git a/contrib/tools/cython/Cython/Compiler/Tests/TestCmdLine.py b/contrib/tools/cython/Cython/Compiler/Tests/TestCmdLine.py new file mode 100644 index 0000000000..bd31da0007 --- /dev/null +++ b/contrib/tools/cython/Cython/Compiler/Tests/TestCmdLine.py @@ -0,0 +1,170 @@ + +import sys +import re +from unittest import TestCase +try: + from StringIO import StringIO +except ImportError: + from io import StringIO # doesn't accept 'str' in Py2 + +from .. import Options +from ..CmdLine import parse_command_line + + +def check_global_options(expected_options, white_list=[]): + """ + returns error message of "" if check Ok + """ + no_value = object() + for name, orig_value in expected_options.items(): + if name not in white_list: + if getattr(Options, name, no_value) != orig_value: + return "error in option " + name + return "" + + +class CmdLineParserTest(TestCase): + def setUp(self): + backup = {} + for name, value in vars(Options).items(): + backup[name] = value + self._options_backup = backup + + def tearDown(self): + no_value = object() + for name, orig_value in self._options_backup.items(): + if getattr(Options, name, no_value) != orig_value: + setattr(Options, name, orig_value) + + def check_default_global_options(self, white_list=[]): + self.assertEqual(check_global_options(self._options_backup, white_list), "") + + def check_default_options(self, options, white_list=[]): + from ..Main import CompilationOptions, default_options + default_options = CompilationOptions(default_options) + no_value = object() + for name in default_options.__dict__.keys(): + if name not in white_list: + self.assertEqual(getattr(options, name, no_value), getattr(default_options, name), msg="error in option " + name) + + def test_short_options(self): + options, sources = parse_command_line([ + '-V', '-l', '-+', '-t', '-v', '-v', '-v', '-p', '-D', '-a', '-3', + ]) + self.assertFalse(sources) + self.assertTrue(options.show_version) + self.assertTrue(options.use_listing_file) + self.assertTrue(options.cplus) + self.assertTrue(options.timestamps) + self.assertTrue(options.verbose >= 3) + self.assertTrue(Options.embed_pos_in_docstring) + self.assertFalse(Options.docstrings) + self.assertTrue(Options.annotate) + self.assertEqual(options.language_level, 3) + + options, sources = parse_command_line([ + '-f', '-2', 'source.pyx', + ]) + self.assertTrue(sources) + self.assertTrue(len(sources) == 1) + self.assertFalse(options.timestamps) + self.assertEqual(options.language_level, 2) + + def test_long_options(self): + options, sources = parse_command_line([ + '--version', '--create-listing', '--cplus', '--embed', '--timestamps', + '--verbose', '--verbose', '--verbose', + '--embed-positions', '--no-docstrings', '--annotate', '--lenient', + ]) + self.assertFalse(sources) + self.assertTrue(options.show_version) + self.assertTrue(options.use_listing_file) + self.assertTrue(options.cplus) + self.assertEqual(Options.embed, 'main') + self.assertTrue(options.timestamps) + self.assertTrue(options.verbose >= 3) + self.assertTrue(Options.embed_pos_in_docstring) + self.assertFalse(Options.docstrings) + self.assertTrue(Options.annotate) + self.assertFalse(Options.error_on_unknown_names) + self.assertFalse(Options.error_on_uninitialized) + + options, sources = parse_command_line([ + '--force', 'source.pyx', + ]) + self.assertTrue(sources) + self.assertTrue(len(sources) == 1) + self.assertFalse(options.timestamps) + + def test_options_with_values(self): + options, sources = parse_command_line([ + '--embed=huhu', + '-I/test/include/dir1', '--include-dir=/test/include/dir2', + '--include-dir', '/test/include/dir3', + '--working=/work/dir', + 'source.pyx', + '--output-file=/output/dir', + '--pre-import=/pre/import', + '--cleanup=3', + '--annotate-coverage=cov.xml', + '--gdb-outdir=/gdb/outdir', + '--directive=wraparound=false', + ]) + self.assertEqual(sources, ['source.pyx']) + self.assertEqual(Options.embed, 'huhu') + self.assertEqual(options.include_path, ['/test/include/dir1', '/test/include/dir2', '/test/include/dir3']) + self.assertEqual(options.working_path, '/work/dir') + self.assertEqual(options.output_file, '/output/dir') + self.assertEqual(Options.pre_import, '/pre/import') + self.assertEqual(Options.generate_cleanup_code, 3) + self.assertTrue(Options.annotate) + self.assertEqual(Options.annotate_coverage_xml, 'cov.xml') + self.assertTrue(options.gdb_debug) + self.assertEqual(options.output_dir, '/gdb/outdir') + + def test_module_name(self): + options, sources = parse_command_line([ + 'source.pyx' + ]) + self.assertEqual(options.module_name, None) + self.check_default_global_options() + self.check_default_options(options) + options, sources = parse_command_line([ + '--module-name', 'foo.bar', + 'source.pyx' + ]) + self.assertEqual(options.module_name, 'foo.bar') + self.check_default_global_options() + self.check_default_options(options, ['module_name']) + + def test_errors(self): + def error(args, regex=None): + old_stderr = sys.stderr + stderr = sys.stderr = StringIO() + try: + self.assertRaises(SystemExit, parse_command_line, list(args)) + finally: + sys.stderr = old_stderr + msg = stderr.getvalue().strip() + self.assertTrue(msg) + if regex: + self.assertTrue(re.search(regex, msg), + '"%s" does not match search "%s"' % + (msg, regex)) + + error(['-1'], + 'Unknown compiler flag: -1') + error(['-I']) + error(['--version=-a']) + error(['--version=--annotate=true']) + error(['--working']) + error(['--verbose=1']) + error(['--cleanup']) + error(['--debug-disposal-code-wrong-name', 'file3.pyx'], + "Unknown debug flag: debug_disposal_code_wrong_name") + error(['--module-name', 'foo.pyx']) + error(['--module-name', 'foo.bar']) + error(['--module-name', 'foo.bar', 'foo.pyx', 'bar.pyx'], + "Only one source file allowed when using --module-name") + error(['--module-name', 'foo.bar', '--timestamps', 'foo.pyx'], + "Cannot use --module-name with --timestamps") diff --git a/contrib/tools/cython/Cython/Compiler/Tests/TestFlowControl.py b/contrib/tools/cython/Cython/Compiler/Tests/TestFlowControl.py new file mode 100644 index 0000000000..443551ab88 --- /dev/null +++ b/contrib/tools/cython/Cython/Compiler/Tests/TestFlowControl.py @@ -0,0 +1,68 @@ + +from __future__ import absolute_import + +from copy import deepcopy +from unittest import TestCase + +from Cython.Compiler.FlowControl import ( + NameAssignment, StaticAssignment, Argument, NameDeletion) + + +class FakeType(object): + is_pyobject = True + + +class FakeNode(object): + pos = ('filename.pyx', 1, 2) + cf_state = None + type = FakeType() + + def infer_type(self, scope): + return self.type + + +class FakeEntry(object): + type = FakeType() + + +class TestGraph(TestCase): + def test_deepcopy(self): + lhs, rhs = FakeNode(), FakeNode() + entry = FakeEntry() + entry.pos = lhs.pos + + name_ass = NameAssignment(lhs, rhs, entry) + ass = deepcopy(name_ass) + self.assertTrue(ass.lhs) + self.assertTrue(ass.rhs) + self.assertTrue(ass.entry) + self.assertEqual(ass.pos, name_ass.pos) + self.assertFalse(ass.is_arg) + self.assertFalse(ass.is_deletion) + + static_ass = StaticAssignment(entry) + ass = deepcopy(static_ass) + self.assertTrue(ass.lhs) + self.assertTrue(ass.rhs) + self.assertTrue(ass.entry) + self.assertEqual(ass.pos, static_ass.pos) + self.assertFalse(ass.is_arg) + self.assertFalse(ass.is_deletion) + + arg_ass = Argument(lhs, rhs, entry) + ass = deepcopy(arg_ass) + self.assertTrue(ass.lhs) + self.assertTrue(ass.rhs) + self.assertTrue(ass.entry) + self.assertEqual(ass.pos, arg_ass.pos) + self.assertTrue(ass.is_arg) + self.assertFalse(ass.is_deletion) + + name_del = NameDeletion(lhs, entry) + ass = deepcopy(name_del) + self.assertTrue(ass.lhs) + self.assertTrue(ass.rhs) + self.assertTrue(ass.entry) + self.assertEqual(ass.pos, name_del.pos) + self.assertFalse(ass.is_arg) + self.assertTrue(ass.is_deletion) diff --git a/contrib/tools/cython/Cython/Compiler/Tests/TestGrammar.py b/contrib/tools/cython/Cython/Compiler/Tests/TestGrammar.py new file mode 100644 index 0000000000..3dddc960b3 --- /dev/null +++ b/contrib/tools/cython/Cython/Compiler/Tests/TestGrammar.py @@ -0,0 +1,129 @@ +# mode: run +# tag: syntax + +""" +Uses TreeFragment to test invalid syntax. +""" + +from __future__ import absolute_import + +from ...TestUtils import CythonTest +from ..Errors import CompileError +from .. import ExprNodes + +# Copied from CPython's test_grammar.py +VALID_UNDERSCORE_LITERALS = [ + '0_0_0', + '4_2', + '1_0000_0000', + '0b1001_0100', + '0xffff_ffff', + '0o5_7_7', + '1_00_00.5', + '1_00_00.5j', + '1_00_00.5e5', + '1_00_00j', + '1_00_00e5_1', + '1e1_0', + '.1_4', + '.1_4e1', + '.1_4j', +] + +# Copied from CPython's test_grammar.py +INVALID_UNDERSCORE_LITERALS = [ + # Trailing underscores: + '0_', + '42_', + '1.4j_', + '0b1_', + '0xf_', + '0o5_', + # Underscores in the base selector: + '0_b0', + '0_xf', + '0_o5', + # Underscore right after the base selector: + '0b_0', + '0x_f', + '0o_5', + # Old-style octal, still disallowed: + #'0_7', + #'09_99', + # Special case with exponent: + '0 if 1_Else 1', + # Underscore right before a dot: + '1_.4', + '1_.4j', + # Underscore right after a dot: + '1._4', + '1._4j', + '._5', + # Underscore right after a sign: + '1.0e+_1', + # Multiple consecutive underscores: + '4_______2', + '0.1__4', + '0b1001__0100', + '0xffff__ffff', + '0o5__77', + '1e1__0', + # Underscore right before j: + '1.4_j', + '1.4e5_j', + # Underscore right before e: + '1_e1', + '1.4_e1', + # Underscore right after e: + '1e_1', + '1.4e_1', + # Whitespace in literals + '1_ 2', + '1 _2', + '1_2.2_ 1', + '1_2.2 _1', + '1_2e _1', + '1_2e2 _1', + '1_2e 2_1', +] + + +class TestGrammar(CythonTest): + + def test_invalid_number_literals(self): + for literal in INVALID_UNDERSCORE_LITERALS: + for expression in ['%s', '1 + %s', '%s + 1', '2 * %s', '%s * 2']: + code = 'x = ' + expression % literal + try: + self.fragment(u'''\ + # cython: language_level=3 + ''' + code) + except CompileError as exc: + assert code in [s.strip() for s in str(exc).splitlines()], str(exc) + else: + assert False, "Invalid Cython code '%s' failed to raise an exception" % code + + def test_valid_number_literals(self): + for literal in VALID_UNDERSCORE_LITERALS: + for i, expression in enumerate(['%s', '1 + %s', '%s + 1', '2 * %s', '%s * 2']): + code = 'x = ' + expression % literal + node = self.fragment(u'''\ + # cython: language_level=3 + ''' + code).root + assert node is not None + + literal_node = node.stats[0].rhs # StatListNode([SingleAssignmentNode('x', expr)]) + if i > 0: + # Add/MulNode() -> literal is first or second operand + literal_node = literal_node.operand2 if i % 2 else literal_node.operand1 + if 'j' in literal or 'J' in literal: + assert isinstance(literal_node, ExprNodes.ImagNode) + elif '.' in literal or 'e' in literal or 'E' in literal and not ('0x' in literal or '0X' in literal): + assert isinstance(literal_node, ExprNodes.FloatNode) + else: + assert isinstance(literal_node, ExprNodes.IntNode) + + +if __name__ == "__main__": + import unittest + unittest.main() diff --git a/contrib/tools/cython/Cython/Compiler/Tests/TestMemView.py b/contrib/tools/cython/Cython/Compiler/Tests/TestMemView.py new file mode 100644 index 0000000000..3792f26e99 --- /dev/null +++ b/contrib/tools/cython/Cython/Compiler/Tests/TestMemView.py @@ -0,0 +1,71 @@ +from Cython.TestUtils import CythonTest +import Cython.Compiler.Errors as Errors +from Cython.Compiler.Nodes import * +from Cython.Compiler.ParseTreeTransforms import * +from Cython.Compiler.Buffer import * + + +class TestMemviewParsing(CythonTest): + + def parse(self, s): + return self.should_not_fail(lambda: self.fragment(s)).root + + def not_parseable(self, expected_error, s): + e = self.should_fail(lambda: self.fragment(s), Errors.CompileError) + self.assertEqual(expected_error, e.message_only) + + def test_default_1dim(self): + self.parse(u"cdef int[:] x") + self.parse(u"cdef short int[:] x") + + def test_default_ndim(self): + self.parse(u"cdef int[:,:,:,:,:] x") + self.parse(u"cdef unsigned long int[:,:,:,:,:] x") + self.parse(u"cdef unsigned int[:,:,:,:,:] x") + + def test_zero_offset(self): + self.parse(u"cdef long double[0:] x") + self.parse(u"cdef int[0:] x") + + def test_zero_offset_ndim(self): + self.parse(u"cdef int[0:,0:,0:,0:] x") + + def test_def_arg(self): + self.parse(u"def foo(int[:,:] x): pass") + + def test_cdef_arg(self): + self.parse(u"cdef foo(int[:,:] x): pass") + + def test_general_slice(self): + self.parse(u'cdef float[::ptr, ::direct & contig, 0::full & strided] x') + + def test_non_slice_memview(self): + self.not_parseable(u"An axis specification in memoryview declaration does not have a ':'.", + u"cdef double[:foo, bar] x") + self.not_parseable(u"An axis specification in memoryview declaration does not have a ':'.", + u"cdef double[0:foo, bar] x") + + def test_basic(self): + t = self.parse(u"cdef int[:] x") + memv_node = t.stats[0].base_type + self.assertTrue(isinstance(memv_node, MemoryViewSliceTypeNode)) + + # we also test other similar declarations (buffers, anonymous C arrays) + # since the parsing has to distinguish between them. + + def disable_test_no_buf_arg(self): # TODO + self.not_parseable(u"Expected ']'", + u"cdef extern foo(object[int, ndim=2])") + + def disable_test_parse_sizeof(self): # TODO + self.parse(u"sizeof(int[NN])") + self.parse(u"sizeof(int[])") + self.parse(u"sizeof(int[][NN])") + self.not_parseable(u"Expected an identifier or literal", + u"sizeof(int[:NN])") + self.not_parseable(u"Expected ']'", + u"sizeof(foo[dtype=bar]") + +if __name__ == '__main__': + import unittest + unittest.main() diff --git a/contrib/tools/cython/Cython/Compiler/Tests/TestParseTreeTransforms.py b/contrib/tools/cython/Cython/Compiler/Tests/TestParseTreeTransforms.py new file mode 100644 index 0000000000..8a16f98ccc --- /dev/null +++ b/contrib/tools/cython/Cython/Compiler/Tests/TestParseTreeTransforms.py @@ -0,0 +1,289 @@ +import os.path +import unittest + +from Cython.TestUtils import TransformTest +from Cython.Compiler.ParseTreeTransforms import * +from Cython.Compiler.ParseTreeTransforms import _calculate_pickle_checksums +from Cython.Compiler.Nodes import * +from Cython.Compiler import Main, Symtab + + +class TestNormalizeTree(TransformTest): + def test_parserbehaviour_is_what_we_coded_for(self): + t = self.fragment(u"if x: y").root + self.assertLines(u""" +(root): StatListNode + stats[0]: IfStatNode + if_clauses[0]: IfClauseNode + condition: NameNode + body: ExprStatNode + expr: NameNode +""", self.treetypes(t)) + + def test_wrap_singlestat(self): + t = self.run_pipeline([NormalizeTree(None)], u"if x: y") + self.assertLines(u""" +(root): StatListNode + stats[0]: IfStatNode + if_clauses[0]: IfClauseNode + condition: NameNode + body: StatListNode + stats[0]: ExprStatNode + expr: NameNode +""", self.treetypes(t)) + + def test_wrap_multistat(self): + t = self.run_pipeline([NormalizeTree(None)], u""" + if z: + x + y + """) + self.assertLines(u""" +(root): StatListNode + stats[0]: IfStatNode + if_clauses[0]: IfClauseNode + condition: NameNode + body: StatListNode + stats[0]: ExprStatNode + expr: NameNode + stats[1]: ExprStatNode + expr: NameNode +""", self.treetypes(t)) + + def test_statinexpr(self): + t = self.run_pipeline([NormalizeTree(None)], u""" + a, b = x, y + """) + self.assertLines(u""" +(root): StatListNode + stats[0]: SingleAssignmentNode + lhs: TupleNode + args[0]: NameNode + args[1]: NameNode + rhs: TupleNode + args[0]: NameNode + args[1]: NameNode +""", self.treetypes(t)) + + def test_wrap_offagain(self): + t = self.run_pipeline([NormalizeTree(None)], u""" + x + y + if z: + x + """) + self.assertLines(u""" +(root): StatListNode + stats[0]: ExprStatNode + expr: NameNode + stats[1]: ExprStatNode + expr: NameNode + stats[2]: IfStatNode + if_clauses[0]: IfClauseNode + condition: NameNode + body: StatListNode + stats[0]: ExprStatNode + expr: NameNode +""", self.treetypes(t)) + + + def test_pass_eliminated(self): + t = self.run_pipeline([NormalizeTree(None)], u"pass") + self.assertTrue(len(t.stats) == 0) + +class TestWithTransform(object): # (TransformTest): # Disabled! + + def test_simplified(self): + t = self.run_pipeline([WithTransform(None)], u""" + with x: + y = z ** 3 + """) + + self.assertCode(u""" + + $0_0 = x + $0_2 = $0_0.__exit__ + $0_0.__enter__() + $0_1 = True + try: + try: + $1_0 = None + y = z ** 3 + except: + $0_1 = False + if (not $0_2($1_0)): + raise + finally: + if $0_1: + $0_2(None, None, None) + + """, t) + + def test_basic(self): + t = self.run_pipeline([WithTransform(None)], u""" + with x as y: + y = z ** 3 + """) + self.assertCode(u""" + + $0_0 = x + $0_2 = $0_0.__exit__ + $0_3 = $0_0.__enter__() + $0_1 = True + try: + try: + $1_0 = None + y = $0_3 + y = z ** 3 + except: + $0_1 = False + if (not $0_2($1_0)): + raise + finally: + if $0_1: + $0_2(None, None, None) + + """, t) + + +class TestInterpretCompilerDirectives(TransformTest): + """ + This class tests the parallel directives AST-rewriting and importing. + """ + + # Test the parallel directives (c)importing + + import_code = u""" + cimport cython.parallel + cimport cython.parallel as par + from cython cimport parallel as par2 + from cython cimport parallel + + from cython.parallel cimport threadid as tid + from cython.parallel cimport threadavailable as tavail + from cython.parallel cimport prange + """ + + expected_directives_dict = { + u'cython.parallel': u'cython.parallel', + u'par': u'cython.parallel', + u'par2': u'cython.parallel', + u'parallel': u'cython.parallel', + + u"tid": u"cython.parallel.threadid", + u"tavail": u"cython.parallel.threadavailable", + u"prange": u"cython.parallel.prange", + } + + + def setUp(self): + super(TestInterpretCompilerDirectives, self).setUp() + + compilation_options = Main.CompilationOptions(Main.default_options) + ctx = compilation_options.create_context() + + transform = InterpretCompilerDirectives(ctx, ctx.compiler_directives) + transform.module_scope = Symtab.ModuleScope('__main__', None, ctx) + self.pipeline = [transform] + + self.debug_exception_on_error = DebugFlags.debug_exception_on_error + + def tearDown(self): + DebugFlags.debug_exception_on_error = self.debug_exception_on_error + + def test_parallel_directives_cimports(self): + self.run_pipeline(self.pipeline, self.import_code) + parallel_directives = self.pipeline[0].parallel_directives + self.assertEqual(parallel_directives, self.expected_directives_dict) + + def test_parallel_directives_imports(self): + self.run_pipeline(self.pipeline, + self.import_code.replace(u'cimport', u'import')) + parallel_directives = self.pipeline[0].parallel_directives + self.assertEqual(parallel_directives, self.expected_directives_dict) + + +# TODO: Re-enable once they're more robust. +if False: + from Cython.Debugger import DebugWriter + from Cython.Debugger.Tests.TestLibCython import DebuggerTestCase +else: + # skip test, don't let it inherit unittest.TestCase + DebuggerTestCase = object + + +class TestDebugTransform(DebuggerTestCase): + + def elem_hasattrs(self, elem, attrs): + return all(attr in elem.attrib for attr in attrs) + + def test_debug_info(self): + try: + assert os.path.exists(self.debug_dest) + + t = DebugWriter.etree.parse(self.debug_dest) + # the xpath of the standard ElementTree is primitive, don't use + # anything fancy + L = list(t.find('/Module/Globals')) + assert L + xml_globals = dict((e.attrib['name'], e.attrib['type']) for e in L) + self.assertEqual(len(L), len(xml_globals)) + + L = list(t.find('/Module/Functions')) + assert L + xml_funcs = dict((e.attrib['qualified_name'], e) for e in L) + self.assertEqual(len(L), len(xml_funcs)) + + # test globals + self.assertEqual('CObject', xml_globals.get('c_var')) + self.assertEqual('PythonObject', xml_globals.get('python_var')) + + # test functions + funcnames = ('codefile.spam', 'codefile.ham', 'codefile.eggs', + 'codefile.closure', 'codefile.inner') + required_xml_attrs = 'name', 'cname', 'qualified_name' + assert all(f in xml_funcs for f in funcnames) + spam, ham, eggs = [xml_funcs[funcname] for funcname in funcnames] + + self.assertEqual(spam.attrib['name'], 'spam') + self.assertNotEqual('spam', spam.attrib['cname']) + assert self.elem_hasattrs(spam, required_xml_attrs) + + # test locals of functions + spam_locals = list(spam.find('Locals')) + assert spam_locals + spam_locals.sort(key=lambda e: e.attrib['name']) + names = [e.attrib['name'] for e in spam_locals] + self.assertEqual(list('abcd'), names) + assert self.elem_hasattrs(spam_locals[0], required_xml_attrs) + + # test arguments of functions + spam_arguments = list(spam.find('Arguments')) + assert spam_arguments + self.assertEqual(1, len(list(spam_arguments))) + + # test step-into functions + step_into = spam.find('StepIntoFunctions') + spam_stepinto = [x.attrib['name'] for x in step_into] + assert spam_stepinto + self.assertEqual(2, len(spam_stepinto)) + assert 'puts' in spam_stepinto + assert 'some_c_function' in spam_stepinto + except: + f = open(self.debug_dest) + try: + print(f.read()) + finally: + f.close() + raise + + +class TestAnalyseDeclarationsTransform(unittest.TestCase): + def test_calculate_pickle_checksums(self): + checksums = _calculate_pickle_checksums(['member1', 'member2', 'member3']) + assert 2 <= len(checksums) <= 3, checksums # expecting ['0xc0af380' (MD5), '0x0c75bd4', '0xa7a7b94'] + + +if __name__ == "__main__": + import unittest + unittest.main() diff --git a/contrib/tools/cython/Cython/Compiler/Tests/TestSignatureMatching.py b/contrib/tools/cython/Cython/Compiler/Tests/TestSignatureMatching.py new file mode 100644 index 0000000000..166bb225b9 --- /dev/null +++ b/contrib/tools/cython/Cython/Compiler/Tests/TestSignatureMatching.py @@ -0,0 +1,73 @@ +import unittest + +from Cython.Compiler import PyrexTypes as pt +from Cython.Compiler.ExprNodes import NameNode +from Cython.Compiler.PyrexTypes import CFuncTypeArg + +def cfunctype(*arg_types): + return pt.CFuncType(pt.c_int_type, + [ CFuncTypeArg("name", arg_type, None) for arg_type in arg_types ]) + +def cppclasstype(name, base_classes): + return pt.CppClassType(name, None, 'CPP_'+name, base_classes) + +class SignatureMatcherTest(unittest.TestCase): + """ + Test the signature matching algorithm for overloaded signatures. + """ + def assertMatches(self, expected_type, arg_types, functions): + match = pt.best_match(arg_types, functions) + if expected_type is not None: + self.assertNotEqual(None, match) + self.assertEqual(expected_type, match.type) + + def test_cpp_reference_single_arg(self): + function_types = [ + cfunctype(pt.CReferenceType(pt.c_int_type)), + cfunctype(pt.CReferenceType(pt.c_long_type)), + cfunctype(pt.CReferenceType(pt.c_double_type)), + ] + + functions = [ NameNode(None, type=t) for t in function_types ] + self.assertMatches(function_types[0], [pt.c_int_type], functions) + self.assertMatches(function_types[1], [pt.c_long_type], functions) + self.assertMatches(function_types[2], [pt.c_double_type], functions) + + def test_cpp_reference_two_args(self): + function_types = [ + cfunctype( + pt.CReferenceType(pt.c_int_type), pt.CReferenceType(pt.c_long_type)), + cfunctype( + pt.CReferenceType(pt.c_long_type), pt.CReferenceType(pt.c_long_type)), + ] + + functions = [ NameNode(None, type=t) for t in function_types ] + self.assertMatches(function_types[0], [pt.c_int_type, pt.c_long_type], functions) + self.assertMatches(function_types[1], [pt.c_long_type, pt.c_long_type], functions) + self.assertMatches(function_types[1], [pt.c_long_type, pt.c_int_type], functions) + + def test_cpp_reference_cpp_class(self): + classes = [ cppclasstype("Test%d"%i, []) for i in range(2) ] + function_types = [ + cfunctype(pt.CReferenceType(classes[0])), + cfunctype(pt.CReferenceType(classes[1])), + ] + + functions = [ NameNode(None, type=t) for t in function_types ] + self.assertMatches(function_types[0], [classes[0]], functions) + self.assertMatches(function_types[1], [classes[1]], functions) + + def test_cpp_reference_cpp_class_and_int(self): + classes = [ cppclasstype("Test%d"%i, []) for i in range(2) ] + function_types = [ + cfunctype(pt.CReferenceType(classes[0]), pt.c_int_type), + cfunctype(pt.CReferenceType(classes[0]), pt.c_long_type), + cfunctype(pt.CReferenceType(classes[1]), pt.c_int_type), + cfunctype(pt.CReferenceType(classes[1]), pt.c_long_type), + ] + + functions = [ NameNode(None, type=t) for t in function_types ] + self.assertMatches(function_types[0], [classes[0], pt.c_int_type], functions) + self.assertMatches(function_types[1], [classes[0], pt.c_long_type], functions) + self.assertMatches(function_types[2], [classes[1], pt.c_int_type], functions) + self.assertMatches(function_types[3], [classes[1], pt.c_long_type], functions) diff --git a/contrib/tools/cython/Cython/Compiler/Tests/TestStringEncoding.py b/contrib/tools/cython/Cython/Compiler/Tests/TestStringEncoding.py new file mode 100644 index 0000000000..91d099333a --- /dev/null +++ b/contrib/tools/cython/Cython/Compiler/Tests/TestStringEncoding.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- + +import sys +import unittest + +import Cython.Compiler.StringEncoding as StringEncoding + + +class StringEncodingTest(unittest.TestCase): + """ + Test the StringEncoding module. + """ + def test_string_contains_lone_surrogates(self): + self.assertFalse(StringEncoding.string_contains_lone_surrogates(u"abc")) + self.assertFalse(StringEncoding.string_contains_lone_surrogates(u"\uABCD")) + self.assertFalse(StringEncoding.string_contains_lone_surrogates(u"\N{SNOWMAN}")) + + # This behaves differently in Py2 when freshly parsed and read from a .pyc file, + # but it seems to be a marshalling bug in Py2, which doesn't hurt us in Cython. + if sys.version_info[0] != 2: + self.assertTrue(StringEncoding.string_contains_lone_surrogates(u"\uD800\uDFFF")) + + # In Py2 with 16bit Unicode, the following is indistinguishable from the 32bit character. + obfuscated_surrogate_pair = (u"\uDFFF" + "\uD800")[::-1] + if sys.version_info[0] == 2 and sys.maxunicode == 65565: + self.assertFalse(StringEncoding.string_contains_lone_surrogates(obfuscated_surrogate_pair)) + else: + self.assertTrue(StringEncoding.string_contains_lone_surrogates(obfuscated_surrogate_pair)) + + self.assertTrue(StringEncoding.string_contains_lone_surrogates(u"\uD800")) + self.assertTrue(StringEncoding.string_contains_lone_surrogates(u"\uDFFF")) + self.assertTrue(StringEncoding.string_contains_lone_surrogates(u"\uDFFF\uD800")) + self.assertTrue(StringEncoding.string_contains_lone_surrogates(u"\uD800x\uDFFF")) + + def test_string_contains_surrogates(self): + self.assertFalse(StringEncoding.string_contains_surrogates(u"abc")) + self.assertFalse(StringEncoding.string_contains_surrogates(u"\uABCD")) + self.assertFalse(StringEncoding.string_contains_surrogates(u"\N{SNOWMAN}")) + + self.assertTrue(StringEncoding.string_contains_surrogates(u"\uD800")) + self.assertTrue(StringEncoding.string_contains_surrogates(u"\uDFFF")) + self.assertTrue(StringEncoding.string_contains_surrogates(u"\uD800\uDFFF")) + self.assertTrue(StringEncoding.string_contains_surrogates(u"\uDFFF\uD800")) + self.assertTrue(StringEncoding.string_contains_surrogates(u"\uD800x\uDFFF")) diff --git a/contrib/tools/cython/Cython/Compiler/Tests/TestTreeFragment.py b/contrib/tools/cython/Cython/Compiler/Tests/TestTreeFragment.py new file mode 100644 index 0000000000..9ee8da5478 --- /dev/null +++ b/contrib/tools/cython/Cython/Compiler/Tests/TestTreeFragment.py @@ -0,0 +1,64 @@ +from Cython.TestUtils import CythonTest +from Cython.Compiler.TreeFragment import * +from Cython.Compiler.Nodes import * +from Cython.Compiler.UtilNodes import * +import Cython.Compiler.Naming as Naming + +class TestTreeFragments(CythonTest): + + def test_basic(self): + F = self.fragment(u"x = 4") + T = F.copy() + self.assertCode(u"x = 4", T) + + def test_copy_is_taken(self): + F = self.fragment(u"if True: x = 4") + T1 = F.root + T2 = F.copy() + self.assertEqual("x", T2.stats[0].if_clauses[0].body.lhs.name) + T2.stats[0].if_clauses[0].body.lhs.name = "other" + self.assertEqual("x", T1.stats[0].if_clauses[0].body.lhs.name) + + def test_substitutions_are_copied(self): + T = self.fragment(u"y + y").substitute({"y": NameNode(pos=None, name="x")}) + self.assertEqual("x", T.stats[0].expr.operand1.name) + self.assertEqual("x", T.stats[0].expr.operand2.name) + self.assertTrue(T.stats[0].expr.operand1 is not T.stats[0].expr.operand2) + + def test_substitution(self): + F = self.fragment(u"x = 4") + y = NameNode(pos=None, name=u"y") + T = F.substitute({"x" : y}) + self.assertCode(u"y = 4", T) + + def test_exprstat(self): + F = self.fragment(u"PASS") + pass_stat = PassStatNode(pos=None) + T = F.substitute({"PASS" : pass_stat}) + self.assertTrue(isinstance(T.stats[0], PassStatNode), T) + + def test_pos_is_transferred(self): + F = self.fragment(u""" + x = y + x = u * v ** w + """) + T = F.substitute({"v" : NameNode(pos=None, name="a")}) + v = F.root.stats[1].rhs.operand2.operand1 + a = T.stats[1].rhs.operand2.operand1 + self.assertEqual(v.pos, a.pos) + + def test_temps(self): + TemplateTransform.temp_name_counter = 0 + F = self.fragment(u""" + TMP + x = TMP + """) + T = F.substitute(temps=[u"TMP"]) + s = T.body.stats + self.assertTrue(isinstance(s[0].expr, TempRefNode)) + self.assertTrue(isinstance(s[1].rhs, TempRefNode)) + self.assertTrue(s[0].expr.handle is s[1].rhs.handle) + +if __name__ == "__main__": + import unittest + unittest.main() diff --git a/contrib/tools/cython/Cython/Compiler/Tests/TestTreePath.py b/contrib/tools/cython/Cython/Compiler/Tests/TestTreePath.py new file mode 100644 index 0000000000..bee53b3d2b --- /dev/null +++ b/contrib/tools/cython/Cython/Compiler/Tests/TestTreePath.py @@ -0,0 +1,94 @@ +import unittest +from Cython.Compiler.Visitor import PrintTree +from Cython.TestUtils import TransformTest +from Cython.Compiler.TreePath import find_first, find_all +from Cython.Compiler import Nodes, ExprNodes + +class TestTreePath(TransformTest): + _tree = None + + def _build_tree(self): + if self._tree is None: + self._tree = self.run_pipeline([], u""" + def decorator(fun): # DefNode + return fun # ReturnStatNode, NameNode + @decorator # NameNode + def decorated(): # DefNode + pass + """) + return self._tree + + def test_node_path(self): + t = self._build_tree() + self.assertEqual(2, len(find_all(t, "//DefNode"))) + self.assertEqual(2, len(find_all(t, "//NameNode"))) + self.assertEqual(1, len(find_all(t, "//ReturnStatNode"))) + self.assertEqual(1, len(find_all(t, "//DefNode//ReturnStatNode"))) + + def test_node_path_star(self): + t = self._build_tree() + self.assertEqual(10, len(find_all(t, "//*"))) + self.assertEqual(8, len(find_all(t, "//DefNode//*"))) + self.assertEqual(0, len(find_all(t, "//NameNode//*"))) + + def test_node_path_attribute(self): + t = self._build_tree() + self.assertEqual(2, len(find_all(t, "//NameNode/@name"))) + self.assertEqual(['fun', 'decorator'], find_all(t, "//NameNode/@name")) + + def test_node_path_attribute_dotted(self): + t = self._build_tree() + self.assertEqual(1, len(find_all(t, "//ReturnStatNode/@value.name"))) + self.assertEqual(['fun'], find_all(t, "//ReturnStatNode/@value.name")) + + def test_node_path_child(self): + t = self._build_tree() + self.assertEqual(1, len(find_all(t, "//DefNode/ReturnStatNode/NameNode"))) + self.assertEqual(1, len(find_all(t, "//ReturnStatNode/NameNode"))) + + def test_node_path_node_predicate(self): + t = self._build_tree() + self.assertEqual(0, len(find_all(t, "//DefNode[.//ForInStatNode]"))) + self.assertEqual(2, len(find_all(t, "//DefNode[.//NameNode]"))) + self.assertEqual(1, len(find_all(t, "//ReturnStatNode[./NameNode]"))) + self.assertEqual(Nodes.ReturnStatNode, + type(find_first(t, "//ReturnStatNode[./NameNode]"))) + + def test_node_path_node_predicate_step(self): + t = self._build_tree() + self.assertEqual(2, len(find_all(t, "//DefNode[.//NameNode]"))) + self.assertEqual(8, len(find_all(t, "//DefNode[.//NameNode]//*"))) + self.assertEqual(1, len(find_all(t, "//DefNode[.//NameNode]//ReturnStatNode"))) + self.assertEqual(Nodes.ReturnStatNode, + type(find_first(t, "//DefNode[.//NameNode]//ReturnStatNode"))) + + def test_node_path_attribute_exists(self): + t = self._build_tree() + self.assertEqual(2, len(find_all(t, "//NameNode[@name]"))) + self.assertEqual(ExprNodes.NameNode, + type(find_first(t, "//NameNode[@name]"))) + + def test_node_path_attribute_exists_not(self): + t = self._build_tree() + self.assertEqual(0, len(find_all(t, "//NameNode[not(@name)]"))) + self.assertEqual(2, len(find_all(t, "//NameNode[not(@honking)]"))) + + def test_node_path_and(self): + t = self._build_tree() + self.assertEqual(1, len(find_all(t, "//DefNode[.//ReturnStatNode and .//NameNode]"))) + self.assertEqual(0, len(find_all(t, "//NameNode[@honking and @name]"))) + self.assertEqual(0, len(find_all(t, "//NameNode[@name and @honking]"))) + self.assertEqual(2, len(find_all(t, "//DefNode[.//NameNode[@name] and @name]"))) + + def test_node_path_attribute_string_predicate(self): + t = self._build_tree() + self.assertEqual(1, len(find_all(t, "//NameNode[@name = 'decorator']"))) + + def test_node_path_recursive_predicate(self): + t = self._build_tree() + self.assertEqual(2, len(find_all(t, "//DefNode[.//NameNode[@name]]"))) + self.assertEqual(1, len(find_all(t, "//DefNode[.//NameNode[@name = 'decorator']]"))) + self.assertEqual(1, len(find_all(t, "//DefNode[.//ReturnStatNode[./NameNode[@name = 'fun']]/NameNode]"))) + +if __name__ == '__main__': + unittest.main() diff --git a/contrib/tools/cython/Cython/Compiler/Tests/TestTypes.py b/contrib/tools/cython/Cython/Compiler/Tests/TestTypes.py new file mode 100644 index 0000000000..f2f6f3773b --- /dev/null +++ b/contrib/tools/cython/Cython/Compiler/Tests/TestTypes.py @@ -0,0 +1,19 @@ +from __future__ import absolute_import + +import unittest + +import Cython.Compiler.PyrexTypes as PT + + +class TestMethodDispatcherTransform(unittest.TestCase): + + def test_widest_numeric_type(self): + def assert_widest(type1, type2, widest): + self.assertEqual(widest, PT.widest_numeric_type(type1, type2)) + + assert_widest(PT.c_int_type, PT.c_long_type, PT.c_long_type) + assert_widest(PT.c_double_type, PT.c_long_type, PT.c_double_type) + assert_widest(PT.c_longdouble_type, PT.c_long_type, PT.c_longdouble_type) + + cenum = PT.CEnumType("E", "cenum", typedef_flag=False) + assert_widest(PT.c_int_type, cenum, PT.c_int_type) diff --git a/contrib/tools/cython/Cython/Compiler/Tests/TestUtilityLoad.py b/contrib/tools/cython/Cython/Compiler/Tests/TestUtilityLoad.py new file mode 100644 index 0000000000..3d1906ca0b --- /dev/null +++ b/contrib/tools/cython/Cython/Compiler/Tests/TestUtilityLoad.py @@ -0,0 +1,101 @@ +import unittest + +from Cython.Compiler import Code, UtilityCode + + +def strip_2tup(tup): + return tup[0] and tup[0].strip(), tup[1] and tup[1].strip() + +class TestUtilityLoader(unittest.TestCase): + """ + Test loading UtilityCodes + """ + + expected = "test {{loader}} prototype", "test {{loader}} impl" + + required = "req {{loader}} proto", "req {{loader}} impl" + + context = dict(loader='Loader') + + name = "TestUtilityLoader" + filename = "TestUtilityLoader.c" + cls = Code.UtilityCode + + def test_load_as_string(self): + got = strip_2tup(self.cls.load_as_string(self.name)) + self.assertEqual(got, self.expected) + + got = strip_2tup(self.cls.load_as_string(self.name, self.filename)) + self.assertEqual(got, self.expected) + + def test_load(self): + utility = self.cls.load(self.name) + got = strip_2tup((utility.proto, utility.impl)) + self.assertEqual(got, self.expected) + + required, = utility.requires + got = strip_2tup((required.proto, required.impl)) + self.assertEqual(got, self.required) + + utility = self.cls.load(self.name, from_file=self.filename) + got = strip_2tup((utility.proto, utility.impl)) + self.assertEqual(got, self.expected) + + utility = self.cls.load_cached(self.name, from_file=self.filename) + got = strip_2tup((utility.proto, utility.impl)) + self.assertEqual(got, self.expected) + + +class TestTempitaUtilityLoader(TestUtilityLoader): + """ + Test loading UtilityCodes with Tempita substitution + """ + expected_tempita = (TestUtilityLoader.expected[0].replace('{{loader}}', 'Loader'), + TestUtilityLoader.expected[1].replace('{{loader}}', 'Loader')) + + required_tempita = (TestUtilityLoader.required[0].replace('{{loader}}', 'Loader'), + TestUtilityLoader.required[1].replace('{{loader}}', 'Loader')) + + cls = Code.TempitaUtilityCode + + def test_load_as_string(self): + got = strip_2tup(self.cls.load_as_string(self.name, context=self.context)) + self.assertEqual(got, self.expected_tempita) + + def test_load(self): + utility = self.cls.load(self.name, context=self.context) + got = strip_2tup((utility.proto, utility.impl)) + self.assertEqual(got, self.expected_tempita) + + required, = utility.requires + got = strip_2tup((required.proto, required.impl)) + self.assertEqual(got, self.required_tempita) + + utility = self.cls.load(self.name, from_file=self.filename, context=self.context) + got = strip_2tup((utility.proto, utility.impl)) + self.assertEqual(got, self.expected_tempita) + + +class TestCythonUtilityLoader(TestTempitaUtilityLoader): + """ + Test loading CythonUtilityCodes + """ + + # Just change the attributes and run the same tests + expected = None, "test {{cy_loader}} impl" + expected_tempita = None, "test CyLoader impl" + + required = None, "req {{cy_loader}} impl" + required_tempita = None, "req CyLoader impl" + + context = dict(cy_loader='CyLoader') + + name = "TestCyUtilityLoader" + filename = "TestCyUtilityLoader.pyx" + cls = UtilityCode.CythonUtilityCode + + # Small hack to pass our tests above + cls.proto = None + + test_load = TestUtilityLoader.test_load + test_load_tempita = TestTempitaUtilityLoader.test_load diff --git a/contrib/tools/cython/Cython/Compiler/Tests/TestVisitor.py b/contrib/tools/cython/Cython/Compiler/Tests/TestVisitor.py new file mode 100644 index 0000000000..dbc8e0c03a --- /dev/null +++ b/contrib/tools/cython/Cython/Compiler/Tests/TestVisitor.py @@ -0,0 +1,61 @@ +from Cython.Compiler.ModuleNode import ModuleNode +from Cython.Compiler.Symtab import ModuleScope +from Cython.TestUtils import TransformTest +from Cython.Compiler.Visitor import MethodDispatcherTransform +from Cython.Compiler.ParseTreeTransforms import ( + NormalizeTree, AnalyseDeclarationsTransform, + AnalyseExpressionsTransform, InterpretCompilerDirectives) + + +class TestMethodDispatcherTransform(TransformTest): + _tree = None + + def _build_tree(self): + if self._tree is None: + context = None + + def fake_module(node): + scope = ModuleScope('test', None, None) + return ModuleNode(node.pos, doc=None, body=node, + scope=scope, full_module_name='test', + directive_comments={}) + pipeline = [ + fake_module, + NormalizeTree(context), + InterpretCompilerDirectives(context, {}), + AnalyseDeclarationsTransform(context), + AnalyseExpressionsTransform(context), + ] + self._tree = self.run_pipeline(pipeline, u""" + cdef bytes s = b'asdfg' + cdef dict d = {1:2} + x = s * 3 + d.get('test') + """) + return self._tree + + def test_builtin_method(self): + calls = [0] + class Test(MethodDispatcherTransform): + def _handle_simple_method_dict_get(self, node, func, args, unbound): + calls[0] += 1 + return node + + tree = self._build_tree() + Test(None)(tree) + self.assertEqual(1, calls[0]) + + def test_binop_method(self): + calls = {'bytes': 0, 'object': 0} + class Test(MethodDispatcherTransform): + def _handle_simple_method_bytes___mul__(self, node, func, args, unbound): + calls['bytes'] += 1 + return node + def _handle_simple_method_object___mul__(self, node, func, args, unbound): + calls['object'] += 1 + return node + + tree = self._build_tree() + Test(None)(tree) + self.assertEqual(1, calls['bytes']) + self.assertEqual(0, calls['object']) diff --git a/contrib/tools/cython/Cython/Compiler/Tests/__init__.py b/contrib/tools/cython/Cython/Compiler/Tests/__init__.py new file mode 100644 index 0000000000..fa81adaff6 --- /dev/null +++ b/contrib/tools/cython/Cython/Compiler/Tests/__init__.py @@ -0,0 +1 @@ +# empty file |