GCC Code Coverage Report


Directory: ./
File: src/oas_validator_imp.cpp
Date: 2024-07-09 12:21:25
Exec Total Coverage
Lines: 178 221 80.5%
Functions: 20 22 90.9%
Branches: 169 358 47.2%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2024 Muhammad Nawaz
3 * Licensed under the MIT License. See LICENSE file for more information.
4 */
5 // [ END OF LICENSE c6bd0f49d040fca8d8a9cb05868e66aa63f0e2e0 ]
6
7 #include "oas_validator_imp.hpp"
8 #include <algorithm>
9 #include <fstream>
10 #include <rapidjson/istreamwrapper.h>
11 #include <sstream>
12
13 7 OASValidatorImp::OASValidatorImp(const std::string& oas_specs,
14 7 const std::unordered_map<std::string, std::unordered_set<std::string>>& method_map)
15
10/20
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 7 times.
✗ Branch 12 not taken.
✓ Branch 15 taken 7 times.
✗ Branch 16 not taken.
✓ Branch 19 taken 7 times.
✗ Branch 20 not taken.
✓ Branch 23 taken 7 times.
✗ Branch 24 not taken.
✓ Branch 27 taken 7 times.
✗ Branch 28 not taken.
✓ Branch 31 taken 7 times.
✗ Branch 32 not taken.
✓ Branch 35 taken 7 times.
✗ Branch 36 not taken.
✓ Branch 38 taken 7 times.
✗ Branch 39 not taken.
7 : method_map_(BuildCaseInsensitiveMap(method_map))
16 {
17
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 rapidjson::Document doc;
18
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
7 ParseSpecs(oas_specs, doc);
19
1/2
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 ResolveReferences(doc, doc, doc.GetAllocator());
20
21
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 const rapidjson::Value& paths = doc["paths"];
22 6 std::vector<std::string> ref_keys;
23
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 ref_keys.emplace_back("paths");
24
25
4/6
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 534 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 528 times.
✓ Branch 9 taken 6 times.
534 for (auto path_itr = paths.MemberBegin(); path_itr != paths.MemberEnd(); ++path_itr) {
26
1/2
✓ Branch 1 taken 528 times.
✗ Branch 2 not taken.
528 ProcessPath(path_itr, ref_keys);
27 }
28 10 }
29
30 12 ValidationError OASValidatorImp::ValidateRoute(const std::string& method, const std::string& http_path,
31 std::string& error_msg)
32 {
33 ValidatorsStore* validators;
34
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
24 return GetValidators(method, http_path, validators, error_msg);
35 }
36
37 4 ValidationError OASValidatorImp::ValidateBody(const std::string& method, const std::string& http_path,
38 const std::string& json_body, std::string& error_msg)
39 {
40 ValidatorsStore* validators;
41
42
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 auto err_code = GetValidators(method, http_path, validators, error_msg);
43
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 CHECK_ERROR(err_code)
44
45
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 return validators->ValidateBody(json_body, error_msg);
46 }
47
48 12 ValidationError OASValidatorImp::ValidatePathParam(const std::string& method, const std::string& http_path,
49 std::string& error_msg)
50 {
51 12 std::unordered_map<size_t, ParamRange> param_idxs;
52 ValidatorsStore* validators;
53
54
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 auto err_code = GetValidators(method, http_path, validators, error_msg, &param_idxs);
55
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 CHECK_ERROR(err_code)
56
57
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 return validators->ValidatePathParams(param_idxs, error_msg);
58 12 }
59
60 6 ValidationError OASValidatorImp::ValidateQueryParam(const std::string& method, const std::string& http_path,
61 std::string& error_msg)
62 {
63 6 std::string query;
64 ValidatorsStore* validators;
65
66
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 auto err_code = GetValidators(method, http_path, validators, error_msg, nullptr, &query);
67
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 CHECK_ERROR(err_code)
68
69
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 return validators->ValidateQueryParams(query, error_msg);
70 6 }
71
72 6 ValidationError OASValidatorImp::ValidateHeaders(const std::string& method, const std::string& http_path,
73 const std::unordered_map<std::string, std::string>& headers,
74 std::string& error_msg)
75 {
76 ValidatorsStore* validators;
77
78
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 auto err_code = GetValidators(method, http_path, validators, error_msg);
79
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 CHECK_ERROR(err_code)
80
81
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 return validators->ValidateHeaderParams(headers, error_msg);
82 }
83
84 17 ValidationError OASValidatorImp::ValidateRequest(const std::string& method, const std::string& http_path,
85 std::string& error_msg)
86 {
87 17 std::unordered_map<size_t, ParamRange> param_idxs;
88 17 std::string query;
89 ValidatorsStore* validators;
90
91
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
17 auto err_code = GetValidators(method, http_path, validators, error_msg, &param_idxs, &query);
92
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 CHECK_ERROR(err_code)
93
94
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
17 err_code = validators->ValidatePathParams(param_idxs, error_msg);
95
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 10 times.
17 CHECK_ERROR(err_code)
96
97
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 return validators->ValidateQueryParams(query, error_msg);
98 17 }
99
100 1 ValidationError OASValidatorImp::ValidateRequest(const std::string& method, const std::string& http_path,
101 const std::string& json_body, std::string& error_msg)
102 {
103 1 std::unordered_map<size_t, ParamRange> param_idxs;
104 1 std::string query;
105 ValidatorsStore* validators;
106
107
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 auto err_code = GetValidators(method, http_path, validators, error_msg, &param_idxs, &query);
108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 CHECK_ERROR(err_code)
109
110
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 err_code = validators->ValidateBody(json_body, error_msg);
111
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 CHECK_ERROR(err_code)
112
113
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 err_code = validators->ValidatePathParams(param_idxs, error_msg);
114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 CHECK_ERROR(err_code)
115
116
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 return validators->ValidateQueryParams(query, error_msg);
117 1 }
118
119 3 ValidationError OASValidatorImp::ValidateRequest(const std::string& method, const std::string& http_path,
120 const std::unordered_map<std::string, std::string>& headers,
121 std::string& error_msg)
122 {
123 3 std::unordered_map<size_t, ParamRange> param_idxs;
124 3 std::string query;
125 ValidatorsStore* validators;
126
127
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 auto err_code = GetValidators(method, http_path, validators, error_msg, &param_idxs, &query);
128
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 CHECK_ERROR(err_code)
129
130
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 err_code = validators->ValidatePathParams(param_idxs, error_msg);
131
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 CHECK_ERROR(err_code)
132
133
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 err_code = validators->ValidateQueryParams(query, error_msg);
134
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 CHECK_ERROR(err_code)
135
136
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 return validators->ValidateHeaderParams(headers, error_msg);
137 3 }
138
139 3 ValidationError OASValidatorImp::ValidateRequest(const std::string& method, const std::string& http_path,
140 const std::string& json_body,
141 const std::unordered_map<std::string, std::string>& headers,
142 std::string& error_msg)
143 {
144 3 std::unordered_map<size_t, ParamRange> param_idxs;
145 3 std::string query;
146 ValidatorsStore* validators;
147
148
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 auto err_code = GetValidators(method, http_path, validators, error_msg, &param_idxs, &query);
149
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 CHECK_ERROR(err_code)
150
151
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 err_code = validators->ValidateBody(json_body, error_msg);
152
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 CHECK_ERROR(err_code)
153
154
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 err_code = validators->ValidatePathParams(param_idxs, error_msg);
155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 CHECK_ERROR(err_code)
156
157
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 err_code = validators->ValidateQueryParams(query, error_msg);
158
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 CHECK_ERROR(err_code)
159
160
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 return validators->ValidateHeaderParams(headers, error_msg);
161 3 }
162
163 12 OASValidatorImp::~OASValidatorImp()
164 {
165 #ifndef LUA_OAS_VALIDATOR // LUA manages garbage collection itself
166
2/2
✓ Branch 2 taken 54 times.
✓ Branch 3 taken 6 times.
60 for (auto& per_method_validator : oas_validators_) {
167
2/2
✓ Branch 5 taken 528 times.
✓ Branch 6 taken 54 times.
582 for (auto& per_path_validator : per_method_validator.per_path_validators) {
168
1/2
✓ Branch 0 taken 528 times.
✗ Branch 1 not taken.
528 delete per_path_validator.second;
169 }
170 }
171 #endif
172 6 }
173
174 64 ValidationError OASValidatorImp::GetValidators(const std::string& method, const std::string& http_path,
175 ValidatorsStore*& validators, std::string& error_msg,
176 std::unordered_map<size_t, ParamRange>* param_idxs, std::string* query)
177 {
178 64 auto err_code = method_validator_.Validate(method, error_msg);
179
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 63 times.
64 CHECK_ERROR(err_code)
180
181 63 err_code = GetValidators(method, method, http_path, validators, error_msg, param_idxs, query);
182
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 62 times.
63 if (ValidationError::INVALID_ROUTE == err_code) {
183 try {
184
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1 auto mapped_methods = method_map_.at(method);
185 for (const auto& mapped_method : mapped_methods) {
186 err_code = GetValidators(method, mapped_method, http_path, validators, error_msg, param_idxs, query);
187 if (ValidationError::NONE == err_code) {
188 return err_code;
189 }
190 }
191
1/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
1 } catch (const std::out_of_range&) {
192 1 return err_code;
193 1 }
194 }
195
196 62 return err_code;
197 }
198
199 63 ValidationError OASValidatorImp::GetValidators(const std::string& method, const std::string& mapped_method,
200 const std::string& http_path, ValidatorsStore*& validators,
201 std::string& error_msg,
202 std::unordered_map<size_t, ParamRange>* param_idxs, std::string* query)
203 {
204 63 auto enum_method = kStringToMethod.at(mapped_method);
205
206 63 auto query_pos = http_path.find('?');
207
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 52 times.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
63 if (std::string::npos != query_pos && query) {
208 11 *query = http_path.substr(query_pos);
209 }
210
211 try {
212 // 1st. try, no path params
213
2/2
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 43 times.
126 validators = oas_validators_[static_cast<size_t>(enum_method)].per_path_validators.at(
214
4/6
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 11 times.
✓ Branch 3 taken 52 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 11 times.
✗ Branch 7 not taken.
169 std::string::npos == query_pos ? http_path : http_path.substr(0, query_pos));
215
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
43 } catch (const std::out_of_range&) {
216 // 2nd try, if path has dynamic path parameters
217 43 std::string map_key;
218
1/2
✓ Branch 2 taken 43 times.
✗ Branch 3 not taken.
43 map_key.reserve(http_path.length() + 32);
219 43 const char* beg = http_path.c_str();
220
2/2
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 3 times.
43 const char* const end = http_path.c_str() + (std::string::npos == query_pos ? http_path.length() : query_pos);
221
3/4
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 12 times.
✓ Branch 4 taken 31 times.
✗ Branch 5 not taken.
43 bool found = param_idxs ? oas_validators_[static_cast<size_t>(enum_method)].path_trie.Search(beg, end, map_key,
222 *param_idxs)
223
1/2
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 : oas_validators_[static_cast<size_t>(enum_method)].path_trie.Search(beg, end, map_key);
224
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 1 times.
43 if (found) {
225 try {
226
1/2
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
42 validators = oas_validators_[static_cast<size_t>(enum_method)].per_path_validators.at(map_key);
227 } catch (const std::out_of_range&) {
228 error_msg = R"({"errorCode":"INVALID_ROUTE","details":{"description": "Invalid HTTP method ')" +
229 method + "' or path: '" + http_path + R"('"}})";
230 return ValidationError::INVALID_ROUTE;
231 }
232 } else {
233
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 error_msg = R"({"errorCode":"INVALID_ROUTE","details":{"description": "Invalid HTTP method ')" + method +
234
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 "' or path: '" + http_path + R"('"}})";
235 1 return ValidationError::INVALID_ROUTE;
236 }
237
4/4
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 42 times.
86 }
238 62 return ValidationError::NONE;
239 }
240
241 std::vector<std::string> OASValidatorImp::Split(const std::string& str)
242 {
243 std::vector<std::string> tokens;
244 std::string token;
245 std::istringstream token_stream(str);
246 while (getline(token_stream, token, '/')) {
247 tokens.push_back(token);
248 }
249 return tokens;
250 }
251
252 rapidjson::Value* OASValidatorImp::ResolvePath(rapidjson::Document& doc, const std::string& path)
253 {
254 std::vector<std::string> parts = Split(path);
255 rapidjson::Value* current = &doc;
256 for (const std::string& part : parts) {
257 if (!current->IsObject() || !current->HasMember(part.c_str())) {
258 throw ValidatorInitExc("Invalid path or missing member:" + part);
259 }
260 current = &(*current)[part.c_str()];
261 }
262 return current;
263 }
264
265 7 void OASValidatorImp::ParseSpecs(const std::string& oas_specs, rapidjson::Document& doc)
266 {
267
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 std::ifstream ifs(oas_specs);
268
269
3/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 1 times.
7 if (ifs.is_open()) {
270
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 rapidjson::IStreamWrapper isw(ifs);
271
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 doc.ParseStream(isw);
272
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 ifs.close();
273 } else {
274
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 doc.Parse(oas_specs.c_str());
275 }
276
277
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 6 times.
7 if (doc.HasParseError()) {
278
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
3 throw ValidatorInitExc("Unable to parse specs: " + oas_specs +
279
3/6
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
4 " \nError code: " + std::to_string(doc.GetParseError()) +
280
3/6
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
4 " at offset: " + std::to_string(doc.GetErrorOffset()) +
281
1/2
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
4 " Error message: " + rapidjson::GetParseError_En(doc.GetParseError()));
282 }
283 7 }
284
285 528 void OASValidatorImp::ProcessPath(const rapidjson::Value::ConstMemberIterator& path_itr,
286 std::vector<std::string>& ref_keys)
287 {
288
2/4
✓ Branch 3 taken 528 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 528 times.
✗ Branch 7 not taken.
528 std::string path(path_itr->name.GetString());
289
2/4
✓ Branch 1 taken 528 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 528 times.
✗ Branch 5 not taken.
528 ref_keys.emplace_back(EscapeSlash(path));
290 528 const rapidjson::Value& methods = path_itr->value;
291
292
4/6
✓ Branch 1 taken 528 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1056 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 528 times.
✓ Branch 9 taken 528 times.
1056 for (auto method_itr = methods.MemberBegin(); method_itr != methods.MemberEnd(); ++method_itr) {
293
1/2
✓ Branch 1 taken 528 times.
✗ Branch 2 not taken.
528 ProcessMethod(method_itr, path, ref_keys);
294 }
295
296 528 ref_keys.pop_back(); // Pop the path key
297 528 }
298
299 528 void OASValidatorImp::ProcessMethod(const rapidjson::Value::ConstMemberIterator& method_itr, const std::string& path,
300 std::vector<std::string>& ref_keys)
301 {
302
1/2
✓ Branch 3 taken 528 times.
✗ Branch 4 not taken.
528 ref_keys.emplace_back(method_itr->name.GetString());
303
3/6
✓ Branch 3 taken 528 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 528 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 528 times.
✗ Branch 10 not taken.
528 auto method(kStringToMethod.at(method_itr->name.GetString()));
304 528 auto& per_method_validator = oas_validators_[static_cast<size_t>(method)];
305 528 auto& per_path_validator = per_method_validator.per_path_validators;
306
307 528 ProcessRequestBody(method_itr, path, ref_keys, per_path_validator);
308 528 ProcessParameters(method_itr, path, ref_keys, per_path_validator);
309
310
5/6
✓ Branch 1 taken 186 times.
✓ Branch 2 taken 342 times.
✓ Branch 4 taken 186 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 186 times.
✓ Branch 7 taken 342 times.
528 if (std::string::npos != path.find('{') && std::string::npos != path.find('}')) { // has path params
311 186 per_method_validator.path_trie.Insert(path);
312 }
313
314 528 ref_keys.pop_back(); // Pop the method key
315 528 }
316
317 528 void OASValidatorImp::ProcessRequestBody(const rapidjson::Value::ConstMemberIterator& method_itr,
318 const std::string& path, std::vector<std::string>& ref_keys,
319 std::unordered_map<std::string, ValidatorsStore*>& per_path_validator)
320 {
321
1/2
✓ Branch 5 taken 126 times.
✗ Branch 6 not taken.
654 if ((method_itr->value.HasMember("requestBody")) && (method_itr->value["requestBody"].HasMember("content")) &&
322
5/6
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 402 times.
✓ Branch 6 taken 126 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 126 times.
✓ Branch 9 taken 402 times.
780 (method_itr->value["requestBody"]["content"].HasMember("application/json")) &&
323
1/2
✓ Branch 5 taken 126 times.
✗ Branch 6 not taken.
126 (method_itr->value["requestBody"]["content"]["application/json"].HasMember(
324 "schema"))) { // if "method+path" has json body
325 126 ref_keys.emplace_back("requestBody/content/application%2Fjson/schema");
326 126 per_path_validator.emplace(
327 path,
328
2/4
✓ Branch 7 taken 126 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 126 times.
✗ Branch 11 not taken.
126 new ValidatorsStore(method_itr->value["requestBody"]["content"]["application/json"]["schema"], ref_keys));
329 126 ref_keys.pop_back(); // pop body ref
330 } else { // Otherwise validators without body
331
1/2
✓ Branch 3 taken 402 times.
✗ Branch 4 not taken.
402 per_path_validator.emplace(path, new ValidatorsStore());
332 }
333 528 }
334
335 528 void OASValidatorImp::ProcessParameters(const rapidjson::Value::ConstMemberIterator& method_itr,
336 const std::string& path, std::vector<std::string>& ref_keys,
337 std::unordered_map<std::string, ValidatorsStore*>& per_path_validator)
338 {
339
2/2
✓ Branch 2 taken 396 times.
✓ Branch 3 taken 132 times.
528 if (method_itr->value.HasMember("parameters")) { // if "method+path" has parameters
340 396 ref_keys.emplace_back("parameters");
341 396 per_path_validator.at(path)->AddParamValidators(path, method_itr->value["parameters"], ref_keys);
342 396 ref_keys.pop_back();
343 }
344 528 }
345
346 11484 void OASValidatorImp::ResolveReferences(rapidjson::Value& value, rapidjson::Document& doc,
347 rapidjson::Document::AllocatorType& allocator)
348 {
349
2/2
✓ Branch 1 taken 5346 times.
✓ Branch 2 taken 6138 times.
11484 if (value.IsObject()) {
350 bool should_reiterate;
351
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5346 times.
5346 do {
352 5346 should_reiterate = false;
353
4/6
✓ Branch 1 taken 5346 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 15978 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10632 times.
✓ Branch 8 taken 5346 times.
15978 for (auto itr = value.MemberBegin(); itr != value.MemberEnd();) {
354
3/8
✓ Branch 2 taken 10632 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10632 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 10632 times.
10632 if (strcmp(itr->name.GetString(), "$ref") == 0 && itr->value.IsString()) {
355 std::string ref = itr->value.GetString();
356 if (ref.rfind("#/", 0) == 0) {
357 ref.erase(0, 2); // Remove '#/'
358 rapidjson::Value const* ref_value = ResolvePath(doc, ref);
359 if (ref_value) {
360 value.CopyFrom(*ref_value, allocator);
361 should_reiterate = true; // Signal to reiterate due to structural changes
362 break; // Exit the loop to avoid invalid iterator use
363 }
364 }
365 } else {
366
1/2
✓ Branch 2 taken 10632 times.
✗ Branch 3 not taken.
10632 ResolveReferences(itr->value, doc, allocator);
367 }
368 10632 ++itr;
369 }
370 } while (should_reiterate); // Keep resolving until no more references are found
371
2/2
✓ Branch 1 taken 516 times.
✓ Branch 2 taken 5622 times.
6138 } else if (value.IsArray()) {
372
2/2
✓ Branch 1 taken 846 times.
✓ Branch 2 taken 516 times.
1362 for (rapidjson::SizeType i = 0; i < value.Size(); i++) {
373 846 ResolveReferences(value[i], doc, allocator);
374 }
375 }
376 11484 }
377
378 7 std::unordered_map<std::string, std::unordered_set<std::string>> OASValidatorImp::BuildCaseInsensitiveMap(
379 const std::unordered_map<std::string, std::unordered_set<std::string>>& method_map)
380 {
381
382 7 std::unordered_map<std::string, std::unordered_set<std::string>> case_insensitive_map;
383
384
1/2
✗ Branch 5 not taken.
✓ Branch 6 taken 7 times.
7 for (const auto& entry : method_map) {
385 std::string lower_key(entry.first);
386 std::transform(lower_key.begin(), lower_key.end(), lower_key.begin(), ::tolower);
387 std::string upper_key(entry.first);
388 std::transform(upper_key.begin(), upper_key.end(), upper_key.begin(), ::toupper);
389 case_insensitive_map[lower_key] = entry.second;
390 case_insensitive_map[upper_key] = entry.second;
391 }
392
393 7 return case_insensitive_map;
394 }
395
396 const std::unordered_map<std::string, HttpMethod> OASValidatorImp::kStringToMethod = {
397 {"GET", HttpMethod::GET}, {"POST", HttpMethod::POST}, {"PUT", HttpMethod::PUT},
398 {"DELETE", HttpMethod::DELETE}, {"HEAD", HttpMethod::HEAD}, {"OPTIONS", HttpMethod::OPTIONS},
399 {"PATCH", HttpMethod::PATCH}, {"CONNECT", HttpMethod::CONNECT}, {"TRACE", HttpMethod::TRACE},
400 {"get", HttpMethod::GET}, {"post", HttpMethod::POST}, {"put", HttpMethod::PUT},
401 {"delete", HttpMethod::DELETE}, {"head", HttpMethod::HEAD}, {"options", HttpMethod::OPTIONS},
402 {"patch", HttpMethod::PATCH}, {"connect", HttpMethod::CONNECT}, {"trace", HttpMethod::TRACE}};
403