Asterisk - The Open Source Telephony Project  18.5.0
Data Structures | Macros | Enumerations | Functions | Variables
test_astobj2.c File Reference

astobj2 test module More...

#include "asterisk.h"
#include "asterisk/utils.h"
#include "asterisk/module.h"
#include "asterisk/test.h"
#include "asterisk/astobj2.h"
Include dependency graph for test_astobj2.c:

Go to the source code of this file.

Data Structures

struct  test_obj
 

Macros

#define ITERATIONS   100000
 
#define OBJS   73
 

Enumerations

enum  test_container_type { TEST_CONTAINER_LIST, TEST_CONTAINER_HASH, TEST_CONTAINER_RBTREE }
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static int all_but_one_cb (void *obj, void *arg, int flag)
 
static AO2_GLOBAL_OBJ_STATIC (astobj2_holder)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
 AST_TEST_DEFINE (astobj2_test_1)
 
 AST_TEST_DEFINE (astobj2_test_2)
 
 AST_TEST_DEFINE (astobj2_test_3)
 
 AST_TEST_DEFINE (astobj2_test_4)
 
 AST_TEST_DEFINE (astobj2_test_perf)
 
static int astobj2_test_1_helper (int tst_num, enum test_container_type type, int use_sort, unsigned int lim, struct ast_test *test)
 
static int increment_cb (void *obj, void *arg, int flag)
 
static int insert_test_duplicates (struct ao2_container *container, int *destroy_counter, int number, const char *prefix, struct ast_test *test)
 
static int insert_test_vector (struct ao2_container *container, int *destroy_counter, const int *vector, int count, const char *prefix, struct ast_test *test)
 
static int load_module (void)
 
static int multiple_cb (void *obj, void *arg, int flag)
 
static int test_ao2_callback_traversal (int res, struct ao2_container *container, enum search_flags flags, ao2_callback_fn *cmp_fn, void *arg, const int *vector, int count, const char *prefix, struct ast_test *test)
 
static int test_ao2_find_w_no_flags (int res, struct ao2_container *look_in, int limit, struct ast_test *test)
 
static int test_ao2_find_w_OBJ_KEY (int res, struct ao2_container *look_in, int limit, struct ast_test *test)
 
static int test_ao2_find_w_OBJ_PARTIAL_KEY (int res, struct ao2_container *look_in, int limit, struct ast_test *test)
 
static int test_ao2_find_w_OBJ_POINTER (int res, struct ao2_container *look_in, int limit, struct ast_test *test)
 
static int test_ao2_iteration (int res, struct ao2_container *container, enum ao2_iterator_flags flags, const int *vector, int count, const char *prefix, struct ast_test *test)
 
static int test_cmp_cb (void *obj, void *arg, int flags)
 
static const char * test_container2str (enum test_container_type type)
 
static int test_container_clone (int res, struct ao2_container *orig, struct ast_test *test)
 
static int test_expected_duplicates (int res, struct ao2_container *container, enum search_flags flags, int number, const int *vector, int count, const char *prefix, struct ast_test *test)
 
static int test_hash_cb (const void *obj, const int flags)
 
static struct ao2_containertest_make_nonsorted (enum test_container_type type, int options)
 
static struct ao2_containertest_make_sorted (enum test_container_type type, int options)
 
static void test_obj_destructor (void *v_obj)
 
static enum ast_test_result_state test_performance (struct ast_test *test, enum test_container_type type, unsigned int copt)
 
static int test_sort_cb (const void *obj_left, const void *obj_right, int flags)
 
static int test_traversal_nonsorted (int res, int tst_num, enum test_container_type type, struct ast_test *test)
 
static int test_traversal_sorted (int res, int tst_num, enum test_container_type type, struct ast_test *test)
 
static enum ast_test_result_state testloop (struct ast_test *test, enum test_container_type type, int copt, int iterations)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "ASTOBJ2 Unit Tests" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
int partial_key_match_range
 

Detailed Description

astobj2 test module

Author
David Vossel dvoss.nosp@m.el@d.nosp@m.igium.nosp@m..com

Definition in file test_astobj2.c.

Macro Definition Documentation

◆ ITERATIONS

#define ITERATIONS   100000

Referenced by AST_TEST_DEFINE().

◆ OBJS

#define OBJS   73

Referenced by test_performance().

Enumeration Type Documentation

◆ test_container_type

Enumerator
TEST_CONTAINER_LIST 
TEST_CONTAINER_HASH 
TEST_CONTAINER_RBTREE 

Definition at line 41 of file test_astobj2.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 2074 of file test_astobj2.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 2074 of file test_astobj2.c.

◆ all_but_one_cb()

static int all_but_one_cb ( void *  obj,
void *  arg,
int  flag 
)
static

Definition at line 104 of file test_astobj2.c.

References CMP_MATCH, and test_obj::i.

Referenced by astobj2_test_1_helper().

105 {
106  struct test_obj *cmp_obj = (struct test_obj *) obj;
107 
108  return (cmp_obj->i) ? CMP_MATCH : 0;
109 }

◆ AO2_GLOBAL_OBJ_STATIC()

static AO2_GLOBAL_OBJ_STATIC ( astobj2_holder  )
static

Referenced by AST_TEST_DEFINE().

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 2074 of file test_astobj2.c.

◆ AST_TEST_DEFINE() [1/5]

AST_TEST_DEFINE ( astobj2_test_1  )

Definition at line 648 of file test_astobj2.c.

References AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, astobj2_test_1_helper(), sip_to_pjsip::info(), TEST_CONTAINER_HASH, TEST_CONTAINER_LIST, TEST_CONTAINER_RBTREE, TEST_EXECUTE, and TEST_INIT.

649 {
650  int res = AST_TEST_PASS;
651 
652  switch (cmd) {
653  case TEST_INIT:
654  info->name = "astobj2_test1";
655  info->category = "/main/astobj2/";
656  info->summary = "Test ao2 objects, containers, callbacks, and iterators";
657  info->description =
658  "Builds ao2_containers with various item numbers, bucket sizes, cmp and hash "
659  "functions. Runs a series of tests to manipulate the container using callbacks "
660  "and iterators. Verifies expected behavior.";
661  return AST_TEST_NOT_RUN;
662  case TEST_EXECUTE:
663  break;
664  }
665 
666  /* Test number, container_type, use_sort, number of objects. */
667  if ((res = astobj2_test_1_helper(1, TEST_CONTAINER_LIST, 0, 50, test)) == AST_TEST_FAIL) {
668  return res;
669  }
670 
671  if ((res = astobj2_test_1_helper(2, TEST_CONTAINER_LIST, 1, 50, test)) == AST_TEST_FAIL) {
672  return res;
673  }
674 
675  if ((res = astobj2_test_1_helper(3, TEST_CONTAINER_HASH, 0, 1000, test)) == AST_TEST_FAIL) {
676  return res;
677  }
678 
679  if ((res = astobj2_test_1_helper(4, TEST_CONTAINER_HASH, 1, 1000, test)) == AST_TEST_FAIL) {
680  return res;
681  }
682 
683  if ((res = astobj2_test_1_helper(4, TEST_CONTAINER_RBTREE, 1, 1000, test)) == AST_TEST_FAIL) {
684  return res;
685  }
686 
687  return res;
688 }
static int astobj2_test_1_helper(int tst_num, enum test_container_type type, int use_sort, unsigned int lim, struct ast_test *test)
Definition: test_astobj2.c:421
def info(msg)

◆ AST_TEST_DEFINE() [2/5]

AST_TEST_DEFINE ( astobj2_test_2  )

Definition at line 690 of file test_astobj2.c.

