Skip to content

Commit 488370c

Browse files
committed
Modify RegressionTest and use it for output formatted JSON
1 parent b1c59b7 commit 488370c

3 files changed

Lines changed: 125 additions & 172 deletions

File tree

test/common/modsecurity_test.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,10 @@ bool ModSecurityTest<T>::load_test_json(const std::string &file) {
8484
const auto key = u->filename + ":" + u->name;
8585
(*this)[key].push_back(std::move(u));
8686
}
87-
88-
yajl_tree_free(node);
8987
}
9088

89+
yajl_tree_free(node);
90+
9191
return true;
9292
}
9393

test/regression/regression_test.cc

Lines changed: 114 additions & 165 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ RegressionTest *RegressionTest::from_yajl_node(const yajl_val &node) {
162162
}
163163
if (strcmp(key2, "body") == 0) {
164164
u->request_body = yajl_array_to_str(val2);
165+
u->request_body_lines = yajl_array_to_vec_str(val2);
165166
}
166167
}
167168
}
@@ -175,6 +176,7 @@ RegressionTest *RegressionTest::from_yajl_node(const yajl_val &node) {
175176
}
176177
if (strcmp(key2, "body") == 0) {
177178
u->response_body = yajl_array_to_str(val2);
179+
u->response_body_lines = yajl_array_to_vec_str(val2);
178180
}
179181
if (strcmp(key2, "protocol") == 0) {
180182
u->response_protocol = YAJL_GET_STRING(val2);
@@ -214,6 +216,7 @@ RegressionTest *RegressionTest::from_yajl_node(const yajl_val &node) {
214216
si << keyj << "\n";
215217
}
216218
u->rules = si.str();
219+
u->rules_lines = yajl_array_to_vec_str(val);
217220
}
218221
}
219222

@@ -223,7 +226,7 @@ RegressionTest *RegressionTest::from_yajl_node(const yajl_val &node) {
223226
}
224227

