From 7a7e9733c2288e255f6c3bcc2a56f7088e08b834 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 1 May 2015 18:25:17 -0600 Subject: vector: Traversal, retrieval, insert and locking enhancements Renamed AST_VECTOR_INSERT to AST_VECTOR_REPLACE because it really does replace not insert. The few users of AST_VECTOR_INSERT were refactored. Because these are macros, there should be no ABI compatibility issues. Added AST_VECTOR_INSERT_AT that actually inserts an element into the vector at a specific index pushing existing elements to the right. Added AST_VECTOR_GET_CMP that can retrieve from the vector based on a user-provided compare function. Added AST_VECTOR_CALLBACK function that will execute a function for each element in the vector. Similar to ao2_callback and ao2_callback_data functions although the vector callback can take a variable number of arguments. This should allow easy migration to a vector where a container might be too heavy. Added read/write locked vector and lock manipulation macros. Added unit tests. ASTERISK-25045 #close Change-Id: I2e07ecc709d2f5f91bcab8904e5e9340609b00e0 --- tests/test_message.c | 16 +- tests/test_vector.c | 428 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 436 insertions(+), 8 deletions(-) create mode 100644 tests/test_vector.c (limited to 'tests') diff --git a/tests/test_message.c b/tests/test_message.c index 13e24a842..5db0ed044 100644 --- a/tests/test_message.c +++ b/tests/test_message.c @@ -160,7 +160,7 @@ static int verify_user_event_fields(int user_event, const char *header, const ch bad_headers_head = AST_VECTOR_GET(&bad_headers, user_event); } ast_variable_list_append(&bad_headers_head, bad_header); - AST_VECTOR_INSERT(&bad_headers, user_event, bad_headers_head); + AST_VECTOR_REPLACE(&bad_headers, user_event, bad_headers_head); } regfree(®exbuf); return -1; @@ -492,28 +492,28 @@ AST_TEST_DEFINE(test_message_queue_dialplan_nominal) ast_variable_list_append(&expected_response, expected); expected = ast_variable_new("Value","^foo$", __FILE__); ast_variable_list_append(&expected_response, expected); - AST_VECTOR_INSERT(&expected_user_event_fields, 0, expected_response); + AST_VECTOR_REPLACE(&expected_user_event_fields, 0, expected_response); expected_response = NULL; expected = ast_variable_new("Verify", "^From$", __FILE__); ast_variable_list_append(&expected_response, expected); expected = ast_variable_new("Value","^bar$", __FILE__); ast_variable_list_append(&expected_response, expected); - AST_VECTOR_INSERT(&expected_user_event_fields, 1, expected_response); + AST_VECTOR_REPLACE(&expected_user_event_fields, 1, expected_response); expected_response = NULL; expected = ast_variable_new("Verify", "^Body$", __FILE__); ast_variable_list_append(&expected_response, expected); expected = ast_variable_new("Value", "^a body$", __FILE__); ast_variable_list_append(&expected_response, expected); - AST_VECTOR_INSERT(&expected_user_event_fields, 2, expected_response); + AST_VECTOR_REPLACE(&expected_user_event_fields, 2, expected_response); expected_response = NULL; expected = ast_variable_new("Verify", "^Custom$", __FILE__); ast_variable_list_append(&expected_response, expected); expected = ast_variable_new("Value", "^field$", __FILE__); ast_variable_list_append(&expected_response, expected); - AST_VECTOR_INSERT(&expected_user_event_fields, 3, expected_response); + AST_VECTOR_REPLACE(&expected_user_event_fields, 3, expected_response); ast_msg_set_to(msg, "foo"); ast_msg_set_from(msg, "bar"); @@ -609,21 +609,21 @@ AST_TEST_DEFINE(test_message_queue_both_nominal) ast_variable_list_append(&expected_response, expected); expected = ast_variable_new("Value","^foo$", __FILE__); ast_variable_list_append(&expected_response, expected); - AST_VECTOR_INSERT(&expected_user_event_fields, 0, expected_response); + AST_VECTOR_REPLACE(&expected_user_event_fields, 0, expected_response); expected_response = NULL; expected = ast_variable_new("Verify", "^From$", __FILE__); ast_variable_list_append(&expected_response, expected); expected = ast_variable_new("Value","^bar$", __FILE__); ast_variable_list_append(&expected_response, expected); - AST_VECTOR_INSERT(&expected_user_event_fields, 1, expected_response); + AST_VECTOR_REPLACE(&expected_user_event_fields, 1, expected_response); expected_response = NULL; expected = ast_variable_new("Verify", "^Body$", __FILE__); ast_variable_list_append(&expected_response, expected); expected = ast_variable_new("Value", "^a body$", __FILE__); ast_variable_list_append(&expected_response, expected); - AST_VECTOR_INSERT(&expected_user_event_fields, 2, expected_response); + AST_VECTOR_REPLACE(&expected_user_event_fields, 2, expected_response); ast_msg_set_to(msg, "foo"); ast_msg_set_from(msg, "bar"); diff --git a/tests/test_vector.c b/tests/test_vector.c new file mode 100644 index 000000000..eae188143 --- /dev/null +++ b/tests/test_vector.c @@ -0,0 +1,428 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2015, Fairview 5 Engineering, LLC + * + * George Joseph + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief Vector tests + * + * \author George Joseph + * + * This module will run some vector tests. + * + * \ingroup tests + */ + +/*** MODULEINFO + TEST_FRAMEWORK + core + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include "asterisk/test.h" +#include "asterisk/utils.h" +#include "asterisk/strings.h" +#include "asterisk/module.h" +#include "asterisk/vector.h" + +#define test_validate_cleanup(condition) ({ \ + if (!(condition)) { \ + ast_test_status_update((test), "%s: %s\n", "Condition failed", #condition); \ + rc = AST_TEST_FAIL; \ + goto cleanup; \ + } \ +}) + +static int cleanup_count; + +static void cleanup(char *element) +{ + cleanup_count++; +} + +AST_TEST_DEFINE(basic_ops) +{ + AST_VECTOR(test_struct, char *) sv1; + int rc = AST_TEST_PASS; + + char *AAA = "AAA"; + char *BBB = "BBB"; + char *CCC = "CCC"; + char *ZZZ = "ZZZ"; + + switch (cmd) { + case TEST_INIT: + info->name = "basic"; + info->category = "/main/vector/"; + info->summary = "Test vector basic ops"; + info->description = "Test vector basic ops"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + ast_test_validate(test, AST_VECTOR_INIT(&sv1, 3) == 0); + test_validate_cleanup(sv1.max == 3); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 0); + + test_validate_cleanup(AST_VECTOR_APPEND(&sv1, AAA) == 0); + test_validate_cleanup(AST_VECTOR_APPEND(&sv1, BBB) == 0); + test_validate_cleanup(AST_VECTOR_APPEND(&sv1, CCC) == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3); + test_validate_cleanup(sv1.max == 3); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == BBB); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == CCC); + + test_validate_cleanup(AST_VECTOR_INSERT_AT(&sv1, 1, ZZZ) == 0); + test_validate_cleanup(sv1.max >= 4); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 4); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == ZZZ); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == BBB); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 3) == CCC); + + test_validate_cleanup(*(char **)AST_VECTOR_GET_CMP(&sv1, "AAA", 0 == strcmp) == AAA); + test_validate_cleanup(*(char **)AST_VECTOR_GET_CMP(&sv1, "ZZZ", 0 == strcmp) == ZZZ); + + AST_VECTOR_FREE(&sv1); + ast_test_validate(test, sv1.elems == NULL); + ast_test_validate(test, sv1.current == 0); + ast_test_validate(test, sv1.max == 0); + + ast_test_validate(test, AST_VECTOR_INIT(&sv1, 0) == 0); + test_validate_cleanup(sv1.max == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 0); + + test_validate_cleanup(AST_VECTOR_APPEND(&sv1, AAA) == 0); + test_validate_cleanup(AST_VECTOR_APPEND(&sv1, BBB) == 0); + test_validate_cleanup(AST_VECTOR_APPEND(&sv1, CCC) == 0); + test_validate_cleanup(sv1.max >= 3); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3); + + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == BBB); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == CCC); + + /* Overwrite index 1 */ + test_validate_cleanup(AST_VECTOR_REPLACE(&sv1, 1, ZZZ) == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == ZZZ); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == CCC); + + /* Remove index 0 and bring the last entry into it's empty slot */ + test_validate_cleanup(AST_VECTOR_REMOVE_UNORDERED(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 2); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == CCC); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == ZZZ); + + /* Replace 0 and 2 leaving 1 alone */ + test_validate_cleanup(AST_VECTOR_REPLACE(&sv1, 0, AAA) == 0); + test_validate_cleanup(AST_VECTOR_REPLACE(&sv1, 2, CCC) == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == ZZZ); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == CCC); + + /* Remove 1 and compact preserving order */ + test_validate_cleanup(AST_VECTOR_REMOVE_ORDERED(&sv1, 1) == ZZZ); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 2); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == CCC); + + /* Equivalent of APPEND */ + test_validate_cleanup(AST_VECTOR_REPLACE(&sv1, 2, ZZZ) == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3); + + /* This should fail because comparison is by pointer */ + test_validate_cleanup(AST_VECTOR_REMOVE_ELEM_ORDERED(&sv1, "ZZZ", cleanup) != 0); + + /* This should work because we passing in the specific object to be removed */ + cleanup_count = 0; + test_validate_cleanup(AST_VECTOR_REMOVE_ELEM_ORDERED(&sv1, ZZZ, cleanup) == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 2); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == CCC); + test_validate_cleanup(cleanup_count == 1); + + /* If we want a comparison by value, we need to pass in a comparison + * function. The comparison looks weird but that's what it takes. + */ + cleanup_count = 0; + test_validate_cleanup(AST_VECTOR_REMOVE_CMP_ORDERED(&sv1, "AAA", 0 == strcmp, cleanup) == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 1); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == CCC); + test_validate_cleanup(cleanup_count == 1); + + /* This element is gone so we shouldn't be able to find it or delete it again. */ + test_validate_cleanup(AST_VECTOR_GET_CMP(&sv1, "AAA", 0 == strcmp) == NULL); + test_validate_cleanup(AST_VECTOR_REMOVE_CMP_ORDERED(&sv1, "AAA", 0 == strcmp, cleanup) != 0); + + /* CCC should still be there though */ + test_validate_cleanup(*(char **)AST_VECTOR_GET_CMP(&sv1, "CCC", 0 == strcmp) == CCC); + +cleanup: + AST_VECTOR_FREE(&sv1); + return rc; +} + +static void cleanup_int(int element) +{ + cleanup_count++; +} + +AST_TEST_DEFINE(basic_ops_integer) +{ + AST_VECTOR(test_struct, int) sv1; + int rc = AST_TEST_PASS; + + int AAA = 1; + int BBB = 2; + int CCC = 3; + int ZZZ = 26; + + switch (cmd) { + case TEST_INIT: + info->name = "basic integer"; + info->category = "/main/vector/"; + info->summary = "Test integer vector basic ops"; + info->description = "Test integer vector basic ops"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + ast_test_validate(test, AST_VECTOR_INIT(&sv1, 3) == 0); + test_validate_cleanup(sv1.max == 3); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 0); + + test_validate_cleanup(AST_VECTOR_APPEND(&sv1, AAA) == 0); + test_validate_cleanup(AST_VECTOR_APPEND(&sv1, BBB) == 0); + test_validate_cleanup(AST_VECTOR_APPEND(&sv1, CCC) == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3); + test_validate_cleanup(sv1.max == 3); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == BBB); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == CCC); + + test_validate_cleanup(AST_VECTOR_INSERT_AT(&sv1, 1, ZZZ) == 0); + test_validate_cleanup(sv1.max >= 4); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 4); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == ZZZ); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == BBB); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 3) == CCC); + + test_validate_cleanup(*(int *)AST_VECTOR_GET_CMP(&sv1, AAA, AST_VECTOR_ELEM_DEFAULT_CMP) == AAA); + test_validate_cleanup(*(int *)AST_VECTOR_GET_CMP(&sv1, ZZZ, AST_VECTOR_ELEM_DEFAULT_CMP) == ZZZ); + + AST_VECTOR_FREE(&sv1); + ast_test_validate(test, sv1.elems == NULL); + ast_test_validate(test, sv1.current == 0); + ast_test_validate(test, sv1.max == 0); + + ast_test_validate(test, AST_VECTOR_INIT(&sv1, 0) == 0); + test_validate_cleanup(sv1.max == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 0); + + test_validate_cleanup(AST_VECTOR_APPEND(&sv1, AAA) == 0); + test_validate_cleanup(AST_VECTOR_APPEND(&sv1, BBB) == 0); + test_validate_cleanup(AST_VECTOR_APPEND(&sv1, CCC) == 0); + test_validate_cleanup(sv1.max >= 3); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3); + + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == BBB); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == CCC); + + /* Overwrite index 1 */ + test_validate_cleanup(AST_VECTOR_REPLACE(&sv1, 1, ZZZ) == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == ZZZ); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == CCC); + + /* Remove index 0 and bring the last entry into it's empty slot */ + test_validate_cleanup(AST_VECTOR_REMOVE_UNORDERED(&sv1, 0) == 1); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 2); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == CCC); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == ZZZ); + + /* Replace 0 and 2 leaving 1 alone */ + test_validate_cleanup(AST_VECTOR_REPLACE(&sv1, 0, AAA) == 0); + test_validate_cleanup(AST_VECTOR_REPLACE(&sv1, 2, CCC) == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == ZZZ); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == CCC); + + /* Remove 1 and compact preserving order */ + test_validate_cleanup(AST_VECTOR_REMOVE_ORDERED(&sv1, 1) == ZZZ); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 2); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == CCC); + + /* Equivalent of APPEND */ + test_validate_cleanup(AST_VECTOR_REPLACE(&sv1, 2, ZZZ) == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3); + + /* This should work because we passing in the specific object to be removed */ + cleanup_count = 0; + test_validate_cleanup(AST_VECTOR_REMOVE_ELEM_ORDERED(&sv1, ZZZ, cleanup_int) == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 2); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == CCC); + test_validate_cleanup(cleanup_count == 1); + + /* If we want a comparison by value, we need to pass in a comparison + * function. + */ + cleanup_count = 0; + test_validate_cleanup(AST_VECTOR_REMOVE_CMP_ORDERED(&sv1, AAA, AST_VECTOR_ELEM_DEFAULT_CMP, cleanup_int) == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 1); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == CCC); + test_validate_cleanup(cleanup_count == 1); + + /* This element is gone so we shouldn't be able to find it or delete it again. */ + test_validate_cleanup(AST_VECTOR_GET_CMP(&sv1, AAA, AST_VECTOR_ELEM_DEFAULT_CMP) == NULL); + test_validate_cleanup(AST_VECTOR_REMOVE_CMP_ORDERED(&sv1, AAA, AST_VECTOR_ELEM_DEFAULT_CMP, cleanup_int) != 0); + + /* CCC should still be there though */ + test_validate_cleanup(*(int *)AST_VECTOR_GET_CMP(&sv1, CCC, AST_VECTOR_ELEM_DEFAULT_CMP) == CCC); + +cleanup: + AST_VECTOR_FREE(&sv1); + return rc; +} + + +static int cb(void *obj, void *arg, void *data) +{ + return strcmp(arg, "ARG") == 0 ? 0 : CMP_STOP; +} + +static int cb_first(void *obj, void *arg, void *data) +{ + return data == arg ? CMP_STOP : 0; +} + +AST_TEST_DEFINE(callbacks) +{ + AST_VECTOR(, char *) sv1; + int rc = AST_TEST_PASS; + + switch (cmd) { + case TEST_INIT: + info->name = "callbacks"; + info->category = "/main/vector/"; + info->summary = "Test vector callback ops"; + info->description = "Test vector callback ops"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + AST_VECTOR_INIT(&sv1, 32); + + AST_VECTOR_APPEND(&sv1, "AAA"); + AST_VECTOR_APPEND(&sv1, "BBB"); + AST_VECTOR_APPEND(&sv1, "CCC"); + + test_validate_cleanup(AST_VECTOR_CALLBACK(&sv1, cb, "ARG", test) == 3); + + test_validate_cleanup(AST_VECTOR_CALLBACK(&sv1, cb_first, test, test) == 1); + +cleanup: + AST_VECTOR_FREE(&sv1); + + return rc; +} + +AST_TEST_DEFINE(locks) +{ + AST_VECTOR_RW(, char *) sv1; + int rc = AST_TEST_PASS; + struct timespec ts; + + switch (cmd) { + case TEST_INIT: + info->name = "locks"; + info->category = "/main/vector/"; + info->summary = "Test vector locking ops"; + info->description = "Test vector locking ops"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + /* We're not actually checking that locking works, + * just that the macro expansions work + */ + + AST_VECTOR_RW_INIT(&sv1, 0); + + test_validate_cleanup(AST_VECTOR_RW_RDLOCK(&sv1) == 0); + test_validate_cleanup(AST_VECTOR_RW_UNLOCK(&sv1) == 0); + test_validate_cleanup(AST_VECTOR_RW_WRLOCK(&sv1) == 0); + test_validate_cleanup(AST_VECTOR_RW_UNLOCK(&sv1) == 0); + + test_validate_cleanup(AST_VECTOR_RW_RDLOCK_TRY(&sv1) == 0); + test_validate_cleanup(AST_VECTOR_RW_WRLOCK_TRY(&sv1) != 0); + test_validate_cleanup(AST_VECTOR_RW_UNLOCK(&sv1) == 0); + test_validate_cleanup(AST_VECTOR_RW_WRLOCK_TRY(&sv1) == 0); + test_validate_cleanup(AST_VECTOR_RW_UNLOCK(&sv1) == 0); + + ts.tv_nsec = 0; + ts.tv_sec = 2; + + test_validate_cleanup(AST_VECTOR_RW_RDLOCK_TIMED(&sv1, &ts) == 0); + test_validate_cleanup(AST_VECTOR_RW_WRLOCK_TIMED(&sv1, &ts) != 0); + test_validate_cleanup(AST_VECTOR_RW_UNLOCK(&sv1) == 0); + test_validate_cleanup(AST_VECTOR_RW_WRLOCK_TIMED(&sv1, &ts) == 0); + test_validate_cleanup(AST_VECTOR_RW_UNLOCK(&sv1) == 0); + +cleanup: + AST_VECTOR_RW_FREE(&sv1); + + return rc; +} + +static int unload_module(void) +{ + AST_TEST_UNREGISTER(locks); + AST_TEST_UNREGISTER(callbacks); + AST_TEST_UNREGISTER(basic_ops_integer); + AST_TEST_UNREGISTER(basic_ops); + + return 0; +} + +static int load_module(void) +{ + AST_TEST_REGISTER(locks); + AST_TEST_REGISTER(callbacks); + AST_TEST_REGISTER(basic_ops_integer); + AST_TEST_REGISTER(basic_ops); + + return AST_MODULE_LOAD_SUCCESS; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Vector test module"); -- cgit v1.2.3