References ao2_alloc, AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_list, ao2_container_check(), ao2_container_count(), ao2_find, AO2_GLOBAL_OBJ_STATIC(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_link, ao2_ref, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, c, cleanup(), test_obj::destructor_count, test_obj::i, sip_to_pjsip::info(), NULL, OBJ_POINTER, test_cmp_cb(), TEST_EXECUTE, TEST_INIT, and test_obj_destructor().

691 {
692  int res = AST_TEST_PASS;
693  struct ao2_container *c;
694  struct ao2_iterator i;
695  struct test_obj *obj;
696  int num;
697  static const int NUM_OBJS = 5;
698  int destructor_count = NUM_OBJS;
699  struct test_obj tmp_obj = { 0, };
700 
701  switch (cmd) {
702  case TEST_INIT:
703  info->name = "astobj2_test2";
704  info->category = "/main/astobj2/";
705  info->summary = "Test a certain scenario using ao2 iterators";
706  info->description =
707  "This test is aimed at testing for a specific regression that occurred. "
708  "Add some objects into a container. Mix finds and iteration and make "
709  "sure that the iterator still sees all objects.";
710  return AST_TEST_NOT_RUN;
711  case TEST_EXECUTE:
712  break;
713  }
714 
716  if (!c) {
717  ast_test_status_update(test, "ao2_container_alloc_list failed.\n");
718  res = AST_TEST_FAIL;
719  goto cleanup;
720  }
721 
722  for (num = 1; num <= NUM_OBJS; num++) {
723  if (!(obj = ao2_alloc(sizeof(struct test_obj), test_obj_destructor))) {
724  ast_test_status_update(test, "ao2_alloc failed.\n");
725  res = AST_TEST_FAIL;
726  goto cleanup;
727  }
729  obj->i = num;
730  ao2_link(c, obj);
731  ao2_ref(obj, -1);
732  if (ao2_container_count(c) != num) {
733  ast_test_status_update(test, "container did not link correctly\n");
734  res = AST_TEST_FAIL;
735  }
736  }
737  if (ao2_container_check(c, 0)) {
738  ast_test_status_update(test, "container integrity check failed\n");
739  res = AST_TEST_FAIL;
740  goto cleanup;
741  }
742 
743  /*
744  * Iteration take 1. Just make sure we see all NUM_OBJS objects.
745  */
746  num = 0;
747  i = ao2_iterator_init(c, 0);
748  while ((obj = ao2_iterator_next(&i))) {
749  num++;
750  ao2_ref(obj, -1);
751  }
753 
754  if (num != NUM_OBJS) {
755  ast_test_status_update(test, "iterate take 1, expected '%d', only saw '%d' objects\n",
756  NUM_OBJS, num);
757  res = AST_TEST_FAIL;
758  }
759 
760  /*
761  * Iteration take 2. Do a find for the last object, then iterate and make
762  * sure we find all NUM_OBJS objects.
763  */
764  tmp_obj.i = NUM_OBJS;
765  obj = ao2_find(c, &tmp_obj, OBJ_POINTER);
766  if (!obj) {
767  ast_test_status_update(test, "ao2_find() failed.\n");
768  res = AST_TEST_FAIL;
769  } else {
770  ao2_ref(obj, -1);
771  }
772 
773  num = 0;
774  i = ao2_iterator_init(c, 0);
775  while ((obj = ao2_iterator_next(&i))) {
776  num++;
777  ao2_ref(obj, -1);
778  }
780 
781  if (num != NUM_OBJS) {
782  ast_test_status_update(test, "iterate take 2, expected '%d', only saw '%d' objects\n",
783  NUM_OBJS, num);
784  res = AST_TEST_FAIL;
785  }
786 
787  /*
788  * Iteration take 3. Do a find for an object while in the middle
789  * of iterating;
790  */
791  num = 0;
792  i = ao2_iterator_init(c, 0);
793  while ((obj = ao2_iterator_next(&i))) {
794  if (num == 1) {
795  struct test_obj *obj2;
796  tmp_obj.i = NUM_OBJS - 1;
797  obj2 = ao2_find(c, &tmp_obj, OBJ_POINTER);
798  if (!obj2) {
799  ast_test_status_update(test, "ao2_find() failed.\n");
800  res = AST_TEST_FAIL;
801  } else {
802  ao2_ref(obj2, -1);
803  }
804  }
805  num++;
806  ao2_ref(obj, -1);
807  }
809 
810  if (num != NUM_OBJS) {
811  ast_test_status_update(test, "iterate take 3, expected '%d', only saw '%d' objects\n",
812  NUM_OBJS, num);
813  res = AST_TEST_FAIL;
814  }
815 
816 
817 cleanup:
818  if (c) {
819  ao2_ref(c, -1);
820  }
821 
822  return res;
823 }
int * destructor_count
Definition: test_astobj2.c:77
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define OBJ_POINTER
Definition: astobj2.h:1154
static int test_cmp_cb(void *obj, void *arg, int flags)
Definition: test_astobj2.c:119
static void test_obj_destructor(void *v_obj)
Definition: test_astobj2.c:87
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Definition: astobj2.h:1335
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
static struct test_val c
#define NULL
Definition: resample.c:96
int ao2_container_check(struct ao2_container *self, enum search_flags flags)
Perform an integrity check on the specified container.
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define ao2_ref(o, delta)
Definition: astobj2.h:464
def info(msg)
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
Generic container type.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_link(container, obj)
Definition: astobj2.h:1549

◆ AST_TEST_DEFINE() [3/5]

AST_TEST_DEFINE ( astobj2_test_3  )

Definition at line 827 of file test_astobj2.c.

References ao2_alloc, ao2_ref, ao2_t_global_obj_ref, ao2_t_global_obj_release, ao2_t_global_obj_replace, ao2_t_global_obj_replace_unref, ao2_t_ref, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, cleanup(), test_obj::destructor_count, test_obj::i, sip_to_pjsip::info(), NULL, TEST_EXECUTE, TEST_INIT, and test_obj_destructor().

828 {
829  int res = AST_TEST_PASS;
830  int destructor_count = 0;
831  int num_objects = 0;
832  struct test_obj *obj = NULL;
833  struct test_obj *obj2 = NULL;
834  struct test_obj *obj3 = NULL;
835 
836  switch (cmd) {
837  case TEST_INIT:
838  info->name = "astobj2_test3";
839  info->category = "/main/astobj2/";
840  info->summary = "Test global ao2 holder";
841  info->description =
842  "This test is to see if the global ao2 holder works as intended.";
843  return AST_TEST_NOT_RUN;
844  case TEST_EXECUTE:
845  break;
846  }
847 
848  /* Put an object in the holder */
849  obj = ao2_alloc(sizeof(struct test_obj), test_obj_destructor);
850  if (!obj) {
851  ast_test_status_update(test, "ao2_alloc failed.\n");
852  res = AST_TEST_FAIL;
853  goto cleanup;
854  }
856  obj->i = ++num_objects;
857  obj2 = ao2_t_global_obj_replace(astobj2_holder, obj, "Save object in the holder");
858  if (obj2) {
859  ast_test_status_update(test, "Returned object not expected.\n");
860  res = AST_TEST_FAIL;
861  goto cleanup;
862  }
863  /* Save object for next check. */
864  obj3 = obj;
865 
866  /* Replace an object in the holder */
867  obj = ao2_alloc(sizeof(struct test_obj), test_obj_destructor);
868  if (!obj) {
869  ast_test_status_update(test, "ao2_alloc failed.\n");
870  res = AST_TEST_FAIL;
871  goto cleanup;
872  }
874  obj->i = ++num_objects;
875  obj2 = ao2_t_global_obj_replace(astobj2_holder, obj, "Replace object in the holder");
876  if (!obj2) {
877  ast_test_status_update(test, "Expected an object.\n");
878  res = AST_TEST_FAIL;
879  goto cleanup;
880  }
881  if (obj2 != obj3) {
882  ast_test_status_update(test, "Replaced object not expected object.\n");
883  res = AST_TEST_FAIL;
884  goto cleanup;
885  }
886  ao2_ref(obj3, -1);
887  obj3 = NULL;
888  ao2_ref(obj2, -1);
889  obj2 = NULL;
890  ao2_ref(obj, -1);
891 
892  /* Replace with unref of an object in the holder */
893  obj = ao2_alloc(sizeof(struct test_obj), test_obj_destructor);
894  if (!obj) {
895  ast_test_status_update(test, "ao2_alloc failed.\n");
896  res = AST_TEST_FAIL;
897  goto cleanup;
898  }
900  obj->i = ++num_objects;
901  if (!ao2_t_global_obj_replace_unref(astobj2_holder, obj, "Replace w/ unref object in the holder")) {
902  ast_test_status_update(test, "Expected an object to be replaced.\n");
903  res = AST_TEST_FAIL;
904  goto cleanup;
905  }
906  /* Save object for next check. */
907  obj3 = obj;
908 
909  /* Get reference to held object. */
910  obj = ao2_t_global_obj_ref(astobj2_holder, "Get a held object reference");
911  if (!obj) {
912  ast_test_status_update(test, "Expected an object.\n");
913  res = AST_TEST_FAIL;
914  goto cleanup;
915  }
916  if (obj != obj3) {
917  ast_test_status_update(test, "Referenced object not expected object.\n");
918  res = AST_TEST_FAIL;
919  goto cleanup;
920  }
921  ao2_ref(obj3, -1);
922  obj3 = NULL;
923  ao2_ref(obj, -1);
924  obj = NULL;
925 
926  /* Release the object in the global holder. */
927  ao2_t_global_obj_release(astobj2_holder, "Check release all objects");
928  destructor_count += num_objects;
929  if (0 < destructor_count) {
931  "all destructors were not called, destructor count is %d\n",
932  destructor_count);
933  res = AST_TEST_FAIL;
934  } else if (destructor_count < 0) {
936  "Destructor was called too many times, destructor count is %d\n",
937  destructor_count);
938  res = AST_TEST_FAIL;
939  }
940 
941 cleanup:
942  if (obj) {
943  ao2_t_ref(obj, -1, "Test cleanup external object 1");
944  }
945  if (obj2) {
946  ao2_t_ref(obj2, -1, "Test cleanup external object 2");
947  }
948  if (obj3) {
949  ao2_t_ref(obj3, -1, "Test cleanup external object 3");
950  }
951  ao2_t_global_obj_release(astobj2_holder, "Test cleanup holder");
952 
953  return res;
954 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:463
int * destructor_count
Definition: test_astobj2.c:77
#define ao2_t_global_obj_replace_unref(holder, obj, tag)
Replace an ao2 object in the global holder, throwing away any old object.
Definition: astobj2.h:906
static void test_obj_destructor(void *v_obj)
Definition: test_astobj2.c:87
#define ao2_t_global_obj_release(holder, tag)
Release the ao2 object held in the global holder.
Definition: astobj2.h:863
#define NULL
Definition: resample.c:96
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_t_global_obj_replace(holder, obj, tag)
Replace an ao2 object in the global holder.
Definition: astobj2.h:883
#define ao2_t_global_obj_ref(holder, tag)
Get a reference to the object stored in the global holder.
Definition: astobj2.h:923
def info(msg)
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124

◆ AST_TEST_DEFINE() [4/5]

AST_TEST_DEFINE ( astobj2_test_4  )

Definition at line 1898 of file test_astobj2.c.

References AST_TEST_NOT_RUN, AST_TEST_PASS, sip_to_pjsip::info(), TEST_CONTAINER_HASH, TEST_CONTAINER_LIST, TEST_CONTAINER_RBTREE, TEST_EXECUTE, TEST_INIT, test_traversal_nonsorted(), and test_traversal_sorted().

1899 {
1900  int res = AST_TEST_PASS;
1901 
1902  switch (cmd) {
1903  case TEST_INIT:
1904  info->name = "astobj2_test4";
1905  info->category = "/main/astobj2/";
1906  info->summary = "Test container traversal/iteration";
1907  info->description =
1908  "This test is to see if the container traversal/iteration works "
1909  "as intended for each supported container type.";
1910  return AST_TEST_NOT_RUN;
1911  case TEST_EXECUTE:
1912  break;
1913  }
1914 
1917 
1921 
1922  return res;
1923 }
static int test_traversal_sorted(int res, int tst_num, enum test_container_type type, struct ast_test *test)
static int test_traversal_nonsorted(int res, int tst_num, enum test_container_type type, struct ast_test *test)
def info(msg)

◆ AST_TEST_DEFINE() [5/5]

AST_TEST_DEFINE ( astobj2_test_perf  )

The number of iteration of testloop to be performed.

Note
In order to keep the elapsed time sane, if AO2_DEBUG is defined in menuselect, only 25000 iterations are performed. Otherwise 100000.

Definition at line 2013 of file test_astobj2.c.

References AST_TEST_NOT_RUN, AST_TEST_PASS, sip_to_pjsip::info(), ITERATIONS, TEST_CONTAINER_HASH, TEST_CONTAINER_LIST, TEST_CONTAINER_RBTREE, TEST_EXECUTE, TEST_INIT, and testloop().

2014 {
2015 /*!
2016  * \brief The number of iteration of testloop to be performed.
2017  * \note
2018  * In order to keep the elapsed time sane, if AO2_DEBUG is defined in menuselect,
2019  * only 25000 iterations are performed. Otherwise 100000.
2020  */
2021 #ifdef AO2_DEBUG
2022 #define ITERATIONS 25000
2023 #else
2024 #define ITERATIONS 100000
2025 #endif
2026 
2027  int res = AST_TEST_PASS;
2028 
2029  switch (cmd) {
2030  case TEST_INIT:
2031  info->name = "astobj2_test_perf";
2032  info->category = "/main/astobj2/perf/";
2033  info->summary = "Test container performance";
2034  info->description =
2035  "Runs container traversal tests.";
2036  return AST_TEST_NOT_RUN;
2037  case TEST_EXECUTE:
2038  break;
2039  }
2040 
2042  if (!res) {
2043  return res;
2044  }
2046  if (!res) {
2047  return res;
2048  }
2050 
2051  return res;
2052 }
#define ITERATIONS
def info(msg)
static enum ast_test_result_state testloop(struct ast_test *test, enum test_container_type type, int copt, int iterations)

◆ astobj2_test_1_helper()

static int astobj2_test_1_helper ( int  tst_num,
enum test_container_type  type,
int  use_sort,
unsigned int  lim,
struct ast_test test 
)
static

Definition at line 421 of file test_astobj2.c.

