object_tc.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /*
  2. * Copyright (c) 2006-2025, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2025-07-18 kurisaW First commit
  9. */
  10. #include <utest.h>
  11. #include <rtthread.h>
  12. #include <string.h>
  13. /**
  14. * @brief Comprehensive test suite for RT-Thread object system
  15. *
  16. * @note This test suite validates:
  17. * 1. Object name handling (truncation, NULL, exact length)
  18. * 2. Static and dynamic object initialization
  19. * 3. Object finding functionality (rt_object_find, rt_thread_find, rt_device_find)
  20. * 4. Object information and enumeration
  21. * 5. Type checking and system object detection
  22. * 6. Memory safety and boundary conditions
  23. */
  24. /* Define TEST_RT_NAME_MAX for testing purposes */
  25. #define TEST_RT_NAME_MAX RT_NAME_MAX
  26. /* Global counter for unique object names */
  27. static rt_uint32_t name_counter = 0;
  28. /* Generate unique name to avoid conflicts, respecting TEST_RT_NAME_MAX */
  29. static rt_err_t generate_unique_name(char *buf, rt_size_t size, const char *prefix)
  30. {
  31. if (!buf || !prefix || size < TEST_RT_NAME_MAX)
  32. return -RT_EINVAL;
  33. for (int i = 0; i < 1000; i++) /* Limit attempts to prevent infinite loop */
  34. {
  35. rt_snprintf(buf, size, "%s%d", prefix, name_counter++);
  36. rt_size_t len = rt_strlen(buf);
  37. if (len >= TEST_RT_NAME_MAX)
  38. {
  39. buf[TEST_RT_NAME_MAX - 1] = '\0';
  40. len = TEST_RT_NAME_MAX - 1;
  41. }
  42. /* Check if name (or truncated name) is unique */
  43. if (rt_object_find(buf, RT_Object_Class_Unknown) == RT_NULL &&
  44. rt_thread_find(buf) == RT_NULL &&
  45. rt_device_find(buf) == RT_NULL)
  46. {
  47. return RT_EOK;
  48. }
  49. }
  50. return -RT_ENOMEM;
  51. }
  52. static void test_object_name_handling(void)
  53. {
  54. struct rt_object static_obj1, static_obj2, static_obj3;
  55. rt_object_t dyn_obj = RT_NULL;
  56. char test_name[TEST_RT_NAME_MAX];
  57. char unique_name[TEST_RT_NAME_MAX];
  58. /* Prepare a test name within TEST_RT_NAME_MAX */
  59. rt_memset(test_name, 'A', TEST_RT_NAME_MAX - 1);
  60. test_name[TEST_RT_NAME_MAX - 1] = '\0';
  61. /* Test 1: Static Object with Name Within TEST_RT_NAME_MAX */
  62. uassert_true(generate_unique_name(unique_name, TEST_RT_NAME_MAX, "long") == RT_EOK);
  63. rt_object_init(&static_obj1, RT_Object_Class_Thread, test_name);
  64. uassert_true(rt_strlen(static_obj1.name) <= TEST_RT_NAME_MAX - 1);
  65. uassert_true(static_obj1.name[TEST_RT_NAME_MAX - 1] == '\0');
  66. uassert_true(rt_strncmp(static_obj1.name, test_name, TEST_RT_NAME_MAX - 1) == 0);
  67. uassert_true(rt_object_is_systemobject(&static_obj1));
  68. rt_object_detach(&static_obj1);
  69. /* Test 2: Dynamic Object with Name Within TEST_RT_NAME_MAX */
  70. uassert_true(generate_unique_name(unique_name, TEST_RT_NAME_MAX, "dyn") == RT_EOK);
  71. dyn_obj = rt_object_allocate(RT_Object_Class_Thread, test_name);
  72. uassert_not_null(dyn_obj);
  73. uassert_true(rt_strlen(dyn_obj->name) <= TEST_RT_NAME_MAX - 1);
  74. uassert_true(dyn_obj->name[TEST_RT_NAME_MAX - 1] == '\0');
  75. uassert_true(rt_strncmp(dyn_obj->name, test_name, TEST_RT_NAME_MAX - 1) == 0);
  76. uassert_false(rt_object_is_systemobject(dyn_obj));
  77. rt_object_delete(dyn_obj);
  78. /* Test 3: NULL Name Handling */
  79. uassert_true(generate_unique_name(unique_name, TEST_RT_NAME_MAX, "null") == RT_EOK);
  80. rt_object_init(&static_obj2, RT_Object_Class_Thread, NULL);
  81. uassert_true(static_obj2.name[0] == '\0');
  82. rt_object_detach(&static_obj2);
  83. uassert_true(generate_unique_name(unique_name, TEST_RT_NAME_MAX, "dynull") == RT_EOK);
  84. dyn_obj = rt_object_allocate(RT_Object_Class_Thread, NULL);
  85. uassert_not_null(dyn_obj);
  86. uassert_true(dyn_obj->name[0] == '\0');
  87. rt_object_delete(dyn_obj);
  88. /* Test 4: Exact Length Name */
  89. char exact_name[TEST_RT_NAME_MAX];
  90. rt_memset(exact_name, 'B', TEST_RT_NAME_MAX - 1);
  91. exact_name[TEST_RT_NAME_MAX - 1] = '\0';
  92. uassert_true(generate_unique_name(unique_name, TEST_RT_NAME_MAX, "exact") == RT_EOK);
  93. rt_object_init(&static_obj3, RT_Object_Class_Thread, exact_name);
  94. uassert_str_equal(static_obj3.name, exact_name);
  95. rt_object_detach(&static_obj3);
  96. }
  97. static void test_object_find_operations(void)
  98. {
  99. rt_object_t found;
  100. rt_thread_t found_thread;
  101. rt_device_t found_device;
  102. char name[TEST_RT_NAME_MAX];
  103. rt_err_t ret;
  104. /* Scenario 1: Object Name Within TEST_RT_NAME_MAX */
  105. /* Test 1.1: Find static thread object with rt_object_find */
  106. struct rt_object static_obj;
  107. uassert_true(generate_unique_name(name, TEST_RT_NAME_MAX, "sobj") == RT_EOK);
  108. rt_object_init(&static_obj, RT_Object_Class_Thread, name);
  109. found = rt_object_find(name, RT_Object_Class_Thread);
  110. uassert_not_null(found);
  111. uassert_ptr_equal(found, &static_obj);
  112. uassert_str_equal(found->name, name);
  113. rt_object_detach(&static_obj);
  114. /* Test 1.2: Find thread object with rt_thread_find */
  115. uassert_true(generate_unique_name(name, TEST_RT_NAME_MAX, "thr") == RT_EOK);
  116. rt_thread_t thread = rt_thread_create(name, RT_NULL, RT_NULL, 1024, 20, 10);
  117. uassert_not_null(thread);
  118. found_thread = rt_thread_find(name);
  119. uassert_not_null(found_thread);
  120. uassert_ptr_equal(found_thread, thread);
  121. uassert_str_equal(found_thread->parent.name, name);
  122. rt_thread_delete(thread);
  123. #ifdef RT_USING_DEVICE
  124. /* Test 1.3: Find device object with rt_device_find */
  125. struct rt_device device;
  126. uassert_true(generate_unique_name(name, TEST_RT_NAME_MAX, "dev") == RT_EOK);
  127. ret = rt_device_register(&device, name, RT_DEVICE_FLAG_RDONLY);
  128. uassert_int_equal(ret, RT_EOK);
  129. found_device = rt_device_find(name);
  130. uassert_not_null(found_device);
  131. uassert_ptr_equal(found_device, &device);
  132. uassert_str_equal(found_device->parent.name, name);
  133. rt_device_unregister(&device);
  134. #endif
  135. /* Test 2: Same Prefix Within TEST_RT_NAME_MAX */
  136. #ifdef RT_USING_DEVICE
  137. struct rt_device dev1, dev2;
  138. char name1[TEST_RT_NAME_MAX] = "norflash1";
  139. char name2[TEST_RT_NAME_MAX] = "norflash2";
  140. ret = rt_device_register(&dev1, name1, RT_DEVICE_FLAG_RDONLY);
  141. uassert_int_equal(ret, RT_EOK);
  142. ret = rt_device_register(&dev2, name2, RT_DEVICE_FLAG_RDONLY);
  143. uassert_int_equal(ret, RT_EOK); /* Expect success if RT-Thread allows distinct names */
  144. found_device = rt_device_find(name1);
  145. uassert_not_null(found_device);
  146. uassert_ptr_equal(found_device, &dev1);
  147. uassert_str_equal(found_device->parent.name, name1);
  148. found_device = rt_device_find(name2);
  149. uassert_not_null(found_device);
  150. uassert_ptr_equal(found_device, &dev2);
  151. uassert_str_equal(found_device->parent.name, name2);
  152. rt_device_unregister(&dev1);
  153. rt_device_unregister(&dev2);
  154. #endif
  155. /* Test 3: Find non-existent object */
  156. const char *nonexist_name = "nonexist";
  157. uassert_true(rt_strlen(nonexist_name) <= TEST_RT_NAME_MAX - 1);
  158. found = rt_object_find(nonexist_name, RT_Object_Class_Thread);
  159. uassert_null(found);
  160. /* Test 4: Find with NULL name */
  161. found = rt_object_find(NULL, RT_Object_Class_Thread);
  162. uassert_null(found);
  163. found_thread = rt_thread_find(NULL);
  164. uassert_null(found_thread);
  165. #ifdef RT_USING_DEVICE
  166. found_device = rt_device_find(NULL);
  167. uassert_null(found_device);
  168. #endif
  169. }
  170. static void test_object_info_enumeration(void)
  171. {
  172. struct rt_object static_objs[3];
  173. rt_object_t dyn_objs[2] = {RT_NULL, RT_NULL};
  174. char names[5][TEST_RT_NAME_MAX];
  175. /* Generate unique names */
  176. for (int i = 0; i < 5; i++)
  177. {
  178. uassert_true(generate_unique_name(names[i], TEST_RT_NAME_MAX, "enum") == RT_EOK);
  179. }
  180. /* Create test objects */
  181. for (int i = 0; i < 3; i++)
  182. {
  183. rt_object_init(&static_objs[i], RT_Object_Class_Thread, names[i]);
  184. }
  185. for (int i = 0; i < 2; i++)
  186. {
  187. dyn_objs[i] = rt_object_allocate(RT_Object_Class_Thread, names[i + 3]);
  188. uassert_not_null(dyn_objs[i]);
  189. }
  190. /* Test 1: Get object information */
  191. struct rt_object_information *info = rt_object_get_information(RT_Object_Class_Thread);
  192. uassert_not_null(info);
  193. uassert_int_equal(info->type, RT_Object_Class_Thread);
  194. /* Test 2: Get object count */
  195. int count = rt_object_get_length(RT_Object_Class_Thread);
  196. uassert_true(count >= 5);
  197. /* Test 3: Get object pointers with sufficient buffer */
  198. rt_object_t *objects = (rt_object_t *)rt_malloc((count + 2) * sizeof(rt_object_t));
  199. uassert_not_null(objects);
  200. int ret = rt_object_get_pointers(RT_Object_Class_Thread, objects, count + 2);
  201. uassert_int_equal(ret, count);
  202. int found_count = 0;
  203. for (int i = 0; i < ret; i++)
  204. {
  205. for (int j = 0; j < 3; j++)
  206. if (objects[i] == &static_objs[j]) found_count++;
  207. for (int j = 0; j < 2; j++)
  208. if (objects[i] == dyn_objs[j]) found_count++;
  209. }
  210. uassert_int_equal(found_count, 5);
  211. rt_free(objects);
  212. /* Test 4: Get object pointers with small buffer */
  213. rt_object_t one_object[1];
  214. ret = rt_object_get_pointers(RT_Object_Class_Thread, one_object, 1);
  215. uassert_true(ret <= 1);
  216. /* Test 5: Empty container (Semaphore) */
  217. #ifdef RT_USING_SEMAPHORE
  218. int empty_count = rt_object_get_length(RT_Object_Class_Semaphore);
  219. uassert_true(empty_count >= 0);
  220. #endif
  221. /* Cleanup */
  222. for (int i = 0; i < 3; i++)
  223. rt_object_detach(&static_objs[i]);
  224. for (int i = 0; i < 2; i++)
  225. if (dyn_objs[i]) rt_object_delete(dyn_objs[i]);
  226. }
  227. static void test_object_type_handling(void)
  228. {
  229. struct rt_object obj;
  230. char name[TEST_RT_NAME_MAX];
  231. uassert_true(generate_unique_name(name, TEST_RT_NAME_MAX, "typ") == RT_EOK);
  232. rt_object_init(&obj, RT_Object_Class_Thread, name);
  233. /* Test 1: Get object type */
  234. uassert_int_equal(rt_object_get_type(&obj), RT_Object_Class_Thread);
  235. /* Test 2: Check system object */
  236. uassert_true(rt_object_is_systemobject(&obj));
  237. /* Test 3: Get name with sufficient buffer */
  238. char name_buf[TEST_RT_NAME_MAX];
  239. rt_err_t ret = rt_object_get_name(&obj, name_buf, sizeof(name_buf));
  240. uassert_int_equal(ret, RT_EOK);
  241. uassert_str_equal(name_buf, name);
  242. /* Test 4: Get name with small buffer */
  243. char small_buf[4] = {0};
  244. ret = rt_object_get_name(&obj, small_buf, sizeof(small_buf));
  245. uassert_int_equal(ret, RT_EOK);
  246. uassert_true(rt_strncmp(small_buf, name, sizeof(small_buf) - 1) == 0);
  247. uassert_true(small_buf[sizeof(small_buf) - 1] == '\0');
  248. /* Test 5: Get name with invalid parameters */
  249. ret = rt_object_get_name(RT_NULL, name_buf, sizeof(name_buf));
  250. uassert_int_equal(ret, -RT_EINVAL);
  251. ret = rt_object_get_name(&obj, NULL, sizeof(name_buf));
  252. uassert_int_equal(ret, -RT_EINVAL);
  253. ret = rt_object_get_name(&obj, name_buf, 0);
  254. uassert_int_equal(ret, -RT_EINVAL);
  255. rt_object_detach(&obj);
  256. }
  257. static rt_err_t testcase_init(void)
  258. {
  259. if (!rt_scheduler_is_available())
  260. {
  261. return -RT_ERROR;
  262. }
  263. name_counter = 0;
  264. return RT_EOK;
  265. }
  266. static rt_err_t testcase_cleanup(void)
  267. {
  268. return RT_EOK;
  269. }
  270. static void test_object_suite(void)
  271. {
  272. #ifdef RT_NAME_MAX < 10
  273. rt_kprintf("Error: Please increase \'RT_NAME_MAX\' to be greater than 10.\n");
  274. return;
  275. #endif
  276. UTEST_UNIT_RUN(test_object_name_handling);
  277. UTEST_UNIT_RUN(test_object_find_operations);
  278. UTEST_UNIT_RUN(test_object_info_enumeration);
  279. UTEST_UNIT_RUN(test_object_type_handling);
  280. }
  281. UTEST_TC_EXPORT(test_object_suite, "testcases.kernel.object_test", testcase_init, testcase_cleanup, 20);