def test_chain_can_take_3_parsers_as_args(runner): p = chain( literal('a'), literal('b'), literal('c') ) assert runner(p, 'abc').value == 'c'
def test_choice_throws_ParsingFailed_when_both_choices_fail(runner): p = choice( literal('a'), literal('b'), ) with pytest.raises(ParsingFailed): runner(p, 'c')
def test_seperated_by_1000_elements(runner): assert runner( seperated_by( literal('a'), literal(',') ), 'a' + ',a' * 999 ).value == ['a'] * 1000
def test_seperated_by_one_element(runner): assert runner( seperated_by( literal('a'), literal(',') ), 'a' ).value == ['a']
def test_enclosed_by(runner): assert runner( enclosed_by( literal('a'), literal('"') ), '"a"' ).value == 'a'
def test_seperated_by_five_elemts(runner): assert runner( seperated_by( literal('a'), literal(',') ), 'a,a,a,a,a' ).value == ['a', 'a', 'a', 'a', 'a']
def test_seperated_by_empty(runner): assert runner( seperated_by( literal('a'), literal(',') ), '' ).value == []
def test_choices(runner): assert runner( choices( literal('a'), literal('b'), literal('c') ), 'b' ).value == 'b'
def test_failure_of_choice_of_2_literals_should_contain_both_literals(): p = choice( literal('first_literal'), literal('second_literal'), ) with pytest.raises(ParsingFailed) as err: run_parser(p, 'xxxxxxxxxxxxxxxxxxx') assert 'first_literal' in str(err.value) assert 'second_literal' in str(err.value)
def test_we_can_chain_many_with_something_else(runner): p = many( literal('a') ) p = bind( p, lambda _: literal('b'), ) assert runner(p, 'aaaab').value == 'b'
def test_that_error_message_respects_ordering_of_failing_choices(): p = choice( literal('first'), literal('second'), ) with pytest.raises(ParsingFailed) as err: run_parser(p, 'xxxxxxxxxxxxxx') error_message = str(err.value) assert 'second' in error_message.split('first')[1] assert 'first' in error_message.split('second')[0]
def test_bind_can_chain_3_literal_parsers(runner, a, b, c): p = literal(a) p = bind( p, lambda x: literal(b), ) p = bind( p, lambda x: literal(c), ) assert runner(p, a + b + c).value == c
def test_choice_should_not_retry_if_the_parser_after_choice_fails(runner): p = choice( literal('a'), # this should match the incomming input literal('aa'), ) p = chain( p, literal('b') ) with pytest.raises(ParsingFailed): runner(p, 'aab')
def test_choice_can_be_chained_1000_times(runner): c = choice( literal('a'), literal('b'), ) p = unit('') for i in range(0, 1000): p = bind( p, lambda x: c, ) assert runner(p, 'a' * 999 + 'b').value == 'b'
def test_literal_choice_can_parse_both_possibilities(runner, a, b): # we must order the two strings because of the possibility that a # can be a prefix of b or the other way around p = choice( try_parser(literal(a)), literal(b), ) if len(a) > len(b) else choice( try_parser(literal(b)), literal(a), ) assert runner(p, a).value == a assert runner(p, b).value == b
def test_failure_of_choice_of_3_literals_should_contain_all_3_literal(): p = choice( literal('first'), choice( literal('second'), literal('third') ) ) with pytest.raises(ParsingFailed) as err: run_parser(p, 'xxxxxxxxxxxxxxxx') error_message = str(err.value) assert 'first' in error_message assert 'second' in error_message assert 'third' in error_message
def test_if_a_choice_failes_in_the_middle_of_chain_it_retries_other_option( runner ): p = choice( try_parser(chain( literal('a'), literal('a') )), chain( literal('a'), literal('b'), ) ) assert runner(p, 'ab').value == 'b'
def test_that_error_message_order_is_preserved_with_3_choices(): p = choice( literal('first'), choice( literal('second'), literal('third'), ) ) with pytest.raises(ParsingFailed) as err: run_parser(p, 'xxxxxxxxxxxxxx') error_message = str(err.value) assert 'second' in error_message.split('first')[1] assert 'third' in error_message.split('first')[1] assert 'first' in error_message.split('second')[0] assert 'third' in error_message.split('second')[1]
def test_stack_performance_with_many_choices( benchmark, input_string, runner, ): parser = many( choices( literal('a'), literal('b'), literal('c'), literal('d'), )) benchmark( runner, parser, input_string, )
def test_that_fmap_does_not_change_error_messages(runner): parser = literal('a') with pytest.raises(ParsingFailed) as error_message_without_fmap: runner(parser, 'b') with pytest.raises(ParsingFailed) as error_message_with_fmap: runner(fmap(lambda char: char + 1, parser), 'b') assert ( str(error_message_without_fmap.value) == str(error_message_with_fmap.value) )
def test_simple_failing_parser_after_n_newlines_has_linenumber_n1_in_error( n, runner, ): p = chain( literal('\n' * n), fail('error') ) with pytest.raises(ParsingFailed) as err: runner(p, ('\n' * n) + 'x') assert display_location(line=n + 1, column=0) in str(err.value)
from parsemon import ParsingFailed, literal, run_parser, until from parsemon.stream import CharacterStream, StringStream @pytest.fixture(params=( CharacterStream, StringStream, )) def runner(request): def fixture(*args, **kwargs): return run_parser(*args, stream_implementation=request.param, **kwargs) return fixture main_parser = literal('a') delimiter = literal('b') def test_until_failes_if_parser_fails_and_delimiter_parser_fails(runner): with pytest.raises(ParsingFailed): runner(until(main_parser, delimiter), 'not_matching_string') def test_until_returns_empty_tuple_when_only_delimiter_is_found(runner): assert runner(until(main_parser, delimiter), 'b').value == tuple() def test_until_consumes_the_delimiter(runner): parsing_result = runner(until(main_parser, delimiter), 'b') assert not parsing_result.remaining_input
def wrapper(document): parser = unit(True) for character in document: parser = chain(parser, literal(character)) return parser
def parser(): for letter in document: yield literal(letter) return True
def test_failure_of_literal_contains_expected_string(): p = literal('abcde') with pytest.raises(ParsingFailed) as err: run_parser(p, 'xxxxx') assert 'abcde' in str(err.value)
def test_literal_parser_throws_ParsingFailed_when_seeing_non_matching_string( runner ): with pytest.raises(ParsingFailed): runner(literal('a'), 'b')
def test_bind_can_chain_two_literal_parsers(runner, a, b): parser = bind( literal(a), lambda x: literal(b), ) assert runner(parser, a + b).value == b
def test_that_or_operator_works_as_expected(runner): assert runner(whitespace | literal('a'), ' ').value == ' ' assert runner(whitespace | literal('a'), 'a').value == 'a'
def test_fmap_can_map_1000_times(runner): parser = literal('a') for i in range(0, 1000): parser = fmap(lambda x: 'b', parser) assert runner(parser, 'a').value == 'b'
def test_fmap_can_replace_parsing_result(runner): parser = fmap( lambda x: 'b', literal('a') ) assert runner(parser, 'a').value == 'b'