References all_but_one_cb(), AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_check(), ao2_container_count(), ao2_container_dump(), ao2_container_stats(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_link, ao2_t_alloc, ao2_t_callback, ao2_t_container_alloc_hash, ao2_t_container_alloc_list, ao2_t_container_alloc_rbtree, ao2_t_iterator_next, ao2_t_link, ao2_t_ref, ao2_t_unlink, ast_random(), ast_test_debug(), AST_TEST_FAIL, AST_TEST_PASS, ast_test_status_update, cleanup(), test_obj::destructor_count, test_obj::i, increment_cb(), multiple_cb(), NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, test_ao2_find_w_no_flags(), test_ao2_find_w_OBJ_KEY(), test_ao2_find_w_OBJ_PARTIAL_KEY(), test_ao2_find_w_OBJ_POINTER(), test_cmp_cb(), test_container2str(), test_container_clone(), TEST_CONTAINER_HASH, TEST_CONTAINER_LIST, TEST_CONTAINER_RBTREE, test_hash_cb(), test_obj_destructor(), and test_sort_cb().

Referenced by AST_TEST_DEFINE().

422 {
423  const char *c_type;
424  struct ao2_container *c1;
425  struct ao2_container *c2;
426  struct ao2_iterator it;
427  struct ao2_iterator *mult_it;
428  struct test_obj *obj;
429  int n_buckets = 0;
430  int increment = 0;
431  int destructor_count = 0;
432  int num;
433  int res = AST_TEST_PASS;
434 
435  c_type = test_container2str(type);
436  ast_test_status_update(test, "Test %d, %s containers (%s).\n",
437  tst_num, c_type, use_sort ? "sorted" : "non-sorted");
438 
439  c1 = NULL;
440  switch (type) {
441  case TEST_CONTAINER_LIST:
442  /* Lists just have one bucket. */
443  n_buckets = 1;
445  use_sort ? test_sort_cb : NULL, test_cmp_cb, "test");
446  break;
447  case TEST_CONTAINER_HASH:
448  n_buckets = (ast_random() % ((lim / 4) + 1)) + 1;
450  test_hash_cb, use_sort ? test_sort_cb : NULL, test_cmp_cb, "test");
451  break;
453  /* RBTrees just have one bucket. */
454  n_buckets = 1;
456  test_sort_cb, test_cmp_cb, "test");
457  break;
458  }
460 
461  if (!c1 || !c2) {
462  ast_test_status_update(test, "ao2_container_alloc failed.\n");
463  res = AST_TEST_FAIL;
464  goto cleanup;
465  }
466 
467  /* Create objects and link into container */
468  for (num = 0; num < lim; ++num) {
469  if (!(obj = ao2_t_alloc(sizeof(struct test_obj), test_obj_destructor, "making zombies"))) {
470  ast_test_status_update(test, "ao2_alloc failed.\n");
471  res = AST_TEST_FAIL;
472  goto cleanup;
473  }
476  obj->i = num;
477  ao2_link(c1, obj);
478  ao2_t_ref(obj, -1, "test");
479  if (ao2_container_check(c1, 0)) {
480  ast_test_status_update(test, "container integrity check failed linking obj num:%d\n", num);
481  res = AST_TEST_FAIL;
482  goto cleanup;
483  }
484  if (ao2_container_count(c1) != num + 1) {
485  ast_test_status_update(test, "container did not link correctly\n");
486  res = AST_TEST_FAIL;
487  }
488  }
489 
490  ast_test_status_update(test, "%s container created: buckets: %d, items: %u\n",
491  c_type, n_buckets, lim);
492 
493  /* Testing ao2_container_clone */
494  res = test_container_clone(res, c1, test);
495 
496  /* Testing ao2_find with no flags */
497  res = test_ao2_find_w_no_flags(res, c1, lim, test);
498 
499  /* Testing ao2_find with OBJ_POINTER */
500  res = test_ao2_find_w_OBJ_POINTER(res, c1, lim, test);
501 
502  /* Testing ao2_find with OBJ_KEY */
503  res = test_ao2_find_w_OBJ_KEY(res, c1, lim, test);
504 
505  /* Testing ao2_find with OBJ_PARTIAL_KEY */
506  res = test_ao2_find_w_OBJ_PARTIAL_KEY(res, c1, lim, test);
507 
508  /* Test Callback with no flags. */
509  increment = 0;
510  ao2_t_callback(c1, 0, increment_cb, &increment, "test callback");
511  if (increment != lim) {
512  ast_test_status_update(test, "callback with no flags failed. Increment is %d\n", increment);
513  res = AST_TEST_FAIL;
514  }
515 
516  /* Test Callback with OBJ_NODATA. This should do nothing different than with no flags here. */
517  increment = 0;
518  ao2_t_callback(c1, OBJ_NODATA, increment_cb, &increment, "test callback");
519  if (increment != lim) {
520  ast_test_status_update(test, "callback with OBJ_NODATA failed. Increment is %d\n", increment);
521  res = AST_TEST_FAIL;
522  }
523 
524  /* Test OBJ_MULTIPLE with OBJ_UNLINK, add items back afterwards */
525  num = lim < 25 ? lim : 25;
526  if (!(mult_it = ao2_t_callback(c1, OBJ_MULTIPLE | OBJ_UNLINK, multiple_cb, &num, "test multiple"))) {
527  ast_test_status_update(test, "OBJ_MULTIPLE with OBJ_UNLINK test failed.\n");
528  res = AST_TEST_FAIL;
529  } else {
530  /* make sure num items unlinked is as expected */
531  if ((lim - ao2_container_count(c1)) != num) {
532  ast_test_status_update(test, "OBJ_MULTIPLE | OBJ_UNLINK test failed, did not unlink correct number of objects.\n");
533  res = AST_TEST_FAIL;
534  }
535  if (ao2_container_check(c1, 0)) {
536  ast_test_status_update(test, "container integrity check failed\n");
537  res = AST_TEST_FAIL;
538  goto cleanup;
539  }
540 
541  /* link what was unlinked back into c1 */
542  while ((obj = ao2_t_iterator_next(mult_it, "test"))) {
543  ao2_t_link(c1, obj, "test");
544  ao2_t_ref(obj, -1, "test"); /* remove ref from iterator */
545  }
546  ao2_iterator_destroy(mult_it);
547  if (ao2_container_check(c1, 0)) {
548  ast_test_status_update(test, "container integrity check failed\n");
549  res = AST_TEST_FAIL;
550  goto cleanup;
551  }
552  }
553 
554  /* Test OBJ_MULTIPLE without unlink and iterate the returned container */
555  num = 5;
556  if (!(mult_it = ao2_t_callback(c1, OBJ_MULTIPLE, multiple_cb, &num, "test multiple"))) {
557  ast_test_status_update(test, "OBJ_MULTIPLE without OBJ_UNLINK test failed.\n");
558  res = AST_TEST_FAIL;
559  } else {
560  while ((obj = ao2_t_iterator_next(mult_it, "test"))) {
561  ao2_t_ref(obj, -1, "test"); /* remove ref from iterator */
562  }
563  ao2_iterator_destroy(mult_it);
564  }
565 
566  /* Test OBJ_MULTIPLE without unlink and no iterating */
567  num = 5;
568  if (!(mult_it = ao2_t_callback(c1, OBJ_MULTIPLE, multiple_cb, &num, "test multiple"))) {
569  ast_test_status_update(test, "OBJ_MULTIPLE with no OBJ_UNLINK and no iterating failed.\n");
570  res = AST_TEST_FAIL;
571  } else {
572  ao2_iterator_destroy(mult_it);
573  }
574 
575  /* Is the container count what we expect after all the finds and unlinks? */
576  if (ao2_container_count(c1) != lim) {
577  ast_test_status_update(test, "container count does not match what is expected after ao2_find tests.\n");
578  res = AST_TEST_FAIL;
579  }
580 
581  /* Testing iterator. Unlink a single object and break. do not add item back */
582  it = ao2_iterator_init(c1, 0);
583  num = ast_random() % lim; /* remove a random object */
584  if (!num) {
585  /*
586  * Well we cannot remove object zero because of test with
587  * all_but_one_cb later.
588  */
589  num = 1;
590  }
591  while ((obj = ao2_t_iterator_next(&it, "test"))) {
592  if (obj->i == num) {
593  ao2_t_unlink(c1, obj, "test");
594  ao2_t_ref(obj, -1, "test");
595  break;
596  }
597  ao2_t_ref(obj, -1, "test");
598  }
600 
601  /* Is the container count what we expect after removing a single item? */
602  if (ao2_container_count(c1) != (lim - 1)) {
603  ast_test_status_update(test, "unlink during iterator failed. Number %d was not removed.\n", num);
604  res = AST_TEST_FAIL;
605  }
606  if (ao2_container_check(c1, 0)) {
607  ast_test_status_update(test, "container integrity check failed\n");
608  res = AST_TEST_FAIL;
609  goto cleanup;
610  }
611 
612  /* Test unlink all with OBJ_MULTIPLE, leave a single object for the container to destroy */
614  /* check to make sure all test_obj destructors were called except for 1 */
615  if (destructor_count != 1) {
616  ast_test_status_update(test, "OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NODATA failed. destructor count %d\n", destructor_count);
617  res = AST_TEST_FAIL;
618  }
619  if (ao2_container_check(c1, 0)) {
620  ast_test_status_update(test, "container integrity check failed\n");
621  res = AST_TEST_FAIL;
622  }
623 #if defined(TEST_CONTAINER_DEBUG_DUMP)
624  ao2_container_dump(c1, 0, "test_1 c1", (void *) test, (ao2_prnt_fn *) ast_test_debug, test_prnt_obj);
625  ao2_container_stats(c1, 0, "test_1 c1", (void *) test, (ao2_prnt_fn *) ast_test_debug);
626 #endif /* defined(TEST_CONTAINER_DEBUG_DUMP) */
627 
628 cleanup:
629  /* destroy containers */
630  if (c1) {
631  ao2_t_ref(c1, -1, "bye c1");
632  }
633  if (c2) {
634  ao2_t_ref(c2, -1, "bye c2");
635  }
636 
637  if (destructor_count > 0) {
638  ast_test_status_update(test, "all destructors were not called, destructor count is %d\n", destructor_count);
639  res = AST_TEST_FAIL;
640  } else if (destructor_count < 0) {
641  ast_test_status_update(test, "Destructor was called too many times, destructor count is %d\n", destructor_count);
642  res = AST_TEST_FAIL;
643  }
644 
645  return res;
646 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:463
int * destructor_count
Definition: test_astobj2.c:77
static const char type[]
Definition: chan_ooh323.c:109
void ao2_container_dump(struct ao2_container *self, enum search_flags flags, const char *name, void *where, ao2_prnt_fn *prnt, ao2_prnt_obj_fn *prnt_obj)
Display contents of the specified container.
void ast_test_debug(struct ast_test *test, const char *fmt,...)
Definition: test.c:113
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_t_alloc(data_size, destructor_fn, debug_msg)
Definition: astobj2.h:409
static int test_ao2_find_w_no_flags(int res, struct ao2_container *look_in, int limit, struct ast_test *test)
Definition: test_astobj2.c:278
static int multiple_cb(void *obj, void *arg, int flag)
Definition: test_astobj2.c:111
static int test_cmp_cb(void *obj, void *arg, int flags)
Definition: test_astobj2.c:119
static void test_obj_destructor(void *v_obj)
Definition: test_astobj2.c:87
static int test_ao2_find_w_OBJ_KEY(int res, struct ao2_container *look_in, int limit, struct ast_test *test)
Definition: test_astobj2.c:356
static int increment_cb(void *obj, void *arg, int flag)
Definition: test_astobj2.c:96
#define ao2_t_link(container, obj, tag)
Add an object to a container.
Definition: astobj2.h:1547
#define ao2_t_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn, tag)
Allocate and initialize a list container.
Definition: astobj2.h:1333
#define ao2_t_unlink(container, obj, tag)
Remove an object from a container.
Definition: astobj2.h:1596
static int all_but_one_cb(void *obj, void *arg, int flag)
Definition: test_astobj2.c:104
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define NULL
Definition: resample.c:96
void ao2_container_stats(struct ao2_container *self, enum search_flags flags, const char *name, void *where, ao2_prnt_fn *prnt)
Display statistics of the specified container.
void() ao2_prnt_fn(void *where, const char *fmt,...)
Print output.
Definition: astobj2.h:1442
int ao2_container_check(struct ao2_container *self, enum search_flags flags)
Perform an integrity check on the specified container.
static int test_container_clone(int res, struct ao2_container *orig, struct ast_test *test)
Definition: test_astobj2.c:216
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
static int test_sort_cb(const void *obj_left, const void *obj_right, int flags)
Definition: test_astobj2.c:158
long int ast_random(void)
Definition: main/utils.c:2064
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1931
#define ao2_t_callback(c, flags, cb_fn, arg, tag)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
Definition: astobj2.h:1714
#define ao2_t_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn, tag)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1308
static int test_ao2_find_w_OBJ_PARTIAL_KEY(int res, struct ao2_container *look_in, int limit, struct ast_test *test)
Definition: test_astobj2.c:393
static int test_hash_cb(const void *obj, const int flags)
Definition: test_astobj2.c:139
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
static int test_ao2_find_w_OBJ_POINTER(int res, struct ao2_container *look_in, int limit, struct ast_test *test)
Definition: test_astobj2.c:317
#define ao2_t_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn, tag)
Allocate and initialize a red-black tree container.
Definition: astobj2.h:1356
Generic container type.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
static const char * test_container2str(enum test_container_type type)
Definition: test_astobj2.c:56
#define ao2_link(container, obj)
Definition: astobj2.h:1549

◆ increment_cb()

static int increment_cb ( void *  obj,
void *  arg,
int  flag 
)
static

Definition at line 96 of file test_astobj2.c.

References test_obj::i.

Referenced by astobj2_test_1_helper().

97 {
98  int *i = (int *) arg;
99 
100  *i = *i + 1;
101  return 0;
102 }

◆ insert_test_duplicates()

static int insert_test_duplicates ( struct ao2_container container,
int *  destroy_counter,
int  number,
const char *  prefix,
struct ast_test test 
)
static

Definition at line 1092 of file test_astobj2.c.

References ao2_alloc, ao2_container_check(), ao2_find, ao2_link, ao2_t_ref, ast_test_status_update, test_obj::destructor_count, test_obj::dup_number, test_obj::i, NULL, OBJ_KEY, and test_obj_destructor().

Referenced by test_traversal_sorted().

