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