def cumulative(): scorer = CumulativeScoreKeeper() with let(__scorer, scorer): yield value(__scorer).suite_finished(scorer.score)
def when(condition): ''' Adds an extra condition ''' old_condition = value(__condition) with let(__condition, lambda: old_condition() and condition()): yield
def weight(maximum): scorer = CumulativeScoreKeeper() with let(__scorer, scorer): yield score = scorer.score value(__scorer).suite_finished(score.rescale(maximum))
def __add_callback(event, callback): ''' Helper function. Adds a callback to and event, the event being __passed, __failed or __skipped. ''' old_callback = value(event) chained = __chain(old_callback, callback) with let(event, chained): yield
def function_reftest(identifier): if not identifier in dir(value(reference_module)): raise Exception(f'Bug in tests: reference module does not contain member called "{identifier}"') with when(defined(identifier, value(tested_module))), let(tested_function_name, identifier): reference_function = getattr(value(reference_module), identifier) tested_function = getattr(value(tested_module), identifier) with check_function_against_reference_implementation(tested=tested_function, reference=reference_function) as check: yield check
def all_or_nothing(): scorer = CumulativeScoreKeeper() with let(__scorer, scorer): yield score = scorer.score if not score.is_perfect: score = score.zero value(__scorer).suite_finished(score)
def check(*args, **kwargs): positional_parameter_names = __get_positional_parameter_names(reference) function_name = value(tested_function_name) positional_argument_strings = [ f'{name} = {str(arg)}' for name, arg in zip(positional_parameter_names, args) ] keyword_argument_strings = [ f'{k}={v}' for k, vi in kwargs.items() ] arguments_string = ', '.join(positional_argument_strings + keyword_argument_strings) call_string = f'{function_name}({arguments_string})' def failure_message_generator(*, failure, **kwargs): failure_message = value(__failure_message) if failure_message: return format.vbox(f'Verifying {call_string}', \ format.indent(2, failure_message), \ format.indent(2, str(failure))) else: raise Exception('Bug in reference tests: no failure message set') def test_function(): def check_return_values(expected, actual): __failure_message.value = f'Comparing return values' assert expected == actual, f'Expected {expected}, got {actual}' def check_positional_argument(index, name, expected, actual): __failure_message.value = f'Comparing {name} (positional argument #{index + 1})' assert expected == actual, f'Expected {expected}, got {actual}' def check_positional_arguments(names, expecteds, actuals): for (index, name, expected, actual) in zip(range(len(names)), names, expecteds, actuals): check_positional_argument(index, name, expected, actual) actual_args = deepcopy(args) actual_kwargs = deepcopy(kwargs) expected_args = deepcopy(args) expected_kwargs = deepcopy(kwargs) __failure_message.value = f'Exception occurred during function call' actual_result = tested(*actual_args, **actual_kwargs) expected_result = reference(*expected_args, **expected_kwargs) check_return_values(expected=expected_result, actual=actual_result) check_positional_arguments(positional_parameter_names, expected_args, actual_args) with reporting.default_failure_message_generator(failure_message_generator), \ let(__failure_message, None): test(test_function)
def setup(): failure_index = 1 def failure_callback(*, failure): nonlocal failure_index if failure_index != 1: print('-' * 40) generator = value(__failure_message_generator) message = generator(failure=failure) message_lines = format.hbox(f'[{failure_index}] ', message).format() print("\n".join(message_lines)) failure_index += 1 with let(__failure_message_generator, __dummy_failure_message_generator), on_fail(failure_callback): yield
def __run_test(test_function): def signal_passed(): value(__passed)() def signal_failed(exception): value(__failed)(failure=exception) def signal_skipped(): value(__skipped)() if __should_test_run(): with let(__test_function, test_function): try: test_function() signal_passed() except NotImplementedError: signal_skipped() except BaseException as e: signal_failed(e) else: signal_skipped()
def score(func): ''' Sets up scoring mechanism. All tests to be scored are to be placed inside a function, given as parameter to this function. Returns the final score of the tests in func. ''' def passed(): value(__scorer).test_passed() def failed(*args, **kwargs): value(__scorer).test_failed() def skipped(): value(__scorer).test_skipped() scorer = CumulativeScoreKeeper() with let(__scorer, scorer), on_pass(passed), on_fail(failed), on_skip(skipped): func() return scorer.score
def failure_message_generator(message_generator): with let(__failure_message_generator, message_generator): yield