1093 {
1094  int count;
1095  struct test_obj *obj;
1096  struct test_obj *obj_dup;
1097 
1098  /* Check if object already exists in the container. */
1099  obj = ao2_find(container, &number, OBJ_KEY);
1100  if (obj) {
1101  ast_test_status_update(test, "%s: Object %d already exists.\n", prefix, number);
1102  ao2_t_ref(obj, -1, "test");
1103  return -1;
1104  }
1105 
1106  /* Add three duplicate keyed objects. */
1107  obj_dup = NULL;
1108  for (count = 0; count < 4; ++count) {
1109  obj = ao2_alloc(sizeof(struct test_obj), test_obj_destructor);
1110  if (!obj) {
1111  ast_test_status_update(test, "%s: ao2_alloc failed.\n", prefix);
1112  if (obj_dup) {
1113  ao2_t_ref(obj_dup, -1, "test");
1114  }
1115  return -1;
1116  }
1117  if (destroy_counter) {
1118  /* This object ultimately needs to be destroyed. */
1119  ++*destroy_counter;
1120  }
1121  obj->destructor_count = destroy_counter;
1122  obj->i = number;
1123  obj->dup_number = count;
1124  ao2_link(container, obj);
1125 
1126  if (count == 2) {
1127  /* Duplicate this object. */
1128  obj_dup = obj;
1129  } else {
1130  ao2_t_ref(obj, -1, "test");
1131  }
1132 
1133  if (ao2_container_check(container, 0)) {
1134  ast_test_status_update(test, "%s: Container integrity check failed linking num:%d dup:%d\n",
1135  prefix, number, count);
1136  if (obj_dup) {
1137  ao2_t_ref(obj_dup, -1, "test");
1138  }
1139  return -1;
1140  }
1141  }
1142 
1143  /* Add the duplicate object. */
1144  ao2_link(container, obj_dup);
1145  ao2_t_ref(obj_dup, -1, "test");
1146 
1147  if (ao2_container_check(container, 0)) {
1148  ast_test_status_update(test, "%s: Container integrity check failed linking obj_dup\n",
1149  prefix);
1150  return -1;
1151  }
1152 
1153  return 0;
1154 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:463
int * destructor_count
Definition: test_astobj2.c:77
#define OBJ_KEY
Definition: astobj2.h:1155
static void test_obj_destructor(void *v_obj)
Definition: test_astobj2.c:87
#define NULL
Definition: resample.c:96
Number structure.
Definition: app_followme.c:154
int ao2_container_check(struct ao2_container *self, enum search_flags flags)
Perform an integrity check on the specified container.
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
int dup_number
Definition: test_astobj2.c:81
static char prefix[MAX_PREFIX]
Definition: http.c:141
#define ao2_link(container, obj)
Definition: astobj2.h:1549

◆ insert_test_vector()

static int insert_test_vector ( struct ao2_container container,
int *  destroy_counter,
const int *  vector,
int  count,
const char *  prefix,
struct ast_test test 
)
static

Definition at line 1040 of file test_astobj2.c.

References ao2_alloc, ao2_container_check(), ao2_container_count(), ao2_link, ao2_t_ref, ast_test_status_update, test_obj::destructor_count, test_obj::i, and test_obj_destructor().

Referenced by test_traversal_nonsorted(), and test_traversal_sorted().

1041 {
1042  int idx;
1043  struct test_obj *obj;
1044 
1045  for (idx = 0; idx < count; ++idx) {
1046  obj = ao2_alloc(sizeof(struct test_obj), test_obj_destructor);
1047  if (!obj) {
1048  ast_test_status_update(test, "%s: ao2_alloc failed.\n", prefix);
1049  return -1;
1050  }
1051  if (destroy_counter) {
1052  /* This object ultimately needs to be destroyed. */
1053  ++*destroy_counter;
1054  }
1055  obj->destructor_count = destroy_counter;
1056  obj->i = vector[idx];
1057  ao2_link(container, obj);
1058  ao2_t_ref(obj, -1, "test");
1059  if (ao2_container_check(container, 0)) {
1060  ast_test_status_update(test, "%s: Container integrity check failed linking vector[%d]:%d\n",
1061  prefix, idx, vector[idx]);
1062  return -1;
1063  }
1064 
1065  if (ao2_container_count(container) != idx + 1) {
1067  "%s: Unexpected container count. Expected:%d Got:%d\n",
1068  prefix, idx + 1, ao2_container_count(container));
1069  return -1;
1070  }
1071  }
1072 
1073  return 0;
1074 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:463
int * destructor_count
Definition: test_astobj2.c:77
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
static void test_obj_destructor(void *v_obj)
Definition: test_astobj2.c:87
int ao2_container_check(struct ao2_container *self, enum search_flags flags)
Perform an integrity check on the specified container.
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
static char prefix[MAX_PREFIX]
Definition: http.c:141
#define ao2_link(container, obj)
Definition: astobj2.h:1549

◆ load_module()

static int load_module ( void  )
static

Definition at line 2064 of file test_astobj2.c.

References AST_MODULE_LOAD_SUCCESS, and AST_TEST_REGISTER.

2065 {
2066  AST_TEST_REGISTER(astobj2_test_1);
2067  AST_TEST_REGISTER(astobj2_test_2);
2068  AST_TEST_REGISTER(astobj2_test_3);
2069  AST_TEST_REGISTER(astobj2_test_4);
2070  AST_TEST_REGISTER(astobj2_test_perf);
2071  return AST_MODULE_LOAD_SUCCESS;
2072 }
#define AST_TEST_REGISTER(cb)
Definition: test.h:127

◆ multiple_cb()

static int multiple_cb ( void *  obj,
void *  arg,
int  flag 
)
static

Definition at line 111 of file test_astobj2.c.

References CMP_MATCH, and test_obj::i.

Referenced by astobj2_test_1_helper().

112 {
113  int *i = (int *) arg;
114  struct test_obj *cmp_obj = (struct test_obj *) obj;
115 
116  return (cmp_obj->i < *i) ? CMP_MATCH : 0;
117 }

◆ test_ao2_callback_traversal()

static int test_ao2_callback_traversal ( int  res,
struct ao2_container container,
enum search_flags  flags,
ao2_callback_fn cmp_fn,
void *  arg,
const int *  vector,
int  count,
const char *  prefix,
struct ast_test test 
)
static

Definition at line 1232 of file test_astobj2.c.

References ao2_callback, ao2_iterator_destroy(), ao2_iterator_next, ao2_ref, AST_TEST_FAIL, ast_test_status_update, test_obj::i, and OBJ_MULTIPLE.

Referenced by test_traversal_nonsorted(), and test_traversal_sorted().

1235 {
1236  struct ao2_iterator *mult_iter;
1237  struct test_obj *obj;
1238  int idx;
1239 
1240  mult_iter = ao2_callback(container, flags | OBJ_MULTIPLE, cmp_fn, arg);
1241  if (!mult_iter) {
1242  ast_test_status_update(test, "%s: Did not return iterator.\n", prefix);
1243  return AST_TEST_FAIL;
1244  }
1245 
1246  /* Check matching objects against the given vector. */
1247  for (idx = 0; idx < count; ++idx) {
1248  obj = ao2_iterator_next(mult_iter);
1249  if (!obj) {
1250  ast_test_status_update(test, "%s: Too few objects found.\n", prefix);
1251  res = AST_TEST_FAIL;
1252  break;
1253  }
1254  if (vector[idx] != obj->i) {
1255  ast_test_status_update(test, "%s: Object %d != vector[%d] %d.\n",
1256  prefix, obj->i, idx, vector[idx]);
1257  res = AST_TEST_FAIL;
1258  }
1259  ao2_ref(obj, -1); /* remove ref from iterator */
1260  }
1261  obj = ao2_iterator_next(mult_iter);
1262  if (obj) {
1263  ast_test_status_update(test, "%s: Too many objects found. Object %d\n",
1264  prefix, obj->i);
1265  ao2_ref(obj, -1); /* remove ref from iterator */
1266  res = AST_TEST_FAIL;
1267  }
1268  ao2_iterator_destroy(mult_iter);
1269 
1270  return res;
1271 }
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
static char prefix[MAX_PREFIX]
Definition: http.c:141

◆ test_ao2_find_w_no_flags()

static int test_ao2_find_w_no_flags ( int  res,
struct ao2_container look_in,
int  limit,
struct ast_test test 
)
static

Definition at line 278 of file test_astobj2.c.

References ao2_find, ao2_t_ref, ast_random(), AST_TEST_FAIL, ast_test_status_update, and test_obj::i.

Referenced by astobj2_test_1_helper().

279 {
280  int i;
281  int num;
282  struct test_obj tmp_obj = { 0, };
283  struct test_obj *obj;
284 
285  for (num = 100; num--;) {
286  i = ast_random() % limit; /* find a random object */
287 
288  tmp_obj.i = i;
289  obj = ao2_find(look_in, &tmp_obj, 0);
290  if (!obj) {
291  ast_test_status_update(test, "COULD NOT FIND:%d, ao2_find() with no flags failed.\n", i);
292  res = AST_TEST_FAIL;
293  } else {
294  if (obj->i != i) {
295  ast_test_status_update(test, "object %d does not match %d\n", obj->i, i);
296  res = AST_TEST_FAIL;
297  }
298  ao2_t_ref(obj, -1, "test");
299  }
300  }
301 
302  return res;
303 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:463
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
long int ast_random(void)
Definition: main/utils.c:2064
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756

◆ test_ao2_find_w_OBJ_KEY()

static int test_ao2_find_w_OBJ_KEY ( int  res,
struct ao2_container look_in,
int  limit,
struct ast_test test 
)
static

Definition at line 356 of file test_astobj2.c.

References ao2_find, ao2_t_ref, ast_random(), AST_TEST_FAIL, ast_test_status_update, test_obj::i, and OBJ_KEY.

Referenced by astobj2_test_1_helper().

357 {
358  int i;
359  int num;
360  struct test_obj *obj;
361 
362  for (num = 75; num--;) {
363  i = ast_random() % limit; /* find a random object */
364 
365  obj = ao2_find(look_in, &i, OBJ_KEY);
366  if (!obj) {
367  ast_test_status_update(test, "COULD NOT FIND:%d, ao2_find() with OBJ_KEY flag failed.\n", i);
368  res = AST_TEST_FAIL;
369  } else {
370  if (obj->i != i) {
371  ast_test_status_update(test, "object %d does not match %d\n", obj->i, i);
372  res = AST_TEST_FAIL;
373  }
374  ao2_t_ref(obj, -1, "test");
375  }
376  }
377 
378  return res;
379 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:463
#define OBJ_KEY
Definition: astobj2.h:1155
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
long int ast_random(void)
Definition: main/utils.c:2064
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756

◆ test_ao2_find_w_OBJ_PARTIAL_KEY()

static int test_ao2_find_w_OBJ_PARTIAL_KEY ( int  res,
struct ao2_container look_in,
int  limit,
struct ast_test test 
)
static

Definition at line 393 of file test_astobj2.c.

References ao2_find, ao2_t_ref, ast_random(), AST_TEST_FAIL, ast_test_status_update, test_obj::i, OBJ_PARTIAL_KEY, and partial_key_match_range.

Referenced by astobj2_test_1_helper().

394 {
395  int i;
396  int num;
397  struct test_obj *obj;
398 
399  /* Set partial match to find exactly. */
401 
402  for (num = 100; num--;) {
403  i = ast_random() % limit; /* find a random object */
404 
405  obj = ao2_find(look_in, &i, OBJ_PARTIAL_KEY);
406  if (!obj) {
407  ast_test_status_update(test, "COULD NOT FIND:%d, ao2_find() with OBJ_PARTIAL_KEY flag failed.\n", i);
408  res = AST_TEST_FAIL;
409  } else {
410  if (obj->i != i) {
411  ast_test_status_update(test, "object %d does not match %d\n", obj->i, i);
412  res = AST_TEST_FAIL;
413  }
414  ao2_t_ref(obj, -1, "test");
415  }
416  }
417 
418  return res;
419 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:463
int partial_key_match_range
Definition: test_astobj2.c:85
#define OBJ_PARTIAL_KEY
Definition: astobj2.h:1156
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
long int ast_random(void)
Definition: main/utils.c:2064
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756

◆ test_ao2_find_w_OBJ_POINTER()

static int test_ao2_find_w_OBJ_POINTER ( int  res,
struct ao2_container look_in,
int  limit,
struct ast_test test 
)
static

Definition at line 317 of file test_astobj2.c.

References ao2_find, ao2_t_ref, ast_random(), AST_TEST_FAIL, ast_test_status_update, test_obj::i, and OBJ_POINTER.

Referenced by astobj2_test_1_helper().

318 {
319  int i;
320  int num;
321  struct test_obj tmp_obj = { 0, };
322  struct test_obj *obj;
323 
324  for (num = 75; num--;) {
325  i = ast_random() % limit; /* find a random object */
326 
327  tmp_obj.i = i;
328  obj = ao2_find(look_in, &tmp_obj, OBJ_POINTER);
329  if (!obj) {
330  ast_test_status_update(test, "COULD NOT FIND:%d, ao2_find() with OBJ_POINTER flag failed.\n", i);
331  res = AST_TEST_FAIL;
332  } else {
333  if (obj->i != i) {
334  ast_test_status_update(test, "object %d does not match %d\n", obj->i, i);
335  res = AST_TEST_FAIL;
336  }
337  ao2_t_ref(obj, -1, "test");
338  }
339  }
340 
341  return res;
342 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:463
#define OBJ_POINTER
Definition: astobj2.h:1154
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
long int ast_random(void)
Definition: main/utils.c:2064
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756

◆ test_ao2_iteration()

static int test_ao2_iteration ( int  res,
struct ao2_container container,
enum ao2_iterator_flags  flags,
const int *  vector,
int  count,
const char *  prefix,
struct ast_test test 
)
static

Definition at line 1171 of file test_astobj2.c.

References ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, AST_TEST_FAIL, ast_test_status_update, and test_obj::i.

Referenced by test_traversal_nonsorted(), and test_traversal_sorted().

1174 {
1175  struct ao2_iterator iter;
1176  struct test_obj *obj;
1177  int idx;
1178 
1179  if (ao2_container_count(container) != count) {
1180  ast_test_status_update(test, "%s: Container count doesn't match vector count.\n",
1181  prefix);
1182  res = AST_TEST_FAIL;
1183  }
1184 
1185  iter = ao2_iterator_init(container, flags);
1186 
1187  /* Check iterated objects against the given vector. */
1188  for (idx = 0; idx < count; ++idx) {
1189  obj = ao2_iterator_next(&iter);
1190  if (!obj) {
1191  ast_test_status_update(test, "%s: Too few objects found.\n", prefix);
1192  res = AST_TEST_FAIL;
1193  break;
1194  }
1195  if (vector[idx] != obj->i) {
1196  ast_test_status_update(test, "%s: Object %d != vector[%d] %d.\n",
1197  prefix, obj->i, idx, vector[idx]);
1198  res = AST_TEST_FAIL;
1199  }
1200  ao2_ref(obj, -1); /* remove ref from iterator */
1201  }
1202  obj = ao2_iterator_next(&iter);
1203  if (obj) {
1204  ast_test_status_update(test, "%s: Too many objects found. Object %d\n",
1205  prefix, obj->i);
1206  ao2_ref(obj, -1); /* remove ref from iterator */
1207  res = AST_TEST_FAIL;
1208  }
1209 
1210  ao2_iterator_destroy(&iter);
1211 
1212  return res;
1213 }
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
static char prefix[MAX_PREFIX]
Definition: http.c:141

◆ test_cmp_cb()

static int test_cmp_cb ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 119 of file test_astobj2.c.

References CMP_MATCH, test_obj::i, OBJ_KEY, OBJ_PARTIAL_KEY, and partial_key_match_range.

Referenced by AST_TEST_DEFINE(), astobj2_test_1_helper(), test_make_nonsorted(), test_make_sorted(), test_performance(), test_traversal_nonsorted(), and test_traversal_sorted().

120 {
121  struct test_obj *cmp_obj = (struct test_obj *) obj;
122 
123  if (flags & OBJ_KEY) {
124  int *i = (int *) arg;
125 
126  return (cmp_obj->i == *i) ? CMP_MATCH : 0;
127  } else if (flags & OBJ_PARTIAL_KEY) {
128  int *i = (int *) arg;
129 
130  return (*i - partial_key_match_range <= cmp_obj->i
131  && cmp_obj->i <= *i + partial_key_match_range) ? CMP_MATCH : 0;
132  } else {
133  struct test_obj *arg_obj = (struct test_obj *) arg;
134 
135  return (cmp_obj->i == arg_obj->i) ? CMP_MATCH : 0;
136  }
137 }
int partial_key_match_range
Definition: test_astobj2.c:85
#define OBJ_KEY
Definition: astobj2.h:1155
#define OBJ_PARTIAL_KEY
Definition: astobj2.h:1156

◆ test_container2str()

static const char* test_container2str ( enum test_container_type  type)
static

Definition at line 56 of file test_astobj2.c.

References TEST_CONTAINER_HASH, TEST_CONTAINER_LIST, and TEST_CONTAINER_RBTREE.

Referenced by astobj2_test_1_helper(), test_traversal_nonsorted(), test_traversal_sorted(), and testloop().

57 {
58  const char *c_type;
59 
60  c_type = "Unknown";
61  switch (type) {
63  c_type = "List";
64  break;
66  c_type = "Hash";
67  break;
69  c_type = "RBTree";
70  break;
71  }
72  return c_type;
73 }
static const char type[]
Definition: chan_ooh323.c:109

◆ test_container_clone()

static int test_container_clone ( int  res,
struct ao2_container orig,
struct ast_test test 
)
static

Definition at line 216 of file test_astobj2.c.

References ao2_container_check(), ao2_container_clone, ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_match_by_addr(), ao2_t_callback, ao2_t_iterator_next, ao2_t_ref, AST_TEST_FAIL, ast_test_status_update, OBJ_POINTER, and OBJ_UNLINK.

Referenced by astobj2_test_1_helper().

217 {
218  struct ao2_container *clone;
219  struct test_obj *obj;
220  struct test_obj *obj2;
221  struct ao2_iterator iter;
222 
223  clone = ao2_container_clone(orig, 0);
224  if (!clone) {
225  ast_test_status_update(test, "ao2_container_clone failed.\n");
226  return AST_TEST_FAIL;
227  }
228  if (ao2_container_check(clone, 0)) {
229  ast_test_status_update(test, "container integrity check failed\n");
230  res = AST_TEST_FAIL;
231  } else if (ao2_container_count(orig) != ao2_container_count(clone)) {
232  ast_test_status_update(test, "Cloned container does not have the same number of objects.\n");
233  res = AST_TEST_FAIL;
234  } else {
235  iter = ao2_iterator_init(orig, 0);
236  for (; (obj = ao2_t_iterator_next(&iter, "test orig")); ao2_t_ref(obj, -1, "test orig")) {
237  /*
238  * Unlink the matching object from the cloned container to make
239  * the next search faster. This is a big speed optimization!
240  */
242  "test clone");
243  if (obj2) {
244  ao2_t_ref(obj2, -1, "test clone");
245  continue;
246  }
248  "Orig container has an object %p not in the clone container.\n", obj);
249  res = AST_TEST_FAIL;
250  }
251  ao2_iterator_destroy(&iter);
252  if (ao2_container_count(clone)) {
253  ast_test_status_update(test, "Cloned container still has objects.\n");
254  res = AST_TEST_FAIL;
255  }
256  if (ao2_container_check(clone, 0)) {
257  ast_test_status_update(test, "container integrity check failed\n");
258  res = AST_TEST_FAIL;
259  }
260  }
261  ao2_t_ref(clone, -1, "bye clone");
262 
263  return res;
264 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:463
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_container_clone(orig, flags)
Definition: astobj2.h:1430
#define OBJ_POINTER
Definition: astobj2.h:1154
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
int ao2_container_check(struct ao2_container *self, enum search_flags flags)
Perform an integrity check on the specified container.
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1931
#define ao2_t_callback(c, flags, cb_fn, arg, tag)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
Definition: astobj2.h:1714
int ao2_match_by_addr(void *obj, void *arg, int flags)
A common ao2_callback is one that matches by address.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
Generic container type.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.

◆ test_expected_duplicates()

static int test_expected_duplicates ( int  res,
struct ao2_container container,
enum search_flags  flags,
int  number,
const int *  vector,
int  count,
const char *  prefix,
struct ast_test test 
)
static

Definition at line 1289 of file test_astobj2.c.

References ao2_find, ao2_iterator_destroy(), ao2_iterator_next, ao2_ref, AST_TEST_FAIL, ast_test_status_update, test_obj::dup_number, test_obj::i, OBJ_KEY, and OBJ_MULTIPLE.

Referenced by test_traversal_sorted().

1292 {
1293  struct ao2_iterator *mult_iter;
1294  struct test_obj *obj;
1295  int idx;
1296 
1297  mult_iter = ao2_find(container, &number, flags | OBJ_MULTIPLE | OBJ_KEY);
1298  if (!mult_iter) {
1299  ast_test_status_update(test, "%s: Did not return iterator.\n", prefix);
1300  return AST_TEST_FAIL;
1301  }
1302 
1303  /* Check matching objects against the given vector. */
1304  for (idx = 0; idx < count; ++idx) {
1305  obj = ao2_iterator_next(mult_iter);
1306  if (!obj) {
1307  ast_test_status_update(test, "%s: Too few objects found.\n", prefix);
1308  res = AST_TEST_FAIL;
1309  break;
1310  }
1311  if (number != obj->i) {
1312  ast_test_status_update(test, "%s: Object %d != %d.\n",
1313  prefix, obj->i, number);
1314  res = AST_TEST_FAIL;
1315  }
1316  if (vector[idx] != obj->dup_number) {
1317  ast_test_status_update(test, "%s: Object dup id %d != vector[%d] %d.\n",
1318  prefix, obj->dup_number, idx, vector[idx]);
1319  res = AST_TEST_FAIL;
1320  }
1321  ao2_ref(obj, -1); /* remove ref from iterator */
1322  }
1323  obj = ao2_iterator_next(mult_iter);
1324  if (obj) {
1326  "%s: Too many objects found. Object %d, dup id %d\n",
1327  prefix, obj->i, obj->dup_number);
1328  ao2_ref(obj, -1); /* remove ref from iterator */
1329  res = AST_TEST_FAIL;
1330  }
1331  ao2_iterator_destroy(mult_iter);
1332 
1333  return res;
1334 }
#define OBJ_KEY
Definition: astobj2.h:1155
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
Number structure.
Definition: app_followme.c:154
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
int dup_number
Definition: test_astobj2.c:81
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
static char prefix[MAX_PREFIX]
Definition: http.c:141

◆ test_hash_cb()

static int test_hash_cb ( const void *  obj,
const int  flags 
)
static

Definition at line 139 of file test_astobj2.c.

References test_obj::i, OBJ_KEY, and OBJ_PARTIAL_KEY.

Referenced by astobj2_test_1_helper(), test_make_nonsorted(), test_make_sorted(), and test_performance().

140 {
141  if (flags & OBJ_KEY) {
142  const int *i = obj;
143 
144  return *i;
145  } else if (flags & OBJ_PARTIAL_KEY) {
146  /* This is absolutely wrong to be called with this flag value. */
147  abort();
148  /* Just in case abort() doesn't work or something else super silly */
149  *((int *) 0) = 0;
150  return 0;
151  } else {
152  const struct test_obj *hash_obj = obj;
153 
154  return hash_obj->i;
155  }
156 }
#define OBJ_KEY
Definition: astobj2.h:1155
#define OBJ_PARTIAL_KEY
Definition: astobj2.h:1156

◆ test_make_nonsorted()

static struct ao2_container* test_make_nonsorted ( enum test_container_type  type,
int  options 
)
static

Definition at line 967 of file test_astobj2.c.

References AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_hash, ao2_container_alloc_list, container, NULL, test_cmp_cb(), TEST_CONTAINER_HASH, TEST_CONTAINER_LIST, TEST_CONTAINER_RBTREE, and test_hash_cb().

Referenced by test_traversal_nonsorted().

968 {
969  struct ao2_container *container;
970 
971  container = NULL;
972  switch (type) {
973  case TEST_CONTAINER_LIST:
975  NULL, test_cmp_cb);
976  break;
977  case TEST_CONTAINER_HASH:
980  break;
982  /* Container type must be sorted. */
983  break;
984  }
985 
986  return container;
987 }
static const char type[]
Definition: chan_ooh323.c:109
static int test_cmp_cb(void *obj, void *arg, int flags)
Definition: test_astobj2.c:119
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Definition: astobj2.h:1335
#define NULL
Definition: resample.c:96
struct ao2_container * container
Definition: res_fax.c:502
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
static int test_hash_cb(const void *obj, const int flags)
Definition: test_astobj2.c:139
Generic container type.
static struct test_options options

◆ test_make_sorted()

static struct ao2_container* test_make_sorted ( enum test_container_type  type,
int  options 
)
static

Definition at line 1000 of file test_astobj2.c.

References AO2_ALLOC_OPT_LOCK_MUTEX, ao2_t_container_alloc_hash, ao2_t_container_alloc_list, ao2_t_container_alloc_rbtree, container, NULL, test_cmp_cb(), TEST_CONTAINER_HASH, TEST_CONTAINER_LIST, TEST_CONTAINER_RBTREE, test_hash_cb(), and test_sort_cb().

Referenced by test_traversal_sorted().

1001 {
1002  struct ao2_container *container;
1003 
1004  container = NULL;
1005  switch (type) {
1006  case TEST_CONTAINER_LIST:
1008  test_sort_cb, test_cmp_cb, "test");
1009  break;
1010  case TEST_CONTAINER_HASH:
1013  break;
1014  case TEST_CONTAINER_RBTREE:
1016  test_sort_cb, test_cmp_cb, "test");
1017  break;
1018  }
1019 
1020  return container;
1021 }
static const char type[]
Definition: chan_ooh323.c:109
static int test_cmp_cb(void *obj, void *arg, int flags)
Definition: test_astobj2.c:119
#define ao2_t_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn, tag)
Allocate and initialize a list container.
Definition: astobj2.h:1333
#define NULL
Definition: resample.c:96
static int test_sort_cb(const void *obj_left, const void *obj_right, int flags)
Definition: test_astobj2.c:158
struct ao2_container * container
Definition: res_fax.c:502
#define ao2_t_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn, tag)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1308
static int test_hash_cb(const void *obj, const int flags)
Definition: test_astobj2.c:139
#define ao2_t_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn, tag)
Allocate and initialize a red-black tree container.
Definition: astobj2.h:1356
Generic container type.
static struct test_options options

