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