void learn_mock_call_for(const char *function, const char *mock_file, int mock_line, CgreenVector *parameter_names, CgreenVector *actual_values) { CgreenVector *constraints = create_equal_value_constraints_for(parameter_names, actual_values); RecordedExpectation *expectation = create_recorded_expectation(function, mock_file, mock_line, constraints); ensure_learned_mock_calls_list_exists(); cgreen_vector_add(learned_mock_calls, (void*)expectation); }
static RecordedExpectation *create_recorded_expectation(const char *function, const char *test_file, int test_line, va_list constraints) { RecordedExpectation *expectation = NULL; Constraint *constraint = NULL; ensure_expectation_queue_exists(); expectation = (RecordedExpectation *)malloc(sizeof(RecordedExpectation)); expectation->function = function; expectation->test_file = test_file; expectation->test_line = test_line; expectation->constraints = create_cgreen_vector(&destroy_constraint); while ((constraint = va_arg(constraints, Constraint *)) != (Constraint *)0) { cgreen_vector_add(expectation->constraints, constraint); } cgreen_vector_add(expectation_queue, expectation); return expectation; }
static CgreenVector *constraints_vector_from_va_list(va_list constraints) { CgreenVector *vector = create_constraints_vector(); Constraint *constraint; while ((constraint = va_arg(constraints, Constraint *)) != (Constraint *)0) { cgreen_vector_add(vector, constraint); } return vector; }
void expect_never_(const char *function, const char *test_file, int test_line) { UnwantedCall *unwanted = NULL; ensure_unwanted_calls_list_exists(); unwanted = (UnwantedCall *)malloc(sizeof(UnwantedCall)); unwanted->test_file = test_file; unwanted->test_line = test_line; unwanted->function = function; cgreen_vector_add(unwanted_calls, unwanted); }
static CgreenVector *create_vector_of_actuals(va_list actuals, int count) { int i; CgreenVector *actual_values = create_cgreen_vector(NULL); for (i = 0; i < count; i++) { uintptr_t actual = va_arg(actuals, uintptr_t); cgreen_vector_add(actual_values, (void*)actual); } return actual_values; }
static RecordedResult *create_recorded_result(const char *function, intptr_t result) { RecordedResult *record = NULL; ensure_result_queue_exists(); record = (RecordedResult *)malloc(sizeof(RecordedResult)); record->function = function; record->result = result; cgreen_vector_add(result_queue, record); return record; }
static CgreenVector *create_equal_value_constraints_for(CgreenVector *parameter_names, CgreenVector *actual_values) { int i; CgreenVector *constraints = create_constraints_vector(); for (i = 0; i < cgreen_vector_size(parameter_names); i++) { const char* parameter_name = (const char*)cgreen_vector_get(parameter_names, i); uintptr_t actual = (uintptr_t)cgreen_vector_get(actual_values, i); Constraint *constraint = create_equal_to_value_constraint((intptr_t)actual, parameter_name); cgreen_vector_add(constraints, constraint); } return constraints; }
void expect_(TestReporter* test_reporter, const char *function, const char *test_file, int test_line, ...) { va_list constraints; RecordedExpectation *expectation; CgreenVector *constraints_vector; if (have_always_expectation_for(function)) { test_reporter->assert_true( test_reporter, test_file, test_line, false, "Mocked function [%s] already has an expectation that it will always be called a certain way; " "any expectations declared after an always expectation are invalid", function); va_start(constraints, test_line); destroy_constraints(constraints); va_end(constraints); return; } if (have_never_call_expectation_for(function)) { test_reporter->assert_true( test_reporter, test_file, test_line, false, "Mocked function [%s] already has an expectation that it will never be called; " "any expectations declared after a never call expectation are invalid", function); va_start(constraints, test_line); destroy_constraints(constraints); va_end(constraints); return; } va_start(constraints, test_line); constraints_vector = constraints_vector_from_va_list(constraints); expectation = create_recorded_expectation(function, test_file, test_line, constraints_vector); va_end(constraints); expectation->time_to_live = 1; cgreen_vector_add(global_expectation_queue, expectation); }
void enable_mock_(const char *function) { if (enabled_mocks == NULL) { enabled_mocks = create_cgreen_vector(NULL); } cgreen_vector_add(enabled_mocks, (void *)function); }
intptr_t mock_(TestReporter* test_reporter, const char *function, const char *mock_file, int mock_line, const char *parameters, ...) { va_list actuals; CgreenVector *actual_values; CgreenVector *parameter_names; int failures_before_read_only_constraints_executed; int failures_after_read_only_constraints_executed; int i; intptr_t stored_result; RecordedExpectation *expectation = find_expectation(function); va_start(actuals, parameters); actual_values = create_vector_of_actuals(actuals, number_of_parameters_in(parameters)); va_end(actuals); parameter_names = create_vector_of_names(parameters); if (expectation == NULL) { handle_missing_expectation_for(function, mock_file, mock_line, parameter_names, actual_values, test_reporter); destroy_cgreen_vector(actual_values); destroy_cgreen_vector(parameter_names); return 0; } if (is_never_call(expectation)) { report_violated_never_call(test_reporter, expectation); destroy_cgreen_vector(actual_values); destroy_cgreen_vector(parameter_names); return 0; } ensure_successfully_mocked_calls_list_exists(); cgreen_vector_add(successfully_mocked_calls, (void*)function); stored_result = stored_result_or_default_for(expectation->constraints); for (i = 0; i < cgreen_vector_size(expectation->constraints); i++) { Constraint *constraint = (Constraint *)cgreen_vector_get(expectation->constraints, i); if (!is_parameter(constraint)) continue; if (!constraint_is_for_parameter_in(constraint, parameters)) { // if expectation parameter name isn't in parameter_names, // fail test and skip applying constraints unlikely to match report_mock_parameter_name_not_found(test_reporter, expectation, constraint->parameter_name); destroy_expectation_if_time_to_die(expectation); destroy_cgreen_vector(actual_values); destroy_cgreen_vector(parameter_names); return stored_result; } } // if read-only constraints aren't matching, content-setting ones might corrupt memory // apply read-only ones first, and if they don't fail, then do the deeper constraints failures_before_read_only_constraints_executed = test_reporter->failures; for (i = 0; i < cgreen_vector_size(parameter_names); i++) { const char* parameter_name = (const char*)cgreen_vector_get(parameter_names, i); uintptr_t actual = (uintptr_t)cgreen_vector_get(actual_values, i); apply_any_read_only_parameter_constraints(expectation, parameter_name, actual, test_reporter); } failures_after_read_only_constraints_executed = test_reporter->failures; // FIXME: this comparison doesn't work because only parent processes' pass/fail counts are updated, // and even then only once they read from the pipe if (failures_before_read_only_constraints_executed == failures_after_read_only_constraints_executed) { for (i = 0; i < cgreen_vector_size(parameter_names); i++) { const char* parameter_name = (const char*)cgreen_vector_get(parameter_names, i); uintptr_t actual = (uintptr_t)cgreen_vector_get(actual_values, i); apply_any_content_setting_parameter_constraints(expectation, parameter_name, actual, test_reporter); } } destroy_cgreen_vector(parameter_names); destroy_cgreen_vector(actual_values); destroy_expectation_if_time_to_die(expectation); return stored_result; }