View Javadoc
1   /*
2    * Copyright (c) 2001-2017, Zoltan Farkas All Rights Reserved.
3    *
4    * This library is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Lesser General Public
6    * License as published by the Free Software Foundation; either
7    * version 2.1 of the License, or (at your option) any later version.
8    *
9    * This library is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this program; if not, write to the Free Software
16   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17   *
18   * Additionally licensed with:
19   *
20   * Licensed under the Apache License, Version 2.0 (the "License");
21   * you may not use this file except in compliance with the License.
22   * You may obtain a copy of the License at
23   *
24   *      http://www.apache.org/licenses/LICENSE-2.0
25   *
26   * Unless required by applicable law or agreed to in writing, software
27   * distributed under the License is distributed on an "AS IS" BASIS,
28   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29   * See the License for the specific language governing permissions and
30   * limitations under the License.
31   */
32  package org.spf4j.zel.vm;
33  
34  import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
35  import java.io.ByteArrayOutputStream;
36  import java.io.PrintStream;
37  import java.io.UnsupportedEncodingException;
38  import java.math.BigInteger;
39  import java.nio.charset.StandardCharsets;
40  import java.util.concurrent.ExecutionException;
41  import java.util.concurrent.ExecutorService;
42  import java.util.concurrent.Executors;
43  import org.junit.Assert;
44  import org.junit.Test;
45  import org.slf4j.Logger;
46  import org.slf4j.LoggerFactory;
47  
48  /**
49   *
50   * @author zoly
51   */
52  @SuppressFBWarnings("HES_LOCAL_EXECUTOR_SERVICE")
53  public final class ZelTest {
54  
55    private static final Logger LOG = LoggerFactory.getLogger(ZelTest.class);
56  
57    @Test
58    public void helloWorld()
59            throws CompileException, ExecutionException, InterruptedException, UnsupportedEncodingException {
60      ByteArrayOutputStream bos = new ByteArrayOutputStream();
61      Program.compile("out(\"Hello World\")").execute(new ProcessIOStreams(System.in,
62              new PrintStream(bos, true, StandardCharsets.UTF_8.toString()), System.err));
63      Assert.assertEquals("Hello World", new String(bos.toByteArray(), StandardCharsets.UTF_8));
64    }
65  
66    @Test
67    public void testBasicArithmetic()
68            throws CompileException, ExecutionException, InterruptedException {
69      Program prog = Program.compile("// simple expression \n 1+5*4/(1+1)");
70      Number result = (Number) prog.execute();
71      Assert.assertEquals(11, result.intValue());
72    }
73  
74    @Test
75    public void testJavaExec()
76            throws CompileException, ExecutionException, InterruptedException {
77      Program prog = Program.compile("a.toString().substring(0, 1 + 1)", "a");
78      String result = (String) prog.execute(Integer.valueOf(100));
79      Assert.assertEquals("100".substring(0, 2), result);
80    }
81  
82    @Test
83    public void testJavaExecStatic()
84            throws CompileException, ExecutionException, InterruptedException {
85      Program prog = Program.compile("format(\"Number %d\", 3)", "format");
86      String result = (String) prog.execute(new JavaMethodCall(String.class, "format"));
87      Assert.assertEquals(String.format("Number %d", 3), result);
88    }
89  
90    @Test
91    public void testAssignement()
92            throws CompileException, ExecutionException, InterruptedException {
93      Program prog = Program.compile("a = a + 1", "a");
94      Integer result = (Integer) prog.execute(100);
95      Assert.assertEquals(101, result.intValue());
96    }
97  
98    @Test
99    public void testFib()
100           throws CompileException, ExecutionException, InterruptedException {
101     String program
102             = "function deterministic fib (x) { fib(x-1) + fib(x-2) };\n"
103             + "fib(0) = 0;\n"
104             + "fib(1) = 1;\n"
105             + "val1 = fib(100);\n"
106             + "val2 = fib(200);\n"
107             + "val3 = fib(1000);\n"
108             + "val = val1 + val2;"
109                 + "out(\"fib(50)=\", fib(50));"
110             + "out(val3);"
111             + "val2";
112 
113     Program compiledProgram = Program.compile(program);
114     LOG.debug("Program = {}", compiledProgram);
115     Number result = (Number) compiledProgram.execute();
116     Assert.assertEquals(new BigInteger("280571172992510140037611932413038677189525"), result);
117   }
118 
119   public BigInteger fibB(final int i) {
120     if (i <= 1) {
121       return BigInteger.valueOf(i);
122     } else {
123       return fibB(i - 1).add(fibB(i - 2));
124     }
125   }
126 
127   public long fib(final long i) {
128     if (i <= 1) {
129       return i;
130     } else {
131       return fib(i - 1) + fib(i - 2);
132     }
133   }
134 
135   public BigInteger fibBNr(final int i) {
136     if (i <= 1) {
137       return BigInteger.valueOf(i);
138     } else {
139       BigInteger v1 = BigInteger.ZERO;
140       BigInteger v2 = BigInteger.ONE;
141       BigInteger tmp;
142       for (int j = 2; j <= i; j++) {
143         tmp = v2;
144         v2 = v1.add(v2);
145         v1 = tmp;
146       }
147       return v2;
148     }
149   }
150 
151   @Test
152   public void testFibPerformance() throws CompileException, ExecutionException, InterruptedException {
153     String fib = "func det fib (x) {fib(x-1) + fib(x-2)}; fib(0) = 0; fib(1) = 1; fib(x)";
154     Program fibZel = Program.compile(fib, "x");
155     long startTime = System.currentTimeMillis();
156     Number zelResult = (Number) fibZel.execute(40);
157     long intTime = System.currentTimeMillis();
158     long javaResult = fib(40);
159     long stopTime = System.currentTimeMillis();
160     Assert.assertEquals(zelResult.longValue(), javaResult);
161     LOG.debug("zel exec {}", (intTime - startTime));
162     LOG.debug("java exec {}", (stopTime - intTime));
163 
164     startTime = System.currentTimeMillis();
165     BigInteger zelResult2 = (BigInteger) fibZel.execute(10000);
166     intTime = System.currentTimeMillis();
167     BigInteger javaResult2 = fibBNr(10000);
168     stopTime = System.currentTimeMillis();
169     LOG.debug("fib(10000) = {}", zelResult2);
170     LOG.debug("fib(10000) = {}", javaResult2);
171     Assert.assertEquals(zelResult2, javaResult2);
172     LOG.debug("zel exec {}", (intTime - startTime));
173     LOG.debug("java exec {}", (stopTime - intTime));
174   }
175 
176   @Test
177   public void testParallelism() throws CompileException, ExecutionException, InterruptedException {
178     String program = "f1 = func {sleep 5000; 1};"
179             + "f2 = func {sleep 5000; 2};"
180             + "f1() + f2()";
181     Program prog = Program.compile(program);
182     LOG.debug("Program = {}", prog);
183     long startTime = System.currentTimeMillis();
184     Number result = (Number) prog.execute();
185     long endTime = System.currentTimeMillis();
186     Assert.assertEquals(3, result.intValue());
187     Assert.assertTrue("functions need to execute in parallel not in " + (endTime - startTime),
188             endTime - startTime < 5200);
189   }
190 
191   @Test
192   public void testParallelism2() throws CompileException, ExecutionException, InterruptedException {
193     String program = "f1 = func {sleep 5000; 1};"
194             + "f2 = func {sleep 5000; 2};"
195             + "f1() + f2()";
196     Program prog = Program.compile(program);
197     LOG.debug("Program = {}", prog);
198     long startTime = System.currentTimeMillis();
199     Number result = (Number) prog.execute(Executors.newSingleThreadExecutor());
200     long endTime = System.currentTimeMillis();
201     Assert.assertEquals(3, result.intValue());
202     Assert.assertTrue("functions need to execute in parallel not in " + (endTime - startTime),
203             endTime - startTime < 5200);
204   }
205 
206   @Test
207   @SuppressFBWarnings("PRMC_POSSIBLY_REDUNDANT_METHOD_CALLS")
208   public void testCond() throws CompileException, ExecutionException, InterruptedException {
209     Boolean result = (Boolean) Program.compile("x == 1", "x").execute(1);
210     Assert.assertTrue(result);
211     result = (Boolean) Program.compile("x != 1", "x").execute(1);
212     Assert.assertFalse(result);
213     result = (Boolean) Program.compile("x < 1", "x").execute(1);
214     Assert.assertFalse(result);
215     result = (Boolean) Program.compile("x >= 1", "x").execute(1);
216     Assert.assertTrue(result);
217     result = (Boolean) Program.compile("x <= 1", "x").execute(1);
218     Assert.assertTrue(result);
219     result = (Boolean) Program.compile("x > 1", "x").execute(1);
220     Assert.assertFalse(result);
221     Number n = (Number) Program.compile("min(3, 1, 8)").execute();
222     Assert.assertEquals(1, n.intValue());
223     n = (Number) Program.compile("max(3, 1, 8, 10)").execute();
224     Assert.assertEquals(10, n.intValue());
225     n = (Number) Program.compile("sqrt(4)").execute();
226     Assert.assertEquals(2, n.intValue());
227     n = (Number) Program.compile("log(E)").execute();
228     Assert.assertEquals(1, n.intValue());
229 
230   }
231 
232   @Test
233   public void testAsync() throws CompileException, ExecutionException, InterruptedException {
234     String prog = "f = func (a, b) {sleep 1000; a + b };"
235             + "f(f(1, 2),f(3, 4))";
236     ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(8);
237     long startTime = System.currentTimeMillis();
238     Number result = (Number) Program.compile(prog).execute(newFixedThreadPool);
239     long elapsed = System.currentTimeMillis() - startTime;
240     LOG.debug("Elapsed = {} ms", elapsed);
241     //       Assert.assertTrue("Execution is " + elapsed + "should be smaller than 1200" , elapsed < 1200);
242     Assert.assertEquals(10, result.intValue());
243     newFixedThreadPool.shutdown();
244   }
245 
246   @SuppressFBWarnings("MDM_THREAD_YIELD")
247   private static class TestF {
248 
249     public static int f(final int a, final int b) throws InterruptedException {
250       Thread.sleep(1000);
251       return a + b;
252     }
253   }
254 
255   @Test
256   public void testAsync2() throws CompileException, ExecutionException, InterruptedException {
257     ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(8);
258     String prog = "f(f(1, 2)&,f(3, 4)&)&";
259     long startTime = System.currentTimeMillis();
260     Number result = (Number) Program.compile(prog, "f")
261             .execute(newFixedThreadPool, new JavaMethodCall(TestF.class, "f"));
262     long elapsed = System.currentTimeMillis() - startTime;
263     LOG.debug("Elapsed = {} ms", elapsed);
264 //        Assert.assertTrue(elapsed < 2200);
265     Assert.assertEquals(10, result.intValue());
266     newFixedThreadPool.shutdown();
267   }
268 
269   @Test
270   public void testArrays() throws CompileException, ExecutionException, InterruptedException {
271     String result = (String) Program.compile("x.split(\",\")[1]", "x").execute("a,b,c");
272     Assert.assertEquals("b", result);
273     result = (String) Program.compile("x.split(\",\")[1] = \"A\"", "x").execute("a,b,c");
274     Assert.assertEquals("A", result);
275   }
276 
277   @Test
278   public void testCond2() throws CompileException, ExecutionException, InterruptedException {
279     Program p = Program.compile("x >= 0 ? \"positive\" : \"negative\" ", "x");
280     LOG.debug("Program = {}", p);
281     String result = (String) p.execute(1);
282     Assert.assertEquals("positive", result);
283   }
284 
285   @Test
286   public void testCond3() throws CompileException, ExecutionException, InterruptedException {
287     Program p = Program.compile(" if x >= 0 { \"positive\" } else { \"negative\" } ", "x");
288     LOG.debug("Program = {}", p);
289     String result = (String) p.execute(1);
290     Assert.assertEquals("positive", result);
291   }
292 
293   @Test
294   public void testFor() throws CompileException, ExecutionException, InterruptedException {
295     Program p = Program.compile("x = 0; for i=0; i < 10; i++ {out(i); x = x + i}; x ");
296     LOG.debug("Program = {}", p.toAssemblyString());
297     Integer result = (Integer) p.execute(1);
298     Assert.assertEquals(45, result.intValue());
299   }
300 
301   @Test
302   @SuppressFBWarnings("SACM_STATIC_ARRAY_CREATED_IN_METHOD")
303   public void testSwap() throws CompileException, ExecutionException, InterruptedException {
304     Program p = Program.compile("x[0] <-> x[1]; x[1]", "x");
305     LOG.debug("Program = {}", p);
306     String[] testArray = new String[]{"a", "b"};
307     String result = (String) p.execute(new Object[]{testArray});
308     Assert.assertEquals("a", result);
309   }
310 
311   @Test
312   public void testArray() throws CompileException, ExecutionException, InterruptedException {
313     Program p = Program.compile("x = array(2); x.length");
314     LOG.debug("Program = {}", p);
315     Integer result = (Integer) p.execute();
316     Assert.assertEquals(2, result.intValue());
317   }
318 
319   @Test
320   public void testMultiRet() throws CompileException, ExecutionException, InterruptedException {
321     Program p = Program.compile("func test {"
322             + "ret {1, 2} };"
323             + "x,y = test();"
324             + "out(y); ret x");
325     LOG.debug("Program = {}", p);
326     Integer result = (Integer) p.execute();
327     Assert.assertEquals(1, result.intValue());
328   }
329 
330   @Test
331   public void testMultiAssignement() throws CompileException, ExecutionException, InterruptedException {
332     Program p = Program.compile("x, y, z = {1, 2, 3}; ret y");
333     LOG.debug("Program = {}", p.toAssemblyString());
334     Integer result = (Integer) p.execute();
335     Assert.assertEquals(2, result.intValue());
336   }
337 
338   @Test
339   public void testAbs() throws CompileException, ExecutionException, InterruptedException {
340     Program p = Program.compile("|3 - 5|");
341     LOG.debug("Program = {}", p);
342     Integer result = (Integer) p.execute();
343     Assert.assertEquals(2, result.intValue());
344   }
345 
346   @Test
347   public void testDecode() throws CompileException, ExecutionException, InterruptedException {
348     Program p = Program.compile("decode(1+1, 3, 0, 1, -1, 2, 666, 777)");
349     LOG.debug("Program = {}", p);
350     Integer result = (Integer) p.execute();
351     Assert.assertEquals(666, result.intValue());
352   }
353 
354   @Test
355   public void testDecode2() throws CompileException, ExecutionException, InterruptedException {
356     Program p = Program.compile("decode(1+1, 3, 0, 1, -1, 100, 666, 777)");
357     LOG.debug("Program = {}", p);
358     Integer result = (Integer) p.execute();
359     Assert.assertEquals(777, result.intValue());
360   }
361 
362   @Test
363   public void testType() throws CompileException, ExecutionException, InterruptedException {
364     Program p = Program.compile("" + Long.MAX_VALUE);
365     LOG.debug("Program = {}", p);
366     Long result = (Long) p.execute();
367     Assert.assertEquals(Long.MAX_VALUE, result.longValue());
368   }
369 
370   @Test
371   public void testOverflow() throws CompileException, ExecutionException, InterruptedException {
372     Program p = Program.compile("" + Long.MAX_VALUE + " + " + 1);
373     LOG.debug("Program = {}", p);
374     BigInteger result = (BigInteger) p.execute();
375     Assert.assertEquals(BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE),
376             result);
377   }
378 
379   @Test
380   public void testOverflow2() throws CompileException, ExecutionException, InterruptedException {
381     Program p = Program.compile("" + Long.MIN_VALUE + " - " + 1);
382     LOG.debug("Program = {}", p);
383     BigInteger result = (BigInteger) p.execute();
384     Assert.assertEquals(BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.ONE),
385             result);
386   }
387 
388   @Test
389   public void testOverflow3() throws CompileException, ExecutionException, InterruptedException {
390     Program p = Program.compile("" + Long.MIN_VALUE + " - " + Long.MAX_VALUE);
391     LOG.debug("Program = {}", p);
392     BigInteger result = (BigInteger) p.execute();
393     Assert.assertEquals(BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.valueOf(Long.MAX_VALUE)),
394             result);
395   }
396 
397 }