Skip to content

Commit

Permalink
Bring test coverage of _compile_restricted_mode to 100 %.
Browse files Browse the repository at this point in the history
Needs a bit refactoring of the code, too.
  • Loading branch information
Michael Howitz committed Feb 2, 2017
1 parent e52cf46 commit 725b3a8
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 15 deletions.
3 changes: 3 additions & 0 deletions src/RestrictedPython/RCompile.py
Expand Up @@ -83,6 +83,9 @@ def compile(self):
def _compileAndTuplize(gen):
try:
gen.compile()
except TypeError as v:
return CompileResult(
None, (str(v),), gen.rm.warnings, gen.rm.used_names)
except SyntaxError as v:
return CompileResult(
None, (str(v),), gen.rm.warnings, gen.rm.used_names)
Expand Down
24 changes: 9 additions & 15 deletions src/RestrictedPython/compile.py
Expand Up @@ -27,28 +27,22 @@ def _compile_restricted_mode(
c_ast = None
try:
c_ast = ast.parse(source, filename, mode)
except (TypeError, ValueError) as e:
errors.append(str(e))
except SyntaxError as v:
c_ast = None
errors.append('Line {lineno}: {type}: {msg} in on statement: {statement}'.format(
lineno=v.lineno,
type=v.__class__.__name__,
msg=v.msg,
statement=v.text.strip()
))
try:
if c_ast:
policy(errors, warnings, used_names).visit(c_ast)
if not errors:
byte_code = compile(c_ast, filename, mode=mode # ,
#flags=flags,
#dont_inherit=dont_inherit
)
except SyntaxError as v:
byte_code = None
errors.append(v)
except TypeError as v:
byte_code = None
errors.append(v)
if c_ast:
policy(errors, warnings, used_names).visit(c_ast)
if not errors:
byte_code = compile(c_ast, filename, mode=mode # ,
#flags=flags,
#dont_inherit=dont_inherit
)
return CompileResult(byte_code, tuple(errors), warnings, used_names)


Expand Down
65 changes: 65 additions & 0 deletions tests/test_compile.py
Expand Up @@ -3,6 +3,7 @@
from RestrictedPython._compat import IS_PY2

import pytest
import RestrictedPython.compile


@pytest.mark.parametrize(*compile)
Expand All @@ -18,6 +19,70 @@ def test_compile__compile_restricted_exec__1(compile):
assert glob['a'] == 42


@pytest.mark.parametrize(*compile)
def test_compile__compile_restricted_exec__2(compile):
"""It compiles without restrictions if there is no policy."""
if compile is RestrictedPython.compile.compile_restricted_exec:
# The old version does not support a custom policy
result = compile('_a = 42', policy=None)
assert result.errors == ()
assert result.warnings == []
assert result.used_names == {}
glob = {}
exec(result.code, glob)
assert glob['_a'] == 42


@pytest.mark.parametrize(*compile)
def test_compile__compile_restricted_exec__3(compile):
"""It returns a tuple of errors if the code is not allowed.
There is no code in this case.
"""
result = compile('_a = 42\n_b = 43')
errors = (
'Line 1: "_a" is an invalid variable name because it starts with "_"',
'Line 2: "_b" is an invalid variable name because it starts with "_"')
if compile is RestrictedPython.compile.compile_restricted_exec:
assert result.errors == errors
else:
# The old version did only return the first error message.
assert result.errors == (errors[0],)
assert result.warnings == []
assert result.used_names == {}
assert result.code is None


@pytest.mark.parametrize(*compile)
def test_compile__compile_restricted_exec__4(compile):
"""It does not return code on a SyntaxError."""
result = compile('asdf|')
assert result.code is None
assert result.warnings == []
assert result.used_names == {}
if compile is RestrictedPython.compile.compile_restricted_exec:
assert result.errors == (
'Line 1: SyntaxError: invalid syntax in on statement: asdf|',)
else:
# The old version had a less nice error message:
assert result.errors == ('invalid syntax (<string>, line 1)',)


@pytest.mark.parametrize(*compile)
def test_compile__compile_restricted_exec__5(compile):
"""It does not return code if the code contains a NULL byte."""
result = compile('a = 5\x00')
assert result.code is None
assert result.warnings == []
assert result.used_names == {}
if IS_PY2:
assert result.errors == (
'compile() expected string without null bytes',)
else:
assert result.errors == (
'source code string cannot contain null bytes',)


EXEC_STATEMENT = """\
def no_exec():
exec 'q = 1'
Expand Down

0 comments on commit 725b3a8

Please sign in to comment.