Browse Source

Merge pull request #172 from patacrep/invalid_source

Parsing hangs when file is inconsistent
pull/178/head
Louis 9 years ago
parent
commit
a5c9b48674
  1. 6
      patacrep/files.py
  2. 9
      patacrep/songs/chordpro/syntax.py
  3. 3
      test/test_chordpro/errors/invalid_content.source
  4. 43
      test/test_chordpro/test_parser.py

6
patacrep/files.py

@ -62,17 +62,17 @@ def path2posix(string):
) )
@contextmanager @contextmanager
def chdir(path): def chdir(*path):
"""Locally change dir """Locally change dir
Can be used as: Can be used as:
with chdir("some/directory"): with chdir("some", "directory"):
do_stuff() do_stuff()
""" """
olddir = os.getcwd() olddir = os.getcwd()
if path: if path:
os.chdir(path) os.chdir(os.path.join(*path))
yield yield
os.chdir(olddir) os.chdir(olddir)
else: else:

9
patacrep/songs/chordpro/syntax.py

@ -307,12 +307,17 @@ class ChordproParser(Parser):
token = self.parser.token() token = self.parser.token()
if not token or token.type == "ENDOFLINE": if not token or token.type == "ENDOFLINE":
break break
self.parser.errok() if token:
self.parser.errok()
return token return token
def parse_song(content, filename=None): def parse_song(content, filename=None):
"""Parse song and return its metadata.""" """Parse song and return its metadata."""
return ChordproParser(filename).parse( parser = ChordproParser(filename)
parsed_content = parser.parse(
content, content,
lexer=ChordProLexer(filename=filename).lexer, lexer=ChordProLexer(filename=filename).lexer,
) )
if parsed_content is None:
raise SyntaxError('Fatal error during song parsing: {}'.format(filename))
return parsed_content

3
test/test_chordpro/errors/invalid_content.source

@ -0,0 +1,3 @@
{soc}
Chorus
{eoc

43
test/test_chordpro/test_parser.py

@ -44,13 +44,11 @@ class FileTest(unittest.TestCase, metaclass=dynamic.DynamicTest):
@staticmethod @staticmethod
@contextlib.contextmanager @contextlib.contextmanager
def chdir(): def chdir(*path):
"""Context to temporarry change current directory to this file directory """Context to temporarry change current directory, relative to this file directory
""" """
olddir = os.getcwd() with files.chdir(resource_filename(__name__, ""), *path):
os.chdir(resource_filename(__name__, "")) yield
yield
os.chdir(olddir)
def assertRender(self, base, destformat): # pylint: disable=invalid-name def assertRender(self, base, destformat): # pylint: disable=invalid-name
"""Assert that `{base}.source` is correctly rendered in the `destformat`. """Assert that `{base}.source` is correctly rendered in the `destformat`.
@ -92,22 +90,41 @@ class FileTest(unittest.TestCase, metaclass=dynamic.DynamicTest):
cls._create_test(base, dest), cls._create_test(base, dest),
) )
with cls.chdir('errors'):
for source in sorted(glob.glob('*.source')):
base = source[:-len(".source")]
yield (
"test_{}_failure".format(base),
cls._create_failure(base),
)
@classmethod @classmethod
def _create_test(cls, base, dest): def _create_test(cls, base, dest):
"""Return a function testing that `base` compilation in `dest` format. """Return a function testing that `base` compilation in `dest` format.
""" """
test_parse_render = lambda self: self.assertRender(base, dest)
def test_parse_render(self):
"""Test that `base` is correctly parsed and rendered."""
if base is None or dest is None:
return
self.assertRender(base, dest)
test_parse_render.__doc__ = ( test_parse_render.__doc__ = (
"Test that '{base}' is correctly parsed and rendererd into '{format}' format." "Test that '{base}' is correctly parsed and rendererd into '{format}' format."
).format(base=os.path.basename(base), format=dest) ).format(base=os.path.basename(base), format=dest)
return test_parse_render return test_parse_render
@classmethod
def _create_failure(cls, base):
"""Return a function testing that `base` parsing fails.
"""
def test_parse_failure(self):
"""Test that `base` parsing fails."""
sourcename = "{}.source".format(base)
with self.chdir('errors'):
parser = self.song_plugins[LANGUAGES['sgc']]['sgc']
self.assertRaises(SyntaxError, parser, sourcename, self.config)
test_parse_failure.__doc__ = (
"Test that '{base}' parsing fails."
).format(base=os.path.basename(base))
return test_parse_failure
@classmethod @classmethod
def _overwrite_clrf(cls): def _overwrite_clrf(cls):
"""Overwrite `*.crlf.source` files to force the CRLF line endings. """Overwrite `*.crlf.source` files to force the CRLF line endings.

Loading…
Cancel
Save