◆ test_obj_destructor()

static void test_obj_destructor ( void *  v_obj)
static

Definition at line 87 of file test_astobj2.c.

References test_obj::destructor_count.

Referenced by AST_TEST_DEFINE(), astobj2_test_1_helper(), insert_test_duplicates(), insert_test_vector(), and test_performance().

88 {
89  struct test_obj *obj = (struct test_obj *) v_obj;
90 
91  if (obj->destructor_count) {
92  --*obj->destructor_count;
93  }
94 }
int * destructor_count
Definition: test_astobj2.c:77

◆ test_performance()

static enum ast_test_result_state test_performance ( struct ast_test test,
enum test_container_type  type,
unsigned int  copt 
)
static

The number of objects inserted and searched for in the container under test.

Definition at line 1925 of file test_astobj2.c.

References ao2_alloc, AO2_ALLOC_OPT_LOCK_MUTEX, ao2_cleanup, ao2_container_alloc_hash, ao2_container_alloc_list, ao2_container_alloc_rbtree, ao2_find, ao2_link, ao2_ref, AST_TEST_FAIL, AST_TEST_PASS, ast_test_status_update, test_obj::i, NULL, OBJ_KEY, OBJS, test_cleanup(), test_cmp_cb(), TEST_CONTAINER_HASH, TEST_CONTAINER_LIST, TEST_CONTAINER_RBTREE, test_hash_cb(), test_obj_destructor(), and test_sort_cb().

