1 #include "filter_expr_executor.hpp"
2 #include "filter_expr_parser_ast.hpp"
3 #include "filter_expr_printer.hpp"
4
5 #include <nlohmann/json.hpp>
6
7 #include <optional>
8 #include <string_view>
9
10 #include <gtest/gtest.h>
11
12 namespace redfish
13 {
14
filterTrue(std::string_view filterExpr,nlohmann::json json)15 static void filterTrue(std::string_view filterExpr, nlohmann::json json)
16 {
17 std::optional<filter_ast::LogicalAnd> ast = parseFilter(filterExpr);
18 EXPECT_TRUE(ast);
19 if (!ast)
20 {
21 return;
22 }
23 EXPECT_EQ(json["Members"].size(), 1);
24 EXPECT_TRUE(applyFilterToCollection(json, *ast));
25 EXPECT_EQ(json["Members"].size(), 1);
26 }
27
filterFalse(std::string_view filterExpr,nlohmann::json json)28 static void filterFalse(std::string_view filterExpr, nlohmann::json json)
29 {
30 std::optional<filter_ast::LogicalAnd> ast = parseFilter(filterExpr);
31 EXPECT_TRUE(ast);
32 if (!ast)
33 {
34 return;
35 }
36 EXPECT_EQ(json["Members"].size(), 1);
37 EXPECT_TRUE(applyFilterToCollection(json, *ast));
38 EXPECT_EQ(json["Members"].size(), 0);
39 }
40
TEST(FilterParser,Integers)41 TEST(FilterParser, Integers)
42 {
43 const nlohmann::json members = R"({"Members": [{"Count": 2}]})"_json;
44 // Forward true conditions
45 filterTrue("Count eq 2", members);
46 filterTrue("Count ne 3", members);
47 filterTrue("Count gt 1", members);
48 filterTrue("Count ge 2", members);
49 filterTrue("Count lt 3", members);
50 filterTrue("Count le 2", members);
51
52 // Reverse true conditions
53 filterTrue("2 eq Count", members);
54 filterTrue("3 ne Count", members);
55 filterTrue("3 gt Count", members);
56 filterTrue("2 ge Count", members);
57 filterTrue("1 lt Count", members);
58 filterTrue("2 le Count", members);
59
60 // Forward false conditions
61 filterFalse("Count eq 3", members);
62 filterFalse("Count ne 2", members);
63 filterFalse("Count gt 2", members);
64 filterFalse("Count ge 3", members);
65 filterFalse("Count lt 2", members);
66 filterFalse("Count le 1", members);
67
68 // Reverse false conditions
69 filterFalse("3 eq Count", members);
70 filterFalse("2 ne Count", members);
71 filterFalse("2 gt Count", members);
72 filterFalse("1 ge Count", members);
73 filterFalse("2 lt Count", members);
74 filterFalse("3 le Count", members);
75 }
76
TEST(FilterParser,FloatingPointToInteger)77 TEST(FilterParser, FloatingPointToInteger)
78 {
79 const nlohmann::json members = R"({"Members": [{"Count": 2.0}]})"_json;
80 // Forward true conditions
81 filterTrue("Count eq 2", members);
82 filterTrue("Count ne 3", members);
83 filterTrue("Count gt 1", members);
84 filterTrue("Count ge 2", members);
85 filterTrue("Count lt 3", members);
86 filterTrue("Count le 2", members);
87
88 // Reverse true conditions
89 filterTrue("2 eq Count", members);
90 filterTrue("3 ne Count", members);
91 filterTrue("3 gt Count", members);
92 filterTrue("2 ge Count", members);
93 filterTrue("1 lt Count", members);
94 filterTrue("2 le Count", members);
95
96 // Forward false conditions
97 filterFalse("Count eq 3", members);
98 filterFalse("Count ne 2", members);
99 filterFalse("Count gt 2", members);
100 filterFalse("Count ge 3", members);
101 filterFalse("Count lt 2", members);
102 filterFalse("Count le 1", members);
103
104 // Reverse false conditions
105 filterFalse("3 eq Count", members);
106 filterFalse("2 ne Count", members);
107 filterFalse("2 gt Count", members);
108 filterFalse("1 ge Count", members);
109 filterFalse("2 lt Count", members);
110 filterFalse("3 le Count", members);
111 }
112
TEST(FilterParser,FloatingPointToFloatingPoint)113 TEST(FilterParser, FloatingPointToFloatingPoint)
114 {
115 const nlohmann::json members = R"({"Members": [{"Count": 2.0}]})"_json;
116 // Forward true conditions
117 filterTrue("Count eq 2.0", members);
118 filterTrue("Count ne 3.0", members);
119 filterTrue("Count gt 1.0", members);
120 filterTrue("Count ge 2.0", members);
121 filterTrue("Count lt 3.0", members);
122 filterTrue("Count le 2.0", members);
123
124 // Reverse true conditions
125 filterTrue("2.0 eq Count", members);
126 filterTrue("3.0 ne Count", members);
127 filterTrue("3.0 gt Count", members);
128 filterTrue("2.0 ge Count", members);
129 filterTrue("1.0 lt Count", members);
130 filterTrue("2.0 le Count", members);
131
132 // Forward false conditions
133 filterFalse("Count eq 3.0", members);
134 filterFalse("Count ne 2.0", members);
135 filterFalse("Count gt 2.0", members);
136 filterFalse("Count ge 3.0", members);
137 filterFalse("Count lt 2.0", members);
138 filterFalse("Count le 1.0", members);
139
140 // Reverse false conditions
141 filterFalse("3.0 eq Count", members);
142 filterFalse("2.0 ne Count", members);
143 filterFalse("2.0 gt Count", members);
144 filterFalse("1.0 ge Count", members);
145 filterFalse("2.0 lt Count", members);
146 filterFalse("3.0 le Count", members);
147 }
148
TEST(FilterParser,String)149 TEST(FilterParser, String)
150 {
151 const nlohmann::json members =
152 R"({"Members": [{"SerialNumber": "1234"}]})"_json;
153 // Forward true conditions
154 filterTrue("SerialNumber eq '1234'", members);
155 filterTrue("SerialNumber ne 'NotFoo'", members);
156 filterTrue("SerialNumber gt '1233'", members);
157 filterTrue("SerialNumber ge '1234'", members);
158 filterTrue("SerialNumber lt '1235'", members);
159 filterTrue("SerialNumber le '1234'", members);
160
161 // Reverse true conditions
162 filterTrue("'1234' eq SerialNumber", members);
163 filterTrue("'NotFoo' ne SerialNumber", members);
164 filterTrue("'1235' gt SerialNumber", members);
165 filterTrue("'1234' ge SerialNumber", members);
166 filterTrue("'1233' lt SerialNumber", members);
167 filterTrue("'1234' le SerialNumber", members);
168
169 // Forward false conditions
170 filterFalse("SerialNumber eq 'NotFoo'", members);
171 filterFalse("SerialNumber ne '1234'", members);
172 filterFalse("SerialNumber gt '1234'", members);
173 filterFalse("SerialNumber ge '1235'", members);
174 filterFalse("SerialNumber lt '1234'", members);
175 filterFalse("SerialNumber le '1233'", members);
176
177 // Reverse false conditions
178 filterFalse("'NotFoo' eq SerialNumber", members);
179 filterFalse("'1234' ne SerialNumber", members);
180 filterFalse("'1234' gt SerialNumber", members);
181 filterFalse("'1233' ge SerialNumber", members);
182 filterFalse("'1234' lt SerialNumber", members);
183 filterFalse("'1235' le SerialNumber", members);
184 }
185
TEST(FilterParser,StringHuman)186 TEST(FilterParser, StringHuman)
187 {
188 // Ensure that we're sorting based on human facing numbers, not
189 // lexicographic comparison
190
191 const nlohmann::json members = R"({"Members": [{}]})"_json;
192 // Forward true conditions
193 filterFalse("'20' eq '3'", members);
194 filterTrue("'20' ne '3'", members);
195 filterTrue("'20' gt '3'", members);
196 filterTrue("'20' ge '3'", members);
197 filterFalse("'20' lt '3'", members);
198 filterFalse("'20' le '3'", members);
199 }
200
TEST(FilterParser,StringSemver)201 TEST(FilterParser, StringSemver)
202 {
203 const nlohmann::json members =
204 R"({"Members": [{"Version": "20.0.2"}]})"_json;
205 // Forward true conditions
206 filterTrue("Version eq '20.0.2'", members);
207 filterTrue("Version ne '20.2.0'", members);
208 filterTrue("Version gt '20.0.1'", members);
209 filterTrue("Version gt '1.9.9'", members);
210 filterTrue("Version gt '10.9.9'", members);
211 }
212
TEST(FilterParser,Dates)213 TEST(FilterParser, Dates)
214 {
215 const nlohmann::json members =
216 R"({"Members": [{"Created": "2021-11-30T22:41:35.123+00:00"}]})"_json;
217
218 // Note, all comparisons below differ by a single millisecond
219 // Forward true conditions
220 filterTrue("Created eq '2021-11-30T22:41:35.123+00:00'", members);
221 filterTrue("Created ne '2021-11-30T22:41:35.122+00:00'", members);
222 filterTrue("Created gt '2021-11-30T22:41:35.122+00:00'", members);
223 filterTrue("Created ge '2021-11-30T22:41:35.123+00:00'", members);
224 filterTrue("Created lt '2021-11-30T22:41:35.124+00:00'", members);
225 filterTrue("Created le '2021-11-30T22:41:35.123+00:00'", members);
226
227 // Reverse true conditions
228 filterTrue("'2021-11-30T22:41:35.123+00:00' eq Created", members);
229 filterTrue("'2021-11-30T22:41:35.122+00:00' ne Created", members);
230 filterTrue("'2021-11-30T22:41:35.124+00:00' gt Created", members);
231 filterTrue("'2021-11-30T22:41:35.123+00:00' ge Created", members);
232 filterTrue("'2021-11-30T22:41:35.122+00:00' lt Created", members);
233 filterTrue("'2021-11-30T22:41:35.123+00:00' le Created", members);
234
235 // Forward false conditions
236 filterFalse("Created eq '2021-11-30T22:41:35.122+00:00'", members);
237 filterFalse("Created ne '2021-11-30T22:41:35.123+00:00'", members);
238 filterFalse("Created gt '2021-11-30T22:41:35.123+00:00'", members);
239 filterFalse("Created ge '2021-11-30T22:41:35.124+00:00'", members);
240 filterFalse("Created lt '2021-11-30T22:41:35.123+00:00'", members);
241 filterFalse("Created le '2021-11-30T22:41:35.122+00:00'", members);
242
243 // Reverse false conditions
244 filterFalse("'2021-11-30T22:41:35.122+00:00' eq Created", members);
245 filterFalse("'2021-11-30T22:41:35.123+00:00' ne Created", members);
246 filterFalse("'2021-11-30T22:41:35.123+00:00' gt Created", members);
247 filterFalse("'2021-11-30T22:41:35.122+00:00' ge Created", members);
248 filterFalse("'2021-11-30T22:41:35.123+00:00' lt Created", members);
249 filterFalse("'2021-11-30T22:41:35.124+00:00' le Created", members);
250 }
251
252 } // namespace redfish
253