PageRenderTime 45ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/amanda/tags/3_3_0_qa07/common-src/match-test.c

#
C | 992 lines | 743 code | 122 blank | 127 comment | 58 complexity | 2c13a9929daab21830eb76e4eed04cd1 MD5 | raw file
  1. /*
  2. * Copyright (c) 2010 Zmanda, Inc. All Rights Reserved.
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms of the GNU General Public License version 2 as published
  6. * by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful, but
  9. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  10. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  11. * for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License along
  14. * with this program; if not, write to the Free Software Foundation, Inc.,
  15. * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  16. *
  17. * Contact information: Zmanda Inc, 465 S. Mathilda Ave., Suite 300
  18. * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
  19. */
  20. #include "amanda.h"
  21. #include "testutils.h"
  22. #include "match.h"
  23. /*
  24. * Tests
  25. */
  26. static gboolean
  27. test_validate_regexp(void)
  28. {
  29. gboolean ok = TRUE;
  30. struct {
  31. char *regexp;
  32. gboolean should_validate;
  33. } tests[] = {
  34. { ".*", TRUE },
  35. { "*", FALSE },
  36. { "[abc", FALSE },
  37. { "(abc", FALSE },
  38. { "{1,}", FALSE },
  39. { NULL, FALSE },
  40. }, *t;
  41. for (t = tests; t->regexp; t++) {
  42. char *validated_err = validate_regexp(t->regexp);
  43. if (!validated_err != !!t->should_validate) {
  44. ok = FALSE;
  45. if (t->should_validate) {
  46. g_fprintf(stderr, "should have validated regular expr %s: %s\n",
  47. t->regexp, validated_err);
  48. } else {
  49. g_fprintf(stderr, "unexpectedly validated regular expr %s\n",
  50. t->regexp);
  51. }
  52. }
  53. }
  54. return ok;
  55. }
  56. static gboolean
  57. test_match(void)
  58. {
  59. gboolean ok = TRUE;
  60. struct {
  61. char *expr, *str;
  62. gboolean should_match, should_match_no_newline;
  63. } tests[] = {
  64. /* literal, unanchored matching */
  65. { "a", "a", TRUE, TRUE },
  66. { "a", "A", FALSE, FALSE },
  67. { "a", "ab", TRUE, TRUE },
  68. { "a", "ba", TRUE, TRUE },
  69. { "a", "bab", TRUE, TRUE },
  70. /* dot */
  71. { ".", "", FALSE, FALSE },
  72. { ".", "a", TRUE, TRUE },
  73. { "..", "a", FALSE, FALSE },
  74. { "..", "bc", TRUE, TRUE },
  75. /* brackets */
  76. { "[abc]", "xbx", TRUE, TRUE },
  77. { "[abc]", "xyz", FALSE, FALSE },
  78. { "[^abc]", "cba", FALSE, FALSE },
  79. { "[^abc]", "xyz", TRUE, TRUE },
  80. { "[a-c]", "b", TRUE, TRUE },
  81. { "[^a-c]", "-", TRUE, TRUE },
  82. { "[1-9-]", "-", TRUE, TRUE },
  83. { "[ab\\-cd]", "-", FALSE, FALSE }, /* NOTE! */
  84. /* anchors */
  85. { "^xy", "xyz", TRUE, TRUE },
  86. { "^xy", "wxyz", FALSE, FALSE },
  87. { "yz$", "xyz", TRUE, TRUE },
  88. { "yz$", "yza", FALSE, FALSE },
  89. { "^123$", "123", TRUE, TRUE },
  90. { "^123$", "0123", FALSE, FALSE },
  91. { "^123$", "1234", FALSE, FALSE },
  92. /* capture groups */
  93. { "([a-c])([x-y])", "pqaxyr", TRUE, TRUE },
  94. { "([a-c])([x-y])", "paqrxy", FALSE, FALSE },
  95. { "([a-c])/\\1", "a/b", FALSE, FALSE },
  96. { "([a-c])/\\1", "c/c", TRUE, TRUE },
  97. /* * */
  98. { ">[0-9]*<", "><", TRUE, TRUE },
  99. { ">[0-9]*<", ">3<", TRUE, TRUE },
  100. { ">[0-9]*<", ">34<", TRUE, TRUE },
  101. { ">[0-9]*<", ">345<", TRUE, TRUE },
  102. { ">[0-9]*<", ">x<", FALSE, FALSE },
  103. /* | */
  104. { ":(abc|ABC);", ":abc;", TRUE, TRUE },
  105. { ":(abc|ABC);", ":ABC;", TRUE, TRUE },
  106. { ":(abc|ABC);", ":abcBC;", FALSE, FALSE },
  107. /* + */
  108. { ">[0-9]+<", "><", FALSE, FALSE },
  109. { ">[0-9]+<", ">3<", TRUE, TRUE },
  110. { ">[0-9]+<", ">34<", TRUE, TRUE },
  111. { ">[0-9]+<", ">345<", TRUE, TRUE },
  112. { ">[0-9]+<", ">x<", FALSE, FALSE },
  113. /* { .. } */
  114. { ">[0-9]{0,1}<", "><", TRUE, TRUE },
  115. { ">[0-9]{0,1}<", ">9<", TRUE, TRUE },
  116. { ">[0-9]{0,1}<", ">98<", FALSE, FALSE },
  117. { ">[0-9]{2,3}<", "><", FALSE, FALSE },
  118. { ">[0-9]{2,3}<", ">5<", FALSE, FALSE },
  119. { ">[0-9]{2,3}<", ">55<", TRUE, TRUE },
  120. { ">[0-9]{2,3}<", ">555<", TRUE, TRUE },
  121. { ">[0-9]{2,3}<", ">5555<", FALSE, FALSE },
  122. /* quoting metacharacters */
  123. { "\\\\", "\\", TRUE, TRUE },
  124. { "\\,", ",", TRUE, TRUE },
  125. { "\\[", "[", TRUE, TRUE },
  126. { "\\*", "*", TRUE, TRUE },
  127. { "\\?", "?", TRUE, TRUE },
  128. { "\\+", "+", TRUE, TRUE },
  129. { "\\.", ".", TRUE, TRUE },
  130. { "\\|", "|", TRUE, TRUE },
  131. { "\\^", "^", TRUE, TRUE },
  132. { "\\$", "$", TRUE, TRUE },
  133. /* differences between match and match_no_newline */
  134. { "x.y", "x\ny", FALSE, TRUE },
  135. { "x[^yz]y", "x\ny", FALSE, TRUE },
  136. { "^y", "x\ny", TRUE, FALSE },
  137. { "x$", "x\ny", TRUE, FALSE },
  138. { NULL, NULL, FALSE, FALSE },
  139. }, *t;
  140. for (t = tests; t->expr; t++) {
  141. gboolean matched = match(t->expr, t->str);
  142. if (!!matched != !!t->should_match) {
  143. ok = FALSE;
  144. if (t->should_match) {
  145. g_fprintf(stderr, "%s should have matched regular expr %s\n",
  146. t->str, t->expr);
  147. } else {
  148. g_fprintf(stderr, "%s unexpectedly matched regular expr %s\n",
  149. t->str, t->expr);
  150. }
  151. }
  152. matched = match_no_newline(t->expr, t->str);
  153. if (!!matched != !!t->should_match_no_newline) {
  154. ok = FALSE;
  155. if (t->should_match) {
  156. g_fprintf(stderr, "%s should have matched (no_newline) regular expr %s\n",
  157. t->str, t->expr);
  158. } else {
  159. g_fprintf(stderr, "%s unexpectedly matched (no_newline) regular expr %s\n",
  160. t->str, t->expr);
  161. }
  162. }
  163. }
  164. return ok;
  165. }
  166. static gboolean
  167. test_validate_glob(void)
  168. {
  169. gboolean ok = TRUE;
  170. struct {
  171. char *glob;
  172. gboolean should_validate;
  173. } tests[] = {
  174. { "foo.*", TRUE },
  175. { "*.txt", TRUE },
  176. { "x[abc]y", TRUE },
  177. { "x[!abc]y", TRUE },
  178. { "[abc", FALSE },
  179. { "[!abc", FALSE },
  180. { "??*", TRUE },
  181. { "**?", TRUE }, /* legal, but weird */
  182. { "foo\\", FALSE }, /* un-escaped \ is illegal */
  183. { "foo\\\\", TRUE }, /* but escaped is OK */
  184. { "(){}+.^$|", TRUE }, /* funny characters OK */
  185. { "/usr/bin/*", TRUE }, /* filename seps are OK */
  186. { NULL, FALSE },
  187. }, *t;
  188. for (t = tests; t->glob; t++) {
  189. char *validated_err = validate_glob(t->glob);
  190. if (!validated_err != !!t->should_validate) {
  191. ok = FALSE;
  192. if (t->should_validate) {
  193. g_fprintf(stderr, "should have validated glob %s: %s\n",
  194. t->glob, validated_err);
  195. } else {
  196. g_fprintf(stderr, "unexpectedly validated glob %s\n",
  197. t->glob);
  198. }
  199. }
  200. }
  201. return ok;
  202. }
  203. static gboolean
  204. test_glob_to_regex(void)
  205. {
  206. gboolean ok = TRUE;
  207. struct { char *glob, *regex; } tests[] = {
  208. { "abc", "^abc$" },
  209. { "*.txt", "^[^/]*\\.txt$" },
  210. { "?.txt", "^[^/]\\.txt$" },
  211. { "?*.txt", "^[^/][^/]*\\.txt$" },
  212. { "foo.[tT][xX][tT]", "^foo\\.[tT][xX][tT]$" },
  213. { "foo.[tT][!yY][tT]", "^foo\\.[tT][^yY][tT]$" },
  214. { "foo\\\\", "^foo\\\\$" },
  215. { "(){}+.^$|", "^\\(\\)\\{\\}\\+\\.\\^\\$\\|$" },
  216. { "/usr/bin/*", "^/usr/bin/[^/]*$" },
  217. { NULL, NULL },
  218. }, *t;
  219. for (t = tests; t->glob; t++) {
  220. char *regex = glob_to_regex(t->glob);
  221. if (0 != strcmp(regex, t->regex)) {
  222. ok = FALSE;
  223. g_fprintf(stderr, "glob_to_regex(\"%s\") returned \"%s\"; expected \"%s\"\n",
  224. t->glob, regex, t->regex);
  225. }
  226. }
  227. return ok;
  228. }
  229. static gboolean
  230. test_match_glob(void)
  231. {
  232. gboolean ok = TRUE;
  233. struct {
  234. char *expr, *str;
  235. gboolean should_match;
  236. } tests[] = {
  237. /* literal, unanchored matching */
  238. { "a", "a", TRUE },
  239. { "abc", "abc", TRUE },
  240. { "abc", "abcd", FALSE },
  241. { "abc", "dabc", FALSE },
  242. { "abc", "/usr/bin/abc", FALSE },
  243. { "*.txt", "foo.txt", TRUE },
  244. { "*.txt", ".txt", TRUE },
  245. { "*.txt", "txt", FALSE },
  246. { "?.txt", "X.txt", TRUE },
  247. { "?.txt", ".txt", FALSE },
  248. { "?.txt", "XY.txt", FALSE },
  249. { "?*.txt", ".txt", FALSE },
  250. { "?*.txt", "a.txt", TRUE },
  251. { "?*.txt", "aa.txt", TRUE },
  252. { "?*.txt", "aaa.txt", TRUE },
  253. { "foo.[tT][xX][tT]", "foo.txt", TRUE },
  254. { "foo.[tT][xX][tT]", "foo.TXt", TRUE },
  255. { "foo.[tT][xX][tT]", "foo.TXT", TRUE },
  256. { "foo.[tT][xX][tT]", "foo.TaT", FALSE },
  257. { "foo.[tT][!yY][tT]", "foo.TXt", TRUE },
  258. { "foo.[tT][!yY][tT]", "foo.TXT", TRUE },
  259. { "foo.[tT][!yY][tT]", "foo.TyT", FALSE },
  260. { "foo\\\\", "foo", FALSE },
  261. { "foo\\\\", "foo\\", TRUE },
  262. { "foo\\\\", "foo\\\\", FALSE },
  263. { "(){}+.^$|", "(){}+.^$|", TRUE },
  264. { "/usr/bin/*", "/usr/bin/tar", TRUE },
  265. { "/usr/bin/*", "/usr/bin/local/tar", FALSE },
  266. { "/usr/bin/*", "/usr/sbin/tar", FALSE },
  267. { "/usr/bin/*", "/opt/usr/bin/tar", FALSE },
  268. { "/usr?bin", "/usr/bin", FALSE },
  269. { "/usr*bin", "/usr/bin", FALSE },
  270. { NULL, NULL, FALSE },
  271. }, *t;
  272. for (t = tests; t->expr; t++) {
  273. gboolean matched = match_glob(t->expr, t->str);
  274. if (!!matched != !!t->should_match) {
  275. ok = FALSE;
  276. if (t->should_match) {
  277. g_fprintf(stderr, "%s should have matched glob %s\n",
  278. t->str, t->expr);
  279. } else {
  280. g_fprintf(stderr, "%s unexpectedly matched glob %s\n",
  281. t->str, t->expr);
  282. }
  283. }
  284. }
  285. return ok;
  286. }
  287. static gboolean
  288. test_match_tar(void)
  289. {
  290. gboolean ok = TRUE;
  291. struct {
  292. char *expr, *str;
  293. gboolean should_match;
  294. } tests[] = {
  295. /* literal, unanchored matching */
  296. { "a", "a", TRUE },
  297. { "abc", "abc", TRUE },
  298. { "abc", "abcd", FALSE },
  299. { "abc", "dabc", FALSE },
  300. { "abc", "/usr/bin/abc", TRUE },
  301. { "*.txt", "foo.txt", TRUE },
  302. { "*.txt", ".txt", TRUE },
  303. { "*.txt", "txt", FALSE },
  304. { "?.txt", "X.txt", TRUE },
  305. { "?.txt", ".txt", FALSE },
  306. { "?.txt", "XY.txt", FALSE },
  307. { "?*.txt", ".txt", FALSE },
  308. { "?*.txt", "a.txt", TRUE },
  309. { "?*.txt", "aa.txt", TRUE },
  310. { "?*.txt", "aaa.txt", TRUE },
  311. { "foo.[tT][xX][tT]", "foo.txt", TRUE },
  312. { "foo.[tT][xX][tT]", "foo.TXt", TRUE },
  313. { "foo.[tT][xX][tT]", "foo.TXT", TRUE },
  314. { "foo.[tT][xX][tT]", "foo.TaT", FALSE },
  315. { "foo.[tT][!yY][tT]", "foo.TXt", TRUE },
  316. { "foo.[tT][!yY][tT]", "foo.TXT", TRUE },
  317. { "foo.[tT][!yY][tT]", "foo.TyT", FALSE },
  318. { "foo\\\\", "foo", FALSE },
  319. { "foo\\\\", "foo\\", TRUE },
  320. { "foo\\\\", "foo\\\\", FALSE },
  321. { "(){}+.^$|", "(){}+.^$|", TRUE },
  322. { "/usr/bin/*", "/usr/bin/tar", TRUE },
  323. { "/usr/bin/*", "/usr/bin/local/tar", TRUE }, /* different from match_glob */
  324. { "/usr/bin/*", "/usr/sbin/tar", FALSE },
  325. { "/usr/bin/*", "/opt/usr/bin/tar", FALSE },
  326. { "/usr?bin", "/usr/bin", FALSE },
  327. { "/usr*bin", "/usr/bin", TRUE }, /* different from match_glob */
  328. /* examples from the amgtar manpage */
  329. { "./temp-files", "./temp-files", TRUE },
  330. { "./temp-files", "./temp-files/foo", TRUE },
  331. { "./temp-files", "./temp-files/foo/bar", TRUE },
  332. { "./temp-files", "./temp-files.bak", FALSE },
  333. { "./temp-files", "./backup/temp-files", FALSE },
  334. { "./temp-files/", "./temp-files", FALSE },
  335. { "./temp-files/", "./temp-files/", TRUE },
  336. { "./temp-files/", "./temp-files/foo", FALSE },
  337. { "./temp-files/", "./temp-files/foo/bar", FALSE },
  338. { "./temp-files/", "./temp-files.bak", FALSE },
  339. { "/temp-files/", "./temp-files", FALSE },
  340. { "/temp-files/", "./temp-files/", FALSE },
  341. { "/temp-files/", "./temp-files/foo", FALSE },
  342. { "/temp-files/", "./temp-files/foo/bar", FALSE },
  343. { "/temp-files/", "./temp-files.bak", FALSE },
  344. { "./temp-files/*", "./temp-files", FALSE },
  345. { "./temp-files/*", "./temp-files/", TRUE },
  346. { "./temp-files/*", "./temp-files/foo", TRUE },
  347. { "./temp-files/*", "./temp-files/foo/bar", TRUE },
  348. { "temp-files", "./my/temp-files", TRUE },
  349. { "temp-files", "./my/temp-files/bar", TRUE },
  350. { "temp-files", "./temp-files", TRUE },
  351. { "temp-files", "./her-temp-files", FALSE },
  352. { "temp-files", "./her/old-temp-files", FALSE },
  353. { "temp-files", "./her/old-temp-files/bar", FALSE },
  354. { "generated-*", "./my/generated-xyz", TRUE },
  355. { "generated-*", "./my/generated-xyz/bar", TRUE },
  356. { "generated-*", "./generated-xyz", TRUE },
  357. { "generated-*", "./her-generated-xyz", FALSE },
  358. { "generated-*", "./her/old-generated-xyz", FALSE },
  359. { "generated-*", "./her/old-generated-xyz/bar", FALSE },
  360. { "*.iso", "./my/amanda.iso", TRUE },
  361. { "*.iso", "./amanda.iso", TRUE },
  362. { "proxy/local/cache", "./usr/proxy/local/cache", TRUE },
  363. { "proxy/local/cache", "./proxy/local/cache", TRUE },
  364. { "proxy/local/cache", "./proxy/local/cache/7a", TRUE },
  365. { NULL, NULL, FALSE },
  366. }, *t;
  367. for (t = tests; t->expr; t++) {
  368. gboolean matched = match_tar(t->expr, t->str);
  369. if (!!matched != !!t->should_match) {
  370. ok = FALSE;
  371. if (t->should_match) {
  372. g_fprintf(stderr, "%s should have matched tar %s\n",
  373. t->str, t->expr);
  374. } else {
  375. g_fprintf(stderr, "%s unexpectedly matched tar %s\n",
  376. t->str, t->expr);
  377. }
  378. }
  379. }
  380. return ok;
  381. }
  382. static gboolean
  383. test_make_exact_host_expression(void)
  384. {
  385. gboolean ok = TRUE;
  386. guint i, j;
  387. const char *test_strs[] = {
  388. "host",
  389. "host.org",
  390. "host.host.org",
  391. /* note that these will inter-match: */
  392. /*
  393. ".host",
  394. ".host.org",
  395. ".host.host.org",
  396. "host.",
  397. "host.org.",
  398. "host.host.org.",
  399. */
  400. "org",
  401. "^host",
  402. "host$",
  403. "^host$",
  404. "ho[s]t",
  405. "ho[!s]t",
  406. "ho\\st",
  407. "ho/st",
  408. "ho?t",
  409. "h*t",
  410. "h**t",
  411. };
  412. for (i = 0; i < G_N_ELEMENTS(test_strs); i++) {
  413. for (j = 0; j < G_N_ELEMENTS(test_strs); j++) {
  414. char *expr = make_exact_host_expression(test_strs[i]);
  415. gboolean matched = match_host(expr, test_strs[j]);
  416. if (!!matched != !!(i == j)) {
  417. ok = FALSE;
  418. if (matched) {
  419. g_fprintf(stderr, "expr %s for str %s unexpectedly matched %s\n",
  420. expr, test_strs[i], test_strs[j]);
  421. } else {
  422. g_fprintf(stderr, "expr %s for str %s should have matched %s\n",
  423. expr, test_strs[i], test_strs[j]);
  424. }
  425. }
  426. }
  427. }
  428. return ok;
  429. }
  430. static gboolean
  431. test_match_host(void)
  432. {
  433. gboolean ok = TRUE;
  434. struct {
  435. char *expr, *str;
  436. gboolean should_match;
  437. } tests[] = {
  438. /* from the amanda(8) manpage */
  439. { "hosta", "hosta", TRUE },
  440. { "hosta", "foo.hosta.org", TRUE },
  441. { "hosta", "hoSTA.dOMAIna.ORG", TRUE },
  442. { "hosta", "hostb", FALSE },
  443. { "hOsta", "hosta", TRUE },
  444. { "hOsta", "foo.hosta.org", TRUE },
  445. { "hOsta", "hoSTA.dOMAIna.ORG", TRUE },
  446. { "hOsta", "hostb", FALSE },
  447. { "host", "host", TRUE },
  448. { "host", "hosta", FALSE },
  449. { "host?", "hosta", TRUE },
  450. { "host?", "hostb", TRUE },
  451. { "host?", "host", FALSE },
  452. { "host?", "hostabc", FALSE },
  453. { "ho*na", "hona", TRUE },
  454. { "ho*na", "hoina", TRUE },
  455. { "ho*na", "hoina.org", TRUE },
  456. { "ho*na", "ns.hoina.org", TRUE },
  457. { "ho*na", "ho.aina.org", FALSE },
  458. { "ho**na", "hona", TRUE },
  459. { "ho**na", "hoina", TRUE },
  460. { "ho**na", "hoina.org", TRUE },
  461. { "ho**na", "ns.hoina.org", TRUE },
  462. { "ho**na", "ho.aina.org", TRUE },
  463. { "^hosta", "hosta", TRUE },
  464. { "^hosta", "hosta.org", TRUE },
  465. { "^hosta", "hostabc", FALSE },
  466. { "^hosta", "www.hosta", FALSE },
  467. { "^hosta", "www.hosta.org", FALSE },
  468. { "/opt", "opt", FALSE },
  469. { ".hosta.", "hosta", TRUE },
  470. { ".hosta.", "foo.hosta", TRUE },
  471. { ".hosta.", "hosta.org", TRUE },
  472. { ".hosta.", "foo.hosta.org", TRUE },
  473. { "/hosta", "hosta", FALSE },
  474. { "/hosta", "foo.hosta", FALSE },
  475. { "/hosta", "hosta.org", FALSE },
  476. { "/hosta", "foo.hosta.org", FALSE },
  477. { ".opt.", "opt", TRUE },
  478. { ".opt.", "www.opt", TRUE },
  479. { ".opt.", "www.opt.com", TRUE },
  480. { ".opt.", "opt.com", TRUE },
  481. /* other examples */
  482. { "^hosta$", "hosta", TRUE },
  483. { "^hosta$", "foo.hosta", FALSE },
  484. { "^hosta$", "hosta.org", FALSE },
  485. { "^hosta$", "foo.hosta.org", FALSE },
  486. { "^lu.vis.ta$", "lu.vis.ta", TRUE },
  487. { "^lu.vis.ta$", "lu-vis.ta", FALSE },
  488. { "^lu.vis.ta$", "luvista", FALSE },
  489. { "^lu.vis.ta$", "foo.lu.vis.ta", FALSE },
  490. { "^lu.vis.ta$", "lu.vis.ta.org", FALSE },
  491. { "^lu.vis.ta$", "foo.lu.vis.ta.org", FALSE },
  492. { "mo[st]a", "mota", TRUE },
  493. { "mo[st]a", "mosa", TRUE },
  494. { "mo[st]a", "mosta", FALSE },
  495. { "mo[!st]a", "mota", FALSE },
  496. { "mo[!st]a", "moma", TRUE },
  497. { "mo[!st]a", "momma", FALSE },
  498. { "host[acd]", "hosta", TRUE },
  499. { "host[acd]", "hostb", FALSE },
  500. { "host[acd]", "hostc", TRUE },
  501. { "host[!acd]", "hosta", FALSE },
  502. { "host[!acd]", "hostb", TRUE },
  503. { "host[!acd]", "hostc", FALSE },
  504. { "toast", "www.toast.com", TRUE },
  505. { ".toast", "www.toast.com", TRUE },
  506. { "toast.", "www.toast.com", TRUE },
  507. { ".toast.", "www.toast.com", TRUE },
  508. { NULL, NULL, FALSE },
  509. }, *t;
  510. for (t = tests; t->expr; t++) {
  511. gboolean matched = match_host(t->expr, t->str);
  512. if (!!matched != !!t->should_match) {
  513. ok = FALSE;
  514. if (t->should_match) {
  515. g_fprintf(stderr, "%s should have matched host expr %s\n",
  516. t->str, t->expr);
  517. } else {
  518. g_fprintf(stderr, "%s unexpectedly matched host expr %s\n",
  519. t->str, t->expr);
  520. }
  521. }
  522. }
  523. return ok;
  524. }
  525. static gboolean
  526. test_make_exact_disk_expression(void)
  527. {
  528. gboolean ok = TRUE;
  529. guint i, j;
  530. const char *test_strs[] = {
  531. "/disk",
  532. "/disk/disk",
  533. "d[i]sk",
  534. "d**k",
  535. "d*k",
  536. "d?sk",
  537. "d.sk",
  538. "d[!pqr]sk",
  539. "^disk",
  540. "disk$",
  541. "^disk$",
  542. /* these intermatch due to some special-casing */
  543. /*
  544. "//windows/share",
  545. "\\\\windows\\share",
  546. */
  547. };
  548. for (i = 0; i < G_N_ELEMENTS(test_strs); i++) {
  549. for (j = 0; j < G_N_ELEMENTS(test_strs); j++) {
  550. char *expr = make_exact_disk_expression(test_strs[i]);
  551. gboolean matched = match_disk(expr, test_strs[j]);
  552. if (!!matched != !!(i == j)) {
  553. ok = FALSE;
  554. if (matched) {
  555. g_fprintf(stderr, "expr %s for str %s unexpectedly matched %s\n",
  556. expr, test_strs[i], test_strs[j]);
  557. } else {
  558. g_fprintf(stderr, "expr %s for str %s should have matched %s\n",
  559. expr, test_strs[i], test_strs[j]);
  560. }
  561. }
  562. }
  563. }
  564. return ok;
  565. }
  566. static gboolean
  567. test_match_disk(void)
  568. {
  569. gboolean ok = TRUE;
  570. struct {
  571. char *expr, *str;
  572. gboolean should_match;
  573. } tests[] = {
  574. /* from the amanda(8) manpage */
  575. { "sda*", "/dev/sda1", TRUE },
  576. { "sda*", "/dev/sda2", TRUE },
  577. { "sda*", "/dev/sdb2", FALSE },
  578. { "opt", "opt", TRUE },
  579. { "opt", "/opt", TRUE },
  580. { "opt", "/opt/foo", TRUE },
  581. { "opt", "opt/foo", TRUE },
  582. { "/opt", "opt", TRUE },
  583. { "/opt", "opt/", TRUE },
  584. { "/opt", "/opt", TRUE },
  585. { "/opt", "/opt/", TRUE },
  586. { "/opt", "/local/opt/", TRUE },
  587. { "/opt", "/opt/local/", TRUE },
  588. { "opt/", "opt", TRUE },
  589. { "opt/", "opt/", TRUE },
  590. { "opt/", "/opt", TRUE },
  591. { "opt/", "/opt/", TRUE },
  592. { "opt/", "/local/opt/", TRUE },
  593. { "opt/", "/opt/local/", TRUE },
  594. { "/", "/", TRUE },
  595. { "/", "/opt/local/", FALSE },
  596. { "/usr$", "/", FALSE },
  597. { "/usr$", "/usr", TRUE },
  598. { "/usr$", "/usr/local", FALSE },
  599. { "share", "\\\\windows1\\share", TRUE },
  600. { "share", "\\\\windows2\\share", TRUE },
  601. { "share", "//windows1/share", TRUE },
  602. { "share", "//windows2/share", TRUE },
  603. { "share*", "\\\\windows\\share1", TRUE },
  604. { "share*", "\\\\windows\\share2", TRUE },
  605. { "share*", "//windows/share3", TRUE },
  606. { "share*", "//windows/share4", TRUE },
  607. { "//windows/share", "//windows/share", TRUE },
  608. { "//windows/share", "\\\\windows\\share", TRUE },
  609. { "\\\\windows\\share", "//windows/share", FALSE },
  610. { "\\\\windows\\share", "\\\\windows\\share", FALSE },
  611. { "\\\\\\\\windows\\\\share", "//windows/share", FALSE },
  612. { "\\\\\\\\windows\\\\share", "\\\\windows\\share", TRUE },
  613. /* other expressions */
  614. { "^local", "/local", FALSE },
  615. { "^/local", "/local", TRUE },
  616. { "^local", "/local/vore", FALSE },
  617. { "^/local", "/local/vore", TRUE },
  618. { "^local", "/usr/local", FALSE },
  619. { "local/bin", "/local/bin", TRUE },
  620. { "local/bin", "/opt/local/bin", TRUE },
  621. { "local/bin", "/local/bin/git", TRUE },
  622. { "//windows/share", "//windows/share/files", TRUE },
  623. { "//windows/share", "\\\\windows\\share\\files", TRUE },
  624. { "\\\\windows\\share", "//windows/share/files", FALSE },
  625. { "\\\\windows\\share", "\\\\windows\\share\\files", FALSE },
  626. /* longer expressions */
  627. { "local/var", "/local/var", TRUE },
  628. { "local/var", "/opt/local/var", TRUE },
  629. { "local/var", "/local/var/lib", TRUE },
  630. { "local/var", "/local/usr/var", FALSE },
  631. /* trailing slashes */
  632. { "/usr/bin", "/usr/bin", TRUE },
  633. { "/usr/bin", "/usr/bin/", TRUE },
  634. { "/usr/bin/", "/usr/bin", TRUE },
  635. { "/usr/bin/", "/usr/bin/", TRUE },
  636. { "/usr/bin", "/usr/bin//", TRUE },
  637. { "/usr/bin//", "/usr/bin", FALSE },
  638. { "/usr/bin//", "/usr/bin//", TRUE },
  639. /* quoting '/' is weird: it doesn't work on the leading slash. Note that
  640. * the documentation does not specify how to quote metacharacters in a host
  641. * or disk expression. */
  642. { "/usr\\/bin", "/usr/bin", TRUE },
  643. { "^/usr\\/bin$", "/usr/bin", TRUE },
  644. { "\\/usr\\/bin", "/usr/bin", FALSE },
  645. { "^\\/usr\\/bin$", "/usr/bin", TRUE },
  646. { "/usr\\/bin\\/", "/usr/bin/", TRUE },
  647. { "^/usr\\/bin\\/$", "/usr/bin/", TRUE },
  648. { "\\/usr\\/bin\\/", "/usr/bin/", FALSE },
  649. { "^\\/usr\\/bin\\/$", "/usr/bin/", TRUE },
  650. { "oracle", "oracle", TRUE },
  651. { "oracle", "/oracle", TRUE },
  652. { "oracle", "oracle/", TRUE },
  653. { "oracle", "/oracle/", TRUE },
  654. { "/oracle", "oracle", TRUE },
  655. { "/oracle", "/oracle", TRUE },
  656. { "/oracle", "oracle/", TRUE },
  657. { "/oracle", "/oracle/", TRUE },
  658. { "^oracle", "oracle", TRUE },
  659. { "^oracle", "/oracle", FALSE },
  660. { "^oracle", "oracle/", TRUE },
  661. { "^oracle", "/oracle/", FALSE },
  662. { "^/oracle", "oracle", FALSE },
  663. { "^/oracle", "/oracle", TRUE },
  664. { "^/oracle", "oracle/", FALSE },
  665. { "^/oracle", "/oracle/", TRUE },
  666. { "oracle", "oracle", TRUE },
  667. { "oracle", "/oracle", TRUE },
  668. { "oracle", "oracle/", TRUE },
  669. { "oracle", "/oracle/", TRUE },
  670. { "oracle$", "oracle", TRUE },
  671. { "oracle$", "/oracle", TRUE },
  672. { "oracle$", "oracle/", FALSE },
  673. { "oracle$", "/oracle/", FALSE },
  674. { "oracle/$", "oracle", FALSE },
  675. { "oracle/$", "/oracle", FALSE },
  676. { "oracle/$", "oracle/", TRUE },
  677. { "oracle/$", "/oracle/", TRUE },
  678. { NULL, NULL, FALSE },
  679. }, *t;
  680. for (t = tests; t->expr; t++) {
  681. gboolean matched = match_disk(t->expr, t->str);
  682. if (!!matched != !!t->should_match) {
  683. ok = FALSE;
  684. if (t->should_match) {
  685. g_fprintf(stderr, "%s should have matched disk expr %s\n",
  686. t->str, t->expr);
  687. } else {
  688. g_fprintf(stderr, "%s unexpectedly matched disk expr %s\n",
  689. t->str, t->expr);
  690. }
  691. }
  692. }
  693. return ok;
  694. }
  695. static gboolean
  696. test_match_datestamp(void)
  697. {
  698. gboolean ok = TRUE;
  699. struct {
  700. char *expr, *str;
  701. gboolean should_match;
  702. } tests[] = {
  703. /* from the amanda(8) manpage */
  704. { "20001212-14", "20001212", TRUE },
  705. { "20001212-14", "20001212010203", TRUE },
  706. { "20001212-14", "20001213", TRUE },
  707. { "20001212-14", "20001213010203", TRUE },
  708. { "20001212-14", "20001214", TRUE },
  709. { "20001212-14", "20001215", FALSE },
  710. { "20001212-4", "20001212", TRUE },
  711. { "20001212-4", "20001212010203", TRUE },
  712. { "20001212-4", "20001213", TRUE },
  713. { "20001212-4", "20001213010203", TRUE },
  714. { "20001212-4", "20001214", TRUE },
  715. { "20001212-4", "20001215", FALSE },
  716. { "20001212-214", "20001212", TRUE },
  717. { "20001212-214", "20001212010203", TRUE },
  718. { "20001212-214", "20001213", TRUE },
  719. { "20001212-214", "20001213010203", TRUE },
  720. { "20001212-214", "20001214", TRUE },
  721. { "20001212-214", "20001215", FALSE },
  722. { "20001212-24", "20001211", FALSE },
  723. { "20001212-24", "20001214010203", TRUE },
  724. { "20001212-24", "20001221010203", TRUE },
  725. { "20001212-24", "20001224", TRUE },
  726. { "20001212-24", "20001225", FALSE },
  727. { "2000121", "20001209", FALSE },
  728. { "2000121", "20001210", TRUE },
  729. { "2000121", "20001210012345", TRUE },
  730. { "2000121", "20001219", TRUE },
  731. { "2000121", "20001219012345", TRUE },
  732. { "2000121", "20001220", FALSE },
  733. { "2", "19991231", FALSE },
  734. { "2", "20000101", TRUE },
  735. { "2", "20100419", TRUE },
  736. { "^2", "19991231", FALSE },
  737. { "^2", "20000101", TRUE },
  738. { "^2", "20100419", TRUE },
  739. { "2000-2010", "19991231235959", FALSE },
  740. { "2000-2010", "20001010", TRUE },
  741. { "2000-2010", "20101231", TRUE },
  742. { "2000-2010", "20111010", FALSE },
  743. { "200010$", "200010", TRUE }, /* but it's not a real datestamp */
  744. { "200010$", "20001001", FALSE },
  745. { "200010$", "20001001061500", FALSE },
  746. { "20000615$", "20000615", TRUE },
  747. { "20000615$", "20000615000000", FALSE },
  748. { "20000615$", "20000615010306", FALSE },
  749. { NULL, NULL, FALSE },
  750. }, *t;
  751. for (t = tests; t->expr; t++) {
  752. gboolean matched = match_datestamp(t->expr, t->str);
  753. if (!!matched != !!t->should_match) {
  754. ok = FALSE;
  755. if (t->should_match) {
  756. g_fprintf(stderr, "%s should have matched datestamp expr %s\n",
  757. t->str, t->expr);
  758. } else {
  759. g_fprintf(stderr, "%s unexpectedly matched datestamp expr %s\n",
  760. t->str, t->expr);
  761. }
  762. }
  763. }
  764. return ok;
  765. }
  766. static gboolean
  767. test_match_level(void)
  768. {
  769. gboolean ok = TRUE;
  770. struct {
  771. char *expr, *str;
  772. gboolean should_match;
  773. } tests[] = {
  774. /* exact matches, optionally ignoring "^" */
  775. { "3$", "2", FALSE },
  776. { "3$", "3", TRUE },
  777. { "3$", "4", FALSE },
  778. { "3$", "32", FALSE },
  779. { "^3$", "2", FALSE },
  780. { "^3$", "3", TRUE },
  781. { "^3$", "4", FALSE },
  782. { "^3$", "32", FALSE },
  783. /* prefix matches */
  784. { "3", "2", FALSE },
  785. { "3", "3", TRUE },
  786. { "3", "4", FALSE },
  787. { "3", "32", TRUE },
  788. /* ranges */
  789. { "2-5", "1", FALSE },
  790. { "2-5", "13", FALSE },
  791. { "2-5", "23", FALSE },
  792. { "2-5", "2", TRUE },
  793. { "2-5", "4", TRUE },
  794. { "2-5", "5", TRUE },
  795. { "2-5", "53", FALSE },
  796. { "2-5", "63", FALSE },
  797. { "2-5", "6", FALSE },
  798. { "9-15", "8", FALSE },
  799. { "9-15", "19", FALSE },
  800. { "9-15", "91", FALSE },
  801. { "9-15", "9", TRUE },
  802. { "9-15", "14", TRUE },
  803. { "9-15", "15", TRUE },
  804. { "9-15", "152", FALSE },
  805. { "9-15", "16", FALSE },
  806. { "19-21", "18", FALSE },
  807. { "19-21", "19", TRUE },
  808. { "19-21", "21", TRUE },
  809. { "19-21", "22", FALSE },
  810. /* single range is the same as an exact match */
  811. { "99-99", "98", FALSE },
  812. { "99-99", "99", TRUE },
  813. { "99-99", "100", FALSE },
  814. /* reversed range never matches */
  815. { "21-19", "18", FALSE },
  816. { "21-19", "19", FALSE },
  817. { "21-19", "21", FALSE },
  818. { "21-19", "22", FALSE },
  819. { NULL, NULL, FALSE },
  820. }, *t;
  821. for (t = tests; t->expr; t++) {
  822. gboolean matched = match_level(t->expr, t->str);
  823. if (!!matched != !!t->should_match) {
  824. ok = FALSE;
  825. if (t->should_match) {
  826. g_fprintf(stderr, "%s should have matched level expr %s\n",
  827. t->str, t->expr);
  828. } else {
  829. g_fprintf(stderr, "%s unexpectedly matched level expr %s\n",
  830. t->str, t->expr);
  831. }
  832. }
  833. }
  834. return ok;
  835. }
  836. /*
  837. * Main driver
  838. */
  839. int
  840. main(int argc, char **argv)
  841. {
  842. static TestUtilsTest tests[] = {
  843. TU_TEST(test_validate_regexp, 90),
  844. TU_TEST(test_match, 90),
  845. TU_TEST(test_validate_glob, 90),
  846. TU_TEST(test_glob_to_regex, 90),
  847. TU_TEST(test_match_glob, 90),
  848. TU_TEST(test_match_tar, 90),
  849. TU_TEST(test_make_exact_host_expression, 90),
  850. TU_TEST(test_match_host, 90),
  851. TU_TEST(test_make_exact_disk_expression, 90),
  852. TU_TEST(test_match_disk, 90),
  853. TU_TEST(test_match_datestamp, 90),
  854. TU_TEST(test_match_level, 90),
  855. TU_END()
  856. };
  857. return testutils_run_tests(argc, argv, tests);
  858. }