param_test.h 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /*
  2. * Parameterized Test Framework
  3. *
  4. * Peripherals like SPI has several parameters like: freq, mode, DMA, etc.
  5. * This framework helps to test different parameter sets with the same program.
  6. *
  7. * Each "parameter set" is a set with different parameters (freq, mode, etc.).
  8. * A parameter group is a group of several parameter sets. Each unit test performs
  9. * tests among the sets in a group.
  10. *
  11. * The test will be execute in the following sequence:
  12. * 1. ``pre_test``: initialize the context
  13. * 2. take a set out of the parameter group
  14. * 3. ``def_param``: fill in default value for the parameter set if not set
  15. * 4. ``loop``: execute test program for the set in the initialized context
  16. * 5. loop executing 2-4 until the last set
  17. * 6. ``post_test``: free the resources used.
  18. *
  19. * Usage example:
  20. *
  21. * 1. Define your own parameter set type:
  22. * typedef struct {
  23. * const char pset_name[PSET_NAME_LEN];
  24. * //The test work till the frequency below,
  25. * //set the frequency to higher and remove checks in the driver to know how fast the system can run.
  26. * const int *freq_list; // list of tested frequency, terminated by 0
  27. * int freq_limit; //freq larger (not equal) than this will be ignored
  28. * spi_dup_t dup;
  29. * int mode;
  30. * bool length_aligned;
  31. * int test_size;
  32. *
  33. * int master_limit; // the master disable dummy bits and discard readings over this freq
  34. * bool master_iomux;
  35. * int master_dma_chan;
  36. *
  37. * bool slave_iomux;
  38. * int slave_dma_chan;
  39. * int slave_tv_ns;
  40. * bool slave_unaligned_addr;
  41. * } spitest_param_set_t;
  42. *
  43. * 2. Define a parameter set:
  44. * spitest_param_set_t mode_pgroup[] = {
  45. * //non-DMA tests
  46. * { .pset_name = "mode 0, no DMA",
  47. * .freq_list = test_freq_mode,
  48. * .master_limit = FREQ_LIMIT_MODE,
  49. * .dup = FULL_DUPLEX,
  50. * .master_iomux= true,
  51. * .slave_iomux = true,
  52. * .slave_tv_ns = TV_WITH_ESP_SLAVE,
  53. * .mode = 0,
  54. * },
  55. * { .pset_name = "mode 1, no DMA",
  56. * .freq_list = test_freq_mode,
  57. * .master_limit = FREQ_LIMIT_MODE,
  58. * .dup = FULL_DUPLEX,
  59. * .master_iomux= true,
  60. * .slave_iomux = true,
  61. * .slave_tv_ns = TV_WITH_ESP_SLAVE,
  62. * .mode = 1,
  63. * },
  64. * // other configurations...
  65. * };
  66. *
  67. * 3. Define your test functions, and wrap them in the ``param_test_func_t``:
  68. * static const param_test_func_t master_test_func = {
  69. * .pre_test = test_master_init,
  70. * .post_test = test_master_deinit,
  71. * .loop = test_master_loop,
  72. * .def_param = spitest_def_param,
  73. * };
  74. *
  75. * 4. Declare the group by PARAM_GROUP_DECLARE right after the param group:
  76. * PARAM_GROUP_DECLARE(MODE, mode_pgroup)
  77. *
  78. * 5. Declare the test function by TEST_SINGLE_BOARD (for single board test), or TEST_MASTER_SLAVE(for multiboard test)
  79. * TEST_MASTER_SLAVE(MODE, mode_pgroup, "[spi][timeout=120]", &master_test_func, &slave_test_func)
  80. *
  81. * or
  82. * TEST_SINGLE_BOARD(TIMING, timing_pgroup, "[spi][timeout=120]", &local_test_func)
  83. *
  84. * NOTE: suggest to define your own macro to wrap 4 and 5 if your tag and test functions are the same. E.g.:
  85. * #define TEST_SPI_MASTER_SLAVE(name, pgroup) (backslash)
  86. * PARAM_GROUP_DECLARE(name, pgroup) (backslash)
  87. * TEST_MASTER_SLAVE(name, pgroup, "[spi][timeout=120]", &master_test_func, &slave_test_func)
  88. *
  89. * Then declare tests conveniently by:
  90. * TEST_SPI_MASTER_SLAVE(TIMING, timing_pgroup)
  91. * TEST_SPI_MASTER_SLAVE(MODE, mode_pgroup)
  92. *
  93. */
  94. #define PGROUP_NAME_LEN 20 ///< name length of parameter group
  95. #define PGROUP_NAME(name) PGROUP_##name ///< param group name
  96. #define PTEST_MASTER_NAME(name) PTEST_MASTER_##name ///< test function name of master
  97. #define PTEST_SLAVE_NAME(name) PTEST_SLAVE_##name ///< test function name of slave
  98. /// Test set structure holding name, param set array pointer, item size and param set num.
  99. typedef struct {
  100. char name[PGROUP_NAME_LEN]; ///< Name of param group to print
  101. void *param_group; ///< Start of the param group array
  102. int pset_size; ///< Size of each param set
  103. int pset_num; ///< Total number of param sets
  104. } param_group_t;
  105. /// Test functions for the frameowrk
  106. typedef struct {
  107. void (*pre_test)(void** contxt); ///< Initialization function called before tests begin. Initial your context here
  108. void (*post_test)(void* context); ///< Deinit function called after all tests are done.
  109. void (*def_param)(void* inout_pset); ///< Function to fill each pset structure before executed, left NULL if not used.
  110. void (*loop)(const void* pset, void* context); ///< Function execute each param set
  111. } ptest_func_t;
  112. /**
  113. * Test framework to execute init, loop and deinit.
  114. *
  115. * @param param_group Parameter group holder to test in turns.
  116. * @param test_func Function set to execute.
  117. */
  118. void test_serializer(const param_group_t *param_group, const ptest_func_t* test_func);
  119. #define PARAM_GROUP_DECLARE_TYPE(group_name, pset_type, pgroup) \
  120. static const param_group_t PGROUP_NAME(pgroup) = { \
  121. .name = #group_name, \
  122. .param_group = (void*)&pgroup, \
  123. .pset_size = sizeof(pset_type), \
  124. .pset_num = sizeof(pgroup)/sizeof(pset_type), \
  125. };
  126. /**
  127. * Declare parameter group
  128. *
  129. * @param group_name Parameter group name to print in the beginning of the test
  130. * @param param_group Parameter group structure, should be already defined above, and the size and type is defined.
  131. */
  132. #define PARAM_GROUP_DECLARE(group_name, param_group) \
  133. PARAM_GROUP_DECLARE_TYPE(group_name, typeof(param_group[0]), param_group)
  134. /**
  135. * Test parameter group on one board.
  136. *
  137. * @param name Test name to be printed in the menu.
  138. * @param param_group Parameter group to be tested.
  139. * @param tag Tag for environment, etc. e.g. [spi][timeout=120]
  140. * @param test_func ``ptest_func_t`` to be executed.
  141. */
  142. #define TEST_SINGLE_BOARD(name, param_group, tag, test_func) \
  143. TEST_CASE("single board test: "#name, tag) { test_serializer(&PGROUP_NAME(param_group), test_func); }
  144. /**
  145. * Test parameter group for master-slave framework
  146. *
  147. * @param name Test name to be printed in the menu.
  148. * @param param_group Parameter group to be tested.
  149. * @param tag Tag for environment, etc. e.g. [spi][timeout=120]
  150. * @param master_func ``ptest_func_t`` to be executed by master.
  151. * @param slave_func ``ptest_func_t`` to be executed by slave.
  152. */
  153. #define TEST_MASTER_SLAVE(name, param_group, tag, master_func, slave_func) \
  154. static void PTEST_MASTER_NAME(name) (void) { test_serializer(&PGROUP_NAME(param_group), master_func); } \
  155. static void PTEST_SLAVE_NAME(name) (void) { test_serializer(&PGROUP_NAME(param_group), slave_func); } \
  156. TEST_CASE_MULTIPLE_DEVICES("master slave test: "#name, tag, PTEST_MASTER_NAME(name), PTEST_SLAVE_NAME(name))