rfc822: Allow test infrastructure to handle headers with minor errors
[ccan] / ccan / rfc822 / test / testdata.h
1 #ifndef RFC822_TESTDATA_H
2 #define RFC822_TESTDATA_H
3
4 #include <ccan/talloc/talloc.h>
5 #include <ccan/array_size/array_size.h>
6 #include <ccan/foreach/foreach.h>
7
8 struct testhdr {
9         const char *name, *val;
10         enum rfc822_header_errors errors;
11 };
12
13 struct aexample {
14         const char *name;
15         struct testhdr *hdrs;
16         size_t nhdrs;
17         const char *body;
18 };
19
20 #define AEXAMPLE(s)                             \
21         struct aexample s = {           \
22                 .name = #s,                     \
23                 .hdrs = s##_hdrs,               \
24                 .nhdrs = ARRAY_SIZE(s##_hdrs),  \
25                 .body = s##_body,               \
26         };
27
28 struct testhdr test_msg_1_hdrs[] = {
29         {"Date", "Tue, 22 Feb 2011 00:15:59 +1100"},
30         {"From", "Mister From <from@example.com>"},
31         {"To", "Mizz To <to@example.org>"},
32         {"Subject", "Some subject"},
33         {"Message-ID", "<20110221131559.GA28327@example>"},
34         {"MIME-Version", "1.0"},
35         {"Content-Type", "text/plain; charset=us-ascii"},
36         {"Content-Disposition", "inline"},
37 };
38 const char test_msg_1_body[] = "Test message\n";
39 AEXAMPLE(test_msg_1);
40
41 #define test_msg_empty_body_hdrs test_msg_1_hdrs
42 const char test_msg_empty_body_body[] = "";
43 AEXAMPLE(test_msg_empty_body);
44
45 #define test_msg_nlnl_lf_hdrs test_msg_1_hdrs
46 const char test_msg_nlnl_lf_body[] = "Message containing \n\n inside body\n";
47 AEXAMPLE(test_msg_nlnl_lf);
48
49 #define test_msg_nlnl_crlf_hdrs test_msg_1_hdrs
50 const char test_msg_nlnl_crlf_body[] = "Message containing \r\n\r\n inside body\r\n";
51 AEXAMPLE(test_msg_nlnl_crlf);
52
53 #define test_msg_nlnl_mixed_hdrs test_msg_1_hdrs
54 const char test_msg_nlnl_mixed_body[] = "Message containing both \n\n and \r\n\r\n inside body\n\r\n";
55 AEXAMPLE(test_msg_nlnl_mixed);
56
57 #define test_msg_space_body_hdrs test_msg_1_hdrs
58 const char test_msg_space_body_body[] = " Message with LWS at start of body\n";
59 AEXAMPLE(test_msg_space_body);
60
61 struct testhdr bad_hdrs_hdrs[] = {
62         {"From", "Mister From <from@example.com>"},
63         {"To", "Mizz To <to@example.org>"},
64         {"X-Bad-\bName", "This header field has bad characters in the name",
65                  .errors = RFC822_HDR_BAD_NAME_CHARS},
66         {"Subject", "Some subject"},
67         {"Message-ID", "<20110221131559.GA28327@example>"},
68 };
69 #define bad_hdrs_body test_msg_1_body
70 AEXAMPLE(bad_hdrs)
71
72 #define for_each_aexample(_e)                                \
73         foreach_ptr((_e), &test_msg_1, &test_msg_empty_body, \
74                     &test_msg_nlnl_lf, &test_msg_nlnl_crlf, \
75                     &test_msg_nlnl_mixed, \
76                     &test_msg_space_body, \
77                     &bad_hdrs)
78
79 #define for_each_aexample_buf(_e, _buf, _len)   \
80         for_each_aexample((_e))                 \
81         if (((_buf) = assemble_msg((_e), &(_len))) != NULL)
82
83 static inline int num_aexamples(void)
84 {
85         const struct aexample *e;
86         int n = 0;
87
88         for_each_aexample(e)
89                 n++;
90
91         return n;
92 }
93
94 static inline int num_aexample_hdrs(void)
95 {
96         const struct aexample *e;
97         int n = 0;
98
99         for_each_aexample(e)
100                 n += e->nhdrs;
101
102         return n;
103 }
104
105 static inline const char *assemble_msg(const struct aexample *e,
106                                        size_t *len, int crlf)
107 {
108         const char *nl = crlf ? "\r\n" : "\n";
109         int nln = crlf ? 2 : 1;
110         char *msg, *amsg;
111         size_t n = 0;
112         int i;
113
114         msg = talloc_strdup(NULL, "");
115         if (!msg)
116                 return NULL;
117
118         for (i = 0; i < e->nhdrs; i++) {
119                 amsg = talloc_asprintf_append(msg, "%s:%s%s", e->hdrs[i].name,
120                                               e->hdrs[i].val, nl);
121                 if (!amsg) {
122                         talloc_free(msg);
123                         return NULL;
124                 }
125                 msg = amsg;
126                 n += strlen(e->hdrs[i].name) + strlen(e->hdrs[i].val) + 1 + nln;
127         }
128         amsg = talloc_asprintf_append(msg, "%s%s", nl, e->body);
129         if (!amsg) {
130                 talloc_free(msg);
131                 return NULL;
132         }
133         msg = amsg;
134         n += strlen(e->body) + nln;
135         *len = n;
136         return msg;
137 }
138
139 #define NLT(crlf)       ((crlf) ? "CRLF" : "LF")
140
141 #endif /* RFC822_TESTDATA_H */