225228
RegressionTests *RegressionTests::from_yajl_node(const yajl_val &node) {
226-
RegressionTests *u = new RegressionTests(node);
229+
RegressionTests *u = new RegressionTests();
227230
size_t num_tests = node->u.array.len;
228231
for ( int i = 0; i < num_tests; i++ ) {
229232
yajl_val obj = node->u.array.values[i];
@@ -232,94 +235,82 @@ RegressionTests *RegressionTests::from_yajl_node(const yajl_val &node) {
232235
return u;
233236
}
234237

235-
RegressionTests::~RegressionTests() {
236-
#ifdef WITH_YAJL
237-
yajl_tree_free(node);
238-
#endif
239-
}
240-
241238
#ifdef WITH_YAJL
242239

243-
static yajl_gen_status jayl_gen_string_view(yajl_gen g, std::string_view s) {
240+
static yajl_gen_status gen_string_view(yajl_gen g, std::string_view s) {
244241
return yajl_gen_string(g, reinterpret_cast<const unsigned char *>(s.data()), s.length());
245242
}
246243

247-
static yajl_gen_status jayl_gen_key_val(yajl_gen g, std::string_view key, std::string_view val) {
248-
auto s = jayl_gen_string_view(g, key);
249-
if (s != yajl_gen_status_ok) {
244+
static yajl_gen_status gen_key_str(yajl_gen g, std::string_view key, std::string_view val) {
245+
if (auto s{gen_string_view(g, key)}; s != yajl_gen_status_ok) {
250246
return s;
251247
}
252-
return jayl_gen_string_view(g, val);
248+
return gen_string_view(g, val);
253249
}
254250

255-
static yajl_gen_status copy_number(yajl_gen g, std::string_view key, yajl_val val) {
256-
if (!YAJL_IS_NUMBER(val)) {
257-
std::cerr << "error: " << key << " must be number.\n";
258-
exit(1);
251+
static yajl_gen_status gen_key_str_if_non_empty(yajl_gen g, std::string_view key, std::string_view val) {
252+
if (val.empty()) {
253+
return yajl_gen_status_ok;
259254
}
260-
auto s = jayl_gen_string_view(g, key);
261-
if (s != yajl_gen_status_ok) {
255+
return gen_key_str(g, key, val);
256+
}
257+
258+
static yajl_gen_status gen_key_int(yajl_gen g, std::string_view key, int val) {
259+
if (auto s{gen_string_view(g, key)}; s != yajl_gen_status_ok) {
262260
return s;
263261
}
264-
return yajl_gen_number(g,
265-
reinterpret_cast<const char *>(val->u.number.r),
266-
strlen(val->u.number.r));
262+
return yajl_gen_integer(g, val);
267263
}
268264

269-
static yajl_gen_status copy_string(yajl_gen g, std::string_view key, yajl_val val) {
270-
if (!YAJL_IS_STRING(val)) {
271-
std::cerr << "error: " << key << " must be string.\n";
272-
exit(1);
265+
static yajl_gen_status gen_key_opt_int(yajl_gen g, std::string_view key, std::optional<int> val) {
266+
if (!val) {
267+
return yajl_gen_status_ok;
273268
}
274-
return jayl_gen_key_val(g, key, val->u.string);
269+
return gen_key_int(g, key, val.value());
275270
}
276271

277-
static void ensure_obj(std::string_view key, yajl_val obj) {
278-
if (!YAJL_IS_OBJECT(obj)) {
279-
std::cerr << "error: " << key << " must be object.\n";
280-
exit(1);
272+
static yajl_gen_status gen_key_int_if_non_zero(yajl_gen g, std::string_view key, int val) {
273+
if (val == 0) {
274+
return yajl_gen_status_ok;
281275
}
276+
return gen_key_int(g, key, val);
282277
}
283278

284-
static void copy_str_map(yajl_gen g, std::string_view key, yajl_val val) {
285-
if (!YAJL_IS_OBJECT(val)) {
286-
std::cerr << "error: " << key << " must be object.\n";
287-
exit(1);
288-
}
289-
jayl_gen_string_view(g, key);
290-
yajl_gen_map_open(g);
291-
for (size_t i = 0; i < val->u.object.len; ++i) {
292-
const char *key2 = val->u.object.keys[i];
293-
yajl_val val2 = val->u.object.values[i];
294-
copy_string(g, key2, val2);
279+
static yajl_gen_status gen_key_number(yajl_gen g, std::string_view key, std::string_view raw_val) {
280+
if (auto s{gen_string_view(g, key)}; s != yajl_gen_status_ok) {
281+
return s;
295282
}
296-
yajl_gen_map_close(g);
283+
return yajl_gen_number(g, reinterpret_cast<const char *>(raw_val.data()), raw_val.length());
297284
}
298285

299-
static void copy_str_array(yajl_gen g, std::string_view key, yajl_val val) {
300-
if (!YAJL_IS_ARRAY(val)) {
301-
std::cerr << "error: " << key << " must be array.\n";
302-
exit(1);
286+
static yajl_gen_status gen_key_str_array(yajl_gen g, std::string_view key, const std::vector<std::string> &lines) {
287+
if (auto s{gen_string_view(g, key)}; s != yajl_gen_status_ok) {
288+
return s;
303289
}
304-
jayl_gen_string_view(g, key);
305-
yajl_gen_array_open(g);
306-
for (size_t i = 0; i < val->u.array.len; ++i) {
307-
yajl_val val2 = val->u.array.values[i];
308-
if (!YAJL_IS_STRING(val2)) {
309-
std::cerr << "error: array element of " << key << " must be string.\n";
310-
exit(1);
290+
if (auto s{yajl_gen_array_open(g)}; s != yajl_gen_status_ok) {
291+
return s;
292+
}
293+
for (const auto &line : lines) {
294+
if (auto s{gen_string_view(g, line)}; s != yajl_gen_status_ok) {
295+
return s;
311296
}
312-
jayl_gen_string_view(g, val2->u.string);
313297
}
314-
yajl_gen_array_close(g);
298+
return yajl_gen_array_close(g);
315299
}
316300

317-
static void copy_body(yajl_gen g, std::string_view key, yajl_val val) {
318-
if (YAJL_IS_STRING(val)) {
319-
jayl_gen_key_val(g, key, val->u.string);
320-
} else {
321-
copy_str_array(g, key, val);
301+
static yajl_gen_status gen_key_headers(yajl_gen g, std::string_view key, const std::vector<std::pair<std::string, std::string>> &headers) {
302+
if (auto s{gen_string_view(g, key)}; s != yajl_gen_status_ok) {
303+
return s;
304+
}
305+
if (auto s{yajl_gen_map_open(g)}; s != yajl_gen_status_ok) {
306+
return s;
307+
}
308+
for (const auto &header : headers) {
309+
if (auto s{gen_key_str(g, header.first, header.second)}; s != yajl_gen_status_ok) {
310+
return s;
311+
}
322312
}
313+
return yajl_gen_map_close(g);
323314
}
324315

325316
std::string RegressionTests::toJSON() {
@@ -332,115 +323,73 @@ std::string RegressionTests::toJSON() {
332323
return "";
333324
}
334325
yajl_gen_config(g, yajl_gen_beautify, 1);
335-
336-
if (!YAJL_IS_ARRAY(node)) {
337-
std::cerr << "error: toplevel must be array.\n";
338-
exit(1);
339-
}
326+
yajl_gen_config(g, yajl_gen_indent_string, " ");
340327

341328
yajl_gen_array_open(g);
342-
for (size_t i = 0; i < node->u.array.len; ++i) {
343-
yajl_val test_obj = node->u.array.values[i];
344-
ensure_obj("test", test_obj);
329+
for (const auto & test : tests) {
345330
yajl_gen_map_open(g);
346-
for (size_t j = 0; j < test_obj->u.object.len; ++j) {
347-
const char *key = test_obj->u.object.keys[j];
348-
yajl_val val = test_obj->u.object.values[j];
349-
if (strcmp(key, "enabled") == 0
350-
|| strcmp(key, "version_min") == 0
351-
|| strcmp(key, "version_max") == 0
352-
|| strcmp(key, "github_issue") == 0) {
353-
copy_number(g, key, val);
354-
} else if (strcmp(key, "title") == 0
355-
|| strcmp(key, "url") == 0
356-
|| strcmp(key, "resource") == 0) {
357-
copy_string(g, key, val);
358-
} else if (strcmp(key, "client") == 0) {
359-
ensure_obj("client", val);
360-
jayl_gen_string_view(g, "client");
361-
yajl_gen_map_open(g);
362-
for (size_t k = 0; k < val->u.object.len; ++k) {
363-
const char *key2 = val->u.object.keys[k];
364-
yajl_val val2 = val->u.object.values[k];
365-
if (strcmp(key2, "ip") == 0) {
366-
copy_string(g, key2, val2);
367-
} else if (strcmp(key2, "port") == 0) {
368-
copy_number(g, key2, val2);
369-
}
370-
}
371-
yajl_gen_map_close(g);
372-
} else if (strcmp(key, "server") == 0) {
373-
ensure_obj("server", val);
374-
jayl_gen_string_view(g, "server");
375-
yajl_gen_map_open(g);
376-
for (size_t k = 0; k < val->u.object.len; ++k) {
377-
const char *key2 = val->u.object.keys[k];
378-
yajl_val val2 = val->u.object.values[k];
379-
if (strcmp(key2, "ip") == 0
380-
|| strcmp(key2, "hostname") == 0) {
381-
copy_string(g, key2, val2);
382-
} else if (strcmp(key2, "port") == 0) {
383-
copy_number(g, key2, val2);
384-
}
385-
}
386-
yajl_gen_map_close(g);
387-
} else if (strcmp(key, "request") == 0) {
388-
ensure_obj("request", val);
389-
jayl_gen_string_view(g, "request");
390-
yajl_gen_map_open(g);
391-
for (size_t k = 0; k < val->u.object.len; ++k) {
392-
const char *key2 = val->u.object.keys[k];
393-
yajl_val val2 = val->u.object.values[k];
394-
if (strcmp(key2, "url") == 0
395-
|| strcmp(key2, "method") == 0) {
396-
copy_string(g, key2, val2);
397-
} else if (strcmp(key2, "http_version") == 0) {
398-
copy_number(g, key2, val2);
399-
} else if (strcmp(key2, "headers") == 0) {
400-
copy_str_map(g, key2, val2);
401-
} else if (strcmp(key2, "body") == 0) {
402-
copy_body(g, key2, val2);
403-
}
404-
}
405-
yajl_gen_map_close(g);
406-
} else if (strcmp(key, "response") == 0) {
407-
ensure_obj("response", val);
408-
jayl_gen_string_view(g, "response");
409-
yajl_gen_map_open(g);
410-
for (size_t k = 0; k < val->u.object.len; ++k) {
411-
const char *key2 = val->u.object.keys[k];
412-
yajl_val val2 = val->u.object.values[k];
413-
if (strcmp(key2, "protocol") == 0) {
414-
copy_string(g, key2, val2);
415-
} else if (strcmp(key2, "headers") == 0) {
416-
copy_str_map(g, key2, val2);
417-
} else if (strcmp(key2, "body") == 0) {
418-
copy_body(g, key2, val2);
419-
}
420-
}
421-
yajl_gen_map_close(g);
422-
} else if (strcmp(key, "expected") == 0) {
423-
ensure_obj("expected", val);
424-
jayl_gen_string_view(g, "expected");
425-
yajl_gen_map_open(g);
426-
for (size_t k = 0; k < val->u.object.len; ++k) {
427-
const char *key2 = val->u.object.keys[k];
428-
yajl_val val2 = val->u.object.values[k];
429-
if (strcmp(key2, "audit_log") == 0
430-
|| strcmp(key2, "debug_log") == 0
431-
|| strcmp(key2, "error_log") == 0
432-
|| strcmp(key2, "redirect_url") == 0
433-
|| strcmp(key2, "parser_error") == 0) {
434-
copy_string(g, key2, val2);
435-
} else if (strcmp(key2, "http_code") == 0) {
436-
copy_number(g, key2, val2);
437-
}
438-
}
439-
yajl_gen_map_close(g);
440-
} else if (strcmp(key, "rules") == 0) {
441-
copy_str_array(g, key, val);
442-
}
331+
gen_key_int(g, "enabled", test.enabled);
332+
gen_key_int(g, "version_min", test.version_min);
333+
gen_key_opt_int(g, "version_max", test.version_max);
334+
gen_key_str(g, "title", test.title);
335+
gen_key_str_if_non_empty(g, "url", test.url);
336+
gen_key_str_if_non_empty(g, "resource", test.resource);
337+
gen_key_opt_int(g, "github_issue", test.github_issue);
338+
339+
gen_string_view(g, "client");
340+
yajl_gen_map_open(g);
341+
gen_key_str(g, "ip", test.clientIp);
342+
gen_key_int(g, "port", test.clientPort);
343+
yajl_gen_map_close(g);
344+
345+
gen_string_view(g, "server");
346+
yajl_gen_map_open(g);
347+
gen_key_str(g, "ip", test.serverIp);
348+
gen_key_int(g, "port", test.serverPort);
349+
yajl_gen_map_close(g);
350+
351+
gen_string_view(g, "request");
352+
yajl_gen_map_open(g);
353+
gen_key_headers(g, "headers", test.request_headers);
354+
gen_key_str(g, "uri", test.uri);
355+
gen_key_str(g, "method", test.method);
356+
if (!test.httpVersion.empty()) {
357+
gen_key_number(g, "http_version", test.httpVersion);
358+
}
359+
360+
auto request_body_lines{test.request_body_lines};
361+
if (request_body_lines.empty()) {
362+
request_body_lines.push_back("");
363+
}
364+
gen_key_str_array(g, "body", request_body_lines);
365+
366+
yajl_gen_map_close(g);
367+
368+
gen_string_view(g, "response");
369+
yajl_gen_map_open(g);
370+
gen_key_headers(g, "headers", test.response_headers);
371+
372+
auto response_body_lines{test.response_body_lines};
373+
if (response_body_lines.empty()) {
374+
response_body_lines.push_back("");
443375
}
376+
gen_key_str_array(g, "body", response_body_lines);
377+
378+
gen_key_str_if_non_empty(g, "protocol", test.response_protocol);
379+
yajl_gen_map_close(g);
380+
381+
gen_string_view(g, "expected");
382+
yajl_gen_map_open(g);
383+
gen_key_str_if_non_empty(g, "audit_log", test.audit_log);
384+
gen_key_str_if_non_empty(g, "debug_log", test.debug_log);
385+
gen_key_str_if_non_empty(g, "error_log", test.error_log);
386+
gen_key_int(g, "http_code", test.http_code);
387+
gen_key_str_if_non_empty(g, "redirect_url", test.redirect_url);
388+
gen_key_str_if_non_empty(g, "parser_error", test.parser_error);
389+
yajl_gen_map_close(g);
390+
391+
gen_key_str_array(g, "rules", test.rules_lines);
392+
444393
yajl_gen_map_close(g);
445394
}
446395
yajl_gen_array_close(g);

0 commit comments

Comments
 (0)