Skip to content

Commit 7284178

Browse files
Refactor JSON field handling in regression tests
Refactor JSON field processing by introducing a reusable for_each_json_field function. This change simplifies the code in multiple update functions by eliminating redundant logic.
1 parent ba93c3a commit 7284178

File tree

1 file changed

+55
-132
lines changed

1 file changed

+55
-132
lines changed

test/regression/regression_test.cc

Lines changed: 55 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,32 @@ std::vector<std::pair<std::string, std::string>> json_object_to_map(
9292
return values;
9393
}
9494

95+
template <typename Callback>
96+
void for_each_json_field(modsecurity_test::json::JsonValue value,
97+
Callback callback) {
98+
modsecurity_test::json::JsonObject object;
99+
100+
if (modsecurity_test::json::get(value.get_object(), &object) == false) {
101+
return;
102+
}
103+
104+
for (auto field_result : object) {
105+
modsecurity_test::json::JsonField field;
106+
std::string_view key;
107+
modsecurity_test::json::JsonValue child;
108+
109+
if (modsecurity_test::json::get(field_result, &field) == false) {
110+
continue;
111+
}
112+
if (modsecurity_test::json::get(field.unescaped_key(), &key) == false) {
113+
continue;
114+
}
115+
116+
child = field.value();
117+
callback(key, child);
118+
}
119+
}
120+
95121
void set_int_from_json(int &dest, std::string_view want_key,
96122
std::string_view key, modsecurity_test::json::JsonValue value) {
97123
if (key == want_key) {
@@ -204,27 +230,10 @@ std::unique_ptr<RegressionTest> RegressionTest::from_json_document(
204230

205231
std::unique_ptr<RegressionTest> RegressionTest::from_json_value(
206232
modsecurity_test::json::JsonValue value) {
207-
modsecurity_test::json::JsonObject object;
208233
auto test = make_empty_regression_test();
209234

210-
if (modsecurity_test::json::get(value.get_object(), &object) == false) {
211-
return test;
212-
}
213-
214-
for (auto field_result : object) {
215-
modsecurity_test::json::JsonField field;
216-
std::string_view key;
217-
modsecurity_test::json::JsonValue child;
218-
219-
if (modsecurity_test::json::get(field_result, &field)
220-
== false) {
221-
continue;
222-
}
223-
if (modsecurity_test::json::get(field.unescaped_key(), &key) == false) {
224-
continue;
225-
}
226-
child = field.value();
227-
235+
for_each_json_field(value, [&test](std::string_view key,
236+
modsecurity_test::json::JsonValue child) {
228237
set_int_from_json(test->enabled, "enabled", key, child);
229238
set_int_from_json(test->version_min, "version_min", key, child);
230239
set_opt_int_from_json(test->version_max, "version_max", key, child);
@@ -246,89 +255,35 @@ std::unique_ptr<RegressionTest> RegressionTest::from_json_value(
246255
} else if (key == "rules") {
247256
test->update_rules_from_json_value(child);
248257
}
249-
}
258+
});
250259

251260
test->name = test->title;
252261
return test;
253262
}
254263

255264
void RegressionTest::update_client_from_json_value(
256265
modsecurity_test::json::JsonValue value) {
257-
modsecurity_test::json::JsonObject object;
258-
259-
if (modsecurity_test::json::get(value.get_object(), &object) == false) {
260-
return;
261-
}
262-
263-
for (auto field_result : object) {
264-
modsecurity_test::json::JsonField field;
265-
std::string_view key;
266-
modsecurity_test::json::JsonValue child;
267-
268-
if (modsecurity_test::json::get(field_result, &field)
269-
== false) {
270-
continue;
271-
}
272-
if (modsecurity_test::json::get(field.unescaped_key(), &key) == false) {
273-
continue;
274-
}
275-
child = field.value();
276-
266+
for_each_json_field(value, [this](std::string_view key,
267+
modsecurity_test::json::JsonValue child) {
277268
set_string_from_json(clientIp, "ip", key, child);
278269
set_int_from_json(clientPort, "port", key, child);
279-
}
270+
});
280271
}
281272

282273
void RegressionTest::update_server_from_json_value(
283274
modsecurity_test::json::JsonValue value) {
284-
modsecurity_test::json::JsonObject object;
285-
286-
if (modsecurity_test::json::get(value.get_object(), &object) == false) {
287-
return;
288-
}
289-
290-
for (auto field_result : object) {
291-
modsecurity_test::json::JsonField field;
292-
std::string_view key;
293-
modsecurity_test::json::JsonValue child;
294-
295-
if (modsecurity_test::json::get(field_result, &field)
296-
== false) {
297-
continue;
298-
}
299-
if (modsecurity_test::json::get(field.unescaped_key(), &key) == false) {
300-
continue;
301-
}
302-
child = field.value();
303-
275+
for_each_json_field(value, [this](std::string_view key,
276+
modsecurity_test::json::JsonValue child) {
304277
set_string_from_json(serverIp, "ip", key, child);
305278
set_int_from_json(serverPort, "port", key, child);
306279
set_string_from_json(hostname, "hostname", key, child);
307-
}
280+
});
308281
}
309282

310283
void RegressionTest::update_request_from_json_value(
311284
modsecurity_test::json::JsonValue value) {
312-
modsecurity_test::json::JsonObject object;
313-
314-
if (modsecurity_test::json::get(value.get_object(), &object) == false) {
315-
return;
316-
}
317-
318-
for (auto field_result : object) {
319-
modsecurity_test::json::JsonField field;
320-
std::string_view key;
321-
modsecurity_test::json::JsonValue child;
322-
323-
if (modsecurity_test::json::get(field_result, &field)
324-
== false) {
325-
continue;
326-
}
327-
if (modsecurity_test::json::get(field.unescaped_key(), &key) == false) {
328-
continue;
329-
}
330-
child = field.value();
331-
285+
for_each_json_field(value, [this](std::string_view key,
286+
modsecurity_test::json::JsonValue child) {
332287
set_string_from_json(uri, "uri", key, child);
333288
set_string_from_json(method, "method", key, child);
334289
if (key == "http_version") {
@@ -339,70 +294,34 @@ void RegressionTest::update_request_from_json_value(
339294
request_body_lines = json_array_to_vec_string(child);
340295
request_body = join_strings(request_body_lines);
341296
}
342-
}
297+
});
343298
}
344299

345300
void RegressionTest::update_response_from_json_value(
346301
modsecurity_test::json::JsonValue value) {
347-
modsecurity_test::json::JsonObject object;
348-
349-
if (modsecurity_test::json::get(value.get_object(), &object) == false) {
350-
return;
351-
}
352-
353-
for (auto field_result : object) {
354-
modsecurity_test::json::JsonField field;
355-
std::string_view key;
356-
modsecurity_test::json::JsonValue child;
357-
358-
if (modsecurity_test::json::get(field_result, &field)
359-
== false) {
360-
continue;
361-
}
362-
if (modsecurity_test::json::get(field.unescaped_key(), &key) == false) {
363-
continue;
364-
}
365-
child = field.value();
366-
302+
for_each_json_field(value, [this](std::string_view key,
303+
modsecurity_test::json::JsonValue child) {
367304
if (key == "headers") {
368305
response_headers = json_object_to_map(child);
369306
} else if (key == "body") {
370307
response_body_lines = json_array_to_vec_string(child);
371308
response_body = join_strings(response_body_lines);
372309
}
373310
set_string_from_json(response_protocol, "protocol", key, child);
374-
}
311+
});
375312
}
376313

377314
void RegressionTest::update_expected_from_json_value(
378315
modsecurity_test::json::JsonValue value) {
379-
modsecurity_test::json::JsonObject object;
380-
381-
if (modsecurity_test::json::get(value.get_object(), &object) == false) {
382-
return;
383-
}
384-
385-
for (auto field_result : object) {
386-
modsecurity_test::json::JsonField field;
387-
std::string_view key;
388-
modsecurity_test::json::JsonValue child;
389-
390-
if (modsecurity_test::json::get(field_result, &field)
391-
== false) {
392-
continue;
393-
}
394-
if (modsecurity_test::json::get(field.unescaped_key(), &key) == false) {
395-
continue;
396-
}
397-
child = field.value();
398-
316+
for_each_json_field(value, [this](std::string_view key,
317+
modsecurity_test::json::JsonValue child) {
399318
set_string_from_json(audit_log, "audit_log", key, child);
400319
set_string_from_json(debug_log, "debug_log", key, child);
401320
set_string_from_json(error_log, "error_log", key, child);
402321
set_int_from_json(http_code, "http_code", key, child);
403322
set_string_from_json(redirect_url, "redirect_url", key, child);
404323
set_string_from_json(parser_error, "parser_error", key, child);
405-
}
324+
});
406325
}
407326

408327
void RegressionTest::update_rules_from_json_value(
@@ -417,7 +336,6 @@ void RegressionTest::update_rules_from_json_value(
417336
rules = stream.str();
418337
}
419338

420-
421339
constexpr char ascii_tolower(char c) {
422340
return 'A' <= c && c <= 'Z' ? (c + ('a' - 'A')) : c;
423341
}
@@ -430,15 +348,18 @@ bool iequals_ascii(std::string_view a, std::string_view b) {
430348
});
431349
}
432350

433-
static bool has_chunked_header(const std::vector<std::pair<std::string, std::string>> &headers) {
351+
static bool has_chunked_header(
352+
const std::vector<std::pair<std::string, std::string>> &headers) {
434353
return std::any_of(std::begin(headers), std::end(headers),
435354
[](const auto &header) {
436355
const auto &[name, value]{header};
437-
return iequals_ascii(name, "Transfer-Encoding") && iequals_ascii(value, "chunked");
356+
return iequals_ascii(name, "Transfer-Encoding")
357+
&& iequals_ascii(value, "chunked");
438358
});
439359
}
440360

441-
static void update_content_length(std::vector<std::pair<std::string, std::string>> &headers, size_t length) {
361+
static void update_content_length(
362+
std::vector<std::pair<std::string, std::string>> &headers, size_t length) {
442363
if (has_chunked_header(headers)) {
443364
return;
444365
}
@@ -451,7 +372,8 @@ static void update_content_length(std::vector<std::pair<std::string, std::string
451372
}
452373
}
453374
if (!has_content_length) {
454-
headers.emplace_back(std::pair{"Content-Length", std::to_string(length)});
375+
headers.emplace_back(
376+
std::pair{"Content-Length", std::to_string(length)});
455377
}
456378
}
457379

@@ -493,7 +415,8 @@ std::unique_ptr<RegressionTests> RegressionTests::from_json_value(
493415
== false) {
494416
continue;
495417
}
496-
tests->tests.emplace_back(RegressionTest::from_json_value(test_value));
418+
tests->tests.emplace_back(
419+
RegressionTest::from_json_value(test_value));
497420
}
498421
return tests;
499422
}
@@ -506,7 +429,7 @@ std::unique_ptr<RegressionTests> RegressionTests::from_json_value(
506429
}
507430

508431
void RegressionTests::update_content_lengths() {
509-
for (auto & test : tests) {
432+
for (auto &test : tests) {
510433
test->update_content_lengths();
511434
}
512435
}

0 commit comments

Comments
 (0)