1606480958.v7-7-gc71df1d.add-tests-for-key-manipulation-functions.patch 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. Subject: Add tests for key manipulation functions
  2. Origin: v7-7-gc71df1d <https://github.com/latchset/tang/commit/v7-7-gc71df1d>
  3. Upstream-Author: Sergio Correia <scorreia@redhat.com>
  4. Date: Fri Nov 27 09:42:38 2020 -0300
  5. In this commit we add tests for the key manipulation functions added in
  6. src/keys.{c|h}.
  7. --- /dev/null
  8. +++ b/tests/keys/-bWkGaJi0Zdvxaj4DCp28umLcRA.jwk
  9. @@ -0,0 +1 @@
  10. +{"alg":"ECMR","crv":"P-521","d":"AQ3u1g0L__GIGSJRX1LtjSArwJxxQz0kWXIi-X4PqwoheoeY57cw36pmWmyVsn43jDEZ6SAsiNeIw9sHDkFZe1VV","key_ops":["deriveKey"],"kty":"EC","x":"AcfowrKEKteg_jKX1CiR2RQfbUGJ73KXlcl8AgIDAgN7R6yNKWpKhZNBmV2tAxxMCQcIksqQl17UXwemvH2j2fem","y":"ACrb-y4ZhLIGX-41QYgJhniiZ85qkjILbkVUcC8gBYxOAnKWIpMGLsjrT3AYhM6jk6puwnNYbEM28s2caAEogUcA"}
  11. --- /dev/null
  12. +++ b/tests/keys/.r4E2wG1u_YyKUo0N0rIK7jJF5Xg.jwk
  13. @@ -0,0 +1 @@
  14. +{"alg":"ES512","crv":"P-521","d":"Af5SfYh_4LmBDF9dCGDQRDA52yzqnzDeo-GZU05hpnLr6bsIBTFpc8rdcCm95mhZ59ngC-6WNtmAF_nLCDcHKg0A","key_ops":["sign","verify"],"kty":"EC","x":"AUxS3DXdoONUB-6-nyzdd3V42iD7obGTJ1m40t3V6jzXfABWp_gtTidwiKyDJQXxhEzMSToo-V0RGq6Qz2XTOgPe","y":"AFrkJfkLGJz_2v-k3-wdydckVcBXql2NR66HaF0U9NlcfGLezQau7XihArm4GE3-sHoQLsRa-HvYET9zyd9Syh5y"}
  15. --- /dev/null
  16. +++ b/tests/keys/.uZ0s8YTXcGcuWduWWBSiR2OjOVg.jwk
  17. @@ -0,0 +1 @@
  18. +{"alg":"ECMR","crv":"P-521","d":"Acuk66sHvSS5TN-p0XhwHhVKyifYr-ecur-7zfgQZMzSq9SeBJjuX6Ttav-7AbnVvXU_S55BgtGL5iymXGuMguCp","key_ops":["deriveKey"],"kty":"EC","x":"AEz9EwBOIrLeV4in6M1oWVnOWVR7ubkFB0R0-AwyIL7u5-7G3u2tvPIJRQY-l1Wttn7Ar4DhflcMhnb3rk5hT5yh","y":"AZt35wqOhNsnEi-GLAgyCaiW_c6h6Zyo4xwjuvXzmQMDwh9MtdaUigFuBOTlfRj1uri_YBqdpI09nYrqqgx97Ca6"}
  19. --- /dev/null
  20. +++ b/tests/keys/another-bad-file
  21. @@ -0,0 +1 @@
  22. +foobar
  23. --- /dev/null
  24. +++ b/tests/keys/invalid.jwk
  25. @@ -0,0 +1 @@
  26. +foo
  27. --- /dev/null
  28. +++ b/tests/keys/qgmqJSo6AEEuVQY7zVlklqdTMqY.jwk
  29. @@ -0,0 +1 @@
  30. +{"alg":"ES512","crv":"P-521","d":"AUQpuWtoSqURl0OuWQ-I9i4X1F3sDak0Hbf9Ixj7uwjA20A0ABJdCHbai1Ai0t3yoxWKPYi6t2XjjeRzHIKyhXbf","key_ops":["sign","verify"],"kty":"EC","x":"ACbYnvh1EtLePkM5jCtuxLpMroOUNRfv-wQdXgT5AQ5bhSLv6wkrBzh1rwymo-fmCNWzrcTflzqWf-wXAd00lokM","y":"AEaDByxXfbee4TlPXgPRg5S4MVOqgObjX6_JJkySTudSfOygcx7dujsf32dOEI25d8bNKUgdjQt8lc5XtHeWXH3a"}
  31. --- a/tests/meson.build
  32. +++ b/tests/meson.build
  33. @@ -1,22 +1,42 @@
  34. +incdir = include_directories(
  35. + join_paths('..', 'src')
  36. +)
  37. +
  38. +test_data = configuration_data()
  39. +test_data.set('testjwkdir', join_paths(meson.source_root(), 'tests','keys'))
  40. +
  41. +test_keys_c = configure_file(
  42. + input: 'test-keys.c.in',
  43. + output: 'test-keys.c',
  44. + configuration: test_data
  45. +)
  46. +
  47. +test_keys = executable('test-keys',
  48. + test_keys_c,
  49. + 'test-util.c',
  50. + dependencies: [jose],
  51. + include_directories: incdir
  52. +)
  53. +
  54. sd_activate = find_program(
  55. 'systemd-socket-activate',
  56. 'systemd-activate',
  57. required: false
  58. )
  59. +env = environment()
  60. +env.prepend('PATH',
  61. + join_paths(meson.source_root(), 'src'),
  62. + join_paths(meson.build_root(), 'src'),
  63. + separator: ':'
  64. +)
  65. +
  66. if sd_activate.found()
  67. - env = environment()
  68. - env.prepend('PATH',
  69. - join_paths(meson.source_root(), 'src'),
  70. - join_paths(meson.build_root(), 'src'),
  71. - separator: ':'
  72. - )
  73. env.set('SD_ACTIVATE', sd_activate.path() + ' --inetd')
  74. - test('adv', find_program('adv'), env: env)
  75. + test('adv', find_program('adv'), env: env, timeout: 60)
  76. test('rec', find_program('rec'), env: env)
  77. -else
  78. - warning('Will not run the tests due to missing dependencies!')
  79. endif
  80. +test('test-keys', test_keys, env: env, timeout: 60)
  81. # vim:set ts=2 sw=2 et:
  82. --- /dev/null
  83. +++ b/tests/test-keys.c.in
  84. @@ -0,0 +1,257 @@
  85. +/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
  86. +/*
  87. + * Copyright (c) 2020 Red Hat, Inc.
  88. + * Author: Sergio Correia <scorreia@redhat.com>
  89. + *
  90. + * This program is free software: you can redistribute it and/or modify
  91. + * it under the terms of the GNU General Public License as published by
  92. + * the Free Software Foundation, either version 3 of the License, or
  93. + * (at your option) any later version.
  94. + *
  95. + * This program is distributed in the hope that it will be useful,
  96. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  97. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  98. + * GNU General Public License for more details.
  99. + *
  100. + * You should have received a copy of the GNU General Public License
  101. + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  102. + */
  103. +
  104. +#include "keys.c"
  105. +#include "test-util.h"
  106. +
  107. +const char* jwkdir = "@testjwkdir@";
  108. +
  109. +struct thp_result {
  110. + const char* thp;
  111. + int valid;
  112. +};
  113. +
  114. +struct test_result_int {
  115. + const char* data;
  116. + int expected;
  117. +};
  118. +
  119. +static void
  120. +test_create_new_keys(void)
  121. +{
  122. + __attribute__((cleanup(cleanup_str))) char* newdir = create_tempdir();
  123. + ASSERT(newdir);
  124. + __attribute__((cleanup(cleanup_tang_keys_info))) struct tang_keys_info* tki = read_keys(newdir);
  125. + ASSERT(tki);
  126. + ASSERT(tki->m_keys_count == 2);
  127. + remove_tempdir(newdir);
  128. +}
  129. +
  130. +
  131. +static void
  132. +test_is_hash(void)
  133. +{
  134. + const struct test_result_int test_data[] = {
  135. + {NULL, 0},
  136. + {"", 0},
  137. + {"ES512", 0},
  138. + {"ECMR", 0},
  139. + {"foobar", 0},
  140. + {"{", 0},
  141. + {"[}", 0},
  142. + {"[]", 0},
  143. + {"S1", 1},
  144. + {"S224", 1},
  145. + {"S256", 1},
  146. + {"S384", 1},
  147. + {"S512", 1},
  148. + {"S42", 0}
  149. + };
  150. + for (int i = 0, len = ARRAY_COUNT(test_data); i < len; i++) {
  151. + int ret = is_hash(test_data[i].data);
  152. + ASSERT_WITH_MSG(ret == test_data[i].expected, "i = %d, alg = %s", i, test_data[i].data);
  153. + };
  154. +
  155. +}
  156. +
  157. +static void
  158. +test_jwk_generate(void)
  159. +{
  160. + const struct test_result_int test_data[] = {
  161. + {NULL, 0},
  162. + {"", 0},
  163. + {"ES512", 1},
  164. + {"ECMR", 1},
  165. + {"foobar", 0},
  166. + {"{", 0},
  167. + {"[}", 0},
  168. + {"[]", 0}
  169. + };
  170. +
  171. + for (int i = 0, len = ARRAY_COUNT(test_data); i < len; i++) {
  172. + json_auto_t* jwk = jwk_generate(test_data[i].data);
  173. + ASSERT_WITH_MSG(!!jwk == test_data[i].expected, "i = %d, alg = %s", i, test_data[i].data);
  174. + };
  175. +}
  176. +
  177. +static void
  178. +test_find_jws(void)
  179. +{
  180. + const struct thp_result test_data[] = {
  181. + {"00BUQM4A7NYxbOrBR9QDfkzGVGj3k57Fs4jCbJxcLYAgRFHu5B7jtbL97x1T7stQ", 1},
  182. + {"dd5qbN1lQ6UWdZszbfx2oIcH34ShklzFL1SUQg", 1},
  183. + {"dOZkUtZ_gLDUP53GIlyAxHMNuyrk8vdY-XXND32GccqNbT_MKpqGC-13-GNEye48", 1},
  184. + {"DZrlBQvfvlwPQlvH_IieBdc_KpesEramLygVL_rFr7g", 1},
  185. + {"FL_Zt5fFadUL4syeMMpUnss8aKdCrPGFy3102JGR3EE", 1},
  186. + {"qgmqJSo6AEEuVQY7zVlklqdTMqY", 1},
  187. + {"r4E2wG1u_YyKUo0N0rIK7jJF5Xg", 1},
  188. + {"ugJ4Ula-YABQIiJ-0g3B_jpFpF2nl3W-DNpfLdXArhTusV0QCcd1vtgDeGHEPzpm7jEsyC7VYYSSOkZicK22mw", 1},
  189. + {"up0Z4fRhpd4O5QwBaMCXDTlrvxCmZacU0MD8kw", 1},
  190. + {"vllHS-M0aQFCo2yUCcAahMU4TAtXACyeuRf-zbmmTPBg7V0Pb-RRFGo5C6MnpzdirK8B3ORLOsN8RyXClvtjxA", 1},
  191. + {NULL, 1},
  192. + {"a", 0},
  193. + {"foo", 0},
  194. + {"bar", 0},
  195. + {"XXXXXXXXXXXXXXXXXX", 0}
  196. + };
  197. +
  198. + __attribute__((cleanup(cleanup_tang_keys_info))) struct tang_keys_info* tki = read_keys(jwkdir);
  199. + for (int i = 0, len = ARRAY_COUNT(test_data); i < len; i++) {
  200. + json_auto_t* jws = find_jws(tki, test_data[i].thp);
  201. + ASSERT_WITH_MSG(!!jws == test_data[i].valid, "i = %d, thp = %s", i, test_data[i].thp);
  202. + }
  203. +
  204. + /* Passing NULL to find_jws should return the default advertisement */
  205. + json_auto_t* adv = find_jws(tki, NULL);
  206. + ASSERT(adv);
  207. +
  208. +
  209. + /*
  210. + * The default set of signing keys are the signing keys that are not
  211. + * rotated. The payload is made of deriving keys that are also not
  212. + * rotated. The default advertisement should be signed by this set of
  213. + * default signing keys.
  214. + */
  215. + ASSERT(jose_jws_ver(NULL, adv, NULL, tki->m_sign, 1));
  216. +
  217. + /* find_jws should be able to respond to thumbprints of keys using any
  218. + * of jose supported hash algorithms. */
  219. + const char** hashes = supported_hashes();
  220. + size_t idx;
  221. + json_t* jwk;
  222. +
  223. + /* Let's put together all the keys, including rotated ones. */
  224. + json_auto_t* keys = json_deep_copy(tki->m_keys);
  225. + ASSERT(keys);
  226. + ASSERT(json_array_extend(keys, tki->m_rotated_keys) == 0);
  227. + ASSERT(json_array_size(keys) == (size_t)tki->m_keys_count);
  228. +
  229. + for (int i = 0; hashes[i]; i++) {
  230. + json_array_foreach(keys, idx, jwk) {
  231. + if (!jwk_valid_for_signing(jwk)) {
  232. + continue;
  233. + }
  234. + __attribute__((cleanup(cleanup_str))) char* thp = jwk_thumbprint(jwk, hashes[i]);
  235. + ASSERT_WITH_MSG(thp, "i = %d, hash = %s, key idx = %d", i, hashes[i], idx);
  236. + json_auto_t* jws = find_jws(tki, thp);
  237. + ASSERT_WITH_MSG(jws, "i = %d, hash = %s, key idx = %d, thp = %s", i, hashes[i], idx, thp);
  238. +
  239. + /* Signing keys should sign the payload, in addition to the
  240. + * default set of signing keys. */
  241. + json_auto_t* sign = json_deep_copy(tki->m_sign);
  242. + ASSERT_WITH_MSG(sign, "i = %d, hash = %s, key idx = %d, thp = %s", i, hashes[i], idx, thp);
  243. + ASSERT_WITH_MSG(json_array_append(sign, jwk) == 0, "i = %d, hash = %s, key idx = %d, thp = %s", i, hashes[i], idx, thp);
  244. + ASSERT_WITH_MSG(jose_jws_ver(NULL, jws, NULL, sign, 1), "i = %d, hash = %s, key idx = %d, thp = %s", i, hashes[i], idx, thp);
  245. + }
  246. + }
  247. +}
  248. +
  249. +static void
  250. +test_find_jwk(void)
  251. +{
  252. + const struct thp_result test_data[] = {
  253. + {"1HdF3XKRSsuZdkpXNurBPoL_pvxdvCOlHuhB4DP-4xWFqbZ51zo29kR4fSiT3BGy9UrHVJ26JMBLOA1vKq3lxA", 1},
  254. + {"9U8qgy_YjyY6Isuq6QuiKEiYZgNJShcGgJx5FJzCu6m3N6zFaIPy_HDkxkVqAZ9E", 1},
  255. + {"-bWkGaJi0Zdvxaj4DCp28umLcRA", 1},
  256. + {"Cy73glFjs6B6RU7wy6vWxAc-2bJy5VJOT9LyK80eKgZ8k27wXZ-3rjsuNU5tua_yHWtluyoSYtjoKXfI0E8ESw", 1},
  257. + {"kfjbqx_b3BsgPC87HwlOWL9daGMMHBzxcFLClw", 1},
  258. + {"L4xg2tZXTEVbsK39bzOZM1jGWn3HtOxF5gh6F9YVf5Q", 1},
  259. + {"LsVAV2ig5LlfstM8TRSf-c7IAkLpNYbIysNuRCVlxocRCGqAh6-f9PklM4nU4N-J", 1},
  260. + {"OkAcDxYHNlo7-tul8OubYuWXB8CPEhAkcacCmhTclMU", 1},
  261. + {"uZ0s8YTXcGcuWduWWBSiR2OjOVg", 1},
  262. + {"WEpfFyeoNKkE2-TosN_bP-gd9UgRvQCZpVasZQ", 1},
  263. + {NULL, 0},
  264. + {"a", 0},
  265. + {"foo", 0},
  266. + {"bar", 0},
  267. + {"XXXXXXXXXXXXXXXXXX", 0},
  268. + };
  269. +
  270. + __attribute__((cleanup(cleanup_tang_keys_info))) struct tang_keys_info* tki = read_keys(jwkdir);
  271. +
  272. + for (int i = 0, len = ARRAY_COUNT(test_data); i < len; i++) {
  273. + json_auto_t* tjwk = find_jwk(tki, test_data[i].thp);
  274. + ASSERT_WITH_MSG(!!tjwk == test_data[i].valid, "i = %d, thp = %s", i, test_data[i].thp);
  275. + }
  276. + /* Passing NULL to find_jwk should fail */
  277. + json_auto_t* bad_jwk = find_jwk(tki, NULL);
  278. + ASSERT(bad_jwk == NULL);
  279. +
  280. + /* find_jwk should be able to respond to thumbprints of keys using any
  281. + * of jose supported hash algorithms. */
  282. + const char** hashes = supported_hashes();
  283. + size_t idx;
  284. + json_t* jwk;
  285. +
  286. + /* Let's put together all the keys, including rotated ones. */
  287. + json_auto_t* keys = json_deep_copy(tki->m_keys);
  288. + ASSERT(keys);
  289. + ASSERT(json_array_extend(keys, tki->m_rotated_keys) == 0);
  290. + ASSERT(json_array_size(keys) == (size_t)tki->m_keys_count);
  291. +
  292. + for (int i = 0; hashes[i]; i++) {
  293. + json_array_foreach(keys, idx, jwk) {
  294. + if (!jwk_valid_for_deriving_keys(jwk)) {
  295. + continue;
  296. + }
  297. + __attribute__((cleanup(cleanup_str))) char* thp = jwk_thumbprint(jwk, hashes[i]);
  298. + json_auto_t* tjwk = find_jwk(tki, thp);
  299. + ASSERT_WITH_MSG(tjwk, "i = %d, hash = %s, key idx = %d, thp = %s", i, hashes[i], idx, thp);
  300. + }
  301. + }
  302. +}
  303. +
  304. +static void
  305. +test_read_keys(void)
  306. +{
  307. + __attribute__((cleanup(cleanup_tang_keys_info))) struct tang_keys_info* tki = read_keys(jwkdir);
  308. + ASSERT(tki);
  309. +
  310. + /*
  311. + * Keys in tests/keys:
  312. + * - .uZ0s8YTXcGcuWduWWBSiR2OjOVg.jwk
  313. + * - .r4E2wG1u_YyKUo0N0rIK7jJF5Xg.jwk
  314. + * - qgmqJSo6AEEuVQY7zVlklqdTMqY.jwk
  315. + * - -bWkGaJi0Zdvxaj4DCp28umLcRA.jwk
  316. + */
  317. + ASSERT(tki->m_keys_count == 4);
  318. + ASSERT(json_array_size(tki->m_keys) == 2);
  319. + ASSERT(json_array_size(tki->m_rotated_keys) == 2);
  320. +
  321. + const char* invalid_jwkdir = "foobar";
  322. + __attribute__((cleanup(cleanup_tang_keys_info))) struct tang_keys_info* tki2 = read_keys(invalid_jwkdir);
  323. + ASSERT(tki2 == NULL);
  324. +}
  325. +
  326. +static void
  327. +run_tests(void)
  328. +{
  329. + test_read_keys();
  330. + test_find_jwk();
  331. + test_find_jws();
  332. + test_jwk_generate();
  333. + test_is_hash();
  334. + test_create_new_keys();
  335. +}
  336. +
  337. +int main(int argc, char** argv)
  338. +{
  339. + run_tests();
  340. + return 0;
  341. +}
  342. --- /dev/null
  343. +++ b/tests/test-util.c
  344. @@ -0,0 +1,75 @@
  345. +/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
  346. +/*
  347. + * Copyright (c) 2020 Red Hat, Inc.
  348. + * Author: Sergio Correia <scorreia@redhat.com>
  349. + *
  350. + * This program is free software: you can redistribute it and/or modify
  351. + * it under the terms of the GNU General Public License as published by
  352. + * the Free Software Foundation, either version 3 of the License, or
  353. + * (at your option) any later version.
  354. + *
  355. + * This program is distributed in the hope that it will be useful,
  356. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  357. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  358. + * GNU General Public License for more details.
  359. + *
  360. + * You should have received a copy of the GNU General Public License
  361. + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  362. + */
  363. +
  364. +#define _XOPEN_SOURCE 500L
  365. +
  366. +#include <stdarg.h>
  367. +#include <stdlib.h>
  368. +#include <string.h>
  369. +#include <unistd.h>
  370. +#include <stdio.h>
  371. +#include <ftw.h>
  372. +
  373. +#include "test-util.h"
  374. +
  375. +void
  376. +assert_func(const char* filename,
  377. + int lineno,
  378. + const char* funcname,
  379. + const char* expr,
  380. + const char* fmt,
  381. + ...)
  382. +{
  383. + char buffer[MAX_BUF_LEN] = {};
  384. + if (fmt) {
  385. + va_list ap;
  386. + va_start(ap, fmt);
  387. + vsnprintf(buffer, MAX_BUF_LEN, fmt, ap);
  388. + va_end(ap);
  389. + buffer[strcspn(buffer, "\r\n")] = '\0';
  390. + }
  391. + fprintf(stderr, "%s:%d: assertion '%s' failed in %s(). %s\n", filename,
  392. + lineno,
  393. + expr,
  394. + funcname,
  395. + buffer);
  396. + abort();
  397. +}
  398. +
  399. +static int
  400. +nftw_remove_callback(const char* path, const struct stat* stat,
  401. + int type, struct FTW* ftw)
  402. +{
  403. + return remove(path);
  404. +}
  405. +
  406. +char*
  407. +create_tempdir(void)
  408. +{
  409. + char template[] = "/tmp/tang.test.XXXXXX";
  410. + char *tmpdir = mkdtemp(template);
  411. + return strdup(tmpdir);
  412. +}
  413. +
  414. +int
  415. +remove_tempdir(const char* path)
  416. +{
  417. + return nftw(path, nftw_remove_callback, FOPEN_MAX, FTW_DEPTH|FTW_MOUNT|FTW_PHYS);
  418. +}
  419. +
  420. --- /dev/null
  421. +++ b/tests/test-util.h
  422. @@ -0,0 +1,46 @@
  423. +/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
  424. +/*
  425. + * Copyright (c) 2020 Red Hat, Inc.
  426. + * Author: Sergio Correia <scorreia@redhat.com>
  427. + *
  428. + * This program is free software: you can redistribute it and/or modify
  429. + * it under the terms of the GNU General Public License as published by
  430. + * the Free Software Foundation, either version 3 of the License, or
  431. + * (at your option) any later version.
  432. + *
  433. + * This program is distributed in the hope that it will be useful,
  434. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  435. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  436. + * GNU General Public License for more details.
  437. + *
  438. + * You should have received a copy of the GNU General Public License
  439. + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  440. + */
  441. +
  442. +#pragma once
  443. +
  444. +#include <stdarg.h>
  445. +
  446. +#define ARRAY_COUNT(arr) (sizeof(arr)/sizeof(0[arr]))
  447. +#define MAX_BUF_LEN 2048
  448. +
  449. +void
  450. +assert_func(const char* /* filename */,
  451. + int /* line number */,
  452. + const char* /* function name */,
  453. + const char* /* expression */,
  454. + const char* /* format */,
  455. + ...);
  456. +
  457. +#define ASSERT_WITH_MSG(expr, fmt, ...) \
  458. + if (!(expr)) \
  459. + assert_func(__FILE__, __LINE__, __FUNCTION__, #expr, fmt, ##__VA_ARGS__)
  460. +
  461. +#define ASSERT(expr) \
  462. + ASSERT_WITH_MSG(expr, NULL)
  463. +
  464. +char*
  465. +create_tempdir(void);
  466. +
  467. +int
  468. +remove_tempdir(const char* /* path */);