source: tester.c @ 8219374

release-1.10release-1.8release-1.9
Last change on this file since 8219374 was 8219374, checked in by David Benjamin <davidben@mit.edu>, 13 years ago
Use getpwnam_r instead of getpwnam It's re-entrant, so that's probably a good thing in case some other thread calls getpwnam. More relevantly, Solaris has both a standard and a non-standard version, and perl redefines getpwnam to a getpwnam_r. We manage to convince Solaris to use the standard form, but perl doesn't seem to notice and defines the macro wrong. So just avoid the function altogether. Seems as reasonable of an excuse to use the ostensibly better (and infinitely less friendly) one as any.
  • Property mode set to 100644
File size: 33.4 KB
Line 
1#define OWL_PERL
2#define WINDOW FAKE_WINDOW
3#include "owl.h"
4#undef WINDOW
5
6#include <unistd.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10
11#undef instr
12#include <curses.h>
13
14owl_global g;
15
16int numtests;
17
18int owl_regtest(void);
19int owl_util_regtest(void);
20int owl_dict_regtest(void);
21int owl_variable_regtest(void);
22int owl_filter_regtest(void);
23int owl_obarray_regtest(void);
24int owl_editwin_regtest(void);
25int owl_fmtext_regtest(void);
26int owl_smartfilter_regtest(void);
27int owl_history_regtest(void);
28
29extern void owl_perl_xs_init(pTHX);
30
31int main(int argc, char **argv, char **env)
32{
33  FILE *rnull;
34  FILE *wnull;
35  char *perlerr;
36  int status = 0;
37  SCREEN *screen;
38
39  if (argc <= 1) {
40    fprintf(stderr, "Usage: %s --builtin|TEST.t|-le CODE\n", argv[0]);
41    return 1;
42  }
43
44  /* initialize a fake ncurses, detached from std{in,out} */
45  wnull = fopen("/dev/null", "w");
46  rnull = fopen("/dev/null", "r");
47  screen = newterm("xterm", wnull, rnull);
48  /* initialize global structures */
49  owl_global_init(&g);
50
51  perlerr = owl_perlconfig_initperl(NULL, &argc, &argv, &env);
52  if (perlerr) {
53    endwin();
54    fprintf(stderr, "Internal perl error: %s\n", perlerr);
55    status = 1;
56    goto out;
57  }
58
59  owl_global_complete_setup(&g);
60  owl_global_setup_default_filters(&g);
61
62  owl_view_create(owl_global_get_current_view(&g), "main",
63                  owl_global_get_filter(&g, "all"),
64                  owl_global_get_style_by_name(&g, "default"));
65
66  owl_function_firstmsg();
67
68  ENTER;
69  SAVETMPS;
70
71  if (strcmp(argv[1], "--builtin") == 0) {
72    status = owl_regtest();
73  } else if (strcmp(argv[1], "-le") == 0 && argc > 2) {
74    /*
75     * 'prove' runs its harness perl with '-le CODE' to get some
76     * information out.
77     */
78    moreswitches("l");
79    eval_pv(argv[2], true);
80  } else {
81    sv_setpv(get_sv("0", false), argv[1]);
82    sv_setpv(get_sv("main::test_prog", TRUE), argv[1]);
83
84    eval_pv("do $main::test_prog; die($@) if($@)", true);
85  }
86
87  status = 0;
88
89  FREETMPS;
90  LEAVE;
91
92 out:
93  perl_destruct(owl_global_get_perlinterp(&g));
94  perl_free(owl_global_get_perlinterp(&g));
95  /* probably not necessary, but tear down the screen */
96  endwin();
97  delscreen(screen);
98  fclose(rnull);
99  fclose(wnull);
100  return status;
101}
102
103int owl_regtest(void) {
104  numtests = 0;
105  int numfailures=0;
106  /*
107    printf("1..%d\n", OWL_UTIL_NTESTS+OWL_DICT_NTESTS+OWL_VARIABLE_NTESTS
108    +OWL_FILTER_NTESTS+OWL_OBARRAY_NTESTS);
109  */
110  numfailures += owl_util_regtest();
111  numfailures += owl_dict_regtest();
112  numfailures += owl_variable_regtest();
113  numfailures += owl_filter_regtest();
114  numfailures += owl_editwin_regtest();
115  numfailures += owl_fmtext_regtest();
116  numfailures += owl_smartfilter_regtest();
117  numfailures += owl_history_regtest();
118  if (numfailures) {
119      fprintf(stderr, "# *** WARNING: %d failures total\n", numfailures);
120  }
121  printf("1..%d\n", numtests);
122
123  return(numfailures);
124}
125
126#define FAIL_UNLESS(desc,pred) do { int __pred = (pred);                \
127    numtests++;                                                         \
128    printf("%s %d %s", (__pred) ? "ok" : (numfailed++, "not ok"), numtests, desc); \
129    if(!(__pred)) printf("\t(%s:%d)", __FILE__, __LINE__); printf("%c", '\n'); } while(0)
130
131
132int owl_util_regtest(void)
133{
134  int numfailed=0;
135  char *s, *path, *home;
136
137  printf("# BEGIN testing owl_util\n");
138
139#define CHECK_STR_AND_FREE(desc, expected, expr)         \
140    do {                                                 \
141      char *__value = (expr);                            \
142      FAIL_UNLESS((desc), !strcmp((expected), __value)); \
143      g_free(__value);                                 \
144    } while (0)
145
146  CHECK_STR_AND_FREE("owl_text_substitute 2", "fYZYZ",
147                     owl_text_substitute("foo", "o", "YZ"));
148  CHECK_STR_AND_FREE("owl_text_substitute 3", "foo",
149                     owl_text_substitute("fYZYZ", "YZ", "o"));
150  CHECK_STR_AND_FREE("owl_text_substitute 4", "/u/foo/meep",
151                     owl_text_substitute("~/meep", "~", "/u/foo"));
152
153  FAIL_UNLESS("skiptokens 1", 
154              !strcmp("bar quux", skiptokens("foo bar quux", 1)));
155  FAIL_UNLESS("skiptokens 2", 
156              !strcmp("meep", skiptokens("foo 'bar quux' meep", 2)));
157
158  CHECK_STR_AND_FREE("expand_tabs 1", "        hi", owl_text_expand_tabs("\thi"));
159
160  CHECK_STR_AND_FREE("expand_tabs 2", "        hi\nword    tab",
161                     owl_text_expand_tabs("\thi\nword\ttab"));
162
163  CHECK_STR_AND_FREE("expand_tabs 3", "                2 tabs",
164                     owl_text_expand_tabs("\t\t2 tabs"));
165  CHECK_STR_AND_FREE("expand_tabs 4", "α       ααααααα!        ",
166                     owl_text_expand_tabs(\tααααααα!\t"));
167  CHECK_STR_AND_FREE("expand_tabs 5", "A      AAA!!        ",
168                     owl_text_expand_tabs("A\tAAA!!\t"));
169
170  FAIL_UNLESS("skiptokens 1",
171              !strcmp("world", skiptokens("hello world", 1)));
172
173  FAIL_UNLESS("skiptokens 2",
174              !strcmp("c d e", skiptokens("a   b c d e", 2)));
175
176  FAIL_UNLESS("skiptokens 3",
177              !strcmp("\"b\" c d e", skiptokens("a \"b\" c d e", 1)));
178
179  FAIL_UNLESS("skiptokens 4",
180              !strcmp("c d e", skiptokens("a \"b\" c d e", 2)));
181
182  FAIL_UNLESS("skiptokens 5",
183              !strcmp("c d e", skiptokens("a \"'\" c d e", 2)));
184
185#define CHECK_QUOTING(desc, unquoted, quoted)           \
186  do {                                                  \
187      int __argc;                                       \
188      char *__quoted = owl_arg_quote(unquoted);         \
189      char **__argv;                                    \
190      FAIL_UNLESS(desc, !strcmp(quoted, __quoted));     \
191      __argv = owl_parseline(__quoted, &__argc);        \
192      FAIL_UNLESS(desc " - arg count", __argc == 1);    \
193      FAIL_UNLESS(desc " - null-terminated",            \
194                  __argv[__argc] == NULL);              \
195      FAIL_UNLESS(desc " - parsed",                     \
196                  !strcmp(__argv[0], unquoted));        \
197      g_strfreev(__argv);                               \
198      g_free(__quoted);                         \
199    } while (0)
200
201  CHECK_QUOTING("boring text", "mango", "mango");
202  CHECK_QUOTING("spaces", "mangos are tasty", "'mangos are tasty'");
203  CHECK_QUOTING("single quotes", "mango's", "\"mango's\"");
204  CHECK_QUOTING("double quotes", "he said \"mangos are tasty\"",
205                "'he said \"mangos are tasty\"'");
206  CHECK_QUOTING("both quotes",
207                "he said \"mango's are tasty even when you put in "
208                "a random apostrophe\"",
209                "\"he said \"'\"'\"mango's are tasty even when you put in "
210                "a random apostrophe\"'\"'\"\"");
211  CHECK_QUOTING("quote monster", "'\"\"'\"'''\"",
212                "\""
213                "'"
214                "\"'\"'\""
215                "\"'\"'\""
216                "'"
217                "\"'\"'\""
218                "'"
219                "'"
220                "'"
221                "\"'\"'\""
222                "\"");
223
224  GString *quoted = g_string_new("");
225  owl_string_appendf_quoted(quoted, "%q foo %q%q %s %", "hello", "world is", "can't");
226  FAIL_UNLESS("owl_string_appendf",
227              !strcmp(quoted->str, "hello foo 'world is'\"can't\" %s %"));
228  g_string_free(quoted, true);
229
230
231  s = owl_util_baseclass("barnowl");
232  FAIL_UNLESS("baseclass barnowl", !strcmp("barnowl", s));
233  g_free(s);
234  s = owl_util_baseclass("unbarnowl");
235  FAIL_UNLESS("baseclass unbarnowl", !strcmp("barnowl", s));
236  g_free(s);
237  s = owl_util_baseclass("unununbarnowl.d.d");
238  FAIL_UNLESS("baseclass unununbarnowl.d.d", !strcmp("barnowl", s));
239  g_free(s);
240  s = owl_util_baseclass("ununun.d.d");
241  FAIL_UNLESS("baseclass ununun.d.d", !strcmp("", s));
242  g_free(s);
243  s = owl_util_baseclass("d.d.d.d");
244  FAIL_UNLESS("baseclass d.d.d.d", !strcmp("d", s));
245  g_free(s);
246  s = owl_util_baseclass("n.d.d.d");
247  FAIL_UNLESS("baseclass n.d.d.d", !strcmp("n", s));
248  g_free(s);
249  s = owl_util_baseclass("ununun.");
250  FAIL_UNLESS("baseclass ununun.", !strcmp(".", s));
251  g_free(s);
252  s = owl_util_baseclass("unununu");
253  FAIL_UNLESS("baseclass unununu", !strcmp("u", s));
254  g_free(s);
255
256
257  s = owl_util_makepath("foo/bar");
258  FAIL_UNLESS("makepath foo/bar", !strcmp("foo/bar", s));
259  g_free(s);
260  s = owl_util_makepath("//foo///bar");
261  FAIL_UNLESS("makepath //foo///bar", !strcmp("/foo/bar", s));
262  g_free(s);
263  s = owl_util_makepath("foo/~//bar/");
264  FAIL_UNLESS("makepath foo/~//bar/", !strcmp("foo/~/bar/", s));
265  g_free(s);
266  s = owl_util_makepath("~thisuserhadreallybetternotexist/foobar/");
267  FAIL_UNLESS("makepath ~thisuserhadreallybetternotexist/foobar/",
268              !strcmp("~thisuserhadreallybetternotexist/foobar/", s));
269  g_free(s);
270
271  home = g_strdup(owl_global_get_homedir(&g));
272  s = owl_util_makepath("~");
273  FAIL_UNLESS("makepath ~", !strcmp(home, s));
274  g_free(s);
275
276  path = g_strconcat(home, "/foo/bar/baz", NULL);
277  s = owl_util_makepath("~///foo/bar//baz");
278  FAIL_UNLESS("makepath ~///foo/bar//baz", !strcmp(path, s));
279  g_free(s);
280  g_free(path);
281  g_free(home);
282
283  home = owl_util_homedir_for_user("root");
284  if (home == NULL) {
285    /* Just make some noise so we notice. */
286    home = g_strdup("<WHAT>");
287    fprintf(stderr, "owl_util_homedir_for_user failed");
288  }
289
290  s = owl_util_makepath("~root");
291  FAIL_UNLESS("makepath ~root", !strcmp(home, s));
292  g_free(s);
293
294  path = g_strconcat(home, "/foo/bar/baz", NULL);
295  s = owl_util_makepath("~root///foo/bar//baz");
296  FAIL_UNLESS("makepath ~root///foo/bar//baz", !strcmp(path, s));
297  g_free(s);
298  g_free(path);
299  g_free(home);
300
301  /* if (numfailed) printf("*** WARNING: failures encountered with owl_util\n"); */
302  printf("# END testing owl_util (%d failures)\n", numfailed);
303  return(numfailed);
304}
305
306int owl_dict_regtest(void) {
307  owl_dict d;
308  GPtrArray *l;
309  int numfailed=0;
310  char *av = g_strdup("aval"), *bv = g_strdup("bval"), *cv = g_strdup("cval"),
311    *dv = g_strdup("dval");
312
313  printf("# BEGIN testing owl_dict\n");
314  owl_dict_create(&d);
315  FAIL_UNLESS("insert b", 0==owl_dict_insert_element(&d, "b", bv, owl_dict_noop_delete));
316  FAIL_UNLESS("insert d", 0==owl_dict_insert_element(&d, "d", dv, owl_dict_noop_delete));
317  FAIL_UNLESS("insert a", 0==owl_dict_insert_element(&d, "a", av, owl_dict_noop_delete));
318  FAIL_UNLESS("insert c", 0==owl_dict_insert_element(&d, "c", cv, owl_dict_noop_delete));
319  FAIL_UNLESS("reinsert d (no replace)", -2==owl_dict_insert_element(&d, "d", dv, 0));
320  FAIL_UNLESS("find a", av==owl_dict_find_element(&d, "a"));
321  FAIL_UNLESS("find b", bv==owl_dict_find_element(&d, "b"));
322  FAIL_UNLESS("find c", cv==owl_dict_find_element(&d, "c"));
323  FAIL_UNLESS("find d", dv==owl_dict_find_element(&d, "d"));
324  FAIL_UNLESS("find e (non-existent)", NULL==owl_dict_find_element(&d, "e"));
325  FAIL_UNLESS("remove d", dv==owl_dict_remove_element(&d, "d"));
326  FAIL_UNLESS("find d (post-removal)", NULL==owl_dict_find_element(&d, "d"));
327
328  FAIL_UNLESS("get_size", 3==owl_dict_get_size(&d));
329  l = owl_dict_get_keys(&d);
330  FAIL_UNLESS("get_keys result size", 3 == l->len);
331 
332  /* these assume the returned keys are sorted */
333  FAIL_UNLESS("get_keys result val", 0 == strcmp("a", l->pdata[0]));
334  FAIL_UNLESS("get_keys result val", 0 == strcmp("b", l->pdata[1]));
335  FAIL_UNLESS("get_keys result val", 0 == strcmp("c", l->pdata[2]));
336
337  owl_ptr_array_free(l, g_free);
338  owl_dict_cleanup(&d, NULL);
339
340  g_free(av);
341  g_free(bv);
342  g_free(cv);
343  g_free(dv);
344
345  /*  if (numfailed) printf("*** WARNING: failures encountered with owl_dict\n"); */
346  printf("# END testing owl_dict (%d failures)\n", numfailed);
347  return(numfailed);
348}
349
350int owl_variable_regtest(void) {
351  owl_vardict vd;
352  owl_variable *var;
353  int numfailed=0;
354  char *value;
355  const void *v;
356
357  printf("# BEGIN testing owl_variable\n");
358  FAIL_UNLESS("setup", 0==owl_variable_dict_setup(&vd));
359
360  FAIL_UNLESS("get bool var", NULL != (var = owl_variable_get_var(&vd, "rxping")));
361  FAIL_UNLESS("get bool", 0 == owl_variable_get_bool(var));
362  FAIL_UNLESS("get bool (no such)", NULL == owl_variable_get_var(&vd, "mumble"));
363  FAIL_UNLESS("get bool as string",
364              !strcmp((value = owl_variable_get_tostring(var)), "off"));
365  g_free(value);
366  FAIL_UNLESS("set bool 1", 0 == owl_variable_set_bool_on(var));
367  FAIL_UNLESS("get bool 2", 1 == owl_variable_get_bool(var));
368  FAIL_UNLESS("set bool 3", 0 == owl_variable_set_fromstring(var, "off", 0));
369  FAIL_UNLESS("get bool 4", 0 == owl_variable_get_bool(var));
370  FAIL_UNLESS("set bool 5", -1 == owl_variable_set_fromstring(var, "xxx", 0));
371  FAIL_UNLESS("get bool 6", 0 == owl_variable_get_bool(var));
372
373
374  FAIL_UNLESS("get string var", NULL != (var = owl_variable_get_var(&vd, "logpath")));
375  FAIL_UNLESS("get string", 0 == strcmp("~/zlog/people", owl_variable_get_string(var)));
376  FAIL_UNLESS("set string 7", 0 == owl_variable_set_string(var, "whee"));
377  FAIL_UNLESS("get string", !strcmp("whee", owl_variable_get_string(var)));
378
379  FAIL_UNLESS("get int var", NULL != (var = owl_variable_get_var(&vd, "typewinsize")));
380  FAIL_UNLESS("get int", 8 == owl_variable_get_int(var));
381  FAIL_UNLESS("get int (no such)", NULL == owl_variable_get_var(&vd, "mumble"));
382  FAIL_UNLESS("get int as string",
383              !strcmp((value = owl_variable_get_tostring(var)), "8"));
384  g_free(value);
385  FAIL_UNLESS("set int 1", 0 == owl_variable_set_int(var, 12));
386  FAIL_UNLESS("get int 2", 12 == owl_variable_get_int(var));
387  FAIL_UNLESS("set int 1b", -1 == owl_variable_set_int(var, -3));
388  FAIL_UNLESS("get int 2b", 12 == owl_variable_get_int(var));
389  FAIL_UNLESS("set int 3", 0 == owl_variable_set_fromstring(var, "9", 0));
390  FAIL_UNLESS("get int 4", 9 == owl_variable_get_int(var));
391  FAIL_UNLESS("set int 5", -1 == owl_variable_set_fromstring(var, "xxx", 0));
392  FAIL_UNLESS("set int 6", -1 == owl_variable_set_fromstring(var, "", 0));
393  FAIL_UNLESS("get int 7", 9 == owl_variable_get_int(var));
394
395  owl_variable_dict_newvar_string(&vd, "stringvar", "", "", "testval");
396  FAIL_UNLESS("get new string var", NULL != (var = owl_variable_get_var(&vd, "stringvar")));
397  FAIL_UNLESS("get new string var", NULL != (v = owl_variable_get(var)));
398  FAIL_UNLESS("get new string val", !strcmp("testval", owl_variable_get_string(var)));
399  owl_variable_set_string(var, "new val");
400  FAIL_UNLESS("update string val", !strcmp("new val", owl_variable_get_string(var)));
401
402  owl_variable_dict_newvar_int(&vd, "intvar", "", "", 47);
403  FAIL_UNLESS("get new int var", NULL != (var = owl_variable_get_var(&vd, "intvar")));
404  FAIL_UNLESS("get new int var", NULL != (v = owl_variable_get(var)));
405  FAIL_UNLESS("get new int val", 47 == owl_variable_get_int(var));
406  owl_variable_set_int(var, 17);
407  FAIL_UNLESS("update int val", 17 == owl_variable_get_int(var));
408
409  owl_variable_dict_newvar_bool(&vd, "boolvar", "", "", 1);
410  FAIL_UNLESS("get new bool var", NULL != (var = owl_variable_get_var(&vd, "boolvar")));
411  FAIL_UNLESS("get new bool var", NULL != (v = owl_variable_get(var)));
412  FAIL_UNLESS("get new bool val", owl_variable_get_bool(var));
413  owl_variable_set_bool_off(var);
414  FAIL_UNLESS("update bool val", !owl_variable_get_bool(var));
415
416  owl_variable_dict_newvar_string(&vd, "nullstringvar", "", "", NULL);
417  FAIL_UNLESS("get new string (NULL) var", NULL != (var = owl_variable_get_var(&vd, "nullstringvar")));
418  FAIL_UNLESS("get string (NULL)", NULL == (value = owl_variable_get_tostring(var)));
419  g_free(value);
420  var = owl_variable_get_var(&vd, "zsigproc");
421  FAIL_UNLESS("get string (NULL) 2", NULL == (value = owl_variable_get_tostring(var)));
422  g_free(value);
423
424  owl_variable_dict_cleanup(&vd);
425
426  /* if (numfailed) printf("*** WARNING: failures encountered with owl_variable\n"); */
427  printf("# END testing owl_variable (%d failures)\n", numfailed);
428  return(numfailed);
429}
430
431static int owl_filter_test_string(const char *filt, const owl_message *m, int shouldmatch)
432{
433  owl_filter *f;
434  int ok;
435  int failed = 0;
436  if ((f = owl_filter_new_fromstring("test-filter", filt)) == NULL) {
437    printf("not ok can't parse %s\n", filt);
438    failed = 1;
439    goto out;
440  }
441  ok = owl_filter_message_match(f, m);
442  if((shouldmatch && !ok) || (!shouldmatch && ok)) {
443    printf("not ok match %s (got %d, expected %d)\n", filt, ok, shouldmatch);
444    failed = 1;
445  }
446 out:
447  owl_filter_delete(f);
448  if(!failed) {
449    printf("ok %s %s\n", shouldmatch ? "matches" : "doesn't match", filt);
450  }
451  return failed;
452}
453
454int owl_filter_regtest(void) {
455  int numfailed=0;
456  owl_message m;
457  owl_filter *f1, *f2, *f3, *f4, *f5;
458
459  owl_message_init(&m);
460  owl_message_set_type_zephyr(&m);
461  owl_message_set_direction_in(&m);
462  owl_message_set_class(&m, "owl");
463  owl_message_set_instance(&m, "tester");
464  owl_message_set_sender(&m, "owl-user");
465  owl_message_set_recipient(&m, "joe");
466  owl_message_set_attribute(&m, "foo", "bar");
467
468#define TEST_FILTER(f, e) do {                          \
469    numtests++;                                         \
470    numfailed += owl_filter_test_string(f, &m, e);      \
471      } while(0)
472
473  TEST_FILTER("true", 1);
474  TEST_FILTER("false", 0);
475  TEST_FILTER("( true )", 1);
476  TEST_FILTER("not false", 1);
477  TEST_FILTER("( true ) or ( false )", 1);
478  TEST_FILTER("true and false", 0);
479  TEST_FILTER("( true or true ) or ( ( false ) )", 1);
480
481  TEST_FILTER("class owl", 1);
482  TEST_FILTER("class ^owl$", 1);
483  TEST_FILTER("instance test", 1);
484  TEST_FILTER("instance ^test$", 0);
485  TEST_FILTER("instance ^tester$", 1);
486
487  TEST_FILTER("foo bar", 1);
488  TEST_FILTER("class owl and instance tester", 1);
489  TEST_FILTER("type ^zephyr$ and direction ^in$ and ( class ^owl$ or instance ^owl$ )", 1);
490
491  /* Order of operations and precedence */
492  TEST_FILTER("not true or false", 0);
493  TEST_FILTER("true or true and false", 0);
494  TEST_FILTER("true and true and false or true", 1);
495  TEST_FILTER("false and false or true", 1);
496  TEST_FILTER("true and false or false", 0);
497
498  f1 = owl_filter_new_fromstring("f1", "class owl");
499  owl_global_add_filter(&g, f1);
500  TEST_FILTER("filter f1", 1);
501  owl_global_remove_filter(&g, "f1");
502
503  /* Test recursion prevention */
504  FAIL_UNLESS("self reference", (f2 = owl_filter_new_fromstring("test", "filter test")) == NULL);
505  owl_filter_delete(f2);
506
507  /* mutual recursion */
508  f3 = owl_filter_new_fromstring("f3", "filter f4");
509  owl_global_add_filter(&g, f3);
510  FAIL_UNLESS("mutual recursion", (f4 = owl_filter_new_fromstring("f4", "filter f3")) == NULL);
511  owl_global_remove_filter(&g, "f3");
512  owl_filter_delete(f4);
513
514  /* support referencing a filter several times */
515  FAIL_UNLESS("DAG", (f5 = owl_filter_new_fromstring("dag", "filter f1 or filter f1")) != NULL);
516  owl_filter_delete(f5);
517
518  return 0;
519}
520
521int owl_editwin_regtest(void) {
522  int numfailed = 0;
523  const char *p;
524  owl_editwin *oe;
525  const char *autowrap_string = "we feel our owls should live "
526                                "closer to our ponies.";
527
528  printf("# BEGIN testing owl_editwin\n");
529
530  oe = owl_editwin_new(NULL, 80, 80, OWL_EDITWIN_STYLE_MULTILINE, NULL);
531
532  /* TODO: make the strings a little more lenient w.r.t trailing whitespace */
533
534  /* check paragraph fill */
535  owl_editwin_insert_string(oe, "blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah.\n\nblah");
536  owl_editwin_move_to_top(oe);
537  owl_editwin_fill_paragraph(oe);
538  p = owl_editwin_get_text(oe);
539  FAIL_UNLESS("text was correctly wrapped", p && !strcmp(p, "blah blah blah blah blah blah blah blah blah blah blah blah blah blah\n"
540                                                            "blah blah blah.\n"
541                                                            "\n"
542                                                            "blah"));
543
544  owl_editwin_unref(oe); oe = NULL;
545  oe = owl_editwin_new(NULL, 80, 80, OWL_EDITWIN_STYLE_MULTILINE, NULL);
546
547  /* check that lines ending with ". " correctly fill */
548  owl_editwin_insert_string(oe, "blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah. \n\nblah");
549  owl_editwin_move_to_top(oe);
550  owl_editwin_fill_paragraph(oe);
551  p = owl_editwin_get_text(oe);
552  FAIL_UNLESS("text was correctly wrapped", p && !strcmp(p, "blah blah blah blah blah blah blah blah blah blah blah blah blah blah\n"
553                                                            "blah blah blah. \n"
554                                                            "\n"
555                                                            "blah"));
556
557  owl_editwin_unref(oe); oe = NULL;
558
559  /* Test owl_editwin_move_to_beginning_of_line. */
560  oe = owl_editwin_new(NULL, 80, 80, OWL_EDITWIN_STYLE_MULTILINE, NULL);
561  owl_editwin_insert_string(oe, "\n");
562  owl_editwin_insert_string(oe, "12345678\n");
563  owl_editwin_insert_string(oe, "\n");
564  owl_editwin_insert_string(oe, "abcdefg\n");
565  owl_editwin_move_to_top(oe);
566  FAIL_UNLESS("already at beginning of line",
567              owl_editwin_move_to_beginning_of_line(oe) == 0);
568  owl_editwin_line_move(oe, 1);
569  owl_editwin_point_move(oe, 5);
570  FAIL_UNLESS("find beginning of line after empty first line",
571              owl_editwin_move_to_beginning_of_line(oe) == -5);
572  owl_editwin_line_move(oe, 1);
573  FAIL_UNLESS("find beginning empty middle line",
574              owl_editwin_move_to_beginning_of_line(oe) == 0);
575  owl_editwin_line_move(oe, 1);
576  owl_editwin_point_move(oe, 2);
577  FAIL_UNLESS("find beginning of line after empty middle line",
578              owl_editwin_move_to_beginning_of_line(oe) == -2);
579  owl_editwin_unref(oe); oe = NULL;
580
581  /* Test automatic line-wrapping. */
582  owl_global_set_edit_maxwrapcols(&g, 10);
583  oe = owl_editwin_new(NULL, 80, 80, OWL_EDITWIN_STYLE_MULTILINE, NULL);
584  for (p = autowrap_string; *p; p++) {
585    owl_input j;
586    j.ch = *p;
587    j.uch = *p; /* Assuming ASCII. */
588    owl_editwin_process_char(oe, j);
589  }
590  p = owl_editwin_get_text(oe);
591  FAIL_UNLESS("text was automatically wrapped",
592              p && !strcmp(p, "we feel\n"
593                           "our owls\n"
594                           "should\n"
595                           "live\n"
596                           "closer to\n"
597                           "our\n"
598                           "ponies."));
599  owl_editwin_unref(oe); oe = NULL;
600  owl_global_set_edit_maxwrapcols(&g, 70);
601
602  /* Test owl_editwin_current_column. */
603  oe = owl_editwin_new(NULL, 80, 80, OWL_EDITWIN_STYLE_MULTILINE, NULL);
604  FAIL_UNLESS("initial column zero", owl_editwin_current_column(oe) == 0);
605  owl_editwin_insert_string(oe, "abcdef");
606  FAIL_UNLESS("simple insert", owl_editwin_current_column(oe) == 6);
607  owl_editwin_insert_string(oe, "\t");
608  FAIL_UNLESS("insert tabs", owl_editwin_current_column(oe) == 8);
609  owl_editwin_insert_string(oe, "123\n12\t3");
610  FAIL_UNLESS("newline with junk", owl_editwin_current_column(oe) == 9);
611  owl_editwin_move_to_beginning_of_line(oe);
612  FAIL_UNLESS("beginning of line", owl_editwin_current_column(oe) == 0);
613  owl_editwin_unref(oe); oe = NULL;
614
615  printf("# END testing owl_editwin (%d failures)\n", numfailed);
616
617  return numfailed;
618}
619
620int owl_fmtext_regtest(void) {
621  int numfailed = 0;
622  int start, end;
623  owl_fmtext fm1;
624  owl_fmtext fm2;
625  owl_regex re;
626  char *str;
627
628  printf("# BEGIN testing owl_fmtext\n");
629
630  owl_fmtext_init_null(&fm1);
631  owl_fmtext_init_null(&fm2);
632
633  /* Verify text gets correctly appended. */
634  owl_fmtext_append_normal(&fm1, "1234567898");
635  owl_fmtext_append_fmtext(&fm2, &fm1);
636  FAIL_UNLESS("string lengths correct",
637              owl_fmtext_num_bytes(&fm2) == strlen(owl_fmtext_get_text(&fm2)));
638
639  /* Test owl_fmtext_num_lines. */
640  owl_fmtext_clear(&fm1);
641  FAIL_UNLESS("empty line correct", owl_fmtext_num_lines(&fm1) == 0);
642  owl_fmtext_append_normal(&fm1, "12345\n67898");
643  FAIL_UNLESS("trailing chars correct", owl_fmtext_num_lines(&fm1) == 2);
644  owl_fmtext_append_normal(&fm1, "\n");
645  FAIL_UNLESS("trailing newline correct", owl_fmtext_num_lines(&fm1) == 2);
646  owl_fmtext_append_bold(&fm1, "");
647  FAIL_UNLESS("trailing attributes correct", owl_fmtext_num_lines(&fm1) == 2);
648
649  /* Test owl_fmtext_truncate_lines */
650  owl_fmtext_clear(&fm1);
651  owl_fmtext_append_normal(&fm1, "0\n1\n2\n3\n4\n");
652
653  owl_fmtext_clear(&fm2);
654  owl_fmtext_truncate_lines(&fm1, 1, 3, &fm2);
655  str = owl_fmtext_print_plain(&fm2);
656  FAIL_UNLESS("lines corrected truncated",
657              str && !strcmp(str, "1\n2\n3\n"));
658  g_free(str);
659
660  owl_fmtext_clear(&fm2);
661  owl_fmtext_truncate_lines(&fm1, 1, 5, &fm2);
662  str = owl_fmtext_print_plain(&fm2);
663  FAIL_UNLESS("lines corrected truncated",
664              str && !strcmp(str, "1\n2\n3\n4\n"));
665  g_free(str);
666
667  /* Test owl_fmtext_truncate_cols. */
668  owl_fmtext_clear(&fm1);
669  owl_fmtext_append_normal(&fm1, "123456789012345\n");
670  owl_fmtext_append_normal(&fm1, "123456789\n");
671  owl_fmtext_append_normal(&fm1, "1234567890\n");
672
673  owl_fmtext_clear(&fm2);
674  owl_fmtext_truncate_cols(&fm1, 4, 9, &fm2);
675  str = owl_fmtext_print_plain(&fm2);
676  FAIL_UNLESS("columns correctly truncated",
677              str && !strcmp(str, "567890"
678                                  "56789\n"
679                                  "567890"));
680  g_free(str);
681
682  owl_fmtext_clear(&fm1);
683  owl_fmtext_append_normal(&fm1, "12\t1234");
684  owl_fmtext_append_bold(&fm1, "56\n");
685  owl_fmtext_append_bold(&fm1, "12345678\t\n");
686
687  owl_fmtext_clear(&fm2);
688  owl_fmtext_truncate_cols(&fm1, 4, 13, &fm2);
689  str = owl_fmtext_print_plain(&fm2);
690  FAIL_UNLESS("columns correctly truncated",
691              str && !strcmp(str, "    123456"
692                                  "5678      "));
693  g_free(str);
694
695  /* Test owl_fmtext_expand_tabs. */
696  owl_fmtext_clear(&fm1);
697  owl_fmtext_append_normal(&fm1, "12\t1234");
698  owl_fmtext_append_bold(&fm1, "567\t1\n12345678\t1");
699  owl_fmtext_clear(&fm2);
700  owl_fmtext_expand_tabs(&fm1, &fm2, 0);
701  str = owl_fmtext_print_plain(&fm2);
702  FAIL_UNLESS("no tabs remaining", strchr(str, '\t') == NULL);
703  FAIL_UNLESS("tabs corrected expanded",
704              str && !strcmp(str, "12      1234567 1\n"
705                                  "12345678        1"));
706  g_free(str);
707
708  owl_fmtext_clear(&fm2);
709  owl_fmtext_expand_tabs(&fm1, &fm2, 1);
710  str = owl_fmtext_print_plain(&fm2);
711  FAIL_UNLESS("no tabs remaining", strchr(str, '\t') == NULL);
712  FAIL_UNLESS("tabs corrected expanded",
713              str && !strcmp(str, "12     1234567 1\n"
714                                  "12345678       1"));
715  g_free(str);
716
717  /* Test owl_fmtext_search. */
718  owl_fmtext_clear(&fm1);
719  owl_fmtext_append_normal(&fm1, "123123123123");
720  owl_regex_create(&re, "12");
721  {
722    int count = 0, offset;
723    offset = owl_fmtext_search(&fm1, &re, 0);
724    while (offset >= 0) {
725      FAIL_UNLESS("search matches",
726                  !strncmp("12", owl_fmtext_get_text(&fm1) + offset, 2));
727      count++;
728      offset = owl_fmtext_search(&fm1, &re, offset+1);
729    }
730    FAIL_UNLESS("exactly four matches", count == 4);
731  }
732  owl_regex_cleanup(&re);
733
734  /* Test owl_fmtext_line_number. */
735  owl_fmtext_clear(&fm1);
736  owl_fmtext_append_normal(&fm1, "123\n456\n");
737  owl_fmtext_append_bold(&fm1, "");
738  FAIL_UNLESS("lines start at 0", 0 == owl_fmtext_line_number(&fm1, 0));
739  FAIL_UNLESS("trailing formatting characters part of false line",
740              2 == owl_fmtext_line_number(&fm1, owl_fmtext_num_bytes(&fm1)));
741  owl_regex_create_quoted(&re, "456");
742  FAIL_UNLESS("correctly find second line (line 1)",
743              1 == owl_fmtext_line_number(&fm1, owl_fmtext_search(&fm1, &re, 0)));
744  owl_regex_cleanup(&re);
745
746  /* Test owl_fmtext_line_extents. */
747  owl_fmtext_clear(&fm1);
748  owl_fmtext_append_normal(&fm1, "123\n456\n789");
749  owl_fmtext_line_extents(&fm1, 1, &start, &end);
750  FAIL_UNLESS("line contents",
751              !strncmp("456\n", owl_fmtext_get_text(&fm1)+start, end-start));
752  owl_fmtext_line_extents(&fm1, 2, &start, &end);
753  FAIL_UNLESS("point to end of buffer", end == owl_fmtext_num_bytes(&fm1));
754
755  owl_fmtext_cleanup(&fm1);
756  owl_fmtext_cleanup(&fm2);
757
758  printf("# END testing owl_fmtext (%d failures)\n", numfailed);
759
760  return numfailed;
761}
762
763static int owl_smartfilter_test_equals(const char *filtname, const char *expected) {
764  owl_filter *f = NULL;
765  char *filtstr = NULL;
766  int failed = 0;
767  f = owl_global_get_filter(&g, filtname);
768  if (f == NULL) {
769    printf("not ok filter missing: %s\n", filtname);
770    failed = 1;
771    goto out;
772  }
773
774  /* TODO: Come up with a better way to test this. */
775  filtstr = owl_filter_print(f);
776  if (strcmp(expected, filtstr)) {
777    printf("not ok filter incorrect: |%s| instead of |%s|\n",
778           filtstr, expected);
779    failed = 1;
780    goto out;
781  }
782
783 out:
784  g_free(filtstr);
785  return failed;
786}
787
788static int owl_classinstfilt_test(const char *c, const char *i, int related, const char *expected) {
789  char *filtname = NULL;
790  int failed = 0;
791
792  filtname = owl_function_classinstfilt(c, i, related);
793  if (filtname == NULL) {
794    printf("not ok null filtname: %s %s %s\n", c, i ? i : "(null)",
795           related ? "related" : "not related");
796    failed = 1;
797    goto out;
798  }
799  if (owl_smartfilter_test_equals(filtname, expected)) {
800    failed = 1;
801    goto out;
802  }
803 out:
804  if (!failed) {
805    printf("ok %s\n", filtname);
806  }
807  if (filtname)
808    owl_global_remove_filter(&g, filtname);
809  g_free(filtname);
810  return failed;
811}
812
813static int owl_zuserfilt_test(const char *longuser, const char *expected) {
814  char *filtname = NULL;
815  int failed = 0;
816
817  filtname = owl_function_zuserfilt(longuser);
818  if (filtname == NULL) {
819    printf("not ok null filtname: %s\n", longuser);
820    failed = 1;
821    goto out;
822  }
823  if (owl_smartfilter_test_equals(filtname, expected)) {
824    failed = 1;
825    goto out;
826  }
827 out:
828  if (!failed) {
829    printf("ok %s\n", filtname);
830  }
831  if (filtname)
832    owl_global_remove_filter(&g, filtname);
833  g_free(filtname);
834  return failed;
835}
836
837
838int owl_smartfilter_regtest(void) {
839  int numfailed = 0;
840
841  printf("# BEGIN testing owl_smartfilter\n");
842
843  /* Check classinst making. */
844
845#define TEST_CLASSINSTFILT(c, i, r, e) do {             \
846    numtests++;                                         \
847    numfailed += owl_classinstfilt_test(c, i, r, e);    \
848  } while (0)
849  TEST_CLASSINSTFILT("message", NULL, false,
850                     "class ^message$\n");
851  TEST_CLASSINSTFILT("message", NULL, true,
852                     "class ^(un)*message(\\.d)*$\n");
853  TEST_CLASSINSTFILT("message", "personal", false,
854                     "class ^message$ and instance ^personal$\n");
855  TEST_CLASSINSTFILT("message", "personal", true,
856                     "class ^(un)*message(\\.d)*$ and ( instance ^(un)*personal(\\.d)*$ )\n");
857
858  TEST_CLASSINSTFILT("message", "evil\tinstance", false,
859                     "class ^message$ and instance '^evil\tinstance$'\n");
860  TEST_CLASSINSTFILT("message", "evil instance", false,
861                     "class ^message$ and instance '^evil instance$'\n");
862  TEST_CLASSINSTFILT("message", "evil'instance", false,
863                     "class ^message$ and instance \"^evil'instance$\"\n");
864  TEST_CLASSINSTFILT("message", "evil\"instance", false,
865                     "class ^message$ and instance '^evil\"instance$'\n");
866  TEST_CLASSINSTFILT("message", "evil$instance", false,
867                     "class ^message$ and instance ^evil\\$instance$\n");
868
869#define TEST_ZUSERFILT(l, e) do {                       \
870    numtests++;                                         \
871    numfailed += owl_zuserfilt_test(l, e);              \
872  } while (0)
873  TEST_ZUSERFILT("user",
874                 "( type ^zephyr$ and filter personal and "
875                 "( ( direction ^in$ and sender "
876                 "^user$"
877                 " ) or ( direction ^out$ and recipient "
878                 "^user$"
879                 " ) ) ) or ( ( class ^login$ ) and ( sender "
880                 "^user$"
881                 " ) )\n");
882  TEST_ZUSERFILT("very evil\t.user",
883                 "( type ^zephyr$ and filter personal and "
884                 "( ( direction ^in$ and sender "
885                 "'^very evil\t\\.user$'"
886                 " ) or ( direction ^out$ and recipient "
887                 "'^very evil\t\\.user$'"
888                 " ) ) ) or ( ( class ^login$ ) and ( sender "
889                 "'^very evil\t\\.user$'"
890                 " ) )\n");
891
892  printf("# END testing owl_smartfilter (%d failures)\n", numfailed);
893
894  return numfailed;
895}
896
897int owl_history_regtest(void)
898{
899  int numfailed = 0;
900  int i;
901  owl_history h;
902
903  printf("# BEGIN testing owl_history\n");
904  owl_history_init(&h);
905
906  /* Operations on empty history. */
907  FAIL_UNLESS("prev NULL", owl_history_get_prev(&h) == NULL);
908  FAIL_UNLESS("next NULL", owl_history_get_next(&h) == NULL);
909  FAIL_UNLESS("untouched", !owl_history_is_touched(&h));
910
911  /* Insert a few records. */
912  owl_history_store(&h, "a", false);
913  owl_history_store(&h, "b", false);
914  owl_history_store(&h, "c", false);
915  owl_history_store(&h, "d", true);
916
917  /* Walk up and down the history a bit. */
918  FAIL_UNLESS("untouched", !owl_history_is_touched(&h));
919  FAIL_UNLESS("prev c", strcmp(owl_history_get_prev(&h), "c") == 0);
920  FAIL_UNLESS("touched", owl_history_is_touched(&h));
921  FAIL_UNLESS("next d", strcmp(owl_history_get_next(&h), "d") == 0);
922  FAIL_UNLESS("untouched", !owl_history_is_touched(&h));
923  FAIL_UNLESS("next NULL", owl_history_get_next(&h) == NULL);
924  FAIL_UNLESS("prev c", strcmp(owl_history_get_prev(&h), "c") == 0);
925  FAIL_UNLESS("prev b", strcmp(owl_history_get_prev(&h), "b") == 0);
926  FAIL_UNLESS("prev a", strcmp(owl_history_get_prev(&h), "a") == 0);
927  FAIL_UNLESS("prev NULL", owl_history_get_prev(&h) == NULL);
928
929  /* Now insert something. It should reset and blow away 'd'. */
930  owl_history_store(&h, "e", false);
931  FAIL_UNLESS("untouched", !owl_history_is_touched(&h));
932  FAIL_UNLESS("next NULL", owl_history_get_next(&h) == NULL);
933  FAIL_UNLESS("prev c", strcmp(owl_history_get_prev(&h), "c") == 0);
934  FAIL_UNLESS("touched", owl_history_is_touched(&h));
935  FAIL_UNLESS("next e", strcmp(owl_history_get_next(&h), "e") == 0);
936  FAIL_UNLESS("untouched", !owl_history_is_touched(&h));
937
938  /* Lines get de-duplicated on insert. */
939  owl_history_store(&h, "e", false);
940  owl_history_store(&h, "e", false);
941  owl_history_store(&h, "e", false);
942  FAIL_UNLESS("prev c", strcmp(owl_history_get_prev(&h), "c") == 0);
943  FAIL_UNLESS("next e", strcmp(owl_history_get_next(&h), "e") == 0);
944
945  /* But a partial is not deduplicated, as it'll go away soon. */
946  owl_history_store(&h, "e", true);
947  FAIL_UNLESS("prev e", strcmp(owl_history_get_prev(&h), "e") == 0);
948  FAIL_UNLESS("prev c", strcmp(owl_history_get_prev(&h), "c") == 0);
949  FAIL_UNLESS("next e", strcmp(owl_history_get_next(&h), "e") == 0);
950  FAIL_UNLESS("next e", strcmp(owl_history_get_next(&h), "e") == 0);
951
952  /* Reset moves to the front... */
953  owl_history_store(&h, "f", true);
954  FAIL_UNLESS("prev e", strcmp(owl_history_get_prev(&h), "e") == 0);
955  FAIL_UNLESS("prev c", strcmp(owl_history_get_prev(&h), "c") == 0);
956  owl_history_reset(&h);
957  FAIL_UNLESS("untouched", !owl_history_is_touched(&h));
958  /* ...and destroys any pending partial entry... */
959  FAIL_UNLESS("prev c", strcmp(owl_history_get_prev(&h), "c") == 0);
960  FAIL_UNLESS("prev b", strcmp(owl_history_get_prev(&h), "b") == 0);
961  /* ...but not non-partial ones. */
962  owl_history_reset(&h);
963  FAIL_UNLESS("untouched", !owl_history_is_touched(&h));
964
965  /* Finally, check we are bounded by OWL_HISTORYSIZE. */
966  for (i = 0; i < OWL_HISTORYSIZE; i++) {
967    char *string = g_strdup_printf("mango%d", i);
968    owl_history_store(&h, string, false);
969    g_free(string);
970  }
971  /* The OWL_HISTORYSIZE'th prev gets NULL. */
972  for (i = OWL_HISTORYSIZE - 2; i >= 0; i--) {
973    char *string = g_strdup_printf("mango%d", i);
974    FAIL_UNLESS("prev mango_N", strcmp(owl_history_get_prev(&h), string) == 0);
975    g_free(string);
976  }
977  FAIL_UNLESS("prev NULL", owl_history_get_prev(&h) == NULL);
978
979  owl_history_cleanup(&h);
980
981  printf("# END testing owl_history (%d failures)\n", numfailed);
982  return numfailed;
983}
Note: See TracBrowser for help on using the repository browser.