<commit_before>from datetime import datetime
import re

from bdd_tester.exceptions import StepException


@given('an IATI activity')
def step_impl(context):
    # this is a dummy step. It's here because
    # behave / BDD requires at least one 'given' step.
    assert(True)

@then('`{xpath_expression}` should be present')
def step_impl(context, xpath_expression):
    vals = context.xml.xpath(xpath_expression)
    if len(vals) == 0:
        msg = '`{}` not found'.format(xpath_expression)
        raise StepException(context, msg)

@then('every `{xpath_expression}` should match the regex `{regex_str}`')
def step_impl(context, xpath_expression, regex_str):
    vals = context.xml.xpath(xpath_expression)
    regex = re.compile(regex_str)
    success = True
    bad_vals = []
    for val in vals:
        if not bool(regex.search(val)):
            success = False
            bad_vals.append(val)
    msg = '{} {} not match the regex `{}`'.format(
        ', '.join(bad_vals),
        'does' if len(bad_vals) == 1 else 'do',
        regex_str,
    )
    raise StepException(context, msg)

@given('`{xpath_expression}` is present')
def step_impl(context, xpath_expression):
    vals = context.xml.xpath(xpath_expression)
    if len(vals) > 0:
        assert(True)
    else:
        msg = '`{}` is not present'.format(
            xpath_expression,
        )
        raise StepException(context, msg)

@then('`{xpath_expression}` should not be present')
def step_impl(context, xpath_expression):
    vals = context.xml.xpath(xpath_expression)
    if len(vals) == 0:
        assert(True)
    else:
        msg = '`{}` is present, but should not be'.format(
            xpath_expression,
        )
        raise StepException(context, msg)

@given('`{xpath_expression}` is a valid date')
def step_impl(context, xpath_expression):
    vals = context.xml.xpath(xpath_expression)
    for val in vals:
        try:
            _ = datetime.strptime(val, '%Y-%m-%d')
            assert(True)
            return
        except ValueError:
            msg = '"{}" is not a valid date'.format(val)
            raise StepException(context, msg)

    msg = '`{}` not found'.format(xpath_expression)
    raise StepException(context, msg)

@then('`{xpath_expression1}` should be chronologically before `{xpath_expression2}`')
def step_impl(context, xpath_expression1, xpath_expression2):
    less_str = context.xml.xpath(xpath_expression1)[0]
    more_str = context.xml.xpath(xpath_expression2)[0]

    less = datetime.strptime(less_str, '%Y-%m-%d').date()
    more = datetime.strptime(more_str, '%Y-%m-%d').date()

    if less > more:
        msg = '{} should be before {}, but isn\'t'.format(
            less_str,
            more_str,
        )
        raise StepException(context, msg)

@then('`{xpath_expression}` should be today, or in the past')
def step_impl(context, xpath_expression):
    val = context.xml.xpath(xpath_expression)[0]
    date = datetime.strptime(val, '%Y-%m-%d').date()
    if date > context.today:
        msg = '{} should be before {}, but isn\'t'.format(
            date,
            context.today,
        )
        raise StepException(context, msg)

def either_or(context, tmpl, xpath_expressions):
    exceptions = []
    for xpath_expression in xpath_expressions:
        try:
            context.execute_steps(tmpl.format(
                expression=xpath_expression)
            )
            assert(True)
            return
        except AssertionError as e:
            msg = str(e).split('StepException: ')[1]
            exceptions.append(msg)

    msg = ' and '.join([msg for msg in exceptions])
    raise StepException(context, msg)

