test_cronexpr.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. #include <gtest/gtest.h>
  2. #include <assert.h>
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <limits.h>
  7. #include "ccronexpr.h"
  8. #define MAX_SECONDS 60
  9. #define CRON_MAX_MINUTES 60
  10. #define CRON_MAX_HOURS 24
  11. #define CRON_MAX_DAYS_OF_WEEK 8
  12. #define CRON_MAX_DAYS_OF_MONTH 32
  13. #define CRON_MAX_MONTHS 12
  14. #define INVALID_INSTANT ((time_t) -1)
  15. #define DATE_FORMAT "%Y-%m-%d_%H:%M:%S"
  16. #ifndef ARRAY_LEN
  17. #define ARRAY_LEN(x) sizeof(x)/sizeof(x[0])
  18. #endif
  19. #ifdef CRON_TEST_MALLOC
  20. static int cronAllocations = 0;
  21. static int cronTotalAllocations = 0;
  22. static int maxAlloc = 0;
  23. void* cron_malloc(size_t n)
  24. {
  25. cronAllocations++;
  26. cronTotalAllocations++;
  27. if (cronAllocations > maxAlloc) {
  28. maxAlloc = cronAllocations;
  29. }
  30. return malloc(n);
  31. }
  32. void cron_free(void* p)
  33. {
  34. cronAllocations--;
  35. free(p);
  36. }
  37. #endif
  38. #ifndef ANDROID
  39. #ifndef _WIN32
  40. time_t timegm(struct tm* __tp);
  41. #else /* _WIN32 */
  42. static time_t timegm(struct tm* tm)
  43. {
  44. return _mkgmtime(tm);
  45. }
  46. #endif /* _WIN32 */
  47. #else /* ANDROID */
  48. static time_t timegm(struct tm* const t)
  49. {
  50. /* time_t is signed on Android. */
  51. static const time_t kTimeMax = ~(1L << (sizeof(time_t) * CHAR_BIT - 1));
  52. static const time_t kTimeMin = (1L << (sizeof(time_t) * CHAR_BIT - 1));
  53. time64_t result = timegm64(t);
  54. if (result < kTimeMin || result > kTimeMax)
  55. return -1;
  56. return result;
  57. }
  58. #endif
  59. static int crons_equal(cron_expr* cr1, cron_expr* cr2)
  60. {
  61. unsigned int i;
  62. for (i = 0; i < ARRAY_LEN(cr1->seconds); i++) {
  63. if (cr1->seconds[i] != cr2->seconds[i]) {
  64. printf("seconds not equal @%d %02x != %02x", i, cr1->seconds[i], cr2->seconds[i]);
  65. return 0;
  66. }
  67. }
  68. for (i = 0; i < ARRAY_LEN(cr1->minutes); i++) {
  69. if (cr1->minutes[i] != cr2->minutes[i]) {
  70. printf("minutes not equal @%d %02x != %02x", i, cr1->minutes[i], cr2->minutes[i]);
  71. return 0;
  72. }
  73. }
  74. for (i = 0; i < ARRAY_LEN(cr1->hours); i++) {
  75. if (cr1->hours[i] != cr2->hours[i]) {
  76. printf("hours not equal @%d %02x != %02x", i, cr1->hours[i], cr2->hours[i]);
  77. return 0;
  78. }
  79. }
  80. for (i = 0; i < ARRAY_LEN(cr1->days_of_week); i++) {
  81. if (cr1->days_of_week[i] != cr2->days_of_week[i]) {
  82. printf("days_of_week not equal @%d %02x != %02x", i, cr1->days_of_week[i], cr2->days_of_week[i]);
  83. return 0;
  84. }
  85. }
  86. for (i = 0; i < ARRAY_LEN(cr1->days_of_month); i++) {
  87. if (cr1->days_of_month[i] != cr2->days_of_month[i]) {
  88. printf("days_of_month not equal @%d %02x != %02x", i, cr1->days_of_month[i], cr2->days_of_month[i]);
  89. return 0;
  90. }
  91. }
  92. for (i = 0; i < ARRAY_LEN(cr1->months); i++) {
  93. if (cr1->months[i] != cr2->months[i]) {
  94. printf("months not equal @%d %02x != %02x", i, cr1->months[i], cr2->months[i]);
  95. return 0;
  96. }
  97. }
  98. return 1;
  99. }
  100. int one_dec_num(const char ch)
  101. {
  102. switch (ch) {
  103. case '0':
  104. return 0;
  105. case '1':
  106. return 1;
  107. case '2':
  108. return 2;
  109. case '3':
  110. return 3;
  111. case '4':
  112. return 4;
  113. case '5':
  114. return 5;
  115. case '6':
  116. return 6;
  117. case '7':
  118. return 7;
  119. case '8':
  120. return 8;
  121. case '9':
  122. return 9;
  123. default:
  124. return -1;
  125. }
  126. }
  127. int two_dec_num(const char* first)
  128. {
  129. return one_dec_num(first[0]) * 10 + one_dec_num(first[1]);
  130. }
  131. int four_dec_num(const char* first)
  132. {
  133. return ((one_dec_num(first[0]) * 1000)
  134. + (one_dec_num(first[1]) * 100)
  135. + (one_dec_num(first[2]) * 10)
  136. + (one_dec_num(first[3]) * 1));
  137. }
  138. /* strptime is not available in msvc */
  139. /* 2012-07-01_09:53:50 */
  140. /* 0123456789012345678 */
  141. struct tm* poors_mans_strptime(const char* str)
  142. {
  143. struct tm* cal = (struct tm*)malloc(sizeof(struct tm));
  144. assert(cal != NULL);
  145. memset(cal, 0, sizeof(struct tm));
  146. cal->tm_year = four_dec_num(str) - 1900;
  147. cal->tm_mon = two_dec_num(str + 5) - 1;
  148. cal->tm_mday = two_dec_num(str + 8);
  149. cal->tm_wday = 0;
  150. cal->tm_yday = 0;
  151. cal->tm_hour = two_dec_num(str + 11);
  152. cal->tm_min = two_dec_num(str + 14);
  153. cal->tm_sec = two_dec_num(str + 17);
  154. return cal;
  155. }
  156. void check_next(const char* pattern, const char* initial, const char* expected)
  157. {
  158. const char* err = NULL;
  159. cron_expr parsed;
  160. cron_parse_expr(pattern, &parsed, &err);
  161. struct tm* calinit = poors_mans_strptime(initial);
  162. #ifdef CRON_USE_LOCAL_TIME
  163. time_t dateinit = mktime(calinit);
  164. #else
  165. time_t dateinit = timegm(calinit);
  166. #endif
  167. assert(-1 != dateinit);
  168. time_t datenext = cron_next(&parsed, dateinit);
  169. #ifdef CRON_USE_LOCAL_TIME
  170. struct tm* calnext = localtime(&datenext);
  171. #else
  172. struct tm* calnext = gmtime(&datenext);
  173. #endif
  174. assert(calnext);
  175. char* buffer = (char*)malloc(21);
  176. memset(buffer, 0, 21);
  177. strftime(buffer, 20, DATE_FORMAT, calnext);
  178. if (0 != strcmp(expected, buffer)) {
  179. printf("Pattern: %s\n", pattern);
  180. printf("Initial: %s\n", initial);
  181. printf("Expected: %s\n", expected);
  182. printf("Actual: %s\n", buffer);
  183. assert(0);
  184. }
  185. free(buffer);
  186. free(calinit);
  187. }
  188. void check_same(const char* expr1, const char* expr2)
  189. {
  190. cron_expr parsed1;
  191. cron_parse_expr(expr1, &parsed1, NULL);
  192. cron_expr parsed2;
  193. cron_parse_expr(expr2, &parsed2, NULL);
  194. assert(crons_equal(&parsed1, &parsed2));
  195. }
  196. void check_calc_invalid()
  197. {
  198. cron_expr parsed;
  199. cron_parse_expr("0 0 0 31 6 *", &parsed, NULL);
  200. struct tm* calinit = poors_mans_strptime("2012-07-01_09:53:50");
  201. time_t dateinit = timegm(calinit);
  202. time_t res = cron_next(&parsed, dateinit);
  203. assert(INVALID_INSTANT == res);
  204. free(calinit);
  205. }
  206. void check_expr_invalid(const char* expr)
  207. {
  208. const char* err = NULL;
  209. cron_expr test;
  210. cron_parse_expr(expr, &test, &err);
  211. assert(err);
  212. }
  213. void test_expr()
  214. {
  215. #ifdef CRON_USE_LOCAL_TIME
  216. check_next("* 15 11 * * *", "2019-03-09_11:43:00", "2019-03-10_11:15:00");
  217. #else
  218. check_next("*/15 * 1-4 * * *", "2012-07-01_09:53:50", "2012-07-02_01:00:00");
  219. check_next("*/15 * 1-4 * * *", "2012-07-01_09:53:00", "2012-07-02_01:00:00");
  220. check_next("0 */2 1-4 * * *", "2012-07-01_09:00:00", "2012-07-02_01:00:00");
  221. check_next("0 */2 * * * *", "2012-07-01_09:00:00", "2012-07-01_09:02:00");
  222. check_next("0 */2 * * * *", "2013-07-01_09:00:00", "2013-07-01_09:02:00");
  223. check_next("0 */2 * * * *", "2018-09-14_14:24:00", "2018-09-14_14:26:00");
  224. check_next("0 */2 * * * *", "2018-09-14_14:25:00", "2018-09-14_14:26:00");
  225. check_next("0 */20 * * * *", "2018-09-14_14:24:00", "2018-09-14_14:40:00");
  226. check_next("* * * * * *", "2012-07-01_09:00:00", "2012-07-01_09:00:01");
  227. check_next("* * * * * *", "2012-12-01_09:00:58", "2012-12-01_09:00:59");
  228. check_next("10 * * * * *", "2012-12-01_09:42:09", "2012-12-01_09:42:10");
  229. check_next("11 * * * * *", "2012-12-01_09:42:10", "2012-12-01_09:42:11");
  230. check_next("10 * * * * *", "2012-12-01_09:42:10", "2012-12-01_09:43:10");
  231. check_next("10-15 * * * * *", "2012-12-01_09:42:09", "2012-12-01_09:42:10");
  232. check_next("10-15 * * * * *", "2012-12-01_21:42:14", "2012-12-01_21:42:15");
  233. check_next("0 * * * * *", "2012-12-01_21:10:42", "2012-12-01_21:11:00");
  234. check_next("0 * * * * *", "2012-12-01_21:11:00", "2012-12-01_21:12:00");
  235. check_next("0 11 * * * *", "2012-12-01_21:10:42", "2012-12-01_21:11:00");
  236. check_next("0 10 * * * *", "2012-12-01_21:11:00", "2012-12-01_22:10:00");
  237. check_next("0 0 * * * *", "2012-09-30_11:01:00", "2012-09-30_12:00:00");
  238. check_next("0 0 * * * *", "2012-09-30_12:00:00", "2012-09-30_13:00:00");
  239. check_next("0 0 * * * *", "2012-09-10_23:01:00", "2012-09-11_00:00:00");
  240. check_next("0 0 * * * *", "2012-09-11_00:00:00", "2012-09-11_01:00:00");
  241. check_next("0 0 0 * * *", "2012-09-01_14:42:43", "2012-09-02_00:00:00");
  242. check_next("0 0 0 * * *", "2012-09-02_00:00:00", "2012-09-03_00:00:00");
  243. check_next("* * * 10 * *", "2012-10-09_15:12:42", "2012-10-10_00:00:00");
  244. check_next("* * * 10 * *", "2012-10-11_15:12:42", "2012-11-10_00:00:00");
  245. check_next("0 0 0 * * *", "2012-09-30_15:12:42", "2012-10-01_00:00:00");
  246. check_next("0 0 0 * * *", "2012-10-01_00:00:00", "2012-10-02_00:00:00");
  247. check_next("0 0 0 * * *", "2012-08-30_15:12:42", "2012-08-31_00:00:00");
  248. check_next("0 0 0 * * *", "2012-08-31_00:00:00", "2012-09-01_00:00:00");
  249. check_next("0 0 0 * * *", "2012-10-30_15:12:42", "2012-10-31_00:00:00");
  250. check_next("0 0 0 * * *", "2012-10-31_00:00:00", "2012-11-01_00:00:00");
  251. check_next("0 0 0 1 * *", "2012-10-30_15:12:42", "2012-11-01_00:00:00");
  252. check_next("0 0 0 1 * *", "2012-11-01_00:00:00", "2012-12-01_00:00:00");
  253. check_next("0 0 0 1 * *", "2010-12-31_15:12:42", "2011-01-01_00:00:00");
  254. check_next("0 0 0 1 * *", "2011-01-01_00:00:00", "2011-02-01_00:00:00");
  255. check_next("0 0 0 31 * *", "2011-10-30_15:12:42", "2011-10-31_00:00:00");
  256. check_next("0 0 0 1 * *", "2011-10-30_15:12:42", "2011-11-01_00:00:00");
  257. check_next("* * * * * 2", "2010-10-25_15:12:42", "2010-10-26_00:00:00");
  258. check_next("* * * * * 2", "2010-10-20_15:12:42", "2010-10-26_00:00:00");
  259. check_next("* * * * * 2", "2010-10-27_15:12:42", "2010-11-02_00:00:00");
  260. check_next("55 5 * * * *", "2010-10-27_15:04:54", "2010-10-27_15:05:55");
  261. check_next("55 5 * * * *", "2010-10-27_15:05:55", "2010-10-27_16:05:55");
  262. check_next("55 * 10 * * *", "2010-10-27_09:04:54", "2010-10-27_10:00:55");
  263. check_next("55 * 10 * * *", "2010-10-27_10:00:55", "2010-10-27_10:01:55");
  264. check_next("* 5 10 * * *", "2010-10-27_09:04:55", "2010-10-27_10:05:00");
  265. check_next("* 5 10 * * *", "2010-10-27_10:05:00", "2010-10-27_10:05:01");
  266. check_next("55 * * 3 * *", "2010-10-02_10:05:54", "2010-10-03_00:00:55");
  267. check_next("55 * * 3 * *", "2010-10-03_00:00:55", "2010-10-03_00:01:55");
  268. check_next("* * * 3 11 *", "2010-10-02_14:42:55", "2010-11-03_00:00:00");
  269. check_next("* * * 3 11 *", "2010-11-03_00:00:00", "2010-11-03_00:00:01");
  270. check_next("0 0 0 29 2 *", "2007-02-10_14:42:55", "2008-02-29_00:00:00");
  271. check_next("0 0 0 29 2 *", "2008-02-29_00:00:00", "2012-02-29_00:00:00");
  272. check_next("0 0 7 ? * MON-FRI", "2009-09-26_00:42:55", "2009-09-28_07:00:00");
  273. check_next("0 0 7 ? * MON-FRI", "2009-09-28_07:00:00", "2009-09-29_07:00:00");
  274. check_next("0 30 23 30 1/3 ?", "2010-12-30_00:00:00", "2011-01-30_23:30:00");
  275. check_next("0 30 23 30 1/3 ?", "2011-01-30_23:30:00", "2011-04-30_23:30:00");
  276. check_next("0 30 23 30 1/3 ?", "2011-04-30_23:30:00", "2011-07-30_23:30:00");
  277. #endif
  278. }
  279. void test_parse()
  280. {
  281. check_same("* * * 2 * *", "* * * 2 * ?");
  282. check_same("57,59 * * * * *", "57/2 * * * * *");
  283. check_same("1,3,5 * * * * *", "1-6/2 * * * * *");
  284. check_same("* * 4,8,12,16,20 * * *", "* * 4/4 * * *");
  285. check_same("* * * * * 0-6", "* * * * * TUE,WED,THU,FRI,SAT,SUN,MON");
  286. check_same("* * * * * 0", "* * * * * SUN");
  287. check_same("* * * * * 0", "* * * * * 7");
  288. check_same("* * * * 1-12 *", "* * * * FEB,JAN,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC *");
  289. check_same("* * * * 2 *", "* * * * Feb *");
  290. check_same("* * * * 1 *", "* * * * 1 *");
  291. check_expr_invalid("77 * * * * *");
  292. check_expr_invalid("44-77 * * * * *");
  293. check_expr_invalid("* 77 * * * *");
  294. check_expr_invalid("* 44-77 * * * *");
  295. check_expr_invalid("* * 27 * * *");
  296. check_expr_invalid("* * 23-28 * * *");
  297. check_expr_invalid("* * * 45 * *");
  298. check_expr_invalid("* * * 28-45 * *");
  299. check_expr_invalid("0 0 0 25 13 ?");
  300. check_expr_invalid("0 0 0 25 0 ?");
  301. check_expr_invalid("0 0 0 32 12 ?");
  302. check_expr_invalid("* * * * 11-13 *");
  303. check_expr_invalid("-5 * * * * *");
  304. check_expr_invalid("3-2 */5 * * * *");
  305. check_expr_invalid("/5 * * * * *");
  306. check_expr_invalid("*/0 * * * * *");
  307. check_expr_invalid("*/-0 * * * * *");
  308. check_expr_invalid("* 1 1 0 * *");
  309. }
  310. void test_bits()
  311. {
  312. uint8_t testbyte[8];
  313. memset(testbyte, 0, 8);
  314. int err = 0;
  315. int i;
  316. for (i = 0; i <= 63; i++) {
  317. cron_set_bit(testbyte, i);
  318. if (!cron_get_bit(testbyte, i)) {
  319. printf("Bit set error! Bit: %d!\n", i);
  320. err = 1;
  321. }
  322. cron_del_bit(testbyte, i);
  323. if (cron_get_bit(testbyte, i)) {
  324. printf("Bit clear error! Bit: %d!\n", i);
  325. err = 1;
  326. }
  327. assert(!err);
  328. }
  329. for (i = 0; i < 12; i++) {
  330. cron_set_bit(testbyte, i);
  331. }
  332. if (testbyte[0] != 0xff) {
  333. err = 1;
  334. }
  335. if (testbyte[1] != 0x0f) {
  336. err = 1;
  337. }
  338. assert(!err);
  339. }
  340. /* For this test to work you need to set "-DCRON_TEST_MALLOC=1"*/
  341. #ifdef CRON_TEST_MALLOC
  342. void test_memory()
  343. {
  344. cron_expr cron;
  345. const char* err;
  346. cron_parse_expr("* * * * * *", &cron, &err);
  347. if (cronAllocations != 0) {
  348. printf("Allocations != 0 but %d", cronAllocations);
  349. assert(0);
  350. }
  351. printf("Allocations: total: %d, max: %d", cronTotalAllocations, maxAlloc);
  352. }
  353. #endif
  354. int main()
  355. {
  356. test_bits();
  357. test_expr();
  358. test_parse();
  359. check_calc_invalid();
  360. #ifdef CRON_TEST_MALLOC
  361. test_memory(); /* For this test to work you need to set "-DCRON_TEST_MALLOC=1"*/
  362. #endif
  363. printf("\nAll OK!\n");
  364. return 0;
  365. }