Referenced by testloop().

1927 {
1928 /*!
1929  * \brief The number of objects inserted and searched for in the container under test.
1930  */
1931 #define OBJS 73
1932  int res = AST_TEST_PASS;
1933  struct ao2_container *c1 = NULL;
1934  struct test_obj *tobj[OBJS];
1935  struct test_obj *tobj2;
1936  int i;
1937 
1938  switch (type) {
1939  case TEST_CONTAINER_HASH:
1942  break;
1943  case TEST_CONTAINER_LIST:
1946  break;
1947  case TEST_CONTAINER_RBTREE:
1950  break;
1951  }
1952 
1953  for (i = 0; i < OBJS; i++) {
1954  tobj[i] = NULL;
1955  }
1956 
1957  if (!c1) {
1958  ast_test_status_update(test, "Container c1 creation failed.\n");
1959  res = AST_TEST_FAIL;
1960  goto test_cleanup;
1961  }
1962 
1963  for (i = 0; i < OBJS; i++) {
1964  tobj[i] = ao2_alloc(sizeof(struct test_obj), test_obj_destructor);
1965  if (!tobj[i]) {
1966  ast_test_status_update(test, "test object creation failed.\n");
1967  res = AST_TEST_FAIL;
1968  goto test_cleanup;
1969  }
1970  tobj[i]->i = i;
1971  ao2_link(c1, tobj[i]);
1972  }
1973 
1974  for (i = 0; i < OBJS; i++) {
1975  if ((!(tobj2 = ao2_find(c1, &i, OBJ_KEY)))) {
1976  ast_test_status_update(test, "Should have found object %d in container.\n", i);
1977  res = AST_TEST_FAIL;
1978  goto test_cleanup;
1979  }
1980  ao2_ref(tobj2, -1);
1981  tobj2 = NULL;
1982  }
1983 
1984 test_cleanup:
1985  for (i = 0; i < OBJS ; i++) {
1986  ao2_cleanup(tobj[i]);
1987  }
1988  ao2_cleanup(c1);
1989  return res;
1990 }
static const char type[]
Definition: chan_ooh323.c:109
#define OBJ_KEY
Definition: astobj2.h:1155
static int test_cmp_cb(void *obj, void *arg, int flags)
Definition: test_astobj2.c:119
static void test_obj_destructor(void *v_obj)
Definition: test_astobj2.c:87
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Definition: astobj2.h:1335
#define NULL
Definition: resample.c:96
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
static int test_sort_cb(const void *obj_left, const void *obj_right, int flags)
Definition: test_astobj2.c:158
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define OBJS
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
static void test_cleanup(void)
Definition: test.c:1211
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
static int test_hash_cb(const void *obj, const int flags)
Definition: test_astobj2.c:139
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Definition: astobj2.h:1358
Generic container type.
#define ao2_link(container, obj)
Definition: astobj2.h:1549

◆ test_sort_cb()

static int test_sort_cb ( const void *  obj_left,
const void *  obj_right,
int  flags 
)
static

Definition at line 158 of file test_astobj2.c.

References test_obj::dup_number, test_obj::i, OBJ_KEY, OBJ_PARTIAL_KEY, and partial_key_match_range.

Referenced by astobj2_test_1_helper(), test_make_sorted(), and test_performance().

159 {
160  const struct test_obj *test_left = obj_left;
161 
162  if (flags & OBJ_KEY) {
163  const int *i = obj_right;
164 
165  return test_left->i - *i;
166  } else if (flags & OBJ_PARTIAL_KEY) {
167  int *i = (int *) obj_right;
168 
169  if (*i - partial_key_match_range <= test_left->i
170  && test_left->i <= *i + partial_key_match_range) {
171  return 0;
172  }
173 
174  return test_left->i - *i;
175  } else {
176  const struct test_obj *test_right = obj_right;
177 
178  return test_left->i - test_right->i;
179  }
180 }
int partial_key_match_range
Definition: test_astobj2.c:85
#define OBJ_KEY
Definition: astobj2.h:1155
#define OBJ_PARTIAL_KEY
Definition: astobj2.h:1156

◆ test_traversal_nonsorted()

static int test_traversal_nonsorted ( int  res,
int  tst_num,
enum test_container_type  type,
struct ast_test test 
)
static

Container object insertion vector.

Container object insertion vector reversed.

Definition at line 1348 of file test_astobj2.c.

References AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN, AO2_ITERATOR_DESCENDING, ao2_t_ref, ARRAY_LEN, AST_TEST_FAIL, ast_test_status_update, test_obj::destructor_count, insert_test_vector(), NULL, OBJ_ORDER_ASCENDING, OBJ_ORDER_DESCENDING, OBJ_PARTIAL_KEY, partial_key_match_range, test_ao2_callback_traversal(), test_ao2_iteration(), test_cleanup(), test_cmp_cb(), test_container2str(), TEST_CONTAINER_HASH, TEST_CONTAINER_LIST, TEST_CONTAINER_RBTREE, and test_make_nonsorted().

Referenced by AST_TEST_DEFINE().

