diff options
Diffstat (limited to 'Lib/test/test_tools/test_c_analyzer')
20 files changed, 0 insertions, 4314 deletions
diff --git a/Lib/test/test_tools/test_c_analyzer/__init__.py b/Lib/test/test_tools/test_c_analyzer/__init__.py deleted file mode 100644 index d0b4c045104..00000000000 --- a/Lib/test/test_tools/test_c_analyzer/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -import contextlib -import os.path -import test.test_tools -from test.support import load_package_tests - - -@contextlib.contextmanager -def tool_imports_for_tests(): - test.test_tools.skip_if_missing('c-analyzer') - with test.test_tools.imports_under_tool('c-analyzer'): - yield - - -def load_tests(*args): - return load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_tools/test_c_analyzer/__main__.py b/Lib/test/test_tools/test_c_analyzer/__main__.py deleted file mode 100644 index b5b017de8a8..00000000000 --- a/Lib/test/test_tools/test_c_analyzer/__main__.py +++ /dev/null @@ -1,5 +0,0 @@ -from . import load_tests -import unittest - - -unittest.main() diff --git a/Lib/test/test_tools/test_c_analyzer/test_common/__init__.py b/Lib/test/test_tools/test_c_analyzer/test_common/__init__.py deleted file mode 100644 index bc502ef32d2..00000000000 --- a/Lib/test/test_tools/test_c_analyzer/test_common/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -import os.path -from test.support import load_package_tests - - -def load_tests(*args): - return load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_tools/test_c_analyzer/test_common/test_files.py b/Lib/test/test_tools/test_c_analyzer/test_common/test_files.py deleted file mode 100644 index 0c97d2a0bbf..00000000000 --- a/Lib/test/test_tools/test_c_analyzer/test_common/test_files.py +++ /dev/null @@ -1,470 +0,0 @@ -import os.path -import unittest - -from .. import tool_imports_for_tests -with tool_imports_for_tests(): - from c_analyzer.common.files import ( - iter_files, _walk_tree, glob_tree, - ) - - -def fixpath(filename): - return filename.replace('/', os.path.sep) - - -class IterFilesTests(unittest.TestCase): - - maxDiff = None - - _return_walk = None - - @property - def calls(self): - try: - return self._calls - except AttributeError: - self._calls = [] - return self._calls - - def set_files(self, *filesperroot): - roots = [] - result = [] - for root, files in filesperroot: - root = fixpath(root) - roots.append(root) - result.append([os.path.join(root, fixpath(f)) - for f in files]) - self._return_walk = result - return roots - - def _walk(self, root, *, suffix=None, walk=None): - self.calls.append(('_walk', (root, suffix, walk))) - return iter(self._return_walk.pop(0)) - - def _glob(self, root, *, suffix=None): - self.calls.append(('_glob', (root, suffix))) - return iter(self._return_walk.pop(0)) - - def test_typical(self): - dirnames = self.set_files( - ('spam', ['file1.c', 'file2.c']), - ('eggs', ['ham/file3.h']), - ) - suffixes = ('.c', '.h') - - files = list(iter_files(dirnames, suffixes, - _glob=self._glob, - _walk=self._walk)) - - self.assertEqual(files, [ - fixpath('spam/file1.c'), - fixpath('spam/file2.c'), - fixpath('eggs/ham/file3.h'), - ]) - self.assertEqual(self.calls, [ - ('_walk', ('spam', None, _walk_tree)), - ('_walk', ('eggs', None, _walk_tree)), - ]) - - def test_single_root(self): - self._return_walk = [ - [fixpath('spam/file1.c'), fixpath('spam/file2.c')], - ] - - files = list(iter_files('spam', '.c', - _glob=self._glob, - _walk=self._walk)) - - self.assertEqual(files, [ - fixpath('spam/file1.c'), - fixpath('spam/file2.c'), - ]) - self.assertEqual(self.calls, [ - ('_walk', ('spam', '.c', _walk_tree)), - ]) - - def test_one_root(self): - self._return_walk = [ - [fixpath('spam/file1.c'), fixpath('spam/file2.c')], - ] - - files = list(iter_files(['spam'], '.c', - _glob=self._glob, - _walk=self._walk)) - - self.assertEqual(files, [ - fixpath('spam/file1.c'), - fixpath('spam/file2.c'), - ]) - self.assertEqual(self.calls, [ - ('_walk', ('spam', '.c', _walk_tree)), - ]) - - def test_multiple_roots(self): - dirnames = self.set_files( - ('spam', ['file1.c', 'file2.c']), - ('eggs', ['ham/file3.c']), - ) - - files = list(iter_files(dirnames, '.c', - _glob=self._glob, - _walk=self._walk)) - - self.assertEqual(files, [ - fixpath('spam/file1.c'), - fixpath('spam/file2.c'), - fixpath('eggs/ham/file3.c'), - ]) - self.assertEqual(self.calls, [ - ('_walk', ('spam', '.c', _walk_tree)), - ('_walk', ('eggs', '.c', _walk_tree)), - ]) - - def test_no_roots(self): - files = list(iter_files([], '.c', - _glob=self._glob, - _walk=self._walk)) - - self.assertEqual(files, []) - self.assertEqual(self.calls, []) - - def test_single_suffix(self): - self._return_walk = [ - [fixpath('spam/file1.c'), - fixpath('spam/eggs/file3.c'), - ], - ] - - files = list(iter_files('spam', '.c', - _glob=self._glob, - _walk=self._walk)) - - self.assertEqual(files, [ - fixpath('spam/file1.c'), - fixpath('spam/eggs/file3.c'), - ]) - self.assertEqual(self.calls, [ - ('_walk', ('spam', '.c', _walk_tree)), - ]) - - def test_one_suffix(self): - self._return_walk = [ - [fixpath('spam/file1.c'), - fixpath('spam/file1.h'), - fixpath('spam/file1.o'), - fixpath('spam/eggs/file3.c'), - ], - ] - - files = list(iter_files('spam', ['.c'], - _glob=self._glob, - _walk=self._walk)) - - self.assertEqual(files, [ - fixpath('spam/file1.c'), - fixpath('spam/eggs/file3.c'), - ]) - self.assertEqual(self.calls, [ - ('_walk', ('spam', None, _walk_tree)), - ]) - - def test_multiple_suffixes(self): - self._return_walk = [ - [fixpath('spam/file1.c'), - fixpath('spam/file1.h'), - fixpath('spam/file1.o'), - fixpath('spam/eggs/file3.c'), - ], - ] - - files = list(iter_files('spam', ('.c', '.h'), - _glob=self._glob, - _walk=self._walk)) - - self.assertEqual(files, [ - fixpath('spam/file1.c'), - fixpath('spam/file1.h'), - fixpath('spam/eggs/file3.c'), - ]) - self.assertEqual(self.calls, [ - ('_walk', ('spam', None, _walk_tree)), - ]) - - def test_no_suffix(self): - expected = [fixpath('spam/file1.c'), - fixpath('spam/file1.h'), - fixpath('spam/file1.o'), - fixpath('spam/eggs/file3.c'), - ] - for suffix in (None, '', ()): - with self.subTest(suffix): - self.calls.clear() - self._return_walk = [list(expected)] - - files = list(iter_files('spam', suffix, - _glob=self._glob, - _walk=self._walk)) - - self.assertEqual(files, expected) - self.assertEqual(self.calls, [ - ('_walk', ('spam', suffix, _walk_tree)), - ]) - - def test_relparent(self): - dirnames = self.set_files( - ('/x/y/z/spam', ['file1.c', 'file2.c']), - ('/x/y/z/eggs', ['ham/file3.c']), - ) - - files = list(iter_files(dirnames, '.c', fixpath('/x/y'), - _glob=self._glob, - _walk=self._walk)) - - self.assertEqual(files, [ - fixpath('z/spam/file1.c'), - fixpath('z/spam/file2.c'), - fixpath('z/eggs/ham/file3.c'), - ]) - self.assertEqual(self.calls, [ - ('_walk', (fixpath('/x/y/z/spam'), '.c', _walk_tree)), - ('_walk', (fixpath('/x/y/z/eggs'), '.c', _walk_tree)), - ]) - - def test_glob(self): - dirnames = self.set_files( - ('spam', ['file1.c', 'file2.c']), - ('eggs', ['ham/file3.c']), - ) - - files = list(iter_files(dirnames, '.c', - get_files=glob_tree, - _walk=self._walk, - _glob=self._glob)) - - self.assertEqual(files, [ - fixpath('spam/file1.c'), - fixpath('spam/file2.c'), - fixpath('eggs/ham/file3.c'), - ]) - self.assertEqual(self.calls, [ - ('_glob', ('spam', '.c')), - ('_glob', ('eggs', '.c')), - ]) - - - def test_alt_walk_func(self): - dirnames = self.set_files( - ('spam', ['file1.c', 'file2.c']), - ('eggs', ['ham/file3.c']), - ) - def get_files(root): - return None - - files = list(iter_files(dirnames, '.c', - get_files=get_files, - _walk=self._walk, - _glob=self._glob)) - - self.assertEqual(files, [ - fixpath('spam/file1.c'), - fixpath('spam/file2.c'), - fixpath('eggs/ham/file3.c'), - ]) - self.assertEqual(self.calls, [ - ('_walk', ('spam', '.c', get_files)), - ('_walk', ('eggs', '.c', get_files)), - ]) - - - - - - -# def test_no_dirnames(self): -# dirnames = [] -# filter_by_name = None -# -# files = list(iter_files(dirnames, filter_by_name, -# _walk=self._walk)) -# -# self.assertEqual(files, []) -# self.assertEqual(self.calls, []) -# -# def test_no_filter(self): -# self._return_walk = [ -# [('spam', (), ('file1', 'file2.c', 'file3.h', 'file4.o')), -# ], -# ] -# dirnames = [ -# 'spam', -# ] -# filter_by_name = None -# -# files = list(iter_files(dirnames, filter_by_name, -# _walk=self._walk)) -# -# self.assertEqual(files, [ -# fixpath('spam/file1'), -# fixpath('spam/file2.c'), -# fixpath('spam/file3.h'), -# fixpath('spam/file4.o'), -# ]) -# self.assertEqual(self.calls, [ -# ('_walk', ('spam',)), -# ]) -# -# def test_no_files(self): -# self._return_walk = [ -# [('spam', (), ()), -# ], -# [(fixpath('eggs/ham'), (), ()), -# ], -# ] -# dirnames = [ -# 'spam', -# fixpath('eggs/ham'), -# ] -# filter_by_name = None -# -# files = list(iter_files(dirnames, filter_by_name, -# _walk=self._walk)) -# -# self.assertEqual(files, []) -# self.assertEqual(self.calls, [ -# ('_walk', ('spam',)), -# ('_walk', (fixpath('eggs/ham'),)), -# ]) -# -# def test_tree(self): -# self._return_walk = [ -# [('spam', ('sub1', 'sub2', 'sub3'), ('file1',)), -# (fixpath('spam/sub1'), ('sub1sub1',), ('file2', 'file3')), -# (fixpath('spam/sub1/sub1sub1'), (), ('file4',)), -# (fixpath('spam/sub2'), (), ()), -# (fixpath('spam/sub3'), (), ('file5',)), -# ], -# [(fixpath('eggs/ham'), (), ('file6',)), -# ], -# ] -# dirnames = [ -# 'spam', -# fixpath('eggs/ham'), -# ] -# filter_by_name = None -# -# files = list(iter_files(dirnames, filter_by_name, -# _walk=self._walk)) -# -# self.assertEqual(files, [ -# fixpath('spam/file1'), -# fixpath('spam/sub1/file2'), -# fixpath('spam/sub1/file3'), -# fixpath('spam/sub1/sub1sub1/file4'), -# fixpath('spam/sub3/file5'), -# fixpath('eggs/ham/file6'), -# ]) -# self.assertEqual(self.calls, [ -# ('_walk', ('spam',)), -# ('_walk', (fixpath('eggs/ham'),)), -# ]) -# -# def test_filter_suffixes(self): -# self._return_walk = [ -# [('spam', (), ('file1', 'file2.c', 'file3.h', 'file4.o')), -# ], -# ] -# dirnames = [ -# 'spam', -# ] -# filter_by_name = ('.c', '.h') -# -# files = list(iter_files(dirnames, filter_by_name, -# _walk=self._walk)) -# -# self.assertEqual(files, [ -# fixpath('spam/file2.c'), -# fixpath('spam/file3.h'), -# ]) -# self.assertEqual(self.calls, [ -# ('_walk', ('spam',)), -# ]) -# -# def test_some_filtered(self): -# self._return_walk = [ -# [('spam', (), ('file1', 'file2', 'file3', 'file4')), -# ], -# ] -# dirnames = [ -# 'spam', -# ] -# def filter_by_name(filename, results=[False, True, False, True]): -# self.calls.append(('filter_by_name', (filename,))) -# return results.pop(0) -# -# files = list(iter_files(dirnames, filter_by_name, -# _walk=self._walk)) -# -# self.assertEqual(files, [ -# fixpath('spam/file2'), -# fixpath('spam/file4'), -# ]) -# self.assertEqual(self.calls, [ -# ('_walk', ('spam',)), -# ('filter_by_name', ('file1',)), -# ('filter_by_name', ('file2',)), -# ('filter_by_name', ('file3',)), -# ('filter_by_name', ('file4',)), -# ]) -# -# def test_none_filtered(self): -# self._return_walk = [ -# [('spam', (), ('file1', 'file2', 'file3', 'file4')), -# ], -# ] -# dirnames = [ -# 'spam', -# ] -# def filter_by_name(filename, results=[True, True, True, True]): -# self.calls.append(('filter_by_name', (filename,))) -# return results.pop(0) -# -# files = list(iter_files(dirnames, filter_by_name, -# _walk=self._walk)) -# -# self.assertEqual(files, [ -# fixpath('spam/file1'), -# fixpath('spam/file2'), -# fixpath('spam/file3'), -# fixpath('spam/file4'), -# ]) -# self.assertEqual(self.calls, [ -# ('_walk', ('spam',)), -# ('filter_by_name', ('file1',)), -# ('filter_by_name', ('file2',)), -# ('filter_by_name', ('file3',)), -# ('filter_by_name', ('file4',)), -# ]) -# -# def test_all_filtered(self): -# self._return_walk = [ -# [('spam', (), ('file1', 'file2', 'file3', 'file4')), -# ], -# ] -# dirnames = [ -# 'spam', -# ] -# def filter_by_name(filename, results=[False, False, False, False]): -# self.calls.append(('filter_by_name', (filename,))) -# return results.pop(0) -# -# files = list(iter_files(dirnames, filter_by_name, -# _walk=self._walk)) -# -# self.assertEqual(files, []) -# self.assertEqual(self.calls, [ -# ('_walk', ('spam',)), -# ('filter_by_name', ('file1',)), -# ('filter_by_name', ('file2',)), -# ('filter_by_name', ('file3',)), -# ('filter_by_name', ('file4',)), -# ]) diff --git a/Lib/test/test_tools/test_c_analyzer/test_common/test_info.py b/Lib/test/test_tools/test_c_analyzer/test_common/test_info.py deleted file mode 100644 index 69dbb582c6b..00000000000 --- a/Lib/test/test_tools/test_c_analyzer/test_common/test_info.py +++ /dev/null @@ -1,197 +0,0 @@ -import string -import unittest - -from ..util import PseudoStr, StrProxy, Object -from .. import tool_imports_for_tests -with tool_imports_for_tests(): - from c_analyzer.common.info import ( - UNKNOWN, - ID, - ) - - -class IDTests(unittest.TestCase): - - VALID_ARGS = ( - 'x/y/z/spam.c', - 'func', - 'eggs', - ) - VALID_KWARGS = dict(zip(ID._fields, VALID_ARGS)) - VALID_EXPECTED = VALID_ARGS - - def test_from_raw(self): - tests = [ - ('', None), - (None, None), - ('spam', (None, None, 'spam')), - (('spam',), (None, None, 'spam')), - (('x/y/z/spam.c', 'spam'), ('x/y/z/spam.c', None, 'spam')), - (self.VALID_ARGS, self.VALID_EXPECTED), - (self.VALID_KWARGS, self.VALID_EXPECTED), - ] - for raw, expected in tests: - with self.subTest(raw): - id = ID.from_raw(raw) - - self.assertEqual(id, expected) - - def test_minimal(self): - id = ID( - filename=None, - funcname=None, - name='eggs', - ) - - self.assertEqual(id, ( - None, - None, - 'eggs', - )) - - def test_init_typical_global(self): - id = ID( - filename='x/y/z/spam.c', - funcname=None, - name='eggs', - ) - - self.assertEqual(id, ( - 'x/y/z/spam.c', - None, - 'eggs', - )) - - def test_init_typical_local(self): - id = ID( - filename='x/y/z/spam.c', - funcname='func', - name='eggs', - ) - - self.assertEqual(id, ( - 'x/y/z/spam.c', - 'func', - 'eggs', - )) - - def test_init_all_missing(self): - for value in ('', None): - with self.subTest(repr(value)): - id = ID( - filename=value, - funcname=value, - name=value, - ) - - self.assertEqual(id, ( - None, - None, - None, - )) - - def test_init_all_coerced(self): - tests = [ - ('str subclass', - dict( - filename=PseudoStr('x/y/z/spam.c'), - funcname=PseudoStr('func'), - name=PseudoStr('eggs'), - ), - ('x/y/z/spam.c', - 'func', - 'eggs', - )), - ('non-str', - dict( - filename=StrProxy('x/y/z/spam.c'), - funcname=Object(), - name=('a', 'b', 'c'), - ), - ('x/y/z/spam.c', - '<object>', - "('a', 'b', 'c')", - )), - ] - for summary, kwargs, expected in tests: - with self.subTest(summary): - id = ID(**kwargs) - - for field in ID._fields: - value = getattr(id, field) - self.assertIs(type(value), str) - self.assertEqual(tuple(id), expected) - - def test_iterable(self): - id = ID(**self.VALID_KWARGS) - - filename, funcname, name = id - - values = (filename, funcname, name) - for value, expected in zip(values, self.VALID_EXPECTED): - self.assertEqual(value, expected) - - def test_fields(self): - id = ID('a', 'b', 'z') - - self.assertEqual(id.filename, 'a') - self.assertEqual(id.funcname, 'b') - self.assertEqual(id.name, 'z') - - def test_validate_typical(self): - id = ID( - filename='x/y/z/spam.c', - funcname='func', - name='eggs', - ) - - id.validate() # This does not fail. - - def test_validate_missing_field(self): - for field in ID._fields: - with self.subTest(field): - id = ID(**self.VALID_KWARGS) - id = id._replace(**{field: None}) - - if field == 'funcname': - id.validate() # The field can be missing (not set). - id = id._replace(filename=None) - id.validate() # Both fields can be missing (not set). - continue - - with self.assertRaises(TypeError): - id.validate() - - def test_validate_bad_field(self): - badch = tuple(c for c in string.punctuation + string.digits) - notnames = ( - '1a', - 'a.b', - 'a-b', - '&a', - 'a++', - ) + badch - tests = [ - ('filename', ()), # Any non-empty str is okay. - ('funcname', notnames), - ('name', notnames), - ] - seen = set() - for field, invalid in tests: - for value in invalid: - seen.add(value) - with self.subTest(f'{field}={value!r}'): - id = ID(**self.VALID_KWARGS) - id = id._replace(**{field: value}) - - with self.assertRaises(ValueError): - id.validate() - - for field, invalid in tests: - valid = seen - set(invalid) - for value in valid: - with self.subTest(f'{field}={value!r}'): - id = ID(**self.VALID_KWARGS) - id = id._replace(**{field: value}) - - id.validate() # This does not fail. diff --git a/Lib/test/test_tools/test_c_analyzer/test_common/test_show.py b/Lib/test/test_tools/test_c_analyzer/test_common/test_show.py deleted file mode 100644 index 91ca2f3b344..00000000000 --- a/Lib/test/test_tools/test_c_analyzer/test_common/test_show.py +++ /dev/null @@ -1,54 +0,0 @@ -import unittest - -from .. import tool_imports_for_tests -with tool_imports_for_tests(): - from c_analyzer.variables import info - from c_analyzer.common.show import ( - basic, - ) - - -TYPICAL = [ - info.Variable.from_parts('src1/spam.c', None, 'var1', 'static const char *'), - info.Variable.from_parts('src1/spam.c', 'ham', 'initialized', 'static int'), - info.Variable.from_parts('src1/spam.c', None, 'var2', 'static PyObject *'), - info.Variable.from_parts('src1/eggs.c', 'tofu', 'ready', 'static int'), - info.Variable.from_parts('src1/spam.c', None, 'freelist', 'static (PyTupleObject *)[10]'), - info.Variable.from_parts('src1/sub/ham.c', None, 'var1', 'static const char const *'), - info.Variable.from_parts('src2/jam.c', None, 'var1', 'static int'), - info.Variable.from_parts('src2/jam.c', None, 'var2', 'static MyObject *'), - info.Variable.from_parts('Include/spam.h', None, 'data', 'static const int'), - ] - - -class BasicTests(unittest.TestCase): - - maxDiff = None - - def setUp(self): - self.lines = [] - - def print(self, line): - self.lines.append(line) - - def test_typical(self): - basic(TYPICAL, - _print=self.print) - - self.assertEqual(self.lines, [ - 'src1/spam.c:var1 static const char *', - 'src1/spam.c:ham():initialized static int', - 'src1/spam.c:var2 static PyObject *', - 'src1/eggs.c:tofu():ready static int', - 'src1/spam.c:freelist static (PyTupleObject *)[10]', - 'src1/sub/ham.c:var1 static const char const *', - 'src2/jam.c:var1 static int', - 'src2/jam.c:var2 static MyObject *', - 'Include/spam.h:data static const int', - ]) - - def test_no_rows(self): - basic([], - _print=self.print) - - self.assertEqual(self.lines, []) diff --git a/Lib/test/test_tools/test_c_analyzer/test_cpython/__init__.py b/Lib/test/test_tools/test_c_analyzer/test_cpython/__init__.py deleted file mode 100644 index bc502ef32d2..00000000000 --- a/Lib/test/test_tools/test_c_analyzer/test_cpython/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -import os.path -from test.support import load_package_tests - - -def load_tests(*args): - return load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_tools/test_c_analyzer/test_cpython/test___main__.py b/Lib/test/test_tools/test_c_analyzer/test_cpython/test___main__.py deleted file mode 100644 index 6d69ed7525b..00000000000 --- a/Lib/test/test_tools/test_c_analyzer/test_cpython/test___main__.py +++ /dev/null @@ -1,296 +0,0 @@ -import sys -import unittest - -from .. import tool_imports_for_tests -with tool_imports_for_tests(): - from c_analyzer.variables import info - from cpython import SOURCE_DIRS - from cpython.supported import IGNORED_FILE - from cpython.known import DATA_FILE as KNOWN_FILE - from cpython.__main__ import ( - cmd_check, cmd_show, parse_args, main, - ) - - -TYPICAL = [ - (info.Variable.from_parts('src1/spam.c', None, 'var1', 'const char *'), - True, - ), - (info.Variable.from_parts('src1/spam.c', 'ham', 'initialized', 'int'), - True, - ), - (info.Variable.from_parts('src1/spam.c', None, 'var2', 'PyObject *'), - False, - ), - (info.Variable.from_parts('src1/eggs.c', 'tofu', 'ready', 'int'), - True, - ), - (info.Variable.from_parts('src1/spam.c', None, 'freelist', '(PyTupleObject *)[10]'), - False, - ), - (info.Variable.from_parts('src1/sub/ham.c', None, 'var1', 'const char const *'), - True, - ), - (info.Variable.from_parts('src2/jam.c', None, 'var1', 'int'), - True, - ), - (info.Variable.from_parts('src2/jam.c', None, 'var2', 'MyObject *'), - False, - ), - (info.Variable.from_parts('Include/spam.h', None, 'data', 'const int'), - True, - ), - ] - - -class CMDBase(unittest.TestCase): - - maxDiff = None - -# _return_known_from_file = None -# _return_ignored_from_file = None - _return_find = () - - @property - def calls(self): - try: - return self._calls - except AttributeError: - self._calls = [] - return self._calls - -# def _known_from_file(self, *args): -# self.calls.append(('_known_from_file', args)) -# return self._return_known_from_file or {} -# -# def _ignored_from_file(self, *args): -# self.calls.append(('_ignored_from_file', args)) -# return self._return_ignored_from_file or {} - - def _find(self, known, ignored, skip_objects=False): - self.calls.append(('_find', (known, ignored, skip_objects))) - return self._return_find - - def _show(self, *args): - self.calls.append(('_show', args)) - - def _print(self, *args): - self.calls.append(('_print', args)) - - -class CheckTests(CMDBase): - - def test_defaults(self): - self._return_find = [] - - cmd_check('check', - _find=self._find, - _show=self._show, - _print=self._print, - ) - - self.assertEqual( - self.calls[0], - ('_find', (KNOWN_FILE, IGNORED_FILE, False)), - ) - - def test_all_supported(self): - self._return_find = [(v, s) for v, s in TYPICAL if s] - dirs = ['src1', 'src2', 'Include'] - - cmd_check('check', - known='known.tsv', - ignored='ignored.tsv', - _find=self._find, - _show=self._show, - _print=self._print, - ) - - self.assertEqual(self.calls, [ - ('_find', ('known.tsv', 'ignored.tsv', False)), - #('_print', ('okay',)), - ]) - - def test_some_unsupported(self): - self._return_find = TYPICAL - - with self.assertRaises(SystemExit) as cm: - cmd_check('check', - known='known.tsv', - ignored='ignored.tsv', - _find=self._find, - _show=self._show, - _print=self._print, - ) - - unsupported = [v for v, s in TYPICAL if not s] - self.assertEqual(self.calls, [ - ('_find', ('known.tsv', 'ignored.tsv', False)), - ('_print', ('ERROR: found unsupported global variables',)), - ('_print', ()), - ('_show', (sorted(unsupported),)), - ('_print', (' (3 total)',)), - ]) - self.assertEqual(cm.exception.code, 1) - - -class ShowTests(CMDBase): - - def test_defaults(self): - self._return_find = [] - - cmd_show('show', - _find=self._find, - _show=self._show, - _print=self._print, - ) - - self.assertEqual( - self.calls[0], - ('_find', (KNOWN_FILE, IGNORED_FILE, False)), - ) - - def test_typical(self): - self._return_find = TYPICAL - - cmd_show('show', - known='known.tsv', - ignored='ignored.tsv', - _find=self._find, - _show=self._show, - _print=self._print, - ) - - supported = [v for v, s in TYPICAL if s] - unsupported = [v for v, s in TYPICAL if not s] - self.assertEqual(self.calls, [ - ('_find', ('known.tsv', 'ignored.tsv', False)), - ('_print', ('supported:',)), - ('_print', ('----------',)), - ('_show', (sorted(supported),)), - ('_print', (' (6 total)',)), - ('_print', ()), - ('_print', ('unsupported:',)), - ('_print', ('------------',)), - ('_show', (sorted(unsupported),)), - ('_print', (' (3 total)',)), - ]) - - -class ParseArgsTests(unittest.TestCase): - - maxDiff = None - - def test_no_args(self): - self.errmsg = None - def fail(msg): - self.errmsg = msg - sys.exit(msg) - - with self.assertRaises(SystemExit): - parse_args('cg', [], _fail=fail) - - self.assertEqual(self.errmsg, 'missing command') - - def test_check_no_args(self): - cmd, cmdkwargs = parse_args('cg', [ - 'check', - ]) - - self.assertEqual(cmd, 'check') - self.assertEqual(cmdkwargs, { - 'ignored': IGNORED_FILE, - 'known': KNOWN_FILE, - #'dirs': SOURCE_DIRS, - }) - - def test_check_full_args(self): - cmd, cmdkwargs = parse_args('cg', [ - 'check', - '--ignored', 'spam.tsv', - '--known', 'eggs.tsv', - #'dir1', - #'dir2', - #'dir3', - ]) - - self.assertEqual(cmd, 'check') - self.assertEqual(cmdkwargs, { - 'ignored': 'spam.tsv', - 'known': 'eggs.tsv', - #'dirs': ['dir1', 'dir2', 'dir3'] - }) - - def test_show_no_args(self): - cmd, cmdkwargs = parse_args('cg', [ - 'show', - ]) - - self.assertEqual(cmd, 'show') - self.assertEqual(cmdkwargs, { - 'ignored': IGNORED_FILE, - 'known': KNOWN_FILE, - #'dirs': SOURCE_DIRS, - 'skip_objects': False, - }) - - def test_show_full_args(self): - cmd, cmdkwargs = parse_args('cg', [ - 'show', - '--ignored', 'spam.tsv', - '--known', 'eggs.tsv', - #'dir1', - #'dir2', - #'dir3', - ]) - - self.assertEqual(cmd, 'show') - self.assertEqual(cmdkwargs, { - 'ignored': 'spam.tsv', - 'known': 'eggs.tsv', - #'dirs': ['dir1', 'dir2', 'dir3'], - 'skip_objects': False, - }) - - -def new_stub_commands(*names): - calls = [] - def cmdfunc(cmd, **kwargs): - calls.append((cmd, kwargs)) - commands = {name: cmdfunc for name in names} - return commands, calls - - -class MainTests(unittest.TestCase): - - def test_no_command(self): - with self.assertRaises(ValueError): - main(None, {}) - - def test_check(self): - commands, calls = new_stub_commands('check', 'show') - - cmdkwargs = { - 'ignored': 'spam.tsv', - 'known': 'eggs.tsv', - 'dirs': ['dir1', 'dir2', 'dir3'], - } - main('check', cmdkwargs, _COMMANDS=commands) - - self.assertEqual(calls, [ - ('check', cmdkwargs), - ]) - - def test_show(self): - commands, calls = new_stub_commands('check', 'show') - - cmdkwargs = { - 'ignored': 'spam.tsv', - 'known': 'eggs.tsv', - 'dirs': ['dir1', 'dir2', 'dir3'], - } - main('show', cmdkwargs, _COMMANDS=commands) - - self.assertEqual(calls, [ - ('show', cmdkwargs), - ]) diff --git a/Lib/test/test_tools/test_c_analyzer/test_cpython/test_functional.py b/Lib/test/test_tools/test_c_analyzer/test_cpython/test_functional.py deleted file mode 100644 index 92797904844..00000000000 --- a/Lib/test/test_tools/test_c_analyzer/test_cpython/test_functional.py +++ /dev/null @@ -1,34 +0,0 @@ -import unittest - -from .. import tool_imports_for_tests -with tool_imports_for_tests(): - pass - - -class SelfCheckTests(unittest.TestCase): - - @unittest.expectedFailure - def test_known(self): - # Make sure known macros & vartypes aren't hiding unknown local types. - # XXX finish! - raise NotImplementedError - - @unittest.expectedFailure - def test_compare_nm_results(self): - # Make sure the "show" results match the statics found by "nm" command. - # XXX Skip if "nm" is not available. - # XXX finish! - raise NotImplementedError - - -class DummySourceTests(unittest.TestCase): - - @unittest.expectedFailure - def test_check(self): - # XXX finish! - raise NotImplementedError - - @unittest.expectedFailure - def test_show(self): - # XXX finish! - raise NotImplementedError diff --git a/Lib/test/test_tools/test_c_analyzer/test_cpython/test_supported.py b/Lib/test/test_tools/test_c_analyzer/test_cpython/test_supported.py deleted file mode 100644 index a244b97e1fc..00000000000 --- a/Lib/test/test_tools/test_c_analyzer/test_cpython/test_supported.py +++ /dev/null @@ -1,98 +0,0 @@ -import re -import textwrap -import unittest - -from .. import tool_imports_for_tests -with tool_imports_for_tests(): - from c_analyzer.common.info import ID - from c_analyzer.variables.info import Variable - from cpython.supported import ( - is_supported, ignored_from_file, - ) - - -class IsSupportedTests(unittest.TestCase): - - @unittest.expectedFailure - def test_supported(self): - statics = [ - Variable('src1/spam.c', None, 'var1', 'const char *'), - Variable('src1/spam.c', None, 'var1', 'int'), - ] - for static in statics: - with self.subTest(static): - result = is_supported(static) - - self.assertTrue(result) - - @unittest.expectedFailure - def test_not_supported(self): - statics = [ - Variable('src1/spam.c', None, 'var1', 'PyObject *'), - Variable('src1/spam.c', None, 'var1', 'PyObject[10]'), - ] - for static in statics: - with self.subTest(static): - result = is_supported(static) - - self.assertFalse(result) - - -class IgnoredFromFileTests(unittest.TestCase): - - maxDiff = None - - _return_read_tsv = () - - @property - def calls(self): - try: - return self._calls - except AttributeError: - self._calls = [] - return self._calls - - def _read_tsv(self, *args): - self.calls.append(('_read_tsv', args)) - return self._return_read_tsv - - def test_typical(self): - lines = textwrap.dedent(''' - filename funcname name kind reason - file1.c - var1 variable ... - file1.c func1 local1 variable | - file1.c - var2 variable ??? - file1.c func2 local2 variable | - file2.c - var1 variable reasons - ''').strip().splitlines() - lines = [re.sub(r'\s{1,8}', '\t', line, 4).replace('|', '') - for line in lines] - self._return_read_tsv = [tuple(v.strip() for v in line.split('\t')) - for line in lines[1:]] - - ignored = ignored_from_file('spam.c', _read_tsv=self._read_tsv) - - self.assertEqual(ignored, { - 'variables': { - ID('file1.c', '', 'var1'): '...', - ID('file1.c', 'func1', 'local1'): '', - ID('file1.c', '', 'var2'): '???', - ID('file1.c', 'func2', 'local2'): '', - ID('file2.c', '', 'var1'): 'reasons', - }, - }) - self.assertEqual(self.calls, [ - ('_read_tsv', ('spam.c', 'filename\tfuncname\tname\tkind\treason')), - ]) - - def test_empty(self): - self._return_read_tsv = [] - - ignored = ignored_from_file('spam.c', _read_tsv=self._read_tsv) - - self.assertEqual(ignored, { - 'variables': {}, - }) - self.assertEqual(self.calls, [ - ('_read_tsv', ('spam.c', 'filename\tfuncname\tname\tkind\treason')), - ]) diff --git a/Lib/test/test_tools/test_c_analyzer/test_parser/__init__.py b/Lib/test/test_tools/test_c_analyzer/test_parser/__init__.py deleted file mode 100644 index bc502ef32d2..00000000000 --- a/Lib/test/test_tools/test_c_analyzer/test_parser/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -import os.path -from test.support import load_package_tests - - -def load_tests(*args): - return load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_tools/test_c_analyzer/test_parser/test_declarations.py b/Lib/test/test_tools/test_c_analyzer/test_parser/test_declarations.py deleted file mode 100644 index 674fcb1af1c..00000000000 --- a/Lib/test/test_tools/test_c_analyzer/test_parser/test_declarations.py +++ /dev/null @@ -1,795 +0,0 @@ -import textwrap -import unittest - -from .. import tool_imports_for_tests -with tool_imports_for_tests(): - from c_analyzer.parser.declarations import ( - iter_global_declarations, iter_local_statements, - parse_func, _parse_var, parse_compound, - iter_variables, - ) - - -class TestCaseBase(unittest.TestCase): - - maxDiff = None - - @property - def calls(self): - try: - return self._calls - except AttributeError: - self._calls = [] - return self._calls - - -class IterGlobalDeclarationsTests(TestCaseBase): - - def test_functions(self): - tests = [ - (textwrap.dedent(''' - void func1() { - return; - } - '''), - textwrap.dedent(''' - void func1() { - return; - } - ''').strip(), - ), - (textwrap.dedent(''' - static unsigned int * _func1( - const char *arg1, - int *arg2 - long long arg3 - ) - { - return _do_something(arg1, arg2, arg3); - } - '''), - textwrap.dedent(''' - static unsigned int * _func1( const char *arg1, int *arg2 long long arg3 ) { - return _do_something(arg1, arg2, arg3); - } - ''').strip(), - ), - (textwrap.dedent(''' - static PyObject * - _func1(const char *arg1, PyObject *arg2) - { - static int initialized = 0; - if (!initialized) { - initialized = 1; - _init(arg1); - } - - PyObject *result = _do_something(arg1, arg2); - Py_INCREF(result); - return result; - } - '''), - textwrap.dedent(''' - static PyObject * _func1(const char *arg1, PyObject *arg2) { - static int initialized = 0; - if (!initialized) { - initialized = 1; - _init(arg1); - } - PyObject *result = _do_something(arg1, arg2); - Py_INCREF(result); - return result; - } - ''').strip(), - ), - ] - for lines, expected in tests: - body = textwrap.dedent( - expected.partition('{')[2].rpartition('}')[0] - ).strip() - expected = (expected, body) - with self.subTest(lines): - lines = lines.splitlines() - - stmts = list(iter_global_declarations(lines)) - - self.assertEqual(stmts, [expected]) - - @unittest.expectedFailure - def test_declarations(self): - tests = [ - 'int spam;', - 'long long spam;', - 'static const int const *spam;', - 'int spam;', - 'typedef int myint;', - 'typedef PyObject * (*unaryfunc)(PyObject *);', - # typedef struct - # inline struct - # enum - # inline enum - ] - for text in tests: - expected = (text, - ' '.join(l.strip() for l in text.splitlines())) - with self.subTest(lines): - lines = lines.splitlines() - - stmts = list(iter_global_declarations(lines)) - - self.assertEqual(stmts, [expected]) - - @unittest.expectedFailure - def test_declaration_multiple_vars(self): - lines = ['static const int const *spam, *ham=NULL, eggs = 3;'] - - stmts = list(iter_global_declarations(lines)) - - self.assertEqual(stmts, [ - ('static const int const *spam;', None), - ('static const int *ham=NULL;', None), - ('static const int eggs = 3;', None), - ]) - - def test_mixed(self): - lines = textwrap.dedent(''' - int spam; - static const char const *eggs; - - PyObject * start(void) { - static int initialized = 0; - if (initialized) { - initialized = 1; - init(); - } - return _start(); - } - - char* ham; - - static int stop(char *reason) { - ham = reason; - return _stop(); - } - ''').splitlines() - expected = [ - (textwrap.dedent(''' - PyObject * start(void) { - static int initialized = 0; - if (initialized) { - initialized = 1; - init(); - } - return _start(); - } - ''').strip(), - textwrap.dedent(''' - static int initialized = 0; - if (initialized) { - initialized = 1; - init(); - } - return _start(); - ''').strip(), - ), - (textwrap.dedent(''' - static int stop(char *reason) { - ham = reason; - return _stop(); - } - ''').strip(), - textwrap.dedent(''' - ham = reason; - return _stop(); - ''').strip(), - ), - ] - - stmts = list(iter_global_declarations(lines)) - - self.assertEqual(stmts, expected) - #self.assertEqual([stmt for stmt, _ in stmts], - # [stmt for stmt, _ in expected]) - #self.assertEqual([body for _, body in stmts], - # [body for _, body in expected]) - - def test_no_statements(self): - lines = [] - - stmts = list(iter_global_declarations(lines)) - - self.assertEqual(stmts, []) - - def test_bogus(self): - tests = [ - (textwrap.dedent(''' - int spam; - static const char const *eggs; - - PyObject * start(void) { - static int initialized = 0; - if (initialized) { - initialized = 1; - init(); - } - return _start(); - } - - char* ham; - - static int _stop(void) { - // missing closing bracket - - static int stop(char *reason) { - ham = reason; - return _stop(); - } - '''), - [(textwrap.dedent(''' - PyObject * start(void) { - static int initialized = 0; - if (initialized) { - initialized = 1; - init(); - } - return _start(); - } - ''').strip(), - textwrap.dedent(''' - static int initialized = 0; - if (initialized) { - initialized = 1; - init(); - } - return _start(); - ''').strip(), - ), - # Neither "stop()" nor "_stop()" are here. - ], - ), - ] - for lines, expected in tests: - with self.subTest(lines): - lines = lines.splitlines() - - stmts = list(iter_global_declarations(lines)) - - self.assertEqual(stmts, expected) - #self.assertEqual([stmt for stmt, _ in stmts], - # [stmt for stmt, _ in expected]) - #self.assertEqual([body for _, body in stmts], - # [body for _, body in expected]) - - def test_ignore_comments(self): - tests = [ - ('// msg', None), - ('// int stmt;', None), - (' // ... ', None), - ('// /*', None), - ('/* int stmt; */', None), - (""" - /** - * ... - * int stmt; - */ - """, None), - ] - for lines, expected in tests: - with self.subTest(lines): - lines = lines.splitlines() - - stmts = list(iter_global_declarations(lines)) - - self.assertEqual(stmts, [expected] if expected else []) - - -class IterLocalStatementsTests(TestCaseBase): - - def test_vars(self): - tests = [ - # POTS - 'int spam;', - 'unsigned int spam;', - 'char spam;', - 'float spam;', - - # typedefs - 'uint spam;', - 'MyType spam;', - - # complex - 'struct myspam spam;', - 'union choice spam;', - # inline struct - # inline union - # enum? - ] - # pointers - tests.extend([ - # POTS - 'int * spam;', - 'unsigned int * spam;', - 'char *spam;', - 'char const *spam = "spamspamspam...";', - # typedefs - 'MyType *spam;', - # complex - 'struct myspam *spam;', - 'union choice *spam;', - # packed with details - 'const char const *spam;', - # void pointer - 'void *data = NULL;', - # function pointers - 'int (* func)(char *arg1);', - 'char * (* func)(void);', - ]) - # storage class - tests.extend([ - 'static int spam;', - 'extern int spam;', - 'static unsigned int spam;', - 'static struct myspam spam;', - ]) - # type qualifier - tests.extend([ - 'const int spam;', - 'const unsigned int spam;', - 'const struct myspam spam;', - ]) - # combined - tests.extend([ - 'const char *spam = eggs;', - 'static const char const *spam = "spamspamspam...";', - 'extern const char const *spam;', - 'static void *data = NULL;', - 'static int (const * func)(char *arg1) = func1;', - 'static char * (* func)(void);', - ]) - for line in tests: - expected = line - with self.subTest(line): - stmts = list(iter_local_statements([line])) - - self.assertEqual(stmts, [(expected, None)]) - - @unittest.expectedFailure - def test_vars_multiline_var(self): - lines = textwrap.dedent(''' - PyObject * - spam - = NULL; - ''').splitlines() - expected = 'PyObject * spam = NULL;' - - stmts = list(iter_local_statements(lines)) - - self.assertEqual(stmts, [(expected, None)]) - - @unittest.expectedFailure - def test_declaration_multiple_vars(self): - lines = ['static const int const *spam, *ham=NULL, ham2[]={1, 2, 3}, ham3[2]={1, 2}, eggs = 3;'] - - stmts = list(iter_global_declarations(lines)) - - self.assertEqual(stmts, [ - ('static const int const *spam;', None), - ('static const int *ham=NULL;', None), - ('static const int ham[]={1, 2, 3};', None), - ('static const int ham[2]={1, 2};', None), - ('static const int eggs = 3;', None), - ]) - - @unittest.expectedFailure - def test_other_simple(self): - raise NotImplementedError - - @unittest.expectedFailure - def test_compound(self): - raise NotImplementedError - - @unittest.expectedFailure - def test_mixed(self): - raise NotImplementedError - - def test_no_statements(self): - lines = [] - - stmts = list(iter_local_statements(lines)) - - self.assertEqual(stmts, []) - - @unittest.expectedFailure - def test_bogus(self): - raise NotImplementedError - - def test_ignore_comments(self): - tests = [ - ('// msg', None), - ('// int stmt;', None), - (' // ... ', None), - ('// /*', None), - ('/* int stmt; */', None), - (""" - /** - * ... - * int stmt; - */ - """, None), - # mixed with statements - ('int stmt; // ...', ('int stmt;', None)), - ( 'int stmt; /* ... */', ('int stmt;', None)), - ( '/* ... */ int stmt;', ('int stmt;', None)), - ] - for lines, expected in tests: - with self.subTest(lines): - lines = lines.splitlines() - - stmts = list(iter_local_statements(lines)) - - self.assertEqual(stmts, [expected] if expected else []) - - -class ParseFuncTests(TestCaseBase): - - def test_typical(self): - tests = [ - ('PyObject *\nspam(char *a)\n{\nreturn _spam(a);\n}', - 'return _spam(a);', - ('spam', 'PyObject * spam(char *a)'), - ), - ] - for stmt, body, expected in tests: - with self.subTest(stmt): - name, signature = parse_func(stmt, body) - - self.assertEqual((name, signature), expected) - - -class ParseVarTests(TestCaseBase): - - def test_typical(self): - tests = [ - # POTS - ('int spam;', ('spam', 'int')), - ('unsigned int spam;', ('spam', 'unsigned int')), - ('char spam;', ('spam', 'char')), - ('float spam;', ('spam', 'float')), - - # typedefs - ('uint spam;', ('spam', 'uint')), - ('MyType spam;', ('spam', 'MyType')), - - # complex - ('struct myspam spam;', ('spam', 'struct myspam')), - ('union choice spam;', ('spam', 'union choice')), - # inline struct - # inline union - # enum? - ] - # pointers - tests.extend([ - # POTS - ('int * spam;', ('spam', 'int *')), - ('unsigned int * spam;', ('spam', 'unsigned int *')), - ('char *spam;', ('spam', 'char *')), - ('char const *spam = "spamspamspam...";', ('spam', 'char const *')), - # typedefs - ('MyType *spam;', ('spam', 'MyType *')), - # complex - ('struct myspam *spam;', ('spam', 'struct myspam *')), - ('union choice *spam;', ('spam', 'union choice *')), - # packed with details - ('const char const *spam;', ('spam', 'const char const *')), - # void pointer - ('void *data = NULL;', ('data', 'void *')), - # function pointers - ('int (* func)(char *);', ('func', 'int (*)(char *)')), - ('char * (* func)(void);', ('func', 'char * (*)(void)')), - ]) - # storage class - tests.extend([ - ('static int spam;', ('spam', 'static int')), - ('extern int spam;', ('spam', 'extern int')), - ('static unsigned int spam;', ('spam', 'static unsigned int')), - ('static struct myspam spam;', ('spam', 'static struct myspam')), - ]) - # type qualifier - tests.extend([ - ('const int spam;', ('spam', 'const int')), - ('const unsigned int spam;', ('spam', 'const unsigned int')), - ('const struct myspam spam;', ('spam', 'const struct myspam')), - ]) - # combined - tests.extend([ - ('const char *spam = eggs;', ('spam', 'const char *')), - ('static const char const *spam = "spamspamspam...";', - ('spam', 'static const char const *')), - ('extern const char const *spam;', - ('spam', 'extern const char const *')), - ('static void *data = NULL;', ('data', 'static void *')), - ('static int (const * func)(char *) = func1;', - ('func', 'static int (const *)(char *)')), - ('static char * (* func)(void);', - ('func', 'static char * (*)(void)')), - ]) - for stmt, expected in tests: - with self.subTest(stmt): - name, vartype = _parse_var(stmt) - - self.assertEqual((name, vartype), expected) - - -@unittest.skip('not finished') -class ParseCompoundTests(TestCaseBase): - - def test_typical(self): - headers, bodies = parse_compound(stmt, blocks) - ... - - -class IterVariablesTests(TestCaseBase): - - _return_iter_source_lines = None - _return_iter_global = None - _return_iter_local = None - _return_parse_func = None - _return_parse_var = None - _return_parse_compound = None - - def _iter_source_lines(self, filename): - self.calls.append( - ('_iter_source_lines', (filename,))) - return self._return_iter_source_lines.splitlines() - - def _iter_global(self, lines): - self.calls.append( - ('_iter_global', (lines,))) - try: - return self._return_iter_global.pop(0) - except IndexError: - return ('???', None) - - def _iter_local(self, lines): - self.calls.append( - ('_iter_local', (lines,))) - try: - return self._return_iter_local.pop(0) - except IndexError: - return ('???', None) - - def _parse_func(self, stmt, body): - self.calls.append( - ('_parse_func', (stmt, body))) - try: - return self._return_parse_func.pop(0) - except IndexError: - return ('???', '???') - - def _parse_var(self, lines): - self.calls.append( - ('_parse_var', (lines,))) - try: - return self._return_parse_var.pop(0) - except IndexError: - return ('???', '???') - - def _parse_compound(self, stmt, blocks): - self.calls.append( - ('_parse_compound', (stmt, blocks))) - try: - return self._return_parse_compound.pop(0) - except IndexError: - return (['???'], ['???']) - - def test_empty_file(self): - self._return_iter_source_lines = '' - self._return_iter_global = [ - [], - ] - self._return_parse_func = None - self._return_parse_var = None - self._return_parse_compound = None - - srcvars = list(iter_variables('spam.c', - _iter_source_lines=self._iter_source_lines, - _iter_global=self._iter_global, - _iter_local=self._iter_local, - _parse_func=self._parse_func, - _parse_var=self._parse_var, - _parse_compound=self._parse_compound, - )) - - self.assertEqual(srcvars, []) - self.assertEqual(self.calls, [ - ('_iter_source_lines', ('spam.c',)), - ('_iter_global', ([],)), - ]) - - def test_no_statements(self): - content = textwrap.dedent(''' - ... - ''') - self._return_iter_source_lines = content - self._return_iter_global = [ - [], - ] - self._return_parse_func = None - self._return_parse_var = None - self._return_parse_compound = None - - srcvars = list(iter_variables('spam.c', - _iter_source_lines=self._iter_source_lines, - _iter_global=self._iter_global, - _iter_local=self._iter_local, - _parse_func=self._parse_func, - _parse_var=self._parse_var, - _parse_compound=self._parse_compound, - )) - - self.assertEqual(srcvars, []) - self.assertEqual(self.calls, [ - ('_iter_source_lines', ('spam.c',)), - ('_iter_global', (content.splitlines(),)), - ]) - - def test_typical(self): - content = textwrap.dedent(''' - ... - ''') - self._return_iter_source_lines = content - self._return_iter_global = [ - [('<lines 1>', None), # var1 - ('<lines 2>', None), # non-var - ('<lines 3>', None), # var2 - ('<lines 4>', '<body 1>'), # func1 - ('<lines 9>', None), # var4 - ], - ] - self._return_iter_local = [ - # func1 - [('<lines 5>', None), # var3 - ('<lines 6>', [('<header 1>', '<block 1>')]), # if - ('<lines 8>', None), # non-var - ], - # if - [('<lines 7>', None), # var2 ("collision" with global var) - ], - ] - self._return_parse_func = [ - ('func1', '<sig 1>'), - ] - self._return_parse_var = [ - ('var1', '<vartype 1>'), - (None, None), - ('var2', '<vartype 2>'), - ('var3', '<vartype 3>'), - ('var2', '<vartype 2b>'), - ('var4', '<vartype 4>'), - (None, None), - (None, None), - (None, None), - ('var5', '<vartype 5>'), - ] - self._return_parse_compound = [ - ([[ - 'if (', - '<simple>', - ')', - ], - ], - ['<block 1>']), - ] - - srcvars = list(iter_variables('spam.c', - _iter_source_lines=self._iter_source_lines, - _iter_global=self._iter_global, - _iter_local=self._iter_local, - _parse_func=self._parse_func, - _parse_var=self._parse_var, - _parse_compound=self._parse_compound, - )) - - self.assertEqual(srcvars, [ - (None, 'var1', '<vartype 1>'), - (None, 'var2', '<vartype 2>'), - ('func1', 'var3', '<vartype 3>'), - ('func1', 'var2', '<vartype 2b>'), - ('func1', 'var4', '<vartype 4>'), - (None, 'var5', '<vartype 5>'), - ]) - self.assertEqual(self.calls, [ - ('_iter_source_lines', ('spam.c',)), - ('_iter_global', (content.splitlines(),)), - ('_parse_var', ('<lines 1>',)), - ('_parse_var', ('<lines 2>',)), - ('_parse_var', ('<lines 3>',)), - ('_parse_func', ('<lines 4>', '<body 1>')), - ('_iter_local', (['<body 1>'],)), - ('_parse_var', ('<lines 5>',)), - ('_parse_compound', ('<lines 6>', [('<header 1>', '<block 1>')])), - ('_parse_var', ('if (',)), - ('_parse_var', ('<simple>',)), - ('_parse_var', (')',)), - ('_parse_var', ('<lines 8>',)), - ('_iter_local', (['<block 1>'],)), - ('_parse_var', ('<lines 7>',)), - ('_parse_var', ('<lines 9>',)), - ]) - - def test_no_locals(self): - content = textwrap.dedent(''' - ... - ''') - self._return_iter_source_lines = content - self._return_iter_global = [ - [('<lines 1>', None), # var1 - ('<lines 2>', None), # non-var - ('<lines 3>', None), # var2 - ('<lines 4>', '<body 1>'), # func1 - ], - ] - self._return_iter_local = [ - # func1 - [('<lines 5>', None), # non-var - ('<lines 6>', [('<header 1>', '<block 1>')]), # if - ('<lines 8>', None), # non-var - ], - # if - [('<lines 7>', None), # non-var - ], - ] - self._return_parse_func = [ - ('func1', '<sig 1>'), - ] - self._return_parse_var = [ - ('var1', '<vartype 1>'), - (None, None), - ('var2', '<vartype 2>'), - (None, None), - (None, None), - (None, None), - (None, None), - (None, None), - (None, None), - ] - self._return_parse_compound = [ - ([[ - 'if (', - '<simple>', - ')', - ], - ], - ['<block 1>']), - ] - - srcvars = list(iter_variables('spam.c', - _iter_source_lines=self._iter_source_lines, - _iter_global=self._iter_global, - _iter_local=self._iter_local, - _parse_func=self._parse_func, - _parse_var=self._parse_var, - _parse_compound=self._parse_compound, - )) - - self.assertEqual(srcvars, [ - (None, 'var1', '<vartype 1>'), - (None, 'var2', '<vartype 2>'), - ]) - self.assertEqual(self.calls, [ - ('_iter_source_lines', ('spam.c',)), - ('_iter_global', (content.splitlines(),)), - ('_parse_var', ('<lines 1>',)), - ('_parse_var', ('<lines 2>',)), - ('_parse_var', ('<lines 3>',)), - ('_parse_func', ('<lines 4>', '<body 1>')), - ('_iter_local', (['<body 1>'],)), - ('_parse_var', ('<lines 5>',)), - ('_parse_compound', ('<lines 6>', [('<header 1>', '<block 1>')])), - ('_parse_var', ('if (',)), - ('_parse_var', ('<simple>',)), - ('_parse_var', (')',)), - ('_parse_var', ('<lines 8>',)), - ('_iter_local', (['<block 1>'],)), - ('_parse_var', ('<lines 7>',)), - ]) diff --git a/Lib/test/test_tools/test_c_analyzer/test_parser/test_preprocessor.py b/Lib/test/test_tools/test_c_analyzer/test_parser/test_preprocessor.py deleted file mode 100644 index b7f950f8139..00000000000 --- a/Lib/test/test_tools/test_c_analyzer/test_parser/test_preprocessor.py +++ /dev/null @@ -1,1561 +0,0 @@ -import textwrap -import unittest -import sys - -from ..util import wrapped_arg_combos, StrProxy -from .. import tool_imports_for_tests -with tool_imports_for_tests(): - from c_analyzer.parser.preprocessor import ( - iter_lines, - # directives - parse_directive, PreprocessorDirective, - Constant, Macro, IfDirective, Include, OtherDirective, - ) - - -class TestCaseBase(unittest.TestCase): - - maxDiff = None - - def reset(self): - self._calls = [] - self.errors = None - - @property - def calls(self): - try: - return self._calls - except AttributeError: - self._calls = [] - return self._calls - - errors = None - - def try_next_exc(self): - if not self.errors: - return - if exc := self.errors.pop(0): - raise exc - - def check_calls(self, *expected): - self.assertEqual(self.calls, list(expected)) - self.assertEqual(self.errors or [], []) - - -class IterLinesTests(TestCaseBase): - - parsed = None - - def check_calls(self, *expected): - super().check_calls(*expected) - self.assertEqual(self.parsed or [], []) - - def _parse_directive(self, line): - self.calls.append( - ('_parse_directive', line)) - self.try_next_exc() - return self.parsed.pop(0) - - def test_no_lines(self): - lines = [] - - results = list( - iter_lines(lines, _parse_directive=self._parse_directive)) - - self.assertEqual(results, []) - self.check_calls() - - def test_no_directives(self): - lines = textwrap.dedent(''' - - // xyz - typedef enum { - SPAM - EGGS - } kind; - - struct info { - kind kind; - int status; - }; - - typedef struct spam { - struct info info; - } myspam; - - static int spam = 0; - - /** - * ... - */ - static char * - get_name(int arg, - char *default, - ) - { - return default - } - - int check(void) { - return 0; - } - - ''')[1:-1].splitlines() - expected = [(lno, line, None, ()) - for lno, line in enumerate(lines, 1)] - expected[1] = (2, ' ', None, ()) - expected[20] = (21, ' ', None, ()) - del expected[19] - del expected[18] - - results = list( - iter_lines(lines, _parse_directive=self._parse_directive)) - - self.assertEqual(results, expected) - self.check_calls() - - def test_single_directives(self): - tests = [ - ('#include <stdio>', Include('<stdio>')), - ('#define SPAM 1', Constant('SPAM', '1')), - ('#define SPAM() 1', Macro('SPAM', (), '1')), - ('#define SPAM(a, b) a = b;', Macro('SPAM', ('a', 'b'), 'a = b;')), - ('#if defined(SPAM)', IfDirective('if', 'defined(SPAM)')), - ('#ifdef SPAM', IfDirective('ifdef', 'SPAM')), - ('#ifndef SPAM', IfDirective('ifndef', 'SPAM')), - ('#elseif defined(SPAM)', IfDirective('elseif', 'defined(SPAM)')), - ('#else', OtherDirective('else', None)), - ('#endif', OtherDirective('endif', None)), - ('#error ...', OtherDirective('error', '...')), - ('#warning ...', OtherDirective('warning', '...')), - ('#__FILE__ ...', OtherDirective('__FILE__', '...')), - ('#__LINE__ ...', OtherDirective('__LINE__', '...')), - ('#__DATE__ ...', OtherDirective('__DATE__', '...')), - ('#__TIME__ ...', OtherDirective('__TIME__', '...')), - ('#__TIMESTAMP__ ...', OtherDirective('__TIMESTAMP__', '...')), - ] - for line, directive in tests: - with self.subTest(line): - self.reset() - self.parsed = [ - directive, - ] - text = textwrap.dedent(''' - static int spam = 0; - {} - static char buffer[256]; - ''').strip().format(line) - lines = text.strip().splitlines() - - results = list( - iter_lines(lines, _parse_directive=self._parse_directive)) - - self.assertEqual(results, [ - (1, 'static int spam = 0;', None, ()), - (2, line, directive, ()), - ((3, 'static char buffer[256];', None, ('defined(SPAM)',)) - if directive.kind in ('if', 'ifdef', 'elseif') - else (3, 'static char buffer[256];', None, ('! defined(SPAM)',)) - if directive.kind == 'ifndef' - else (3, 'static char buffer[256];', None, ())), - ]) - self.check_calls( - ('_parse_directive', line), - ) - - def test_directive_whitespace(self): - line = ' # define eggs ( a , b ) { a = b ; } ' - directive = Macro('eggs', ('a', 'b'), '{ a = b; }') - self.parsed = [ - directive, - ] - lines = [line] - - results = list( - iter_lines(lines, _parse_directive=self._parse_directive)) - - self.assertEqual(results, [ - (1, line, directive, ()), - ]) - self.check_calls( - ('_parse_directive', '#define eggs ( a , b ) { a = b ; }'), - ) - - @unittest.skipIf(sys.platform == 'win32', 'needs fix under Windows') - def test_split_lines(self): - directive = Macro('eggs', ('a', 'b'), '{ a = b; }') - self.parsed = [ - directive, - ] - text = textwrap.dedent(r''' - static int spam = 0; - #define eggs(a, b) \ - { \ - a = b; \ - } - static char buffer[256]; - ''').strip() - lines = [line + '\n' for line in text.splitlines()] - lines[-1] = lines[-1][:-1] - - results = list( - iter_lines(lines, _parse_directive=self._parse_directive)) - - self.assertEqual(results, [ - (1, 'static int spam = 0;\n', None, ()), - (5, '#define eggs(a, b) { a = b; }\n', directive, ()), - (6, 'static char buffer[256];', None, ()), - ]) - self.check_calls( - ('_parse_directive', '#define eggs(a, b) { a = b; }'), - ) - - def test_nested_conditions(self): - directives = [ - IfDirective('ifdef', 'SPAM'), - IfDirective('if', 'SPAM == 1'), - IfDirective('elseif', 'SPAM == 2'), - OtherDirective('else', None), - OtherDirective('endif', None), - OtherDirective('endif', None), - ] - self.parsed = list(directives) - text = textwrap.dedent(r''' - static int spam = 0; - - #ifdef SPAM - static int start = 0; - # if SPAM == 1 - static char buffer[10]; - # elif SPAM == 2 - static char buffer[100]; - # else - static char buffer[256]; - # endif - static int end = 0; - #endif - - static int eggs = 0; - ''').strip() - lines = [line for line in text.splitlines() if line.strip()] - - results = list( - iter_lines(lines, _parse_directive=self._parse_directive)) - - self.assertEqual(results, [ - (1, 'static int spam = 0;', None, ()), - (2, '#ifdef SPAM', directives[0], ()), - (3, 'static int start = 0;', None, ('defined(SPAM)',)), - (4, '# if SPAM == 1', directives[1], ('defined(SPAM)',)), - (5, 'static char buffer[10];', None, ('defined(SPAM)', 'SPAM == 1')), - (6, '# elif SPAM == 2', directives[2], ('defined(SPAM)', 'SPAM == 1')), - (7, 'static char buffer[100];', None, ('defined(SPAM)', '! (SPAM == 1)', 'SPAM == 2')), - (8, '# else', directives[3], ('defined(SPAM)', '! (SPAM == 1)', 'SPAM == 2')), - (9, 'static char buffer[256];', None, ('defined(SPAM)', '! (SPAM == 1)', '! (SPAM == 2)')), - (10, '# endif', directives[4], ('defined(SPAM)', '! (SPAM == 1)', '! (SPAM == 2)')), - (11, 'static int end = 0;', None, ('defined(SPAM)',)), - (12, '#endif', directives[5], ('defined(SPAM)',)), - (13, 'static int eggs = 0;', None, ()), - ]) - self.check_calls( - ('_parse_directive', '#ifdef SPAM'), - ('_parse_directive', '#if SPAM == 1'), - ('_parse_directive', '#elif SPAM == 2'), - ('_parse_directive', '#else'), - ('_parse_directive', '#endif'), - ('_parse_directive', '#endif'), - ) - - def test_split_blocks(self): - directives = [ - IfDirective('ifdef', 'SPAM'), - OtherDirective('else', None), - OtherDirective('endif', None), - ] - self.parsed = list(directives) - text = textwrap.dedent(r''' - void str_copy(char *buffer, *orig); - - int init(char *name) { - static int initialized = 0; - if (initialized) { - return 0; - } - #ifdef SPAM - static char buffer[10]; - str_copy(buffer, char); - } - - void copy(char *buffer, *orig) { - strncpy(buffer, orig, 9); - buffer[9] = 0; - } - - #else - static char buffer[256]; - str_copy(buffer, char); - } - - void copy(char *buffer, *orig) { - strcpy(buffer, orig); - } - - #endif - ''').strip() - lines = [line for line in text.splitlines() if line.strip()] - - results = list( - iter_lines(lines, _parse_directive=self._parse_directive)) - - self.assertEqual(results, [ - (1, 'void str_copy(char *buffer, *orig);', None, ()), - (2, 'int init(char *name) {', None, ()), - (3, ' static int initialized = 0;', None, ()), - (4, ' if (initialized) {', None, ()), - (5, ' return 0;', None, ()), - (6, ' }', None, ()), - - (7, '#ifdef SPAM', directives[0], ()), - - (8, ' static char buffer[10];', None, ('defined(SPAM)',)), - (9, ' str_copy(buffer, char);', None, ('defined(SPAM)',)), - (10, '}', None, ('defined(SPAM)',)), - (11, 'void copy(char *buffer, *orig) {', None, ('defined(SPAM)',)), - (12, ' strncpy(buffer, orig, 9);', None, ('defined(SPAM)',)), - (13, ' buffer[9] = 0;', None, ('defined(SPAM)',)), - (14, '}', None, ('defined(SPAM)',)), - - (15, '#else', directives[1], ('defined(SPAM)',)), - - (16, ' static char buffer[256];', None, ('! (defined(SPAM))',)), - (17, ' str_copy(buffer, char);', None, ('! (defined(SPAM))',)), - (18, '}', None, ('! (defined(SPAM))',)), - (19, 'void copy(char *buffer, *orig) {', None, ('! (defined(SPAM))',)), - (20, ' strcpy(buffer, orig);', None, ('! (defined(SPAM))',)), - (21, '}', None, ('! (defined(SPAM))',)), - - (22, '#endif', directives[2], ('! (defined(SPAM))',)), - ]) - self.check_calls( - ('_parse_directive', '#ifdef SPAM'), - ('_parse_directive', '#else'), - ('_parse_directive', '#endif'), - ) - - @unittest.skipIf(sys.platform == 'win32', 'needs fix under Windows') - def test_basic(self): - directives = [ - Include('<stdio.h>'), - IfDirective('ifdef', 'SPAM'), - IfDirective('if', '! defined(HAM) || !HAM'), - Constant('HAM', '0'), - IfDirective('elseif', 'HAM < 0'), - Constant('HAM', '-1'), - OtherDirective('else', None), - OtherDirective('endif', None), - OtherDirective('endif', None), - IfDirective('if', 'defined(HAM) && (HAM < 0 || ! HAM)'), - OtherDirective('undef', 'HAM'), - OtherDirective('endif', None), - IfDirective('ifndef', 'HAM'), - OtherDirective('endif', None), - ] - self.parsed = list(directives) - text = textwrap.dedent(r''' - #include <stdio.h> - print("begin"); - #ifdef SPAM - print("spam"); - #if ! defined(HAM) || !HAM - # DEFINE HAM 0 - #elseif HAM < 0 - # DEFINE HAM -1 - #else - print("ham HAM"); - #endif - #endif - - #if defined(HAM) && \ - (HAM < 0 || ! HAM) - print("ham?"); - #undef HAM - # endif - - #ifndef HAM - print("no ham"); - #endif - print("end"); - ''')[1:-1] - lines = [line + '\n' for line in text.splitlines()] - lines[-1] = lines[-1][:-1] - - results = list( - iter_lines(lines, _parse_directive=self._parse_directive)) - - self.assertEqual(results, [ - (1, '#include <stdio.h>\n', Include('<stdio.h>'), ()), - (2, 'print("begin");\n', None, ()), - # - (3, '#ifdef SPAM\n', - IfDirective('ifdef', 'SPAM'), - ()), - (4, ' print("spam");\n', - None, - ('defined(SPAM)',)), - (5, ' #if ! defined(HAM) || !HAM\n', - IfDirective('if', '! defined(HAM) || !HAM'), - ('defined(SPAM)',)), - (6, '# DEFINE HAM 0\n', - Constant('HAM', '0'), - ('defined(SPAM)', '! defined(HAM) || !HAM')), - (7, ' #elseif HAM < 0\n', - IfDirective('elseif', 'HAM < 0'), - ('defined(SPAM)', '! defined(HAM) || !HAM')), - (8, '# DEFINE HAM -1\n', - Constant('HAM', '-1'), - ('defined(SPAM)', '! (! defined(HAM) || !HAM)', 'HAM < 0')), - (9, ' #else\n', - OtherDirective('else', None), - ('defined(SPAM)', '! (! defined(HAM) || !HAM)', 'HAM < 0')), - (10, ' print("ham HAM");\n', - None, - ('defined(SPAM)', '! (! defined(HAM) || !HAM)', '! (HAM < 0)')), - (11, ' #endif\n', - OtherDirective('endif', None), - ('defined(SPAM)', '! (! defined(HAM) || !HAM)', '! (HAM < 0)')), - (12, '#endif\n', - OtherDirective('endif', None), - ('defined(SPAM)',)), - # - (13, '\n', None, ()), - # - (15, '#if defined(HAM) && (HAM < 0 || ! HAM)\n', - IfDirective('if', 'defined(HAM) && (HAM < 0 || ! HAM)'), - ()), - (16, ' print("ham?");\n', - None, - ('defined(HAM) && (HAM < 0 || ! HAM)',)), - (17, ' #undef HAM\n', - OtherDirective('undef', 'HAM'), - ('defined(HAM) && (HAM < 0 || ! HAM)',)), - (18, '# endif\n', - OtherDirective('endif', None), - ('defined(HAM) && (HAM < 0 || ! HAM)',)), - # - (19, '\n', None, ()), - # - (20, '#ifndef HAM\n', - IfDirective('ifndef', 'HAM'), - ()), - (21, ' print("no ham");\n', - None, - ('! defined(HAM)',)), - (22, '#endif\n', - OtherDirective('endif', None), - ('! defined(HAM)',)), - # - (23, 'print("end");', None, ()), - ]) - - @unittest.skipIf(sys.platform == 'win32', 'needs fix under Windows') - def test_typical(self): - # We use Include/compile.h from commit 66c4f3f38b86. It has - # a good enough mix of code without being too large. - directives = [ - IfDirective('ifndef', 'Py_COMPILE_H'), - Constant('Py_COMPILE_H', None), - - IfDirective('ifndef', 'Py_LIMITED_API'), - - Include('"code.h"'), - - IfDirective('ifdef', '__cplusplus'), - OtherDirective('endif', None), - - Constant('PyCF_MASK', '(CO_FUTURE_DIVISION | CO_FUTURE_ABSOLUTE_IMPORT | CO_FUTURE_WITH_STATEMENT | CO_FUTURE_PRINT_FUNCTION | CO_FUTURE_UNICODE_LITERALS | CO_FUTURE_BARRY_AS_BDFL | CO_FUTURE_GENERATOR_STOP | CO_FUTURE_ANNOTATIONS)'), - Constant('PyCF_MASK_OBSOLETE', '(CO_NESTED)'), - Constant('PyCF_SOURCE_IS_UTF8', ' 0x0100'), - Constant('PyCF_DONT_IMPLY_DEDENT', '0x0200'), - Constant('PyCF_ONLY_AST', '0x0400'), - Constant('PyCF_IGNORE_COOKIE', '0x0800'), - Constant('PyCF_TYPE_COMMENTS', '0x1000'), - Constant('PyCF_ALLOW_TOP_LEVEL_AWAIT', '0x2000'), - - IfDirective('ifndef', 'Py_LIMITED_API'), - OtherDirective('endif', None), - - Constant('FUTURE_NESTED_SCOPES', '"nested_scopes"'), - Constant('FUTURE_GENERATORS', '"generators"'), - Constant('FUTURE_DIVISION', '"division"'), - Constant('FUTURE_ABSOLUTE_IMPORT', '"absolute_import"'), - Constant('FUTURE_WITH_STATEMENT', '"with_statement"'), - Constant('FUTURE_PRINT_FUNCTION', '"print_function"'), - Constant('FUTURE_UNICODE_LITERALS', '"unicode_literals"'), - Constant('FUTURE_BARRY_AS_BDFL', '"barry_as_FLUFL"'), - Constant('FUTURE_GENERATOR_STOP', '"generator_stop"'), - Constant('FUTURE_ANNOTATIONS', '"annotations"'), - - Macro('PyAST_Compile', ('mod', 's', 'f', 'ar'), 'PyAST_CompileEx(mod, s, f, -1, ar)'), - - Constant('PY_INVALID_STACK_EFFECT', 'INT_MAX'), - - IfDirective('ifdef', '__cplusplus'), - OtherDirective('endif', None), - - OtherDirective('endif', None), # ifndef Py_LIMITED_API - - Constant('Py_single_input', '256'), - Constant('Py_file_input', '257'), - Constant('Py_eval_input', '258'), - Constant('Py_func_type_input', '345'), - - OtherDirective('endif', None), # ifndef Py_COMPILE_H - ] - self.parsed = list(directives) - text = textwrap.dedent(r''' - #ifndef Py_COMPILE_H - #define Py_COMPILE_H - - #ifndef Py_LIMITED_API - #include "code.h" - - #ifdef __cplusplus - extern "C" { - #endif - - /* Public interface */ - struct _node; /* Declare the existence of this type */ - PyAPI_FUNC(PyCodeObject *) PyNode_Compile(struct _node *, const char *); - /* XXX (ncoghlan): Unprefixed type name in a public API! */ - - #define PyCF_MASK (CO_FUTURE_DIVISION | CO_FUTURE_ABSOLUTE_IMPORT | \ - CO_FUTURE_WITH_STATEMENT | CO_FUTURE_PRINT_FUNCTION | \ - CO_FUTURE_UNICODE_LITERALS | CO_FUTURE_BARRY_AS_BDFL | \ - CO_FUTURE_GENERATOR_STOP | CO_FUTURE_ANNOTATIONS) - #define PyCF_MASK_OBSOLETE (CO_NESTED) - #define PyCF_SOURCE_IS_UTF8 0x0100 - #define PyCF_DONT_IMPLY_DEDENT 0x0200 - #define PyCF_ONLY_AST 0x0400 - #define PyCF_IGNORE_COOKIE 0x0800 - #define PyCF_TYPE_COMMENTS 0x1000 - #define PyCF_ALLOW_TOP_LEVEL_AWAIT 0x2000 - - #ifndef Py_LIMITED_API - typedef struct { - int cf_flags; /* bitmask of CO_xxx flags relevant to future */ - int cf_feature_version; /* minor Python version (PyCF_ONLY_AST) */ - } PyCompilerFlags; - #endif - - /* Future feature support */ - - typedef struct { - int ff_features; /* flags set by future statements */ - int ff_lineno; /* line number of last future statement */ - } PyFutureFeatures; - - #define FUTURE_NESTED_SCOPES "nested_scopes" - #define FUTURE_GENERATORS "generators" - #define FUTURE_DIVISION "division" - #define FUTURE_ABSOLUTE_IMPORT "absolute_import" - #define FUTURE_WITH_STATEMENT "with_statement" - #define FUTURE_PRINT_FUNCTION "print_function" - #define FUTURE_UNICODE_LITERALS "unicode_literals" - #define FUTURE_BARRY_AS_BDFL "barry_as_FLUFL" - #define FUTURE_GENERATOR_STOP "generator_stop" - #define FUTURE_ANNOTATIONS "annotations" - - struct _mod; /* Declare the existence of this type */ - #define PyAST_Compile(mod, s, f, ar) PyAST_CompileEx(mod, s, f, -1, ar) - PyAPI_FUNC(PyCodeObject *) PyAST_CompileEx( - struct _mod *mod, - const char *filename, /* decoded from the filesystem encoding */ - PyCompilerFlags *flags, - int optimize, - PyArena *arena); - PyAPI_FUNC(PyCodeObject *) PyAST_CompileObject( - struct _mod *mod, - PyObject *filename, - PyCompilerFlags *flags, - int optimize, - PyArena *arena); - PyAPI_FUNC(PyFutureFeatures *) PyFuture_FromAST( - struct _mod * mod, - const char *filename /* decoded from the filesystem encoding */ - ); - PyAPI_FUNC(PyFutureFeatures *) PyFuture_FromASTObject( - struct _mod * mod, - PyObject *filename - ); - - /* _Py_Mangle is defined in compile.c */ - PyAPI_FUNC(PyObject*) _Py_Mangle(PyObject *p, PyObject *name); - - #define PY_INVALID_STACK_EFFECT INT_MAX - PyAPI_FUNC(int) PyCompile_OpcodeStackEffect(int opcode, int oparg); - PyAPI_FUNC(int) PyCompile_OpcodeStackEffectWithJump(int opcode, int oparg, int jump); - - PyAPI_FUNC(int) _PyAST_Optimize(struct _mod *, PyArena *arena, int optimize); - - #ifdef __cplusplus - } - #endif - - #endif /* !Py_LIMITED_API */ - - /* These definitions must match corresponding definitions in graminit.h. */ - #define Py_single_input 256 - #define Py_file_input 257 - #define Py_eval_input 258 - #define Py_func_type_input 345 - - #endif /* !Py_COMPILE_H */ - ''').strip() - lines = [line + '\n' for line in text.splitlines()] - lines[-1] = lines[-1][:-1] - - results = list( - iter_lines(lines, _parse_directive=self._parse_directive)) - - self.assertEqual(results, [ - (1, '#ifndef Py_COMPILE_H\n', - IfDirective('ifndef', 'Py_COMPILE_H'), - ()), - (2, '#define Py_COMPILE_H\n', - Constant('Py_COMPILE_H', None), - ('! defined(Py_COMPILE_H)',)), - (3, '\n', - None, - ('! defined(Py_COMPILE_H)',)), - (4, '#ifndef Py_LIMITED_API\n', - IfDirective('ifndef', 'Py_LIMITED_API'), - ('! defined(Py_COMPILE_H)',)), - (5, '#include "code.h"\n', - Include('"code.h"'), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (6, '\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (7, '#ifdef __cplusplus\n', - IfDirective('ifdef', '__cplusplus'), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (8, 'extern "C" {\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)', 'defined(__cplusplus)')), - (9, '#endif\n', - OtherDirective('endif', None), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)', 'defined(__cplusplus)')), - (10, '\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (11, ' \n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (12, 'struct _node; \n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (13, 'PyAPI_FUNC(PyCodeObject *) PyNode_Compile(struct _node *, const char *);\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (14, ' \n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (15, '\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (19, '#define PyCF_MASK (CO_FUTURE_DIVISION | CO_FUTURE_ABSOLUTE_IMPORT | CO_FUTURE_WITH_STATEMENT | CO_FUTURE_PRINT_FUNCTION | CO_FUTURE_UNICODE_LITERALS | CO_FUTURE_BARRY_AS_BDFL | CO_FUTURE_GENERATOR_STOP | CO_FUTURE_ANNOTATIONS)\n', - Constant('PyCF_MASK', '(CO_FUTURE_DIVISION | CO_FUTURE_ABSOLUTE_IMPORT | CO_FUTURE_WITH_STATEMENT | CO_FUTURE_PRINT_FUNCTION | CO_FUTURE_UNICODE_LITERALS | CO_FUTURE_BARRY_AS_BDFL | CO_FUTURE_GENERATOR_STOP | CO_FUTURE_ANNOTATIONS)'), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (20, '#define PyCF_MASK_OBSOLETE (CO_NESTED)\n', - Constant('PyCF_MASK_OBSOLETE', '(CO_NESTED)'), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (21, '#define PyCF_SOURCE_IS_UTF8 0x0100\n', - Constant('PyCF_SOURCE_IS_UTF8', ' 0x0100'), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (22, '#define PyCF_DONT_IMPLY_DEDENT 0x0200\n', - Constant('PyCF_DONT_IMPLY_DEDENT', '0x0200'), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (23, '#define PyCF_ONLY_AST 0x0400\n', - Constant('PyCF_ONLY_AST', '0x0400'), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (24, '#define PyCF_IGNORE_COOKIE 0x0800\n', - Constant('PyCF_IGNORE_COOKIE', '0x0800'), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (25, '#define PyCF_TYPE_COMMENTS 0x1000\n', - Constant('PyCF_TYPE_COMMENTS', '0x1000'), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (26, '#define PyCF_ALLOW_TOP_LEVEL_AWAIT 0x2000\n', - Constant('PyCF_ALLOW_TOP_LEVEL_AWAIT', '0x2000'), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (27, '\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (28, '#ifndef Py_LIMITED_API\n', - IfDirective('ifndef', 'Py_LIMITED_API'), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (29, 'typedef struct {\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)', '! defined(Py_LIMITED_API)')), - (30, ' int cf_flags; \n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)', '! defined(Py_LIMITED_API)')), - (31, ' int cf_feature_version; \n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)', '! defined(Py_LIMITED_API)')), - (32, '} PyCompilerFlags;\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)', '! defined(Py_LIMITED_API)')), - (33, '#endif\n', - OtherDirective('endif', None), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)', '! defined(Py_LIMITED_API)')), - (34, '\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (35, ' \n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (36, '\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (37, 'typedef struct {\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (38, ' int ff_features; \n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (39, ' int ff_lineno; \n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (40, '} PyFutureFeatures;\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (41, '\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (42, '#define FUTURE_NESTED_SCOPES "nested_scopes"\n', - Constant('FUTURE_NESTED_SCOPES', '"nested_scopes"'), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (43, '#define FUTURE_GENERATORS "generators"\n', - Constant('FUTURE_GENERATORS', '"generators"'), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (44, '#define FUTURE_DIVISION "division"\n', - Constant('FUTURE_DIVISION', '"division"'), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (45, '#define FUTURE_ABSOLUTE_IMPORT "absolute_import"\n', - Constant('FUTURE_ABSOLUTE_IMPORT', '"absolute_import"'), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (46, '#define FUTURE_WITH_STATEMENT "with_statement"\n', - Constant('FUTURE_WITH_STATEMENT', '"with_statement"'), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (47, '#define FUTURE_PRINT_FUNCTION "print_function"\n', - Constant('FUTURE_PRINT_FUNCTION', '"print_function"'), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (48, '#define FUTURE_UNICODE_LITERALS "unicode_literals"\n', - Constant('FUTURE_UNICODE_LITERALS', '"unicode_literals"'), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (49, '#define FUTURE_BARRY_AS_BDFL "barry_as_FLUFL"\n', - Constant('FUTURE_BARRY_AS_BDFL', '"barry_as_FLUFL"'), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (50, '#define FUTURE_GENERATOR_STOP "generator_stop"\n', - Constant('FUTURE_GENERATOR_STOP', '"generator_stop"'), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (51, '#define FUTURE_ANNOTATIONS "annotations"\n', - Constant('FUTURE_ANNOTATIONS', '"annotations"'), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (52, '\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (53, 'struct _mod; \n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (54, '#define PyAST_Compile(mod, s, f, ar) PyAST_CompileEx(mod, s, f, -1, ar)\n', - Macro('PyAST_Compile', ('mod', 's', 'f', 'ar'), 'PyAST_CompileEx(mod, s, f, -1, ar)'), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (55, 'PyAPI_FUNC(PyCodeObject *) PyAST_CompileEx(\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (56, ' struct _mod *mod,\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (57, ' const char *filename, \n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (58, ' PyCompilerFlags *flags,\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (59, ' int optimize,\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (60, ' PyArena *arena);\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (61, 'PyAPI_FUNC(PyCodeObject *) PyAST_CompileObject(\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (62, ' struct _mod *mod,\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (63, ' PyObject *filename,\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (64, ' PyCompilerFlags *flags,\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (65, ' int optimize,\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (66, ' PyArena *arena);\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (67, 'PyAPI_FUNC(PyFutureFeatures *) PyFuture_FromAST(\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (68, ' struct _mod * mod,\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (69, ' const char *filename \n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (70, ' );\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (71, 'PyAPI_FUNC(PyFutureFeatures *) PyFuture_FromASTObject(\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (72, ' struct _mod * mod,\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (73, ' PyObject *filename\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (74, ' );\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (75, '\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (76, ' \n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (77, 'PyAPI_FUNC(PyObject*) _Py_Mangle(PyObject *p, PyObject *name);\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (78, '\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (79, '#define PY_INVALID_STACK_EFFECT INT_MAX\n', - Constant('PY_INVALID_STACK_EFFECT', 'INT_MAX'), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (80, 'PyAPI_FUNC(int) PyCompile_OpcodeStackEffect(int opcode, int oparg);\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (81, 'PyAPI_FUNC(int) PyCompile_OpcodeStackEffectWithJump(int opcode, int oparg, int jump);\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (82, '\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (83, 'PyAPI_FUNC(int) _PyAST_Optimize(struct _mod *, PyArena *arena, int optimize);\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (84, '\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (85, '#ifdef __cplusplus\n', - IfDirective('ifdef', '__cplusplus'), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (86, '}\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)', 'defined(__cplusplus)')), - (87, '#endif\n', - OtherDirective('endif', None), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)', 'defined(__cplusplus)')), - (88, '\n', - None, - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (89, '#endif \n', - OtherDirective('endif', None), - ('! defined(Py_COMPILE_H)', '! defined(Py_LIMITED_API)')), - (90, '\n', - None, - ('! defined(Py_COMPILE_H)',)), - (91, ' \n', - None, - ('! defined(Py_COMPILE_H)',)), - (92, '#define Py_single_input 256\n', - Constant('Py_single_input', '256'), - ('! defined(Py_COMPILE_H)',)), - (93, '#define Py_file_input 257\n', - Constant('Py_file_input', '257'), - ('! defined(Py_COMPILE_H)',)), - (94, '#define Py_eval_input 258\n', - Constant('Py_eval_input', '258'), - ('! defined(Py_COMPILE_H)',)), - (95, '#define Py_func_type_input 345\n', - Constant('Py_func_type_input', '345'), - ('! defined(Py_COMPILE_H)',)), - (96, '\n', - None, - ('! defined(Py_COMPILE_H)',)), - (97, '#endif ', - OtherDirective('endif', None), - ('! defined(Py_COMPILE_H)',)), - ]) - self.check_calls( - ('_parse_directive', '#ifndef Py_COMPILE_H'), - ('_parse_directive', '#define Py_COMPILE_H'), - ('_parse_directive', '#ifndef Py_LIMITED_API'), - ('_parse_directive', '#include "code.h"'), - ('_parse_directive', '#ifdef __cplusplus'), - ('_parse_directive', '#endif'), - ('_parse_directive', '#define PyCF_MASK (CO_FUTURE_DIVISION | CO_FUTURE_ABSOLUTE_IMPORT | CO_FUTURE_WITH_STATEMENT | CO_FUTURE_PRINT_FUNCTION | CO_FUTURE_UNICODE_LITERALS | CO_FUTURE_BARRY_AS_BDFL | CO_FUTURE_GENERATOR_STOP | CO_FUTURE_ANNOTATIONS)'), - ('_parse_directive', '#define PyCF_MASK_OBSOLETE (CO_NESTED)'), - ('_parse_directive', '#define PyCF_SOURCE_IS_UTF8 0x0100'), - ('_parse_directive', '#define PyCF_DONT_IMPLY_DEDENT 0x0200'), - ('_parse_directive', '#define PyCF_ONLY_AST 0x0400'), - ('_parse_directive', '#define PyCF_IGNORE_COOKIE 0x0800'), - ('_parse_directive', '#define PyCF_TYPE_COMMENTS 0x1000'), - ('_parse_directive', '#define PyCF_ALLOW_TOP_LEVEL_AWAIT 0x2000'), - ('_parse_directive', '#ifndef Py_LIMITED_API'), - ('_parse_directive', '#endif'), - ('_parse_directive', '#define FUTURE_NESTED_SCOPES "nested_scopes"'), - ('_parse_directive', '#define FUTURE_GENERATORS "generators"'), - ('_parse_directive', '#define FUTURE_DIVISION "division"'), - ('_parse_directive', '#define FUTURE_ABSOLUTE_IMPORT "absolute_import"'), - ('_parse_directive', '#define FUTURE_WITH_STATEMENT "with_statement"'), - ('_parse_directive', '#define FUTURE_PRINT_FUNCTION "print_function"'), - ('_parse_directive', '#define FUTURE_UNICODE_LITERALS "unicode_literals"'), - ('_parse_directive', '#define FUTURE_BARRY_AS_BDFL "barry_as_FLUFL"'), - ('_parse_directive', '#define FUTURE_GENERATOR_STOP "generator_stop"'), - ('_parse_directive', '#define FUTURE_ANNOTATIONS "annotations"'), - ('_parse_directive', '#define PyAST_Compile(mod, s, f, ar) PyAST_CompileEx(mod, s, f, -1, ar)'), - ('_parse_directive', '#define PY_INVALID_STACK_EFFECT INT_MAX'), - ('_parse_directive', '#ifdef __cplusplus'), - ('_parse_directive', '#endif'), - ('_parse_directive', '#endif'), - ('_parse_directive', '#define Py_single_input 256'), - ('_parse_directive', '#define Py_file_input 257'), - ('_parse_directive', '#define Py_eval_input 258'), - ('_parse_directive', '#define Py_func_type_input 345'), - ('_parse_directive', '#endif'), - ) - - -class ParseDirectiveTests(unittest.TestCase): - - def test_directives(self): - tests = [ - # includes - ('#include "internal/pycore_pystate.h"', Include('"internal/pycore_pystate.h"')), - ('#include <stdio>', Include('<stdio>')), - - # defines - ('#define SPAM int', Constant('SPAM', 'int')), - ('#define SPAM', Constant('SPAM', '')), - ('#define SPAM(x, y) run(x, y)', Macro('SPAM', ('x', 'y'), 'run(x, y)')), - ('#undef SPAM', None), - - # conditionals - ('#if SPAM', IfDirective('if', 'SPAM')), - # XXX complex conditionls - ('#ifdef SPAM', IfDirective('ifdef', 'SPAM')), - ('#ifndef SPAM', IfDirective('ifndef', 'SPAM')), - ('#elseif SPAM', IfDirective('elseif', 'SPAM')), - # XXX complex conditionls - ('#else', OtherDirective('else', '')), - ('#endif', OtherDirective('endif', '')), - - # other - ('#error oops!', None), - ('#warning oops!', None), - ('#pragma ...', None), - ('#__FILE__ ...', None), - ('#__LINE__ ...', None), - ('#__DATE__ ...', None), - ('#__TIME__ ...', None), - ('#__TIMESTAMP__ ...', None), - - # extra whitespace - (' # include <stdio> ', Include('<stdio>')), - ('#else ', OtherDirective('else', '')), - ('#endif ', OtherDirective('endif', '')), - ('#define SPAM int ', Constant('SPAM', 'int')), - ('#define SPAM ', Constant('SPAM', '')), - ] - for line, expected in tests: - if expected is None: - kind, _, text = line[1:].partition(' ') - expected = OtherDirective(kind, text) - with self.subTest(line): - directive = parse_directive(line) - - self.assertEqual(directive, expected) - - def test_bad_directives(self): - tests = [ - # valid directives with bad text - '#define 123', - '#else spam', - '#endif spam', - ] - for kind in PreprocessorDirective.KINDS: - # missing leading "#" - tests.append(kind) - if kind in ('else', 'endif'): - continue - # valid directives with missing text - tests.append('#' + kind) - tests.append('#' + kind + ' ') - for line in tests: - with self.subTest(line): - with self.assertRaises(ValueError): - parse_directive(line) - - def test_not_directives(self): - tests = [ - '', - ' ', - 'directive', - 'directive?', - '???', - ] - for line in tests: - with self.subTest(line): - with self.assertRaises(ValueError): - parse_directive(line) - - -class ConstantTests(unittest.TestCase): - - def test_type(self): - directive = Constant('SPAM', '123') - - self.assertIs(type(directive), Constant) - self.assertIsInstance(directive, PreprocessorDirective) - - def test_attrs(self): - d = Constant('SPAM', '123') - kind, name, value = d.kind, d.name, d.value - - self.assertEqual(kind, 'define') - self.assertEqual(name, 'SPAM') - self.assertEqual(value, '123') - - def test_text(self): - tests = [ - (('SPAM', '123'), 'SPAM 123'), - (('SPAM',), 'SPAM'), - ] - for args, expected in tests: - with self.subTest(args): - d = Constant(*args) - text = d.text - - self.assertEqual(text, expected) - - def test_iter(self): - kind, name, value = Constant('SPAM', '123') - - self.assertEqual(kind, 'define') - self.assertEqual(name, 'SPAM') - self.assertEqual(value, '123') - - def test_defaults(self): - kind, name, value = Constant('SPAM') - - self.assertEqual(kind, 'define') - self.assertEqual(name, 'SPAM') - self.assertIs(value, None) - - def test_coerce(self): - tests = [] - # coerced name, value - for args in wrapped_arg_combos('SPAM', '123'): - tests.append((args, ('SPAM', '123'))) - # missing name, value - for name in ('', ' ', None, StrProxy(' '), ()): - for value in ('', ' ', None, StrProxy(' '), ()): - tests.append( - ((name, value), (None, None))) - # whitespace - tests.extend([ - ((' SPAM ', ' 123 '), ('SPAM', '123')), - ]) - - for args, expected in tests: - with self.subTest(args): - d = Constant(*args) - - self.assertEqual(d[1:], expected) - for i, exp in enumerate(expected, start=1): - if exp is not None: - self.assertIs(type(d[i]), str) - - def test_valid(self): - tests = [ - ('SPAM', '123'), - # unusual name - ('_SPAM_', '123'), - ('X_1', '123'), - # unusual value - ('SPAM', None), - ] - for args in tests: - with self.subTest(args): - directive = Constant(*args) - - directive.validate() - - def test_invalid(self): - tests = [ - # invalid name - ((None, '123'), TypeError), - (('_', '123'), ValueError), - (('1', '123'), ValueError), - (('_1_', '123'), ValueError), - # There is no invalid value (including None). - ] - for args, exctype in tests: - with self.subTest(args): - directive = Constant(*args) - - with self.assertRaises(exctype): - directive.validate() - - -class MacroTests(unittest.TestCase): - - def test_type(self): - directive = Macro('SPAM', ('x', 'y'), '123') - - self.assertIs(type(directive), Macro) - self.assertIsInstance(directive, PreprocessorDirective) - - def test_attrs(self): - d = Macro('SPAM', ('x', 'y'), '123') - kind, name, args, body = d.kind, d.name, d.args, d.body - - self.assertEqual(kind, 'define') - self.assertEqual(name, 'SPAM') - self.assertEqual(args, ('x', 'y')) - self.assertEqual(body, '123') - - def test_text(self): - tests = [ - (('SPAM', ('x', 'y'), '123'), 'SPAM(x, y) 123'), - (('SPAM', ('x', 'y'),), 'SPAM(x, y)'), - ] - for args, expected in tests: - with self.subTest(args): - d = Macro(*args) - text = d.text - - self.assertEqual(text, expected) - - def test_iter(self): - kind, name, args, body = Macro('SPAM', ('x', 'y'), '123') - - self.assertEqual(kind, 'define') - self.assertEqual(name, 'SPAM') - self.assertEqual(args, ('x', 'y')) - self.assertEqual(body, '123') - - def test_defaults(self): - kind, name, args, body = Macro('SPAM', ('x', 'y')) - - self.assertEqual(kind, 'define') - self.assertEqual(name, 'SPAM') - self.assertEqual(args, ('x', 'y')) - self.assertIs(body, None) - - def test_coerce(self): - tests = [] - # coerce name and body - for args in wrapped_arg_combos('SPAM', ('x', 'y'), '123'): - tests.append( - (args, ('SPAM', ('x', 'y'), '123'))) - # coerce args - tests.extend([ - (('SPAM', 'x', '123'), - ('SPAM', ('x',), '123')), - (('SPAM', 'x,y', '123'), - ('SPAM', ('x', 'y'), '123')), - ]) - # coerce arg names - for argnames in wrapped_arg_combos('x', 'y'): - tests.append( - (('SPAM', argnames, '123'), - ('SPAM', ('x', 'y'), '123'))) - # missing name, body - for name in ('', ' ', None, StrProxy(' '), ()): - for argnames in (None, ()): - for body in ('', ' ', None, StrProxy(' '), ()): - tests.append( - ((name, argnames, body), - (None, (), None))) - # missing args - tests.extend([ - (('SPAM', None, '123'), - ('SPAM', (), '123')), - (('SPAM', (), '123'), - ('SPAM', (), '123')), - ]) - # missing arg names - for arg in ('', ' ', None, StrProxy(' '), ()): - tests.append( - (('SPAM', (arg,), '123'), - ('SPAM', (None,), '123'))) - tests.extend([ - (('SPAM', ('x', '', 'z'), '123'), - ('SPAM', ('x', None, 'z'), '123')), - ]) - # whitespace - tests.extend([ - ((' SPAM ', (' x ', ' y '), ' 123 '), - ('SPAM', ('x', 'y'), '123')), - (('SPAM', 'x, y', '123'), - ('SPAM', ('x', 'y'), '123')), - ]) - - for args, expected in tests: - with self.subTest(args): - d = Macro(*args) - - self.assertEqual(d[1:], expected) - for i, exp in enumerate(expected, start=1): - if i == 2: - self.assertIs(type(d[i]), tuple) - elif exp is not None: - self.assertIs(type(d[i]), str) - - def test_init_bad_args(self): - tests = [ - ('SPAM', StrProxy('x'), '123'), - ('SPAM', object(), '123'), - ] - for args in tests: - with self.subTest(args): - with self.assertRaises(TypeError): - Macro(*args) - - def test_valid(self): - tests = [ - # unusual name - ('SPAM', ('x', 'y'), 'run(x, y)'), - ('_SPAM_', ('x', 'y'), 'run(x, y)'), - ('X_1', ('x', 'y'), 'run(x, y)'), - # unusual args - ('SPAM', (), 'run(x, y)'), - ('SPAM', ('_x_', 'y_1'), 'run(x, y)'), - ('SPAM', 'x', 'run(x, y)'), - ('SPAM', 'x, y', 'run(x, y)'), - # unusual body - ('SPAM', ('x', 'y'), None), - ] - for args in tests: - with self.subTest(args): - directive = Macro(*args) - - directive.validate() - - def test_invalid(self): - tests = [ - # invalid name - ((None, ('x', 'y'), '123'), TypeError), - (('_', ('x', 'y'), '123'), ValueError), - (('1', ('x', 'y'), '123'), ValueError), - (('_1', ('x', 'y'), '123'), ValueError), - # invalid args - (('SPAM', (None, 'y'), '123'), ValueError), - (('SPAM', ('x', '_'), '123'), ValueError), - (('SPAM', ('x', '1'), '123'), ValueError), - (('SPAM', ('x', '_1_'), '123'), ValueError), - # There is no invalid body (including None). - ] - for args, exctype in tests: - with self.subTest(args): - directive = Macro(*args) - - with self.assertRaises(exctype): - directive.validate() - - -class IfDirectiveTests(unittest.TestCase): - - def test_type(self): - directive = IfDirective('if', '1') - - self.assertIs(type(directive), IfDirective) - self.assertIsInstance(directive, PreprocessorDirective) - - def test_attrs(self): - d = IfDirective('if', '1') - kind, condition = d.kind, d.condition - - self.assertEqual(kind, 'if') - self.assertEqual(condition, '1') - #self.assertEqual(condition, (ArithmeticCondition('1'),)) - - def test_text(self): - tests = [ - (('if', 'defined(SPAM) && 1 || (EGGS > 3 && defined(HAM))'), - 'defined(SPAM) && 1 || (EGGS > 3 && defined(HAM))'), - ] - for kind in IfDirective.KINDS: - tests.append( - ((kind, 'SPAM'), 'SPAM')) - for args, expected in tests: - with self.subTest(args): - d = IfDirective(*args) - text = d.text - - self.assertEqual(text, expected) - - def test_iter(self): - kind, condition = IfDirective('if', '1') - - self.assertEqual(kind, 'if') - self.assertEqual(condition, '1') - #self.assertEqual(condition, (ArithmeticCondition('1'),)) - - #def test_complex_conditions(self): - # ... - - def test_coerce(self): - tests = [] - for kind in IfDirective.KINDS: - if kind == 'ifdef': - cond = 'defined(SPAM)' - elif kind == 'ifndef': - cond = '! defined(SPAM)' - else: - cond = 'SPAM' - for args in wrapped_arg_combos(kind, 'SPAM'): - tests.append((args, (kind, cond))) - tests.extend([ - ((' ' + kind + ' ', ' SPAM '), (kind, cond)), - ]) - for raw in ('', ' ', None, StrProxy(' '), ()): - tests.append(((kind, raw), (kind, None))) - for kind in ('', ' ', None, StrProxy(' '), ()): - tests.append(((kind, 'SPAM'), (None, 'SPAM'))) - for args, expected in tests: - with self.subTest(args): - d = IfDirective(*args) - - self.assertEqual(tuple(d), expected) - for i, exp in enumerate(expected): - if exp is not None: - self.assertIs(type(d[i]), str) - - def test_valid(self): - tests = [] - for kind in IfDirective.KINDS: - tests.extend([ - (kind, 'SPAM'), - (kind, '_SPAM_'), - (kind, 'X_1'), - (kind, '()'), - (kind, '--'), - (kind, '???'), - ]) - for args in tests: - with self.subTest(args): - directive = IfDirective(*args) - - directive.validate() - - def test_invalid(self): - tests = [] - # kind - tests.extend([ - ((None, 'SPAM'), TypeError), - (('_', 'SPAM'), ValueError), - (('-', 'SPAM'), ValueError), - (('spam', 'SPAM'), ValueError), - ]) - for kind in PreprocessorDirective.KINDS: - if kind in IfDirective.KINDS: - continue - tests.append( - ((kind, 'SPAM'), ValueError)) - # condition - for kind in IfDirective.KINDS: - tests.extend([ - ((kind, None), TypeError), - # Any other condition is valid. - ]) - for args, exctype in tests: - with self.subTest(args): - directive = IfDirective(*args) - - with self.assertRaises(exctype): - directive.validate() - - -class IncludeTests(unittest.TestCase): - - def test_type(self): - directive = Include('<stdio>') - - self.assertIs(type(directive), Include) - self.assertIsInstance(directive, PreprocessorDirective) - - def test_attrs(self): - d = Include('<stdio>') - kind, file, text = d.kind, d.file, d.text - - self.assertEqual(kind, 'include') - self.assertEqual(file, '<stdio>') - self.assertEqual(text, '<stdio>') - - def test_iter(self): - kind, file = Include('<stdio>') - - self.assertEqual(kind, 'include') - self.assertEqual(file, '<stdio>') - - def test_coerce(self): - tests = [] - for arg, in wrapped_arg_combos('<stdio>'): - tests.append((arg, '<stdio>')) - tests.extend([ - (' <stdio> ', '<stdio>'), - ]) - for arg in ('', ' ', None, StrProxy(' '), ()): - tests.append((arg, None )) - for arg, expected in tests: - with self.subTest(arg): - _, file = Include(arg) - - self.assertEqual(file, expected) - if expected is not None: - self.assertIs(type(file), str) - - def test_valid(self): - tests = [ - '<stdio>', - '"spam.h"', - '"internal/pycore_pystate.h"', - ] - for arg in tests: - with self.subTest(arg): - directive = Include(arg) - - directive.validate() - - def test_invalid(self): - tests = [ - (None, TypeError), - # We currently don't check the file. - ] - for arg, exctype in tests: - with self.subTest(arg): - directive = Include(arg) - - with self.assertRaises(exctype): - directive.validate() - - -class OtherDirectiveTests(unittest.TestCase): - - def test_type(self): - directive = OtherDirective('undef', 'SPAM') - - self.assertIs(type(directive), OtherDirective) - self.assertIsInstance(directive, PreprocessorDirective) - - def test_attrs(self): - d = OtherDirective('undef', 'SPAM') - kind, text = d.kind, d.text - - self.assertEqual(kind, 'undef') - self.assertEqual(text, 'SPAM') - - def test_iter(self): - kind, text = OtherDirective('undef', 'SPAM') - - self.assertEqual(kind, 'undef') - self.assertEqual(text, 'SPAM') - - def test_coerce(self): - tests = [] - for kind in OtherDirective.KINDS: - if kind in ('else', 'endif'): - continue - for args in wrapped_arg_combos(kind, '...'): - tests.append((args, (kind, '...'))) - tests.extend([ - ((' ' + kind + ' ', ' ... '), (kind, '...')), - ]) - for raw in ('', ' ', None, StrProxy(' '), ()): - tests.append(((kind, raw), (kind, None))) - for kind in ('else', 'endif'): - for args in wrapped_arg_combos(kind, None): - tests.append((args, (kind, None))) - tests.extend([ - ((' ' + kind + ' ', None), (kind, None)), - ]) - for kind in ('', ' ', None, StrProxy(' '), ()): - tests.append(((kind, '...'), (None, '...'))) - for args, expected in tests: - with self.subTest(args): - d = OtherDirective(*args) - - self.assertEqual(tuple(d), expected) - for i, exp in enumerate(expected): - if exp is not None: - self.assertIs(type(d[i]), str) - - def test_valid(self): - tests = [] - for kind in OtherDirective.KINDS: - if kind in ('else', 'endif'): - continue - tests.extend([ - (kind, '...'), - (kind, '???'), - (kind, 'SPAM'), - (kind, '1 + 1'), - ]) - for kind in ('else', 'endif'): - tests.append((kind, None)) - for args in tests: - with self.subTest(args): - directive = OtherDirective(*args) - - directive.validate() - - def test_invalid(self): - tests = [] - # kind - tests.extend([ - ((None, '...'), TypeError), - (('_', '...'), ValueError), - (('-', '...'), ValueError), - (('spam', '...'), ValueError), - ]) - for kind in PreprocessorDirective.KINDS: - if kind in OtherDirective.KINDS: - continue - tests.append( - ((kind, None), ValueError)) - # text - for kind in OtherDirective.KINDS: - if kind in ('else', 'endif'): - tests.extend([ - # Any text is invalid. - ((kind, 'SPAM'), ValueError), - ((kind, '...'), ValueError), - ]) - else: - tests.extend([ - ((kind, None), TypeError), - # Any other text is valid. - ]) - for args, exctype in tests: - with self.subTest(args): - directive = OtherDirective(*args) - - with self.assertRaises(exctype): - directive.validate() diff --git a/Lib/test/test_tools/test_c_analyzer/test_symbols/__init__.py b/Lib/test/test_tools/test_c_analyzer/test_symbols/__init__.py deleted file mode 100644 index bc502ef32d2..00000000000 --- a/Lib/test/test_tools/test_c_analyzer/test_symbols/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -import os.path -from test.support import load_package_tests - - -def load_tests(*args): - return load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_tools/test_c_analyzer/test_symbols/test_info.py b/Lib/test/test_tools/test_c_analyzer/test_symbols/test_info.py deleted file mode 100644 index 1282a89718c..00000000000 --- a/Lib/test/test_tools/test_c_analyzer/test_symbols/test_info.py +++ /dev/null @@ -1,192 +0,0 @@ -import string -import unittest - -from ..util import PseudoStr, StrProxy, Object -from .. import tool_imports_for_tests -with tool_imports_for_tests(): - from c_analyzer.common.info import ID - from c_analyzer.symbols.info import Symbol - - -class SymbolTests(unittest.TestCase): - - VALID_ARGS = ( - ID('x/y/z/spam.c', 'func', 'eggs'), - Symbol.KIND.VARIABLE, - False, - ) - VALID_KWARGS = dict(zip(Symbol._fields, VALID_ARGS)) - VALID_EXPECTED = VALID_ARGS - - def test_init_typical_binary_local(self): - id = ID(None, None, 'spam') - symbol = Symbol( - id=id, - kind=Symbol.KIND.VARIABLE, - external=False, - ) - - self.assertEqual(symbol, ( - id, - Symbol.KIND.VARIABLE, - False, - )) - - def test_init_typical_binary_global(self): - id = ID('Python/ceval.c', None, 'spam') - symbol = Symbol( - id=id, - kind=Symbol.KIND.VARIABLE, - external=False, - ) - - self.assertEqual(symbol, ( - id, - Symbol.KIND.VARIABLE, - False, - )) - - def test_init_coercion(self): - tests = [ - ('str subclass', - dict( - id=PseudoStr('eggs'), - kind=PseudoStr('variable'), - external=0, - ), - (ID(None, None, 'eggs'), - Symbol.KIND.VARIABLE, - False, - )), - ('with filename', - dict( - id=('x/y/z/spam.c', 'eggs'), - kind=PseudoStr('variable'), - external=0, - ), - (ID('x/y/z/spam.c', None, 'eggs'), - Symbol.KIND.VARIABLE, - False, - )), - ('non-str 1', - dict( - id=('a', 'b', 'c'), - kind=StrProxy('variable'), - external=0, - ), - (ID('a', 'b', 'c'), - Symbol.KIND.VARIABLE, - False, - )), - ('non-str 2', - dict( - id=('a', 'b', 'c'), - kind=Object(), - external=0, - ), - (ID('a', 'b', 'c'), - '<object>', - False, - )), - ] - for summary, kwargs, expected in tests: - with self.subTest(summary): - symbol = Symbol(**kwargs) - - for field in Symbol._fields: - value = getattr(symbol, field) - if field == 'external': - self.assertIs(type(value), bool) - elif field == 'id': - self.assertIs(type(value), ID) - else: - self.assertIs(type(value), str) - self.assertEqual(tuple(symbol), expected) - - def test_init_all_missing(self): - id = ID(None, None, 'spam') - - symbol = Symbol(id) - - self.assertEqual(symbol, ( - id, - Symbol.KIND.VARIABLE, - None, - )) - - def test_fields(self): - id = ID('z', 'x', 'a') - - symbol = Symbol(id, 'b', False) - - self.assertEqual(symbol.id, id) - self.assertEqual(symbol.kind, 'b') - self.assertIs(symbol.external, False) - - def test___getattr__(self): - id = ID('z', 'x', 'a') - symbol = Symbol(id, 'b', False) - - filename = symbol.filename - funcname = symbol.funcname - name = symbol.name - - self.assertEqual(filename, 'z') - self.assertEqual(funcname, 'x') - self.assertEqual(name, 'a') - - def test_validate_typical(self): - id = ID('z', 'x', 'a') - - symbol = Symbol( - id=id, - kind=Symbol.KIND.VARIABLE, - external=False, - ) - - symbol.validate() # This does not fail. - - def test_validate_missing_field(self): - for field in Symbol._fields: - with self.subTest(field): - symbol = Symbol(**self.VALID_KWARGS) - symbol = symbol._replace(**{field: None}) - - with self.assertRaises(TypeError): - symbol.validate() - - def test_validate_bad_field(self): - badch = tuple(c for c in string.punctuation + string.digits) - notnames = ( - '1a', - 'a.b', - 'a-b', - '&a', - 'a++', - ) + badch - tests = [ - ('id', notnames), - ('kind', ('bogus',)), - ] - seen = set() - for field, invalid in tests: - for value in invalid: - if field != 'kind': - seen.add(value) - with self.subTest(f'{field}={value!r}'): - symbol = Symbol(**self.VALID_KWARGS) - symbol = symbol._replace(**{field: value}) - - with self.assertRaises(ValueError): - symbol.validate() - - for field, invalid in tests: - if field == 'kind': - continue - valid = seen - set(invalid) - for value in valid: - with self.subTest(f'{field}={value!r}'): - symbol = Symbol(**self.VALID_KWARGS) - symbol = symbol._replace(**{field: value}) - - symbol.validate() # This does not fail. diff --git a/Lib/test/test_tools/test_c_analyzer/test_variables/__init__.py b/Lib/test/test_tools/test_c_analyzer/test_variables/__init__.py deleted file mode 100644 index bc502ef32d2..00000000000 --- a/Lib/test/test_tools/test_c_analyzer/test_variables/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -import os.path -from test.support import load_package_tests - - -def load_tests(*args): - return load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_tools/test_c_analyzer/test_variables/test_find.py b/Lib/test/test_tools/test_c_analyzer/test_variables/test_find.py deleted file mode 100644 index 7a13cf3f5bf..00000000000 --- a/Lib/test/test_tools/test_c_analyzer/test_variables/test_find.py +++ /dev/null @@ -1,124 +0,0 @@ -import unittest - -from .. import tool_imports_for_tests -with tool_imports_for_tests(): - from c_analyzer.variables import info - from c_analyzer.variables.find import ( - vars_from_binary, - ) - - -class _Base(unittest.TestCase): - - maxDiff = None - - @property - def calls(self): - try: - return self._calls - except AttributeError: - self._calls = [] - return self._calls - - -class VarsFromBinaryTests(_Base): - - _return_iter_vars = () - _return_get_symbol_resolver = None - - def setUp(self): - super().setUp() - - self.kwargs = dict( - _iter_vars=self._iter_vars, - _get_symbol_resolver=self._get_symbol_resolver, - ) - - def _iter_vars(self, binfile, resolve, handle_id): - self.calls.append(('_iter_vars', (binfile, resolve, handle_id))) - return [(v, v.id) for v in self._return_iter_vars] - - def _get_symbol_resolver(self, known=None, dirnames=(), *, - handle_var, - filenames=None, - check_filename=None, - perfilecache=None, - ): - self.calls.append(('_get_symbol_resolver', - (known, dirnames, handle_var, filenames, - check_filename, perfilecache))) - return self._return_get_symbol_resolver - - def test_typical(self): - resolver = self._return_get_symbol_resolver = object() - variables = self._return_iter_vars = [ - info.Variable.from_parts('dir1/spam.c', None, 'var1', 'int'), - info.Variable.from_parts('dir1/spam.c', None, 'var2', 'static int'), - info.Variable.from_parts('dir1/spam.c', None, 'var3', 'char *'), - info.Variable.from_parts('dir1/spam.c', 'func2', 'var4', 'const char *'), - info.Variable.from_parts('dir1/eggs.c', None, 'var1', 'static int'), - info.Variable.from_parts('dir1/eggs.c', 'func1', 'var2', 'static char *'), - ] - known = object() - filenames = object() - - found = list(vars_from_binary('python', - known=known, - filenames=filenames, - **self.kwargs)) - - self.assertEqual(found, [ - info.Variable.from_parts('dir1/spam.c', None, 'var1', 'int'), - info.Variable.from_parts('dir1/spam.c', None, 'var2', 'static int'), - info.Variable.from_parts('dir1/spam.c', None, 'var3', 'char *'), - info.Variable.from_parts('dir1/spam.c', 'func2', 'var4', 'const char *'), - info.Variable.from_parts('dir1/eggs.c', None, 'var1', 'static int'), - info.Variable.from_parts('dir1/eggs.c', 'func1', 'var2', 'static char *'), - ]) - self.assertEqual(self.calls, [ - ('_get_symbol_resolver', (filenames, known, info.Variable.from_id, None, None, {})), - ('_iter_vars', ('python', resolver, None)), - ]) - -# self._return_iter_symbols = [ -# s_info.Symbol(('dir1/spam.c', None, 'var1'), 'variable', False), -# s_info.Symbol(('dir1/spam.c', None, 'var2'), 'variable', False), -# s_info.Symbol(('dir1/spam.c', None, 'func1'), 'function', False), -# s_info.Symbol(('dir1/spam.c', None, 'func2'), 'function', True), -# s_info.Symbol(('dir1/spam.c', None, 'var3'), 'variable', False), -# s_info.Symbol(('dir1/spam.c', 'func2', 'var4'), 'variable', False), -# s_info.Symbol(('dir1/ham.c', None, 'var1'), 'variable', True), -# s_info.Symbol(('dir1/eggs.c', None, 'var1'), 'variable', False), -# s_info.Symbol(('dir1/eggs.c', None, 'xyz'), 'other', False), -# s_info.Symbol(('dir1/eggs.c', '???', 'var2'), 'variable', False), -# s_info.Symbol(('???', None, 'var_x'), 'variable', False), -# s_info.Symbol(('???', '???', 'var_y'), 'variable', False), -# s_info.Symbol((None, None, '???'), 'other', False), -# ] -# known = object() -# -# vars_from_binary('python', knownvars=known, **this.kwargs) -# found = list(globals_from_symbols(['dir1'], self.iter_symbols)) -# -# self.assertEqual(found, [ -# info.Variable.from_parts('dir1/spam.c', None, 'var1', '???'), -# info.Variable.from_parts('dir1/spam.c', None, 'var2', '???'), -# info.Variable.from_parts('dir1/spam.c', None, 'var3', '???'), -# info.Variable.from_parts('dir1/spam.c', 'func2', 'var4', '???'), -# info.Variable.from_parts('dir1/eggs.c', None, 'var1', '???'), -# ]) -# self.assertEqual(self.calls, [ -# ('iter_symbols', (['dir1'],)), -# ]) -# -# def test_no_symbols(self): -# self._return_iter_symbols = [] -# -# found = list(globals_from_symbols(['dir1'], self.iter_symbols)) -# -# self.assertEqual(found, []) -# self.assertEqual(self.calls, [ -# ('iter_symbols', (['dir1'],)), -# ]) - - # XXX need functional test diff --git a/Lib/test/test_tools/test_c_analyzer/test_variables/test_info.py b/Lib/test/test_tools/test_c_analyzer/test_variables/test_info.py deleted file mode 100644 index d424d8eebb8..00000000000 --- a/Lib/test/test_tools/test_c_analyzer/test_variables/test_info.py +++ /dev/null @@ -1,244 +0,0 @@ -import string -import unittest - -from ..util import PseudoStr, StrProxy, Object -from .. import tool_imports_for_tests -with tool_imports_for_tests(): - from c_analyzer.common.info import UNKNOWN, ID - from c_analyzer.variables.info import ( - normalize_vartype, Variable - ) - - -class NormalizeVartypeTests(unittest.TestCase): - - def test_basic(self): - tests = [ - (None, None), - ('', ''), - ('int', 'int'), - (PseudoStr('int'), 'int'), - (StrProxy('int'), 'int'), - ] - for vartype, expected in tests: - with self.subTest(vartype): - normalized = normalize_vartype(vartype) - - self.assertEqual(normalized, expected) - - -class VariableTests(unittest.TestCase): - - VALID_ARGS = ( - ('x/y/z/spam.c', 'func', 'eggs'), - 'static', - 'int', - ) - VALID_KWARGS = dict(zip(Variable._fields, VALID_ARGS)) - VALID_EXPECTED = VALID_ARGS - - def test_init_typical_global(self): - for storage in ('static', 'extern', 'implicit'): - with self.subTest(storage): - static = Variable( - id=ID( - filename='x/y/z/spam.c', - funcname=None, - name='eggs', - ), - storage=storage, - vartype='int', - ) - - self.assertEqual(static, ( - ('x/y/z/spam.c', None, 'eggs'), - storage, - 'int', - )) - - def test_init_typical_local(self): - for storage in ('static', 'local'): - with self.subTest(storage): - static = Variable( - id=ID( - filename='x/y/z/spam.c', - funcname='func', - name='eggs', - ), - storage=storage, - vartype='int', - ) - - self.assertEqual(static, ( - ('x/y/z/spam.c', 'func', 'eggs'), - storage, - 'int', - )) - - def test_init_all_missing(self): - for value in ('', None): - with self.subTest(repr(value)): - static = Variable( - id=value, - storage=value, - vartype=value, - ) - - self.assertEqual(static, ( - None, - None, - None, - )) - - def test_init_all_coerced(self): - id = ID('x/y/z/spam.c', 'func', 'spam') - tests = [ - ('str subclass', - dict( - id=( - PseudoStr('x/y/z/spam.c'), - PseudoStr('func'), - PseudoStr('spam'), - ), - storage=PseudoStr('static'), - vartype=PseudoStr('int'), - ), - (id, - 'static', - 'int', - )), - ('non-str 1', - dict( - id=id, - storage=Object(), - vartype=Object(), - ), - (id, - '<object>', - '<object>', - )), - ('non-str 2', - dict( - id=id, - storage=StrProxy('static'), - vartype=StrProxy('variable'), - ), - (id, - 'static', - 'variable', - )), - ('non-str', - dict( - id=id, - storage=('a', 'b', 'c'), - vartype=('x', 'y', 'z'), - ), - (id, - "('a', 'b', 'c')", - "('x', 'y', 'z')", - )), - ] - for summary, kwargs, expected in tests: - with self.subTest(summary): - static = Variable(**kwargs) - - for field in Variable._fields: - value = getattr(static, field) - if field == 'id': - self.assertIs(type(value), ID) - else: - self.assertIs(type(value), str) - self.assertEqual(tuple(static), expected) - - def test_iterable(self): - static = Variable(**self.VALID_KWARGS) - - id, storage, vartype = static - - values = (id, storage, vartype) - for value, expected in zip(values, self.VALID_EXPECTED): - self.assertEqual(value, expected) - - def test_fields(self): - static = Variable(('a', 'b', 'z'), 'x', 'y') - - self.assertEqual(static.id, ('a', 'b', 'z')) - self.assertEqual(static.storage, 'x') - self.assertEqual(static.vartype, 'y') - - def test___getattr__(self): - static = Variable(('a', 'b', 'z'), 'x', 'y') - - self.assertEqual(static.filename, 'a') - self.assertEqual(static.funcname, 'b') - self.assertEqual(static.name, 'z') - - def test_validate_typical(self): - validstorage = ('static', 'extern', 'implicit', 'local') - self.assertEqual(set(validstorage), set(Variable.STORAGE)) - - for storage in validstorage: - with self.subTest(storage): - static = Variable( - id=ID( - filename='x/y/z/spam.c', - funcname='func', - name='eggs', - ), - storage=storage, - vartype='int', - ) - - static.validate() # This does not fail. - - def test_validate_missing_field(self): - for field in Variable._fields: - with self.subTest(field): - static = Variable(**self.VALID_KWARGS) - static = static._replace(**{field: None}) - - with self.assertRaises(TypeError): - static.validate() - for field in ('storage', 'vartype'): - with self.subTest(field): - static = Variable(**self.VALID_KWARGS) - static = static._replace(**{field: UNKNOWN}) - - with self.assertRaises(TypeError): - static.validate() - - def test_validate_bad_field(self): - badch = tuple(c for c in string.punctuation + string.digits) - notnames = ( - '1a', - 'a.b', - 'a-b', - '&a', - 'a++', - ) + badch - tests = [ - ('id', ()), # Any non-empty str is okay. - ('storage', ('external', 'global') + notnames), - ('vartype', ()), # Any non-empty str is okay. - ] - seen = set() - for field, invalid in tests: - for value in invalid: - seen.add(value) - with self.subTest(f'{field}={value!r}'): - static = Variable(**self.VALID_KWARGS) - static = static._replace(**{field: value}) - - with self.assertRaises(ValueError): - static.validate() - - for field, invalid in tests: - if field == 'id': - continue - valid = seen - set(invalid) - for value in valid: - with self.subTest(f'{field}={value!r}'): - static = Variable(**self.VALID_KWARGS) - static = static._replace(**{field: value}) - - static.validate() # This does not fail. diff --git a/Lib/test/test_tools/test_c_analyzer/test_variables/test_known.py b/Lib/test/test_tools/test_c_analyzer/test_variables/test_known.py deleted file mode 100644 index 49ff45c6d1b..00000000000 --- a/Lib/test/test_tools/test_c_analyzer/test_variables/test_known.py +++ /dev/null @@ -1,139 +0,0 @@ -import re -import textwrap -import unittest - -from .. import tool_imports_for_tests -with tool_imports_for_tests(): - from c_analyzer.common.info import ID - from c_analyzer.variables.info import Variable - from c_analyzer.variables.known import ( - read_file, - from_file, - ) - -class _BaseTests(unittest.TestCase): - - maxDiff = None - - @property - def calls(self): - try: - return self._calls - except AttributeError: - self._calls = [] - return self._calls - - -class ReadFileTests(_BaseTests): - - _return_read_tsv = () - - def _read_tsv(self, *args): - self.calls.append(('_read_tsv', args)) - return self._return_read_tsv - - def test_typical(self): - lines = textwrap.dedent(''' - filename funcname name kind declaration - file1.c - var1 variable static int - file1.c func1 local1 variable static int - file1.c - var2 variable int - file1.c func2 local2 variable char * - file2.c - var1 variable char * - ''').strip().splitlines() - lines = [re.sub(r'\s+', '\t', line, 4) for line in lines] - self._return_read_tsv = [tuple(v.strip() for v in line.split('\t')) - for line in lines[1:]] - - known = list(read_file('known.tsv', _read_tsv=self._read_tsv)) - - self.assertEqual(known, [ - ('variable', ID('file1.c', '', 'var1'), 'static int'), - ('variable', ID('file1.c', 'func1', 'local1'), 'static int'), - ('variable', ID('file1.c', '', 'var2'), 'int'), - ('variable', ID('file1.c', 'func2', 'local2'), 'char *'), - ('variable', ID('file2.c', '', 'var1'), 'char *'), - ]) - self.assertEqual(self.calls, [ - ('_read_tsv', - ('known.tsv', 'filename\tfuncname\tname\tkind\tdeclaration')), - ]) - - def test_empty(self): - self._return_read_tsv = [] - - known = list(read_file('known.tsv', _read_tsv=self._read_tsv)) - - self.assertEqual(known, []) - self.assertEqual(self.calls, [ - ('_read_tsv', ('known.tsv', 'filename\tfuncname\tname\tkind\tdeclaration')), - ]) - - -class FromFileTests(_BaseTests): - - _return_read_file = () - _return_handle_var = () - - def _read_file(self, infile): - self.calls.append(('_read_file', (infile,))) - return iter(self._return_read_file) - - def _handle_var(self, varid, decl): - self.calls.append(('_handle_var', (varid, decl))) - var = self._return_handle_var.pop(0) - return var - - def test_typical(self): - expected = [ - Variable.from_parts('file1.c', '', 'var1', 'static int'), - Variable.from_parts('file1.c', 'func1', 'local1', 'static int'), - Variable.from_parts('file1.c', '', 'var2', 'int'), - Variable.from_parts('file1.c', 'func2', 'local2', 'char *'), - Variable.from_parts('file2.c', '', 'var1', 'char *'), - ] - self._return_read_file = [('variable', v.id, v.vartype) - for v in expected] -# ('variable', ID('file1.c', '', 'var1'), 'static int'), -# ('variable', ID('file1.c', 'func1', 'local1'), 'static int'), -# ('variable', ID('file1.c', '', 'var2'), 'int'), -# ('variable', ID('file1.c', 'func2', 'local2'), 'char *'), -# ('variable', ID('file2.c', '', 'var1'), 'char *'), -# ] - self._return_handle_var = list(expected) # a copy - - known = from_file('known.tsv', - handle_var=self._handle_var, - _read_file=self._read_file, - ) - - self.assertEqual(known, { - 'variables': {v.id: v for v in expected}, - }) -# Variable.from_parts('file1.c', '', 'var1', 'static int'), -# Variable.from_parts('file1.c', 'func1', 'local1', 'static int'), -# Variable.from_parts('file1.c', '', 'var2', 'int'), -# Variable.from_parts('file1.c', 'func2', 'local2', 'char *'), -# Variable.from_parts('file2.c', '', 'var1', 'char *'), -# ]}, -# }) - self.assertEqual(self.calls, [ - ('_read_file', ('known.tsv',)), - *[('_handle_var', (v.id, v.vartype)) - for v in expected], - ]) - - def test_empty(self): - self._return_read_file = [] - - known = from_file('known.tsv', - handle_var=self._handle_var, - _read_file=self._read_file, - ) - - self.assertEqual(known, { - 'variables': {}, - }) - self.assertEqual(self.calls, [ - ('_read_file', ('known.tsv',)), - ]) diff --git a/Lib/test/test_tools/test_c_analyzer/util.py b/Lib/test/test_tools/test_c_analyzer/util.py deleted file mode 100644 index ba73b0a4b5f..00000000000 --- a/Lib/test/test_tools/test_c_analyzer/util.py +++ /dev/null @@ -1,60 +0,0 @@ -import itertools - - -class PseudoStr(str): - pass - - -class StrProxy: - def __init__(self, value): - self.value = value - def __str__(self): - return self.value - def __bool__(self): - return bool(self.value) - - -class Object: - def __repr__(self): - return '<object>' - - -def wrapped_arg_combos(*args, - wrappers=(PseudoStr, StrProxy), - skip=(lambda w, i, v: not isinstance(v, str)), - ): - """Yield every possible combination of wrapped items for the given args. - - Effectively, the wrappers are applied to the args according to the - powerset of the args indicies. So the result includes the args - completely unwrapped. - - If "skip" is supplied (default is to skip all non-str values) and - it returns True for a given arg index/value then that arg will - remain unwrapped, - - Only unique results are returned. If an arg was skipped for one - of the combinations then it could end up matching one of the other - combinations. In that case only one of them will be yielded. - """ - if not args: - return - indices = list(range(len(args))) - # The powerset (from recipe in the itertools docs). - combos = itertools.chain.from_iterable(itertools.combinations(indices, r) - for r in range(len(indices)+1)) - seen = set() - for combo in combos: - for wrap in wrappers: - indexes = [] - applied = list(args) - for i in combo: - arg = args[i] - if skip and skip(wrap, i, arg): - continue - indexes.append(i) - applied[i] = wrap(arg) - key = (wrap, tuple(indexes)) - if key not in seen: - yield tuple(applied) - seen.add(key) |