aboutsummaryrefslogtreecommitdiffstats
path: root/tests/kdl_test.c
blob: ca3ed0ecc5d77bd8311b8b552ae89a1323b2460f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/* Parser cases for the KDL subset. Pure input -> tree, so pure tests. */
#include "kdl.h"

#include <stdio.h>
#include <string.h>

static int fails = 0;

static void ok(const char *name, bool cond, const char *detail) {
  if (!cond) fails++;
  printf("%s %-44s %s\n", cond ? "ok  " : "FAIL", name, cond ? "" : detail);
}

static const kdl_node_t *top(const kdl_node_t *root, const char *name) {
  return kdl_child(root, name);
}

int main(void) {
  char err[256];

  {
    const char *doc = "// a comment\n"
                      "gap 1\n"
                      "rounded true\n"
                      "title \"hello world\"\n"
                      "min_pane cols=24 rows=6\n"
                      "/* block\n   comment */\n"
                      "theme {\n"
                      "  frame_focus \"#ff5fd7\"\n"
                      "  nested { deep \"value\" }\n"
                      "}\n"
                      "oneline { a \"1\"; b \"2\" }\n";
    kdl_node_t *root = kdl_parse(doc, err, sizeof err);
    ok("a document parses", root != NULL, err);
    if (!root) return 1;

    ok("integer argument", kdl_arg_int(top(root, "gap"), 0, -1) == 1, "");
    ok("boolean argument", kdl_arg_bool(top(root, "rounded"), 0, false), "");
    ok("quoted string with a space",
       strcmp(kdl_arg(top(root, "title"), 0, ""), "hello world") == 0, "");
    ok("properties",
       kdl_prop_int(top(root, "min_pane"), "cols", 0) == 24 &&
           kdl_prop_int(top(root, "min_pane"), "rows", 0) == 6,
       "");
    ok("comments are skipped", top(root, "gap") && top(root, "theme"), "");

    const kdl_node_t *theme = top(root, "theme");
    ok("children", theme && theme->nkids == 2, "");
    ok("child values",
       strcmp(kdl_arg(kdl_child(theme, "frame_focus"), 0, ""), "#ff5fd7") == 0,
       "");
    ok("nesting",
       strcmp(kdl_arg(kdl_child(kdl_child(theme, "nested"), "deep"), 0, ""),
              "value") == 0,
       "");

    const kdl_node_t *one = top(root, "oneline");
    ok("semicolons separate single-line children", one && one->nkids == 2,
       one ? "wrong count" : "missing");
    kdl_free(root);
  }

  {
    /* Escapes, and the fork's hard-won lesson that a single-line node without
     * a terminator is a parse error rather than a silent surprise. */
    kdl_node_t *root = kdl_parse("a \"x\\ty\\nz\\\"q\"\n", err, sizeof err);
    ok("string escapes",
       root && strcmp(kdl_arg(top(root, "a"), 0, ""), "x\ty\nz\"q") == 0, err);
    kdl_free(root);
  }

  {
    kdl_node_t *root =
        kdl_parse("keys {\n bind \"ctrl+a\" \"quit\"\n", err, sizeof err);
    ok("an unclosed block is an error, with a line number",
       root == NULL && strstr(err, "line") != NULL, err);
    kdl_free(root);
  }

  {
    kdl_node_t *root = kdl_parse("a \"unterminated\n", err, sizeof err);
    ok("an unterminated string is an error", root == NULL, err);
    kdl_free(root);
  }

  {
    kdl_node_t *root = kdl_parse("", err, sizeof err);
    ok("an empty document is valid", root != NULL && root->nkids == 0, err);
    kdl_free(root);
  }

  printf("\n%s (%d failures)\n", fails ? "FAILED" : "all green", fails);
  return fails ? 1 : 0;
}