GCC Code Coverage Report


Directory: ./
File: src/validators/param_validators.cpp
Date: 2024-07-09 12:21:25
Exec Total Coverage
Lines: 136 159 85.5%
Functions: 15 17 88.2%
Branches: 169 349 48.4%

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 "validators/param_validators.hpp"
8 #include "deserializers/array_deserializer.hpp"
9 #include "deserializers/content_deserializer.hpp"
10 #include "deserializers/object_deserializer.hpp"
11 #include "deserializers/primitive_deserializer.hpp"
12
13 namespace {
14 809 inline char GetStartChar(ParamStyle param_style)
15 {
16
3/3
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 74 times.
✓ Branch 2 taken 653 times.
809 switch (param_style) {
17 82 case ParamStyle::LABEL:
18 82 return '.';
19 74 case ParamStyle::MATRIX:
20 74 return ';';
21 653 default:
22 653 return '\0';
23 }
24 }
25
26 809 inline bool HasNameAtStart(const std::string& in, ParamStyle style, bool explode, ExtendedType type)
27 {
28
3/4
✓ Branch 0 taken 397 times.
✓ Branch 1 taken 370 times.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
809 switch (style) {
29 397 case ParamStyle::SIMPLE:
30 case ParamStyle::LABEL:
31 397 return false;
32 370 case ParamStyle::MATRIX:
33 case ParamStyle::FORM:
34 case ParamStyle::SPACE_DELIM:
35 case ParamStyle::PIPE_DELIM:
36 case ParamStyle::DEEP_OBJ:
37
6/6
✓ Branch 0 taken 259 times.
✓ Branch 1 taken 111 times.
✓ Branch 2 taken 83 times.
✓ Branch 3 taken 176 times.
✓ Branch 4 taken 98 times.
✓ Branch 5 taken 96 times.
370 return (ExtendedType::ARRAY != type && ExtendedType::OBJECT != type) || !explode;
38 42 case ParamStyle::CONTENT:
39 42 return "query" == in;
40 default:
41 return false;
42 }
43 }
44
45 260 inline char GetArrayItemsSeparator(ParamStyle param_style, bool explode)
46 {
47
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 128 times.
260 if (explode) {
48
4/4
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 52 times.
✓ Branch 3 taken 53 times.
132 switch (param_style) {
49 16 case ParamStyle::LABEL:
50 16 return '.';
51 11 case ParamStyle::MATRIX:
52 11 return ';';
53 52 case ParamStyle::FORM:
54 case ParamStyle::SPACE_DELIM:
55 case ParamStyle::PIPE_DELIM:
56 52 return '&';
57 53 default:
58 53 return ',';
59 }
60 } else {
61
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 123 times.
128 if (ParamStyle::SPACE_DELIM == param_style) {
62 5 return '%';
63
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 118 times.
123 } else if (ParamStyle::PIPE_DELIM == param_style) {
64 5 return '|';
65 }
66 }
67 118 return ',';
68 }
69 260 inline bool HasArrayRunningName(ParamStyle param_style, bool explode)
70 {
71
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 128 times.
260 if (explode) {
72
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 69 times.
132 switch (param_style) {
73 63 case ParamStyle::MATRIX:
74 case ParamStyle::FORM:
75 case ParamStyle::SPACE_DELIM:
76 case ParamStyle::PIPE_DELIM:
77 63 return true;
78 69 default:
79 69 return false;
80 }
81 }
82 128 return false;
83 }
84
85 150 inline char GetObjKVSep(bool explode)
86 {
87
2/2
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 85 times.
150 if (explode) {
88 65 return '=';
89 }
90 85 return ',';
91 }
92
93 150 inline char GetObjVKSep(ParamStyle param_style, bool explode)
94 {
95
2/2
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 85 times.
150 if (explode) {
96
4/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 25 times.
65 switch (param_style) {
97 7 case ParamStyle::LABEL:
98 7 return '.';
99 7 case ParamStyle::MATRIX:
100 7 return ';';
101 26 case ParamStyle::FORM:
102 case ParamStyle::DEEP_OBJ:
103 26 return '&';
104 25 default:
105 25 return ',';
106 }
107 }
108 85 return ',';
109 }
110
111 const std::unordered_map<std::string, ParamStyle> PARAM_STYLE_MAP = {{"simple", ParamStyle::SIMPLE},
112 {"label", ParamStyle::LABEL},
113 {"matrix", ParamStyle::MATRIX},
114 {"form", ParamStyle::FORM},
115 {"spaceDelimited", ParamStyle::SPACE_DELIM},
116 {"pipeDelimited", ParamStyle::PIPE_DELIM},
117 {"deepObject", ParamStyle::DEEP_OBJ},
118 {"content", ParamStyle::CONTENT}};
119
120 const std::unordered_map<std::string, PrimitiveType> PRIMITIVE_TYPE_MAP = {{"boolean", PrimitiveType::BOOLEAN},
121 {"integer", PrimitiveType::INTEGER},
122 {"number", PrimitiveType::NUMBER},
123 {"string", PrimitiveType::STRING}};
124
125 const std::unordered_map<std::string, ExtendedType> EXTENDED_TYPE_MAP = {{"boolean", ExtendedType::BOOLEAN},
126 {"integer", ExtendedType::INTEGER},
127 {"number", ExtendedType::NUMBER},
128 {"string", ExtendedType::STRING},
129 {"array", ExtendedType::ARRAY},
130 {"object", ExtendedType::OBJECT}};
131
132 150 ObjKTMap GetKTMap(const rapidjson::Value& param_val, const std::vector<std::string>& ref_keys)
133 {
134 150 ObjKTMap kt_map;
135
7/12
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 150 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 150 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 150 times.
✗ Branch 14 not taken.
✓ Branch 18 taken 324 times.
✓ Branch 19 taken 150 times.
474 for (const auto& prop : param_val["schema"]["properties"].GetObject()) {
136 // Ensure each property has a "type" member, and it's a string
137
2/4
✓ Branch 2 taken 324 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 324 times.
✗ Branch 6 not taken.
324 std::string prop_name(prop.name.GetString());
138
2/4
✓ Branch 1 taken 324 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 324 times.
✗ Branch 4 not taken.
324 if (prop.value.HasMember("type")) {
139
140
3/6
✓ Branch 2 taken 324 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 324 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 324 times.
✗ Branch 9 not taken.
324 std::string prop_type(prop.value["type"].GetString());
141 try {
142
4/8
✓ Branch 1 taken 324 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 324 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 324 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 324 times.
✗ Branch 11 not taken.
324 kt_map.emplace("\"" + prop_name + "\"", PRIMITIVE_TYPE_MAP.at(prop_type));
143 } catch (const std::out_of_range&) {
144 throw ValidatorInitExc("Type '" + prop_type + "' of property '" + prop_name + "' of parameter '" +
145 JoinReference(ref_keys) + "' is not supported");
146 }
147 324 } else {
148 throw ValidatorInitExc("Type id missing for property '" + prop_name + "' of parameter '" +
149 JoinReference(ref_keys) + "'");
150 }
151 474 }
152 150 return kt_map;
153 }
154
155 809 BaseDeserializer* GetDeserializer(const rapidjson::Value& param_val, const std::string& default_style,
156 bool default_explode, const std::vector<std::string>& ref_keys)
157 {
158
3/6
✓ Branch 2 taken 809 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 809 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 809 times.
✗ Branch 9 not taken.
809 std::string param_name(param_val["name"].GetString());
159
3/6
✓ Branch 2 taken 809 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 809 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 809 times.
✗ Branch 9 not taken.
809 std::string in(param_val["in"].GetString());
160
5/8
✓ Branch 1 taken 809 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 719 times.
✓ Branch 4 taken 90 times.
✓ Branch 6 taken 719 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 719 times.
✗ Branch 10 not taken.
809 auto explode(param_val.HasMember("explode") ? param_val["explode"].GetBool() : default_explode);
161 auto param_style =
162
10/18
✓ Branch 1 taken 809 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 713 times.
✓ Branch 4 taken 96 times.
✓ Branch 7 taken 713 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 713 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 713 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 96 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 809 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 713 times.
✓ Branch 23 taken 96 times.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
809 PARAM_STYLE_MAP.at(param_val.HasMember("style") ? param_val["style"].GetString() : default_style);
163
164 809 auto start = GetStartChar(param_style);
165
166
8/12
✓ Branch 1 taken 809 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 767 times.
✓ Branch 4 taken 42 times.
✓ Branch 6 taken 767 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 767 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 767 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 767 times.
✓ Branch 14 taken 42 times.
809 if (param_val.HasMember("schema") && param_val["schema"].HasMember("type")) {
167
4/8
✓ Branch 2 taken 767 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 767 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 767 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 767 times.
✗ Branch 12 not taken.
767 std::string type(param_val["schema"]["type"].GetString());
168
2/4
✓ Branch 1 taken 767 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 767 times.
✗ Branch 5 not taken.
767 auto skip_name = HasNameAtStart(in, param_style, explode, EXTENDED_TYPE_MAP.at(type));
169
4/6
✓ Branch 1 taken 767 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 357 times.
✓ Branch 4 taken 260 times.
✓ Branch 5 taken 150 times.
✗ Branch 6 not taken.
767 switch (EXTENDED_TYPE_MAP.at(type)) {
170 357 case ExtendedType::BOOLEAN:
171 case ExtendedType::INTEGER:
172 case ExtendedType::NUMBER:
173 case ExtendedType::STRING:
174
3/6
✓ Branch 1 taken 357 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 357 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 357 times.
✗ Branch 8 not taken.
357 return new PrimitiveDeserializer(param_name, start, skip_name, PRIMITIVE_TYPE_MAP.at(type));
175 260 case ExtendedType::ARRAY: {
176
8/16
✓ Branch 1 taken 260 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 260 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 260 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 260 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 260 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 260 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 260 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 260 times.
✗ Branch 20 not taken.
260 if (param_val["schema"].HasMember("items") && param_val["schema"]["items"].HasMember("type")) {
177
5/10
✓ Branch 2 taken 260 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 260 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 260 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 260 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 260 times.
✗ Branch 15 not taken.
260 auto items_type_s(std::string(param_val["schema"]["items"]["type"].GetString()));
178 try {
179
1/2
✓ Branch 1 taken 260 times.
✗ Branch 2 not taken.
260 auto items_type = PRIMITIVE_TYPE_MAP.at(items_type_s);
180 260 auto separator = GetArrayItemsSeparator(param_style, explode);
181 260 auto has_running_name = HasArrayRunningName(param_style, explode);
182
4/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 250 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 5 times.
260 bool has_20_separator(ParamStyle::SPACE_DELIM == param_style && !explode);
183 return new ArrayDeserializer(param_name, start, skip_name, items_type, separator, has_running_name,
184
2/4
✓ Branch 1 taken 260 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 260 times.
✗ Branch 5 not taken.
260 has_20_separator);
185 } catch (const std::out_of_range&) {
186 throw ValidatorInitExc("Type '" + items_type_s + "' of items of array parameter '" +
187 JoinReference(ref_keys) + "' is not supported");
188 }
189 260 } else {
190 throw ValidatorInitExc("Array parameter '" + JoinReference(ref_keys) + "' does not have type of items");
191 }
192 }
193 150 case ExtendedType::OBJECT: {
194 150 auto kv_separator = GetObjKVSep(explode);
195 150 auto vk_separator = GetObjVKSep(param_style, explode);
196 150 auto is_deep_obj(ParamStyle::DEEP_OBJ == param_style);
197
1/2
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
150 auto kt_map = GetKTMap(param_val, ref_keys);
198 return new ObjectDeserializer(param_name, start, skip_name, kv_separator, vk_separator, is_deep_obj,
199
2/4
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
150 kt_map);
200 150 }
201 default:
202 throw ValidatorInitExc("Invalid type of parameter: " + JoinReference(ref_keys));
203 }
204
2/4
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
809 } else if (param_val.HasMember("content")) {
205
1/2
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
42 auto skip_name = HasNameAtStart(in, ParamStyle::CONTENT, explode, ExtendedType::OBJECT);
206
2/4
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
42 return new ContentDeserializer(param_name, start, skip_name);
207 }
208 throw ValidatorInitExc("Invalid type of parameter: " + JoinReference(ref_keys));
209 809 }
210 } // namespace
211
212 809 ParamValidator::ParamValidator(const ParamInfo& param_info, const std::vector<std::string>& ref_keys,
213 809 ValidationError err_code)
214 : JsonValidator(param_info.schema, ref_keys, err_code)
215 809 , name_(param_info.name)
216 809 , required_(param_info.required)
217
1/2
✓ Branch 2 taken 809 times.
✗ Branch 3 not taken.
809 , deserializer_(param_info.deserializer)
218 {
219 809 }
220
221 208 ValidationError ParamValidator::ValidateParam(const char* beg, const char* end, std::string& error_msg)
222 {
223 try {
224
2/2
✓ Branch 1 taken 150 times.
✓ Branch 2 taken 58 times.
208 auto ret = deserializer_->Deserialize(beg, end);
225
1/2
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
150 return JsonValidator::Validate(ret, error_msg);
226
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 58 times.
208 } catch (const DeserializationException& exc) {
227
2/4
✓ Branch 2 taken 58 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 58 times.
✗ Branch 6 not taken.
58 error_msg = err_header_ + exc.what() + "}}";
228 58 return code_on_error_;
229 58 }
230 }
231
232 4 bool ParamValidator::IsRequired() const
233 {
234 4 return required_;
235 }
236
237 ValidationError ParamValidator::ErrorOnMissing(std::string& error_msg) const
238 {
239 error_msg = err_header_ + R"("description":"Missing required parameter ')" + name_ + R"('"}})";
240 return code_on_error_;
241 }
242
243 809 ParamValidator::ParamInfo ParamValidator::GetParamInfo(const rapidjson::Value& param_val,
244 const std::string& default_style, bool default_explode,
245 bool default_required, const std::vector<std::string>& ref_keys)
246 {
247
3/6
✓ Branch 2 taken 809 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 809 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 809 times.
✗ Branch 9 not taken.
809 std::string name(param_val["name"].GetString());
248
5/8
✓ Branch 1 taken 809 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 737 times.
✓ Branch 4 taken 72 times.
✓ Branch 6 taken 737 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 737 times.
✗ Branch 10 not taken.
809 auto required(param_val.HasMember("required") ? param_val["required"].GetBool() : default_required);
249
250
3/4
✓ Branch 1 taken 809 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 767 times.
✓ Branch 4 taken 42 times.
809 if (param_val.HasMember("schema")) {
251 1534 return {name, required, GetDeserializer(param_val, default_style, default_explode, ref_keys),
252
3/6
✓ Branch 1 taken 767 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 767 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 767 times.
✗ Branch 8 not taken.
767 param_val["schema"]};
253
6/12
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 42 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 42 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 42 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 42 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 42 times.
✗ Branch 14 not taken.
84 } else if (param_val.HasMember("content") && param_val["content"].HasMember("application/json") &&
254
4/8
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 42 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 42 times.
✗ Branch 10 not taken.
42 param_val["content"]["application/json"].HasMember("schema")) {
255 84 return {name, required, GetDeserializer(param_val, default_style, default_explode, ref_keys),
256
5/10
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 42 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 42 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 42 times.
✗ Branch 14 not taken.
42 param_val["content"]["application/json"]["schema"]};
257 } else {
258 throw ValidatorInitExc("Cannot generate deserializer for parameter: " + JoinReference(ref_keys));
259 }
260 809 }
261
262 289 PathParamValidator::PathParamValidator(const rapidjson::Value& param_val, const std::vector<std::string>& ref_keys)
263
2/4
✓ Branch 1 taken 289 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 289 times.
✗ Branch 5 not taken.
578 : ParamValidator(ParamValidator::GetParamInfo(param_val, "simple", false, true, ref_keys), ref_keys,
264
1/2
✓ Branch 2 taken 289 times.
✗ Branch 3 not taken.
578 ValidationError::INVALID_PATH_PARAM)
265 {
266 289 }
267
268 314 QueryParamValidator::QueryParamValidator(const rapidjson::Value& param_val, const std::vector<std::string>& ref_keys)
269
2/4
✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 314 times.
✗ Branch 5 not taken.
628 : ParamValidator(ParamValidator::GetParamInfo(param_val, "form", true, false, ref_keys), ref_keys,
270 ValidationError::INVALID_QUERY_PARAM)
271
3/12
✓ Branch 2 taken 314 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 314 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 314 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
942 , empty_allowed_(param_val.HasMember("allowEmptyValue") && param_val["allowEmptyValue"].GetBool())
272 {
273 314 }
274
275 bool QueryParamValidator::IsEmptyAllowed() const
276 {
277 return empty_allowed_;
278 }
279
280 206 HeaderParamValidator::HeaderParamValidator(const rapidjson::Value& param_val, const std::vector<std::string>& ref_keys)
281
2/4
✓ Branch 1 taken 206 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 206 times.
✗ Branch 5 not taken.
412 : ParamValidator(ParamValidator::GetParamInfo(param_val, "simple", false, false, ref_keys), ref_keys,
282
1/2
✓ Branch 2 taken 206 times.
✗ Branch 3 not taken.
412 ValidationError::INVALID_HEADER_PARAM)
283 {
284 206 }
285