Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

ExpressionatorTest.java 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. /*
  2. Copyright (c) 2016 James Ahlborn
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package com.healthmarketscience.jackcess.impl.expr;
  14. import java.io.BufferedReader;
  15. import java.io.FileReader;
  16. import java.math.BigDecimal;
  17. import java.text.SimpleDateFormat;
  18. import java.util.Date;
  19. import javax.script.Bindings;
  20. import javax.script.SimpleBindings;
  21. import com.healthmarketscience.jackcess.DataType;
  22. import com.healthmarketscience.jackcess.DatabaseBuilder;
  23. import com.healthmarketscience.jackcess.TestUtil;
  24. import com.healthmarketscience.jackcess.expr.EvalContext;
  25. import com.healthmarketscience.jackcess.expr.Expression;
  26. import com.healthmarketscience.jackcess.expr.FunctionLookup;
  27. import com.healthmarketscience.jackcess.expr.Identifier;
  28. import com.healthmarketscience.jackcess.expr.ParseException;
  29. import com.healthmarketscience.jackcess.expr.TemporalConfig;
  30. import com.healthmarketscience.jackcess.expr.Value;
  31. import com.healthmarketscience.jackcess.impl.BaseEvalContext;
  32. import com.healthmarketscience.jackcess.impl.NumberFormatter;
  33. import junit.framework.TestCase;
  34. /**
  35. *
  36. * @author James Ahlborn
  37. */
  38. public class ExpressionatorTest extends TestCase
  39. {
  40. private static final double[] DBLS = {
  41. -10.3d,-9.0d,-8.234d,-7.11111d,-6.99999d,-5.5d,-4.0d,-3.4159265d,-2.84d,
  42. -1.0000002d,-1.0d,-0.0002013d,0.0d, 0.9234d,1.0d,1.954d,2.200032d,3.001d,
  43. 4.9321d,5.0d,6.66666d,7.396d,8.1d,9.20456200d,10.325d};
  44. private static final int TRUE_NUM = -1;
  45. private static final int FALSE_NUM = 0;
  46. public ExpressionatorTest(String name) {
  47. super(name);
  48. }
  49. public void testParseSimpleExprs() throws Exception
  50. {
  51. validateExpr("\"A\"", "<ELiteralValue>{\"A\"}");
  52. validateExpr("13", "<ELiteralValue>{13}");
  53. validateExpr("-42", "<EUnaryOp>{- <ELiteralValue>{42}}");
  54. validateExpr("(+37)", "<EParen>{(<EUnaryOp>{+ <ELiteralValue>{37}})}");
  55. doTestSimpleBinOp("EBinaryOp", "+", "-", "*", "/", "\\", "^", "&", "Mod");
  56. doTestSimpleBinOp("ECompOp", "<", "<=", ">", ">=", "=", "<>");
  57. doTestSimpleBinOp("ELogicalOp", "And", "Or", "Eqv", "Xor", "Imp");
  58. for(String constStr : new String[]{"True", "False", "Null"}) {
  59. validateExpr(constStr, "<EConstValue>{" + constStr + "}");
  60. }
  61. validateExpr("[Field1]", "<EObjValue>{[Field1]}");
  62. validateExpr("[Table2].[Field3]", "<EObjValue>{[Table2].[Field3]}");
  63. validateExpr("Not \"A\"", "<EUnaryOp>{Not <ELiteralValue>{\"A\"}}");
  64. validateExpr("-[Field1]", "<EUnaryOp>{- <EObjValue>{[Field1]}}");
  65. validateExpr("\"A\" Is Null", "<ENullOp>{<ELiteralValue>{\"A\"} Is Null}");
  66. validateExpr("\"A\" In (1,2,3)", "<EInOp>{<ELiteralValue>{\"A\"} In (<ELiteralValue>{1},<ELiteralValue>{2},<ELiteralValue>{3})}");
  67. validateExpr("\"A\" Not Between 3 And 7", "<EBetweenOp>{<ELiteralValue>{\"A\"} Not Between <ELiteralValue>{3} And <ELiteralValue>{7}}");
  68. validateExpr("(\"A\" Or \"B\")", "<EParen>{(<ELogicalOp>{<ELiteralValue>{\"A\"} Or <ELiteralValue>{\"B\"}})}");
  69. validateExpr("IIf(\"A\",42,False)", "<EFunc>{IIf(<ELiteralValue>{\"A\"},<ELiteralValue>{42},<EConstValue>{False})}");
  70. validateExpr("\"A\" Like \"a*b\"", "<ELikeOp>{<ELiteralValue>{\"A\"} Like \"a*b\"(a.*b)}");
  71. validateExpr("' \"A\" '", "<ELiteralValue>{\" \"\"A\"\" \"}",
  72. "\" \"\"A\"\" \"");
  73. validateExpr("<=1 And >=0", "<ELogicalOp>{<ECompOp>{<EThisValue>{<THIS_COL>} <= <ELiteralValue>{1}} And <ECompOp>{<EThisValue>{<THIS_COL>} >= <ELiteralValue>{0}}}", "<THIS_COL> <= 1 And <THIS_COL> >= 0");
  74. }
  75. private static void doTestSimpleBinOp(String opName, String... ops) throws Exception
  76. {
  77. for(String op : ops) {
  78. validateExpr("\"A\" " + op + " \"B\"",
  79. "<" + opName + ">{<ELiteralValue>{\"A\"} " + op +
  80. " <ELiteralValue>{\"B\"}}");
  81. }
  82. }
  83. public void testOrderOfOperations() throws Exception
  84. {
  85. validateExpr("\"A\" Eqv \"B\"",
  86. "<ELogicalOp>{<ELiteralValue>{\"A\"} Eqv <ELiteralValue>{\"B\"}}");
  87. validateExpr("\"A\" Eqv \"B\" Xor \"C\"",
  88. "<ELogicalOp>{<ELiteralValue>{\"A\"} Eqv <ELogicalOp>{<ELiteralValue>{\"B\"} Xor <ELiteralValue>{\"C\"}}}");
  89. validateExpr("\"A\" Eqv \"B\" Xor \"C\" Or \"D\"",
  90. "<ELogicalOp>{<ELiteralValue>{\"A\"} Eqv <ELogicalOp>{<ELiteralValue>{\"B\"} Xor <ELogicalOp>{<ELiteralValue>{\"C\"} Or <ELiteralValue>{\"D\"}}}}");
  91. validateExpr("\"A\" Eqv \"B\" Xor \"C\" Or \"D\" And \"E\"",
  92. "<ELogicalOp>{<ELiteralValue>{\"A\"} Eqv <ELogicalOp>{<ELiteralValue>{\"B\"} Xor <ELogicalOp>{<ELiteralValue>{\"C\"} Or <ELogicalOp>{<ELiteralValue>{\"D\"} And <ELiteralValue>{\"E\"}}}}}");
  93. validateExpr("\"A\" Or \"B\" Or \"C\"",
  94. "<ELogicalOp>{<ELogicalOp>{<ELiteralValue>{\"A\"} Or <ELiteralValue>{\"B\"}} Or <ELiteralValue>{\"C\"}}");
  95. validateExpr("\"A\" & \"B\" Is Null",
  96. "<ENullOp>{<EBinaryOp>{<ELiteralValue>{\"A\"} & <ELiteralValue>{\"B\"}} Is Null}");
  97. validateExpr("\"A\" Or \"B\" Is Null",
  98. "<ELogicalOp>{<ELiteralValue>{\"A\"} Or <ENullOp>{<ELiteralValue>{\"B\"} Is Null}}");
  99. validateExpr("Not \"A\" & \"B\"",
  100. "<EUnaryOp>{Not <EBinaryOp>{<ELiteralValue>{\"A\"} & <ELiteralValue>{\"B\"}}}");
  101. validateExpr("Not \"A\" Or \"B\"",
  102. "<ELogicalOp>{<EUnaryOp>{Not <ELiteralValue>{\"A\"}} Or <ELiteralValue>{\"B\"}}");
  103. validateExpr("\"A\" + \"B\" Not Between 37 - 15 And 52 / 4",
  104. "<EBetweenOp>{<EBinaryOp>{<ELiteralValue>{\"A\"} + <ELiteralValue>{\"B\"}} Not Between <EBinaryOp>{<ELiteralValue>{37} - <ELiteralValue>{15}} And <EBinaryOp>{<ELiteralValue>{52} / <ELiteralValue>{4}}}");
  105. validateExpr("\"A\" + (\"B\" Not Between 37 - 15 And 52) / 4",
  106. "<EBinaryOp>{<ELiteralValue>{\"A\"} + <EBinaryOp>{<EParen>{(<EBetweenOp>{<ELiteralValue>{\"B\"} Not Between <EBinaryOp>{<ELiteralValue>{37} - <ELiteralValue>{15}} And <ELiteralValue>{52}})} / <ELiteralValue>{4}}}");
  107. }
  108. public void testSimpleMathExpressions() throws Exception
  109. {
  110. for(int i = -10; i <= 10; ++i) {
  111. assertEquals(-i, eval("=-(" + i + ")"));
  112. }
  113. for(int i = -10; i <= 10; ++i) {
  114. assertEquals(i, eval("=+(" + i + ")"));
  115. }
  116. for(double i : DBLS) {
  117. assertEquals(toBD(-i), eval("=-(" + i + ")"));
  118. }
  119. for(double i : DBLS) {
  120. assertEquals(toBD(i), eval("=+(" + i + ")"));
  121. }
  122. for(int i = -10; i <= 10; ++i) {
  123. for(int j = -10; j <= 10; ++j) {
  124. assertEquals((i + j), eval("=" + i + " + " + j));
  125. }
  126. }
  127. for(double i : DBLS) {
  128. for(double j : DBLS) {
  129. assertEquals(toBD(toBD(i).add(toBD(j))), eval("=" + i + " + " + j));
  130. }
  131. }
  132. for(int i = -10; i <= 10; ++i) {
  133. for(int j = -10; j <= 10; ++j) {
  134. assertEquals((i - j), eval("=" + i + " - " + j));
  135. }
  136. }
  137. for(double i : DBLS) {
  138. for(double j : DBLS) {
  139. assertEquals(toBD(toBD(i).subtract(toBD(j))), eval("=" + i + " - " + j));
  140. }
  141. }
  142. for(int i = -10; i <= 10; ++i) {
  143. for(int j = -10; j <= 10; ++j) {
  144. assertEquals((i * j), eval("=" + i + " * " + j));
  145. }
  146. }
  147. for(double i : DBLS) {
  148. for(double j : DBLS) {
  149. assertEquals(toBD(toBD(i).multiply(toBD(j))), eval("=" + i + " * " + j));
  150. }
  151. }
  152. for(int i = -10; i <= 10; ++i) {
  153. for(int j = -10; j <= 10; ++j) {
  154. if(j == 0L) {
  155. evalFail("=" + i + " \\ " + j, ArithmeticException.class);
  156. } else {
  157. assertEquals((i / j), eval("=" + i + " \\ " + j));
  158. }
  159. }
  160. }
  161. for(double i : DBLS) {
  162. for(double j : DBLS) {
  163. if(roundToLongInt(j) == 0) {
  164. evalFail("=" + i + " \\ " + j, ArithmeticException.class);
  165. } else {
  166. assertEquals((roundToLongInt(i) / roundToLongInt(j)),
  167. eval("=" + i + " \\ " + j));
  168. }
  169. }
  170. }
  171. for(int i = -10; i <= 10; ++i) {
  172. for(int j = -10; j <= 10; ++j) {
  173. if(j == 0) {
  174. evalFail("=" + i + " Mod " + j, ArithmeticException.class);
  175. } else {
  176. assertEquals((i % j), eval("=" + i + " Mod " + j));
  177. }
  178. }
  179. }
  180. for(double i : DBLS) {
  181. for(double j : DBLS) {
  182. if(roundToLongInt(j) == 0) {
  183. evalFail("=" + i + " Mod " + j, ArithmeticException.class);
  184. } else {
  185. assertEquals((roundToLongInt(i) % roundToLongInt(j)),
  186. eval("=" + i + " Mod " + j));
  187. }
  188. }
  189. }
  190. for(int i = -10; i <= 10; ++i) {
  191. for(int j = -10; j <= 10; ++j) {
  192. if(j == 0) {
  193. evalFail("=" + i + " / " + j, ArithmeticException.class);
  194. } else {
  195. double result = (double)i / (double)j;
  196. if((int)result == result) {
  197. assertEquals((int)result, eval("=" + i + " / " + j));
  198. } else {
  199. assertEquals(result, eval("=" + i + " / " + j));
  200. }
  201. }
  202. }
  203. }
  204. for(double i : DBLS) {
  205. for(double j : DBLS) {
  206. if(j == 0.0d) {
  207. evalFail("=" + i + " / " + j, ArithmeticException.class);
  208. } else {
  209. assertEquals(toBD(BuiltinOperators.divide(toBD(i), toBD(j))),
  210. eval("=" + i + " / " + j));
  211. }
  212. }
  213. }
  214. for(int i = -10; i <= 10; ++i) {
  215. for(int j = -10; j <= 10; ++j) {
  216. double result = Math.pow(i, j);
  217. if((int)result == result) {
  218. assertEquals((int)result, eval("=" + i + " ^ " + j));
  219. } else {
  220. assertEquals(result, eval("=" + i + " ^ " + j));
  221. }
  222. }
  223. }
  224. }
  225. public void testComparison() throws Exception
  226. {
  227. assertEquals(TRUE_NUM, eval("='blah'<'fuzz'"));
  228. assertEquals(FALSE_NUM, eval("=23>56"));
  229. assertEquals(FALSE_NUM, eval("=23>=56"));
  230. assertEquals(TRUE_NUM, eval("=13.2<=45.8"));
  231. assertEquals(FALSE_NUM, eval("='blah'='fuzz'"));
  232. assertEquals(TRUE_NUM, eval("='blah'<>'fuzz'"));
  233. assertEquals(TRUE_NUM, eval("=CDbl(13.2)<=CDbl(45.8)"));
  234. assertEquals(FALSE_NUM, eval("='blah' Is Null"));
  235. assertEquals(TRUE_NUM, eval("='blah' Is Not Null"));
  236. assertEquals(TRUE_NUM, eval("=Null Is Null"));
  237. assertEquals(FALSE_NUM, eval("=Null Is Not Null"));
  238. assertEquals(TRUE_NUM, eval("='blah' Between 'a' And 'z'"));
  239. assertEquals(TRUE_NUM, eval("='blah' Between 'z' And 'a'"));
  240. assertEquals(FALSE_NUM, eval("='blah' Not Between 'a' And 'z'"));
  241. assertEquals(TRUE_NUM, eval("='blah' In ('foo','bar','blah')"));
  242. assertEquals(FALSE_NUM, eval("='blah' Not In ('foo','bar','blah')"));
  243. assertEquals(TRUE_NUM, eval("=True Xor False"));
  244. assertEquals(TRUE_NUM, eval("=True Or False"));
  245. assertEquals(TRUE_NUM, eval("=False Or True"));
  246. assertEquals(FALSE_NUM, eval("=True Imp False"));
  247. assertEquals(FALSE_NUM, eval("=True Eqv False"));
  248. assertEquals(TRUE_NUM, eval("=Not(True Eqv False)"));
  249. }
  250. public void testDateArith() throws Exception
  251. {
  252. assertEquals(new Date(1041508800000L), eval("=#01/02/2003# + #7:00:00 AM#"));
  253. assertEquals(new Date(1041458400000L), eval("=#01/02/2003# - #7:00:00 AM#"));
  254. assertEquals(new Date(1044680400000L), eval("=#01/02/2003# + '37'"));
  255. assertEquals(new Date(1044680400000L), eval("='37' + #01/02/2003#"));
  256. assertEquals(new Date(1041508800000L), eval("=#01/02/2003 7:00:00 AM#"));
  257. }
  258. public void testNull() throws Exception
  259. {
  260. assertNull(eval("=37 + Null"));
  261. assertNull(eval("=37 - Null"));
  262. assertNull(eval("=37 / Null"));
  263. assertNull(eval("=37 * Null"));
  264. assertNull(eval("=37 ^ Null"));
  265. assertEquals("37", eval("=37 & Null"));
  266. assertEquals("37", eval("=Null & 37"));
  267. assertNull(eval("=37 Mod Null"));
  268. assertNull(eval("=37 \\ Null"));
  269. assertNull(eval("=-(Null)"));
  270. assertNull(eval("=+(Null)"));
  271. assertNull(eval("=Not Null"));
  272. assertEquals(TRUE_NUM, eval("=37 Or Null"));
  273. assertNull(eval("=Null Or 37"));
  274. assertNull(eval("=37 And Null"));
  275. assertNull(eval("=Null And 37"));
  276. assertNull(eval("=37 Xor Null"));
  277. assertNull(eval("=37 Imp Null"));
  278. assertNull(eval("=Null Imp Null"));
  279. assertEquals(TRUE_NUM, eval("=Null Imp 37"));
  280. assertNull(eval("=37 Eqv Null"));
  281. assertNull(eval("=37 < Null"));
  282. assertNull(eval("=37 > Null"));
  283. assertNull(eval("=37 = Null"));
  284. assertNull(eval("=37 <> Null"));
  285. assertNull(eval("=37 <= Null"));
  286. assertNull(eval("=37 >= Null"));
  287. assertNull(eval("=37 Between Null And 54"));
  288. assertEquals(FALSE_NUM, eval("=37 In (23, Null, 45)"));
  289. assertNull(eval("=Null In (23, Null, 45)"));
  290. }
  291. public void testTrickyMathExpressions() throws Exception
  292. {
  293. assertEquals(37, eval("=30+7"));
  294. assertEquals(23, eval("=30+-7"));
  295. assertEquals(23, eval("=30-+7"));
  296. assertEquals(37, eval("=30--7"));
  297. assertEquals(23, eval("=30-7"));
  298. assertEquals(100, eval("=-10^2"));
  299. assertEquals(-100, eval("=-(10)^2"));
  300. assertEquals(-100d, eval("=-\"10\"^2"));
  301. assertEquals(toBD(-98.9d), eval("=1.1+(-\"10\"^2)"));
  302. assertEquals(toBD(99d), eval("=-10E-1+10e+1"));
  303. assertEquals(toBD(-101d), eval("=-10E-1-10e+1"));
  304. }
  305. public void testTypeCoercion() throws Exception
  306. {
  307. assertEquals("foobar", eval("=\"foo\" + \"bar\""));
  308. assertEquals("12foo", eval("=12 + \"foo\""));
  309. assertEquals("foo12", eval("=\"foo\" + 12"));
  310. assertEquals(37d, eval("=\"25\" + 12"));
  311. assertEquals(37d, eval("=12 + \"25\""));
  312. assertEquals(37d, eval("=\" 25 \" + 12"));
  313. assertEquals(37d, eval("=\" &h1A \" + 11"));
  314. assertEquals(37d, eval("=\" &h1a \" + 11"));
  315. assertEquals(37d, eval("=\" &O32 \" + 11"));
  316. evalFail(("=12 - \"foo\""), RuntimeException.class);
  317. evalFail(("=\"foo\" - 12"), RuntimeException.class);
  318. assertEquals("foo1225", eval("=\"foo\" + 12 + 25"));
  319. assertEquals("37foo", eval("=12 + 25 + \"foo\""));
  320. assertEquals("foo37", eval("=\"foo\" + (12 + 25)"));
  321. assertEquals("25foo12", eval("=\"25foo\" + 12"));
  322. assertEquals(new Date(1485579600000L), eval("=#1/1/2017# + 27"));
  323. assertEquals(128208, eval("=#1/1/2017# * 3"));
  324. }
  325. public void testLikeExpression() throws Exception
  326. {
  327. validateExpr("Like \"[abc]*\"", "<ELikeOp>{<EThisValue>{<THIS_COL>} Like \"[abc]*\"([abc].*)}",
  328. "<THIS_COL> Like \"[abc]*\"");
  329. assertTrue(evalCondition("Like \"[abc]*\"", "afcd"));
  330. assertFalse(evalCondition("Like \"[abc]*\"", "fcd"));
  331. validateExpr("Like \"[abc*\"", "<ELikeOp>{<EThisValue>{<THIS_COL>} Like \"[abc*\"((?!))}",
  332. "<THIS_COL> Like \"[abc*\"");
  333. assertFalse(evalCondition("Like \"[abc*\"", "afcd"));
  334. assertFalse(evalCondition("Like \"[abc*\"", "fcd"));
  335. assertTrue(evalCondition("Not Like \"[abc*\"", "fcd"));
  336. assertFalse(evalCondition("Like \"[abc*\"", ""));
  337. }
  338. public void testLiteralDefaultValue() throws Exception
  339. {
  340. assertEquals("-28 blah ", eval("=CDbl(9)-37 & \" blah \"",
  341. Value.Type.STRING));
  342. assertEquals("CDbl(9)-37 & \" blah \"",
  343. eval("CDbl(9)-37 & \" blah \"", Value.Type.STRING));
  344. assertEquals(-28d, eval("=CDbl(9)-37", Value.Type.DOUBLE));
  345. assertEquals(-28d, eval("CDbl(9)-37", Value.Type.DOUBLE));
  346. }
  347. public void testParseSomeExprs() throws Exception
  348. {
  349. BufferedReader br = new BufferedReader(new FileReader("src/test/resources/test_exprs.txt"));
  350. TestContext tc = new TestContext() {
  351. @Override
  352. public Value getThisColumnValue() {
  353. return ValueSupport.toValue(23.0);
  354. }
  355. @Override
  356. public Value getIdentifierValue(Identifier identifier) {
  357. return ValueSupport.toValue(23.0);
  358. }
  359. };
  360. String line = null;
  361. while((line = br.readLine()) != null) {
  362. line = line.trim();
  363. if(line.isEmpty()) {
  364. continue;
  365. }
  366. String[] parts = line.split(";", 3);
  367. Expressionator.Type type = Expressionator.Type.valueOf(parts[0]);
  368. DataType dType =
  369. (("null".equals(parts[1])) ? null : DataType.valueOf(parts[1]));
  370. String exprStr = parts[2];
  371. Value.Type resultType = ((dType != null) ?
  372. BaseEvalContext.toValueType(dType) : null);
  373. Expression expr = Expressionator.parse(
  374. type, exprStr, resultType, tc);
  375. expr.eval(tc);
  376. }
  377. br.close();
  378. }
  379. public void testInvalidExpressions() throws Exception
  380. {
  381. doTestEvalFail("", "empty");
  382. doTestEvalFail("=", "found?");
  383. doTestEvalFail("=(34 + 5", "closing");
  384. doTestEvalFail("=(34 + )", "found?");
  385. doTestEvalFail("=(34 + [A].[B].[C].[D])", "object reference");
  386. doTestEvalFail("=34 + 5,", "delimiter");
  387. doTestEvalFail("=Foo()", "find function");
  388. doTestEvalFail("=(/37)", "left expression");
  389. doTestEvalFail("=(>37)", "left expression");
  390. doTestEvalFail("=(And 37)", "left expression");
  391. doTestEvalFail("=37 In 42", "'In' expression");
  392. doTestEvalFail("=37 Between 42", "'Between' expression");
  393. doTestEvalFail("=(3 + 5) Rnd()", "multiple expressions");
  394. }
  395. private static void doTestEvalFail(String exprStr, String msgStr) {
  396. try {
  397. eval(exprStr);
  398. fail("ParseException should have been thrown");
  399. } catch(ParseException pe) {
  400. // success
  401. assertTrue(pe.getMessage().contains(msgStr));
  402. }
  403. }
  404. private static void validateExpr(String exprStr, String debugStr) {
  405. validateExpr(exprStr, debugStr, exprStr);
  406. }
  407. private static void validateExpr(String exprStr, String debugStr,
  408. String cleanStr) {
  409. Expression expr = Expressionator.parse(
  410. Expressionator.Type.FIELD_VALIDATOR, exprStr, null,
  411. new TestContext());
  412. String foundDebugStr = expr.toDebugString();
  413. if(foundDebugStr.startsWith("<EImplicitCompOp>")) {
  414. assertEquals("<EImplicitCompOp>{<EThisValue>{<THIS_COL>} = " +
  415. debugStr + "}", foundDebugStr);
  416. } else {
  417. assertEquals(debugStr, foundDebugStr);
  418. }
  419. assertEquals(cleanStr, expr.toString());
  420. assertEquals(exprStr, expr.toRawString());
  421. }
  422. static Object eval(String exprStr) {
  423. return eval(exprStr, null);
  424. }
  425. static Object eval(String exprStr, Value.Type resultType) {
  426. TestContext tc = new TestContext();
  427. Expression expr = Expressionator.parse(
  428. Expressionator.Type.DEFAULT_VALUE, exprStr, resultType, tc);
  429. return expr.eval(tc);
  430. }
  431. private static void evalFail(
  432. String exprStr, Class<? extends Exception> failure)
  433. {
  434. TestContext tc = new TestContext();
  435. Expression expr = Expressionator.parse(
  436. Expressionator.Type.DEFAULT_VALUE, exprStr, null, tc);
  437. try {
  438. expr.eval(tc);
  439. fail(failure + " should have been thrown");
  440. } catch(Exception e) {
  441. assertTrue(failure.isInstance(e));
  442. }
  443. }
  444. private static Boolean evalCondition(String exprStr, String thisVal) {
  445. TestContext tc = new TestContext(ValueSupport.toValue(thisVal));
  446. Expression expr = Expressionator.parse(
  447. Expressionator.Type.FIELD_VALIDATOR, exprStr, null, tc);
  448. return (Boolean)expr.eval(tc);
  449. }
  450. static int roundToLongInt(double d) {
  451. return new BigDecimal(d).setScale(0, NumberFormatter.ROUND_MODE)
  452. .intValueExact();
  453. }
  454. static BigDecimal toBD(double d) {
  455. return toBD(BigDecimal.valueOf(d));
  456. }
  457. static BigDecimal toBD(BigDecimal bd) {
  458. return ValueSupport.normalize(bd);
  459. }
  460. private static class TestContext
  461. implements Expressionator.ParseContext, EvalContext
  462. {
  463. private final Value _thisVal;
  464. private final RandomContext _rndCtx = new RandomContext();
  465. private final Bindings _bindings = new SimpleBindings();
  466. private TestContext() {
  467. this(null);
  468. }
  469. private TestContext(Value thisVal) {
  470. _thisVal = thisVal;
  471. }
  472. public Value.Type getResultType() {
  473. return null;
  474. }
  475. public TemporalConfig getTemporalConfig() {
  476. return TemporalConfig.US_TEMPORAL_CONFIG;
  477. }
  478. public SimpleDateFormat createDateFormat(String formatStr) {
  479. SimpleDateFormat sdf = DatabaseBuilder.createDateFormat(formatStr);
  480. sdf.setTimeZone(TestUtil.TEST_TZ);
  481. return sdf;
  482. }
  483. public FunctionLookup getFunctionLookup() {
  484. return DefaultFunctions.LOOKUP;
  485. }
  486. public Value getThisColumnValue() {
  487. if(_thisVal == null) {
  488. throw new UnsupportedOperationException();
  489. }
  490. return _thisVal;
  491. }
  492. public Value getIdentifierValue(Identifier identifier) {
  493. throw new UnsupportedOperationException();
  494. }
  495. public float getRandom(Integer seed) {
  496. return _rndCtx.getRandom(seed);
  497. }
  498. public Bindings getBindings() {
  499. return _bindings;
  500. }
  501. public Object get(String key) {
  502. return _bindings.get(key);
  503. }
  504. public void put(String key, Object value) {
  505. _bindings.put(key, value);
  506. }
  507. }
  508. }