@then('either `{xpath_expression1}` or `{xpath_expression2}` {statement}')
def step_impl(context, xpath_expression1, xpath_expression2, statement):
    xpath_expressions = [xpath_expression1, xpath_expression2]
    tmpl = 'then `{{expression}}` {statement}'.format(
        statement=statement,
    )
    either_or(context, tmpl, xpath_expressions)<commit_msg>[#5] Refactor steps, fixing not working rule for regex and multi transactions<commit_after>from datetime import datetime
import re

from behave import given, then
from bdd_tester.exceptions import StepException


@given('an IATI activity')
def step_given_iati_activity(context):
    # this is a dummy step. It's here because
    # behave / BDD requires at least one 'given' step.
    assert True


@then('every `{xpath_expression}` should match the regex `{regex_str}`')
def step_match_regex(context, xpath_expression, regex_str):
    vals = context.xml.xpath(xpath_expression)
    regex = re.compile(regex_str)
    success = True
    bad_vals = []
    for val in vals:
        if not regex.match(val):
            success = False
            bad_vals.append(val)
    if not success:
        verb = 'does' if len(bad_vals) == 1 else 'do'
        errors = [{
            'message': '{} {} not match the regex `{}`'.format(', '.join(bad_vals), verb, regex_str),
            'path': xpath_expression
        }]
        raise StepException(context, errors)


@given('`{xpath_expression}` is present')
def step_given_present(context, xpath_expression):
    vals = context.xml.xpath(xpath_expression)
    if not vals:
        errors = [{
            'message': '`{}` is not present'.format(xpath_expression),
            'path': xpath_expression
        }]
        raise StepException(context, errors)


@then('`{xpath_expression}` should not be present')
def step_should_not_be_present(context, xpath_expression):
    vals = context.xml.xpath(xpath_expression)
    if vals:
        errors = [{
            'message': '`{}` is present when it shouldn\'t be'.format(xpath_expression),
            'path': xpath_expression
        }]
        raise StepException(context, errors)


@given('`{xpath_expression}` is a valid date')
def step_valid_date(context, xpath_expression):
    vals = context.xml.xpath(xpath_expression)
    errors = []
    if not vals:
        errors.append({
            'message': '`{}` not found'.format(xpath_expression),
            'path': xpath_expression
        })
        raise StepException(context, errors)

    for val in vals:
        try:
            datetime.strptime(val, '%Y-%m-%d')
        except ValueError:
            errors = [{
                'messsage': '`{}` is not a valid date'.format(val),
                'path': xpath_expression
            }]
            raise StepException(context, errors)


@then('`{xpath_expression1}` should be chronologically before `{xpath_expression2}`')
def step_should_be_before(context, xpath_expression1, xpath_expression2):
    less_str = context.xml.xpath(xpath_expression1)[0]
    more_str = context.xml.xpath(xpath_expression2)[0]
    less = datetime.strptime(less_str, '%Y-%m-%d').date()
    more = datetime.strptime(more_str, '%Y-%m-%d').date()

    if less > more:
        errors = [{
            'message': '{} should be before {}'.format(less_str, more_str),
            'path': ''
        }]
        raise StepException(context, errors)


@then('`{xpath_expression}` should be today, or in the past')
def step_should_be_past(context, xpath_expression):
    values = context.xml.xpath(xpath_expression)
    fail = False

    if values:
        errors = []
        tree = context.xml.getroottree()
        for val in values:
            date = datetime.strptime(val, '%Y-%m-%d').date()
            if date > context.today:
                errors.append({
                    'message': '{} should be on or before today ({})'.format(date, context.today),
                    'path': tree.getpath(val.getparent())
                })
                fail = True

    if fail:
        raise StepException(context, errors)


@then('either `{xpath_expression1}` or `{xpath_expression2}` should be present')
def step_should_be_present(context, xpath_expression1, xpath_expression2):
    vals = context.xml.xpath(xpath_expression1) or context.xml.xpath(xpath_expression2)
    if not vals:
        errors = [{
            'message': '`{}` and `{}` not found'.format(xpath_expression1, xpath_expression2),
            'path': ''
        }]
        raise StepException(context, errors)
{'fraction_non_alphanumeric': 0.12489307100085544, 'fraction_numerical': 0.004643773677135525, 'mean_word_length': 2.802973977695167, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 18}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5439840', 'n_tokens_mistral': 2546, 'n_tokens_neox': 2502, 'n_words': 597}