1 /*  $Id: test_expr.cpp 567764 2018-07-24 12:05:33Z ivanov $
2  * ===========================================================================
3  *
4  *                            PUBLIC DOMAIN NOTICE
5  *               National Center for Biotechnology Information
6  *
7  *  This software/database is a "United States Government Work" under the
8  *  terms of the United States Copyright Act.  It was written as part of
9  *  the author's official duties as a United States Government employee and
10  *  thus cannot be copyrighted.  This software/database is freely available
11  *  to the public for use. The National Library of Medicine and the U.S.
12  *  Government have not placed any restriction on its use or reproduction.
13  *
14  *  Although all reasonable efforts have been taken to ensure the accuracy
15  *  and reliability of the software and data, the NLM and the U.S.
16  *  Government do not and cannot warrant the performance or results that
17  *  may be obtained by using this software or data. The NLM and the U.S.
18  *  Government disclaim all warranties, express or implied, including
19  *  warranties of performance, merchantability or fitness for any particular
20  *  purpose.
21  *
22  *  Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Author: Sergey Sikorskiy, Mikhail Zakharov
27  *
28  * File Description:
29  *      Unit tests for expresiion parsing and evaluation.
30  *
31  * ===========================================================================
32  */
33 
34 
35 #include <ncbi_pch.hpp>
36 
37 #include <corelib/ncbifile.hpp>
38 #include <corelib/expr.hpp>
39 #include <corelib/test_boost.hpp>
40 
41 //#include <corelib/ncbifile.hpp>
42 
43 #include <common/test_assert.h>  /* This header must go last */
44 
45 
46 USING_NCBI_SCOPE;
47 
48 
49 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(ParseInt)50 BOOST_AUTO_TEST_CASE(ParseInt)
51 {
52     CExprParser parser;
53 
54     // Int ...
55     parser.Parse("1");
56     BOOST_CHECK_EQUAL(CExprValue::eINT, parser.GetResult().GetType());
57     BOOST_CHECK_EQUAL(1, parser.GetResult().GetInt());
58 
59     parser.Parse("1 + 1");
60     BOOST_CHECK_EQUAL(CExprValue::eINT, parser.GetResult().GetType());
61     BOOST_CHECK_EQUAL(2, parser.GetResult().GetInt());
62 
63     parser.Parse("abc + def");
64 
65     parser.Parse("1 + 2 * 3");
66     BOOST_CHECK_EQUAL(CExprValue::eINT, parser.GetResult().GetType());
67     BOOST_CHECK_EQUAL(7, parser.GetResult().GetInt());
68 
69     parser.Parse("(1 + 2) * 3");
70     BOOST_CHECK_EQUAL(CExprValue::eINT, parser.GetResult().GetType());
71     BOOST_CHECK_EQUAL(9, parser.GetResult().GetInt());
72 }
73 
74 
75 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(ParseDouble)76 BOOST_AUTO_TEST_CASE(ParseDouble)
77 {
78     CExprParser parser;
79 
80     // Double ...
81     parser.Parse("1.0");
82     BOOST_CHECK_EQUAL(CExprValue::eFLOAT, parser.GetResult().GetType());
83     BOOST_CHECK_EQUAL(1.0, parser.GetResult().GetDouble());
84 
85     parser.Parse("pi");
86     BOOST_CHECK_EQUAL(CExprValue::eFLOAT, parser.GetResult().GetType());
87     BOOST_CHECK_EQUAL(3.1415926535897932385E0, parser.GetResult().GetDouble());
88 
89     parser.Parse("e");
90     BOOST_CHECK_EQUAL(CExprValue::eFLOAT, parser.GetResult().GetType());
91     BOOST_CHECK_EQUAL(2.7182818284590452354E0, parser.GetResult().GetDouble());
92 
93     parser.Parse("abs(-1)");
94     BOOST_CHECK_EQUAL(CExprValue::eFLOAT, parser.GetResult().GetType());
95     BOOST_CHECK_EQUAL(1.0, parser.GetResult().GetDouble());
96 }
97 
98 
99 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(ParseBool)100 BOOST_AUTO_TEST_CASE(ParseBool)
101 {
102     CExprParser parser;
103 
104     // Boolean ...
105     parser.Parse("true");
106     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
107     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
108 
109     parser.Parse("false");
110     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
111     BOOST_CHECK_EQUAL(false, parser.GetResult().GetBool());
112 
113     parser.Parse("true && true");
114     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
115     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
116 
117     parser.Parse("true && false");
118     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
119     BOOST_CHECK_EQUAL(false, parser.GetResult().GetBool());
120 
121     parser.Parse("false && true");
122     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
123     BOOST_CHECK_EQUAL(false, parser.GetResult().GetBool());
124 
125     parser.Parse("false && false");
126     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
127     BOOST_CHECK_EQUAL(false, parser.GetResult().GetBool());
128 
129     parser.Parse("true || true");
130     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
131     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
132 
133     parser.Parse("true || false");
134     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
135     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
136 
137     parser.Parse("false || true");
138     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
139     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
140 
141     parser.Parse("false || false");
142     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
143     BOOST_CHECK_EQUAL(false, parser.GetResult().GetBool());
144 
145     parser.Parse("true || true && true");
146     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
147     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
148 
149     parser.Parse("false || true && true");
150     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
151     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
152 
153     parser.Parse("(false || true) && true");
154     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
155     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
156 
157     parser.Parse("true || false && true");
158     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
159     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
160 
161     parser.Parse("(true || false) && true");
162     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
163     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
164 
165     parser.Parse("true || true && false");
166     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
167     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
168 
169     parser.Parse("true && true || true");
170     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
171     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
172 
173     parser.Parse("false && (true || true)");
174     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
175     BOOST_CHECK_EQUAL(false, parser.GetResult().GetBool());
176 
177     parser.Parse("false && true || true");
178     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
179     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
180 
181     parser.Parse("true && false || true");
182     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
183     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
184 
185     parser.Parse("true && true || false");
186     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
187     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
188 
189     parser.Parse("false && true || false");
190     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
191     BOOST_CHECK_EQUAL(false, parser.GetResult().GetBool());
192 
193     parser.Parse("false && (true || false)");
194     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
195     BOOST_CHECK_EQUAL(false, parser.GetResult().GetBool());
196 
197     parser.Parse("2 > 1");
198     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
199     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
200 
201     parser.Parse("1 > 2");
202     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
203     BOOST_CHECK_EQUAL(false, parser.GetResult().GetBool());
204 
205     parser.Parse("1 != 2");
206     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
207     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
208 
209     parser.Parse("true != false");
210     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
211     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
212 
213     parser.Parse("1 == 1");
214     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
215     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
216 
217     parser.Parse("false == false");
218     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
219     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
220 
221     parser.Parse("true == true");
222     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
223     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
224 
225     parser.Parse("true ^ true");
226     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
227     BOOST_CHECK_EQUAL(false, parser.GetResult().GetBool());
228 
229     parser.Parse("false ^ false");
230     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
231     BOOST_CHECK_EQUAL(false, parser.GetResult().GetBool());
232 
233     parser.Parse("true ^ false");
234     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
235     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
236 
237     parser.Parse("false ^ true");
238     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
239     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
240 
241 }
242 
243 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(AddSymbol)244 BOOST_AUTO_TEST_CASE(AddSymbol)
245 {
246     CExprParser parser;
247 
248     parser.AddSymbol("1", Int8(1));
249     parser.AddSymbol("2", double(2.0));
250     parser.AddSymbol("3", false);
251 
252     // request for member 'invalid_data_type' in '* value', which is of
253     // non-class type 'const char'
254     // parser.AddSymbol("4", (const char*)4);
255     // Call is ambiguous
256     // parser.AddSymbol("5", 0);
257     // Call is ambiguous
258     // parser.AddSymbol("5", 1);
259     // 'void*' is not a pointer-to-object type
260     // parser.AddSymbol("4", (void*)0);
261 }
262 
263 ////////////////////////////////////////////////////////////////////////////////
264 /// Test string 2 bool function: checks if given directory exists
DirectoryExists(const string & DirectoryName)265 bool DirectoryExists(const string& DirectoryName)
266 {
267     CDir Directory(DirectoryName);
268 
269     return Directory.Exists();
270 }
271 
272 /// Boost test case checks parsing of string literals
BOOST_AUTO_TEST_CASE(ParseString)273 BOOST_AUTO_TEST_CASE(ParseString)
274 {
275     CExprParser parser;
276 
277     // String literal
278     parser.Parse("\"abc\"");
279     BOOST_CHECK_EQUAL(CExprValue::eSTRING, parser.GetResult().GetType());
280     BOOST_CHECK_EQUAL("abc", parser.GetResult().GetString());
281 
282     // String literal concatenation by "+"
283     parser.Parse("\"abc\"+\"def\"");
284     BOOST_CHECK_EQUAL(CExprValue::eSTRING, parser.GetResult().GetType());
285     BOOST_CHECK_EQUAL("abcdef", parser.GetResult().GetString());
286 
287     // All other operations on strings throw
288     BOOST_CHECK_THROW(parser.Parse("\"abc\"-\"def\""), CExprParserException);
289     BOOST_CHECK_THROW(parser.Parse("\"abc\"*\"def\""), CExprParserException);
290     BOOST_CHECK_THROW(parser.Parse("\"abc\"/\"def\""), CExprParserException);
291     BOOST_CHECK_THROW(parser.Parse("\"abc\"\\\"def\""), CExprParserException);
292     BOOST_CHECK_THROW(parser.Parse("\"abc\"&&\"def\""), CExprParserException);
293     BOOST_CHECK_THROW(parser.Parse("\"abc\"||\"def\""), CExprParserException);
294     BOOST_CHECK_THROW(parser.Parse("\"abc\"^^\"def\""), CExprParserException);
295     BOOST_CHECK_THROW(parser.Parse("!\"abc\""), CExprParserException);
296     BOOST_CHECK_THROW(parser.Parse("-\"abc\""), CExprParserException);
297     BOOST_CHECK_THROW(parser.Parse("~\"abc\""), CExprParserException);
298     BOOST_CHECK_THROW(parser.Parse("\"abc\"%\"def\""), CExprParserException);
299     BOOST_CHECK_THROW(parser.Parse("\"abc\"<\"def\""), CExprParserException);
300     BOOST_CHECK_THROW(parser.Parse("\"abc\">\"def\""), CExprParserException);
301     BOOST_CHECK_THROW(parser.Parse("\"abc\"&\"def\""), CExprParserException);
302     BOOST_CHECK_THROW(parser.Parse("\"abc\"|\"def\""), CExprParserException);
303     BOOST_CHECK_THROW(parser.Parse("\"abc\"^\"def\""), CExprParserException);
304     BOOST_CHECK_THROW(parser.Parse("\"abc\"**\"def\""), CExprParserException);
305 
306     // String to Bool function call
307     parser.AddSymbol("dir", DirectoryExists);
308 
309 #ifndef NCBI_OS_MSWIN
310     parser.Parse("dir(\"/var/log\")");
311 #else
312     parser.Parse("dir(\"c:\\\")");
313 #endif
314     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
315     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
316 
317     parser.Parse("dir(\"/var/NotExistingDirectory\")");
318     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
319     BOOST_CHECK_EQUAL(false, parser.GetResult().GetBool());
320 
321     // String ==/!= check
322     string Dummy("SomeDummyString");
323 
324     parser.AddSymbol("var1", Dummy);
325     parser.Parse("var1 == \"SomeDammyString\"");
326     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
327     BOOST_CHECK_EQUAL(false, parser.GetResult().GetBool());
328 
329     parser.Parse("var1 == \"SomeDummyString\"");
330     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
331     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
332 
333     parser.Parse("var1 != \"SomeDammyString\"");
334     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
335     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
336 
337     parser.Parse("var1 != \"SomeDummyString\"");
338     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
339     BOOST_CHECK_EQUAL(false, parser.GetResult().GetBool());}
340 
341 /// Test special no-division mode
BOOST_AUTO_TEST_CASE(NoDivisionMode)342 BOOST_AUTO_TEST_CASE(NoDivisionMode)
343 {
344     // Switch NoDivision mode
345     CExprParser parser(CExprParser::fLogicalOnly);
346 
347     // Int
348     parser.AddSymbol("/var/log", 2);
349     parser.Parse("/var/log");
350     BOOST_CHECK_EQUAL(CExprValue::eINT, parser.GetResult().GetType());
351     BOOST_CHECK_EQUAL(2, parser.GetResult().GetInt());
352 
353     // Boolean
354     parser.AddSymbol("/var/log1", true);
355     parser.Parse("/var/log1");
356     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
357     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
358 
359     // Check that dot is actually disabled and allowed as variable name
360     parser.AddSymbol("0.1.0/main/Group1/Test1/0.0.2", true);
361     parser.Parse("0.1.0/main/Group1/Test1/0.0.2");
362     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
363     BOOST_CHECK_EQUAL(true, parser.GetResult().GetBool());
364 
365     // Check that dot is actually disabled and allowed as variable name
366     parser.AddSymbol("0.1.0/main/Group1/Test1/0.0.2", true);
367     parser.Parse("false || 0.1.0/main/Group2/Test1/0.0.2");
368     BOOST_CHECK_EQUAL(CExprValue::eBOOL, parser.GetResult().GetType());
369     BOOST_CHECK_EQUAL(false, parser.GetResult().GetBool());
370 }
371 
372