1349 {
1350  struct ao2_container *c1;
1351  struct ao2_container *c2 = NULL;
1352  int partial;
1353  int destructor_count = 0;
1354 
1355  /*! Container object insertion vector. */
1356  static const int test_initial[] = {
1357  1, 0, 2, 6, 4, 7, 5, 3, 9, 8
1358  };
1359 
1360  /*! Container object insertion vector reversed. */
1361  static const int test_reverse[] = {
1362  8, 9, 3, 5, 7, 4, 6, 2, 0, 1
1363  };
1364  static const int test_list_partial_forward[] = {
1365  6, 7, 5
1366  };
1367  static const int test_list_partial_backward[] = {
1368  5, 7, 6
1369  };
1370 
1371  /* The hash orders assume that there are 5 buckets. */
1372  static const int test_hash_end_forward[] = {
1373  0, 5, 1, 6, 2, 7, 3, 8, 4, 9
1374  };
1375  static const int test_hash_end_backward[] = {
1376  9, 4, 8, 3, 7, 2, 6, 1, 5, 0
1377  };
1378  static const int test_hash_begin_forward[] = {
1379  5, 0, 6, 1, 7, 2, 8, 3, 9, 4
1380  };
1381  static const int test_hash_begin_backward[] = {
1382  4, 9, 3, 8, 2, 7, 1, 6, 0, 5
1383  };
1384  static const int test_hash_partial_forward[] = {
1385  5, 6, 7
1386  };
1387  static const int test_hash_partial_backward[] = {
1388  7, 6, 5
1389  };
1390 
1391  ast_test_status_update(test, "Test %d, %s containers.\n",
1392  tst_num, test_container2str(type));
1393 
1394  /* Create container that inserts objects at the end. */
1395  c1 = test_make_nonsorted(type, 0);
1396  if (!c1) {
1397  ast_test_status_update(test, "Container c1 creation failed.\n");
1398  res = AST_TEST_FAIL;
1399  goto test_cleanup;
1400  }
1401  if (insert_test_vector(c1, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c1", test)) {
1402  res = AST_TEST_FAIL;
1403  goto test_cleanup;
1404  }
1405 
1406  /* Create container that inserts objects at the beginning. */
1408  if (!c2) {
1409  ast_test_status_update(test, "Container c2 creation failed.\n");
1410  res = AST_TEST_FAIL;
1411  goto test_cleanup;
1412  }
1413  if (insert_test_vector(c2, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c2", test)) {
1414  res = AST_TEST_FAIL;
1415  goto test_cleanup;
1416  }
1417 
1418  /* Check container iteration directions */
1419  switch (type) {
1420  case TEST_CONTAINER_LIST:
1421  res = test_ao2_iteration(res, c1, 0,
1422  test_initial, ARRAY_LEN(test_initial),
1423  "Iteration (ascending, insert end)", test);
1425  test_reverse, ARRAY_LEN(test_reverse),
1426  "Iteration (descending, insert end)", test);
1427 
1428  res = test_ao2_iteration(res, c2, 0,
1429  test_reverse, ARRAY_LEN(test_reverse),
1430  "Iteration (ascending, insert begin)", test);
1432  test_initial, ARRAY_LEN(test_initial),
1433  "Iteration (descending, insert begin)", test);
1434  break;
1435  case TEST_CONTAINER_HASH:
1436  res = test_ao2_iteration(res, c1, 0,
1437  test_hash_end_forward, ARRAY_LEN(test_hash_end_forward),
1438  "Iteration (ascending, insert end)", test);
1440  test_hash_end_backward, ARRAY_LEN(test_hash_end_backward),
1441  "Iteration (descending, insert end)", test);
1442 
1443  res = test_ao2_iteration(res, c2, 0,
1444  test_hash_begin_forward, ARRAY_LEN(test_hash_begin_forward),
1445  "Iteration (ascending, insert begin)", test);
1447  test_hash_begin_backward, ARRAY_LEN(test_hash_begin_backward),
1448  "Iteration (descending, insert begin)", test);
1449  break;
1450  case TEST_CONTAINER_RBTREE:
1451  break;
1452  }
1453 
1454  /* Check container traversal directions */
1455  switch (type) {
1456  case TEST_CONTAINER_LIST:
1458  test_initial, ARRAY_LEN(test_initial),
1459  "Traversal (ascending, insert end)", test);
1461  test_reverse, ARRAY_LEN(test_reverse),
1462  "Traversal (descending, insert end)", test);
1463 
1465  test_reverse, ARRAY_LEN(test_reverse),
1466  "Traversal (ascending, insert begin)", test);
1468  test_initial, ARRAY_LEN(test_initial),
1469  "Traversal (descending, insert begin)", test);
1470  break;
1471  case TEST_CONTAINER_HASH:
1473  test_hash_end_forward, ARRAY_LEN(test_hash_end_forward),
1474  "Traversal (ascending, insert end)", test);
1476  test_hash_end_backward, ARRAY_LEN(test_hash_end_backward),
1477  "Traversal (descending, insert end)", test);
1478 
1480  test_hash_begin_forward, ARRAY_LEN(test_hash_begin_forward),
1481  "Traversal (ascending, insert begin)", test);
1483  test_hash_begin_backward, ARRAY_LEN(test_hash_begin_backward),
1484  "Traversal (descending, insert begin)", test);
1485  break;
1486  case TEST_CONTAINER_RBTREE:
1487  break;
1488  }
1489 
1490  /* Check traversal with OBJ_PARTIAL_KEY search range. */
1491  partial = 6;
1493  switch (type) {
1494  case TEST_CONTAINER_LIST:
1496  test_cmp_cb, &partial,
1497  test_list_partial_forward, ARRAY_LEN(test_list_partial_forward),
1498  "Traversal OBJ_PARTIAL_KEY (ascending)", test);
1500  test_cmp_cb, &partial,
1501  test_list_partial_backward, ARRAY_LEN(test_list_partial_backward),
1502  "Traversal OBJ_PARTIAL_KEY (descending)", test);
1503  break;
1504  case TEST_CONTAINER_HASH:
1506  test_cmp_cb, &partial,
1507  test_hash_partial_forward, ARRAY_LEN(test_hash_partial_forward),
1508  "Traversal OBJ_PARTIAL_KEY (ascending)", test);
1510  test_cmp_cb, &partial,
1511  test_hash_partial_backward, ARRAY_LEN(test_hash_partial_backward),
1512  "Traversal OBJ_PARTIAL_KEY (descending)", test);
1513  break;
1514  case TEST_CONTAINER_RBTREE:
1515  break;
1516  }
1517 
1518 test_cleanup:
1519  /* destroy containers */
1520  if (c1) {
1521  ao2_t_ref(c1, -1, "bye c1");
1522  }
1523  if (c2) {
1524  ao2_t_ref(c2, -1, "bye c2");
1525  }
1526 
1527  if (destructor_count > 0) {
1529  "all destructors were not called, destructor count is %d\n",
1530  destructor_count);
1531  res = AST_TEST_FAIL;
1532  } else if (destructor_count < 0) {
1534  "Destructor was called too many times, destructor count is %d\n",
1535  destructor_count);
1536  res = AST_TEST_FAIL;
1537  }
1538 
1539  return res;
1540 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:463
static const char type[]
Definition: chan_ooh323.c:109
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
int partial_key_match_range
Definition: test_astobj2.c:85
static int test_ao2_iteration(int res, struct ao2_container *container, enum ao2_iterator_flags flags, const int *vector, int count, const char *prefix, struct ast_test *test)
static int test_cmp_cb(void *obj, void *arg, int flags)
Definition: test_astobj2.c:119
static struct ao2_container * test_make_nonsorted(enum test_container_type type, int options)
Definition: test_astobj2.c:967
#define NULL
Definition: resample.c:96
Insert objects at the beginning of the container. (Otherwise it is the opposite; insert at the end...
Definition: astobj2.h:1176
#define OBJ_PARTIAL_KEY
Definition: astobj2.h:1156
Traverse in ascending order (First to last container object)
Definition: astobj2.h:1125
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
Traverse in descending order (Last to first container object)
Definition: astobj2.h:1127
static int test_ao2_callback_traversal(int res, struct ao2_container *container, enum search_flags flags, ao2_callback_fn *cmp_fn, void *arg, const int *vector, int count, const char *prefix, struct ast_test *test)
static void test_cleanup(void)
Definition: test.c:1211
Generic container type.
static int insert_test_vector(struct ao2_container *container, int *destroy_counter, const int *vector, int count, const char *prefix, struct ast_test *test)
static const char * test_container2str(enum test_container_type type)
Definition: test_astobj2.c:56

◆ test_traversal_sorted()

static int test_traversal_sorted ( int  res,
int  tst_num,
enum test_container_type  type,
struct ast_test test 
)
static

Container object insertion vector.

Container forward traversal/iteration.

Container backward traversal/iteration.

Definition at line 1554 of file test_astobj2.c.

References AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW, AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN, ao2_container_dump(), ao2_container_stats(), AO2_ITERATOR_DESCENDING, ao2_t_ref, ARRAY_LEN, ast_test_debug(), AST_TEST_FAIL, ast_test_status_update, test_obj::destructor_count, insert_test_duplicates(), insert_test_vector(), NULL, OBJ_ORDER_ASCENDING, OBJ_ORDER_DESCENDING, OBJ_PARTIAL_KEY, partial_key_match_range, test_ao2_callback_traversal(), test_ao2_iteration(), test_cleanup(), test_cmp_cb(), test_container2str(), TEST_CONTAINER_HASH, TEST_CONTAINER_LIST, TEST_CONTAINER_RBTREE, test_expected_duplicates(), and test_make_sorted().

Referenced by AST_TEST_DEFINE().

1555 {
1556  struct ao2_container *c1;
1557  struct ao2_container *c2 = NULL;
1558  int partial;
1559  int destructor_count = 0;
1560  int duplicate_number = 100;
1561 
1562  /*! Container object insertion vector. */
1563  static const int test_initial[] = {
1564  1, 0, 2, 6, 4, 7, 5, 3, 9, 8
1565  };
1566 
1567  /*! Container forward traversal/iteration. */
1568  static const int test_forward[] = {
1569  0, 1, 2, 3, 4, 5, 6, 7, 8, 9
1570  };
1571  /*! Container backward traversal/iteration. */
1572  static const int test_backward[] = {
1573  9, 8, 7, 6, 5, 4, 3, 2, 1, 0
1574  };
1575 
1576  static const int test_partial_forward[] = {
1577  5, 6, 7
1578  };
1579  static const int test_partial_backward[] = {
1580  7, 6, 5
1581  };
1582 
1583  /* The hash orders assume that there are 5 buckets. */
1584  static const int test_hash_forward[] = {
1585  0, 5, 1, 6, 2, 7, 3, 8, 4, 9
1586  };
1587  static const int test_hash_backward[] = {
1588  9, 4, 8, 3, 7, 2, 6, 1, 5, 0
1589  };
1590  static const int test_hash_partial_forward[] = {
1591  5, 6, 7
1592  };
1593  static const int test_hash_partial_backward[] = {
1594  7, 6, 5
1595  };
1596 
1597  /* Duplicate identifier order */
1598  static const int test_dup_allow_forward[] = {
1599  0, 1, 2, 3, 2
1600  };
1601  static const int test_dup_allow_backward[] = {
1602  2, 3, 2, 1, 0
1603  };
1604  static const int test_dup_reject[] = {
1605  0
1606  };
1607  static const int test_dup_obj_reject_forward[] = {
1608  0, 1, 2, 3
1609  };
1610  static const int test_dup_obj_reject_backward[] = {
1611  3, 2, 1, 0
1612  };
1613  static const int test_dup_replace[] = {
1614  2
1615  };
1616 
1617  ast_test_status_update(test, "Test %d, %s containers.\n",
1618  tst_num, test_container2str(type));
1619 
1620  /* Create container that inserts duplicate objects after matching objects. */
1622  if (!c1) {
1623  ast_test_status_update(test, "Container c1 creation failed.\n");
1624  res = AST_TEST_FAIL;
1625  goto test_cleanup;
1626  }
1627  if (insert_test_vector(c1, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c1(DUPS_ALLOW)", test)) {
1628  res = AST_TEST_FAIL;
1629  goto test_cleanup;
1630  }
1631 
1632  /* Create container that inserts duplicate objects before matching objects. */
1634  if (!c2) {
1635  ast_test_status_update(test, "Container c2 creation failed.\n");
1636  res = AST_TEST_FAIL;
1637  goto test_cleanup;
1638  }
1639  if (insert_test_vector(c2, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c2(DUPS_ALLOW)", test)) {
1640  res = AST_TEST_FAIL;
1641  goto test_cleanup;
1642  }
1643 
1644 #if defined(TEST_CONTAINER_DEBUG_DUMP)
1645  ao2_container_dump(c1, 0, "c1(DUPS_ALLOW)", (void *) test, (ao2_prnt_fn *) ast_test_debug, test_prnt_obj);
1646  ao2_container_stats(c1, 0, "c1(DUPS_ALLOW)", (void *) test, (ao2_prnt_fn *) ast_test_debug);
1647  ao2_container_dump(c2, 0, "c2(DUPS_ALLOW)", (void *) test, (ao2_prnt_fn *) ast_test_debug, test_prnt_obj);
1648  ao2_container_stats(c2, 0, "c2(DUPS_ALLOW)", (void *) test, (ao2_prnt_fn *) ast_test_debug);
1649 #endif /* defined(TEST_CONTAINER_DEBUG_DUMP) */
1650 
1651  /* Check container iteration directions */
1652  switch (type) {
1653  case TEST_CONTAINER_RBTREE:
1654  case TEST_CONTAINER_LIST:
1655  res = test_ao2_iteration(res, c1, 0,
1656  test_forward, ARRAY_LEN(test_forward),
1657  "Iteration (ascending)", test);
1659  test_backward, ARRAY_LEN(test_backward),
1660  "Iteration (descending)", test);
1661  break;
1662  case TEST_CONTAINER_HASH:
1663  res = test_ao2_iteration(res, c1, 0,
1664  test_hash_forward, ARRAY_LEN(test_hash_forward),
1665  "Iteration (ascending)", test);
1667  test_hash_backward, ARRAY_LEN(test_hash_backward),
1668  "Iteration (descending)", test);
1669  break;
1670  }
1671 
1672  /* Check container traversal directions */
1673  switch (type) {
1674  case TEST_CONTAINER_RBTREE:
1675  case TEST_CONTAINER_LIST:
1677  test_forward, ARRAY_LEN(test_forward),
1678  "Traversal (ascending)", test);
1680  test_backward, ARRAY_LEN(test_backward),
1681  "Traversal (descending)", test);
1682  break;
1683  case TEST_CONTAINER_HASH:
1685  test_hash_forward, ARRAY_LEN(test_hash_forward),
1686  "Traversal (ascending, insert end)", test);
1688  test_hash_backward, ARRAY_LEN(test_hash_backward),
1689  "Traversal (descending)", test);
1690  break;
1691  }
1692 
1693  /* Check traversal with OBJ_PARTIAL_KEY search range. */
1694  partial = 6;
1696  switch (type) {
1697  case TEST_CONTAINER_RBTREE:
1698  case TEST_CONTAINER_LIST:
1700  test_cmp_cb, &partial,
1701  test_partial_forward, ARRAY_LEN(test_partial_forward),
1702  "Traversal OBJ_PARTIAL_KEY (ascending)", test);
1704  test_cmp_cb, &partial,
1705  test_partial_backward, ARRAY_LEN(test_partial_backward),
1706  "Traversal OBJ_PARTIAL_KEY (descending)", test);
1707  break;
1708  case TEST_CONTAINER_HASH:
1710  test_cmp_cb, &partial,
1711  test_hash_partial_forward, ARRAY_LEN(test_hash_partial_forward),
1712  "Traversal OBJ_PARTIAL_KEY (ascending)", test);
1714  test_cmp_cb, &partial,
1715  test_hash_partial_backward, ARRAY_LEN(test_hash_partial_backward),
1716  "Traversal OBJ_PARTIAL_KEY (descending)", test);
1717  break;
1718  }
1719 
1720  /* Add duplicates to initial containers that allow duplicates */
1721  if (insert_test_duplicates(c1, &destructor_count, duplicate_number, "c1(DUPS_ALLOW)", test)) {
1722  res = AST_TEST_FAIL;
1723  goto test_cleanup;
1724  }
1725  if (insert_test_duplicates(c2, &destructor_count, duplicate_number, "c2(DUPS_ALLOW)", test)) {
1726  res = AST_TEST_FAIL;
1727  goto test_cleanup;
1728  }
1729 
1730 #if defined(TEST_CONTAINER_DEBUG_DUMP)
1731  ao2_container_dump(c1, 0, "c1(DUPS_ALLOW) w/ dups", (void *) test, (ao2_prnt_fn *) ast_test_debug, test_prnt_obj);
1732  ao2_container_stats(c1, 0, "c1(DUPS_ALLOW) w/ dups", (void *) test, (ao2_prnt_fn *) ast_test_debug);
1733  ao2_container_dump(c2, 0, "c2(DUPS_ALLOW) w/ dups", (void *) test, (ao2_prnt_fn *) ast_test_debug, test_prnt_obj);
1734  ao2_container_stats(c2, 0, "c2(DUPS_ALLOW) w/ dups", (void *) test, (ao2_prnt_fn *) ast_test_debug);
1735 #endif /* defined(TEST_CONTAINER_DEBUG_DUMP) */
1736 
1737  /* Check duplicates in containers that allow duplicates. */
1738  res = test_expected_duplicates(res, c1, OBJ_ORDER_ASCENDING, duplicate_number,
1739  test_dup_allow_forward, ARRAY_LEN(test_dup_allow_forward),
1740  "Duplicates (ascending, DUPS_ALLOW)", test);
1741  res = test_expected_duplicates(res, c1, OBJ_ORDER_DESCENDING, duplicate_number,
1742  test_dup_allow_backward, ARRAY_LEN(test_dup_allow_backward),
1743  "Duplicates (descending, DUPS_ALLOW)", test);
1744 
1745  ao2_t_ref(c1, -1, "bye c1");
1746  c1 = NULL;
1747  ao2_t_ref(c2, -1, "bye c2");
1748  c2 = NULL;
1749 
1750  /* Create containers that reject duplicate keyed objects. */
1752  if (!c1) {
1753  ast_test_status_update(test, "Container c1 creation failed.\n");
1754  res = AST_TEST_FAIL;
1755  goto test_cleanup;
1756  }
1757  if (insert_test_vector(c1, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c1(DUPS_REJECT)", test)) {
1758  res = AST_TEST_FAIL;
1759  goto test_cleanup;
1760  }
1761  if (insert_test_duplicates(c1, &destructor_count, duplicate_number, "c1(DUPS_REJECT)", test)) {
1762  res = AST_TEST_FAIL;
1763  goto test_cleanup;
1764  }
1766  if (!c2) {
1767  ast_test_status_update(test, "Container c2 creation failed.\n");
1768  res = AST_TEST_FAIL;
1769  goto test_cleanup;
1770  }
1771  if (insert_test_vector(c2, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c2(DUPS_REJECT)", test)) {
1772  res = AST_TEST_FAIL;
1773  goto test_cleanup;
1774  }
1775  if (insert_test_duplicates(c2, &destructor_count, duplicate_number, "c2(DUPS_REJECT)", test)) {
1776  res = AST_TEST_FAIL;
1777  goto test_cleanup;
1778  }
1779 
1780  /* Check duplicates in containers that reject duplicate keyed objects. */
1781  res = test_expected_duplicates(res, c1, OBJ_ORDER_ASCENDING, duplicate_number,
1782  test_dup_reject, ARRAY_LEN(test_dup_reject),
1783  "Duplicates (ascending, DUPS_REJECT)", test);
1784  res = test_expected_duplicates(res, c1, OBJ_ORDER_DESCENDING, duplicate_number,
1785  test_dup_reject, ARRAY_LEN(test_dup_reject),
1786  "Duplicates (descending, DUPS_REJECT)", test);
1787 
1788  ao2_t_ref(c1, -1, "bye c1");
1789  c1 = NULL;
1790  ao2_t_ref(c2, -1, "bye c2");
1791  c2 = NULL;
1792 
1793  /* Create containers that reject duplicate objects. */
1795  if (!c1) {
1796  ast_test_status_update(test, "Container c1 creation failed.\n");
1797  res = AST_TEST_FAIL;
1798  goto test_cleanup;
1799  }
1800  if (insert_test_vector(c1, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c1(DUPS_OBJ_REJECT)", test)) {
1801  res = AST_TEST_FAIL;
1802  goto test_cleanup;
1803  }
1804  if (insert_test_duplicates(c1, &destructor_count, duplicate_number, "c1(DUPS_OBJ_REJECT)", test)) {
1805  res = AST_TEST_FAIL;
1806  goto test_cleanup;
1807  }
1809  if (!c2) {
1810  ast_test_status_update(test, "Container c2 creation failed.\n");
1811  res = AST_TEST_FAIL;
1812  goto test_cleanup;
1813  }
1814  if (insert_test_vector(c2, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c2(DUPS_OBJ_REJECT)", test)) {
1815  res = AST_TEST_FAIL;
1816  goto test_cleanup;
1817  }
1818  if (insert_test_duplicates(c2, &destructor_count, duplicate_number, "c2(DUPS_OBJ_REJECT)", test)) {
1819  res = AST_TEST_FAIL;
1820  goto test_cleanup;
1821  }
1822 
1823  /* Check duplicates in containers that reject duplicate objects. */
1824  res = test_expected_duplicates(res, c1, OBJ_ORDER_ASCENDING, duplicate_number,
1825  test_dup_obj_reject_forward, ARRAY_LEN(test_dup_obj_reject_forward),
1826  "Duplicates (ascending, DUPS_OBJ_REJECT)", test);
1827  res = test_expected_duplicates(res, c1, OBJ_ORDER_DESCENDING, duplicate_number,
1828  test_dup_obj_reject_backward, ARRAY_LEN(test_dup_obj_reject_backward),
1829  "Duplicates (descending, DUPS_OBJ_REJECT)", test);
1830 
1831  ao2_t_ref(c1, -1, "bye c1");
1832  c1 = NULL;
1833  ao2_t_ref(c2, -1, "bye c2");
1834  c2 = NULL;
1835 
1836  /* Create container that replaces duplicate keyed objects. */
1838  if (!c1) {
1839  ast_test_status_update(test, "Container c1 creation failed.\n");
1840  res = AST_TEST_FAIL;
1841  goto test_cleanup;
1842  }
1843  if (insert_test_vector(c1, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c1(DUPS_REJECT)", test)) {
1844  res = AST_TEST_FAIL;
1845  goto test_cleanup;
1846  }
1847  if (insert_test_duplicates(c1, &destructor_count, duplicate_number, "c1(DUPS_REJECT)", test)) {
1848  res = AST_TEST_FAIL;
1849  goto test_cleanup;
1850  }
1852  if (!c2) {
1853  ast_test_status_update(test, "Container c2 creation failed.\n");
1854  res = AST_TEST_FAIL;
1855  goto test_cleanup;
1856  }
1857  if (insert_test_vector(c2, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c2(DUPS_REPLACE)", test)) {
1858  res = AST_TEST_FAIL;
1859  goto test_cleanup;
1860  }
1861  if (insert_test_duplicates(c2, &destructor_count, duplicate_number, "c2(DUPS_REPLACE)", test)) {
1862  res = AST_TEST_FAIL;
1863  goto test_cleanup;
1864  }
1865 
1866  /* Check duplicates in containers that replaces duplicate keyed objects. */
1867  res = test_expected_duplicates(res, c1, OBJ_ORDER_ASCENDING, duplicate_number,
1868  test_dup_replace, ARRAY_LEN(test_dup_replace),
1869  "Duplicates (ascending, DUPS_REPLACE)", test);
1870  res = test_expected_duplicates(res, c1, OBJ_ORDER_DESCENDING, duplicate_number,
1871  test_dup_replace, ARRAY_LEN(test_dup_replace),
1872  "Duplicates (descending, DUPS_REPLACE)", test);
1873 
1874 test_cleanup:
1875  /* destroy containers */
1876  if (c1) {
1877  ao2_t_ref(c1, -1, "bye c1");
1878  }
1879  if (c2) {
1880  ao2_t_ref(c2, -1, "bye c2");
1881  }
1882 
1883  if (destructor_count > 0) {
1885  "all destructors were not called, destructor count is %d\n",
1886  destructor_count);
1887  res = AST_TEST_FAIL;
1888  } else if (destructor_count < 0) {
1890  "Destructor was called too many times, destructor count is %d\n",
1891  destructor_count);
1892  res = AST_TEST_FAIL;
1893  }
1894 
1895  return res;
1896 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:463
static const char type[]
Definition: chan_ooh323.c:109
static int insert_test_duplicates(struct ao2_container *container, int *destroy_counter, int number, const char *prefix, struct ast_test *test)
void ao2_container_dump(struct ao2_container *self, enum search_flags flags, const char *name, void *where, ao2_prnt_fn *prnt, ao2_prnt_obj_fn *prnt_obj)
Display contents of the specified container.
void ast_test_debug(struct ast_test *test, const char *fmt,...)
Definition: test.c:113
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
int partial_key_match_range
Definition: test_astobj2.c:85
static int test_ao2_iteration(int res, struct ao2_container *container, enum ao2_iterator_flags flags, const int *vector, int count, const char *prefix, struct ast_test *test)
static int test_cmp_cb(void *obj, void *arg, int flags)
Definition: test_astobj2.c:119
Allow objects with duplicate keys in container.
Definition: astobj2.h:1185
#define NULL
Definition: resample.c:96
void ao2_container_stats(struct ao2_container *self, enum search_flags flags, const char *name, void *where, ao2_prnt_fn *prnt)
Display statistics of the specified container.
static int test_expected_duplicates(int res, struct ao2_container *container, enum search_flags flags, int number, const int *vector, int count, const char *prefix, struct ast_test *test)
Insert objects at the beginning of the container. (Otherwise it is the opposite; insert at the end...
Definition: astobj2.h:1176
#define OBJ_PARTIAL_KEY
Definition: astobj2.h:1156
void() ao2_prnt_fn(void *where, const char *fmt,...)
Print output.
Definition: astobj2.h:1442
static struct ao2_container * test_make_sorted(enum test_container_type type, int options)
Traverse in ascending order (First to last container object)
Definition: astobj2.h:1125
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
Traverse in descending order (Last to first container object)
Definition: astobj2.h:1127
static int test_ao2_callback_traversal(int res, struct ao2_container *container, enum search_flags flags, ao2_callback_fn *cmp_fn, void *arg, const int *vector, int count, const char *prefix, struct ast_test *test)
static void test_cleanup(void)
Definition: test.c:1211
Replace objects with duplicate keys in container.
Definition: astobj2.h:1215
Reject objects with duplicate keys in container.
Definition: astobj2.h:1192
Generic container type.
Reject duplicate objects in container.
Definition: astobj2.h:1205
static int insert_test_vector(struct ao2_container *container, int *destroy_counter, const int *vector, int count, const char *prefix, struct ast_test *test)
static const char * test_container2str(enum test_container_type type)
Definition: test_astobj2.c:56

◆ testloop()

static enum ast_test_result_state testloop ( struct ast_test test,
enum test_container_type  type,
int  copt,
int  iterations 
)
static

Definition at line 1992 of file test_astobj2.c.

References AST_TEST_PASS, ast_test_status_update, ast_tvdiff_ms(), ast_tvnow(), test_obj::i, test_container2str(), and test_performance().

Referenced by AST_TEST_DEFINE().

1994 {
1995  int res = AST_TEST_PASS;
1996  int i;
1997  int reportcount = iterations / 5;
1998  struct timeval start;
1999 
2000  start = ast_tvnow();
2001  for (i = 1 ; i <= iterations && res == AST_TEST_PASS ; i++) {
2002  if (i % reportcount == 0 && i != iterations) {
2003  ast_test_status_update(test, "%5.2fK traversals, %9s\n",
2004  i / 1000.0, test_container2str(type));
2005  }
2006  res = test_performance(test, type, copt);
2007  }
2008  ast_test_status_update(test, "%5.2fK traversals, %9s : %5lu ms\n",
2009  iterations / 1000.0, test_container2str(type), (unsigned long)ast_tvdiff_ms(ast_tvnow(), start));
2010  return res;
2011 }
static const char type[]
Definition: chan_ooh323.c:109
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:98
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
static enum ast_test_result_state test_performance(struct ast_test *test, enum test_container_type type, unsigned int copt)
static const char * test_container2str(enum test_container_type type)
Definition: test_astobj2.c:56

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 2054 of file test_astobj2.c.

References AST_TEST_UNREGISTER.

2055 {
2056  AST_TEST_UNREGISTER(astobj2_test_1);
2057  AST_TEST_UNREGISTER(astobj2_test_2);
2058  AST_TEST_UNREGISTER(astobj2_test_3);
2059  AST_TEST_UNREGISTER(astobj2_test_4);
2060  AST_TEST_UNREGISTER(astobj2_test_perf);
2061  return 0;
2062 }
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "ASTOBJ2 Unit Tests" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
static

Definition at line 2074 of file test_astobj2.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 2074 of file test_astobj2.c.

◆ partial_key_match_range

int partial_key_match_range

Partial search key +/- matching range.

Definition at line 85 of file test_astobj2.c.

Referenced by test_ao2_find_w_OBJ_PARTIAL_KEY(), test_cmp_cb(), test_sort_cb(), test_traversal_nonsorted(), and test_traversal_sorted().