package org.elasticsearch.painless;
import java.util.ArrayList;
import java.util.Collections;
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class BasicStatementTests extends ScriptTestCase {
public void testIfStatement() {
assertEquals(1, exec("int x = 5; if (x == 5) return 1; return 0;"));
assertEquals(0, exec("int x = 4; if (x == 5) return 1; else return 0;"));
assertEquals(2, exec("int x = 4; if (x == 5) return 1; else if (x == 4) return 2; else return 0;"));
assertEquals(1, exec("int x = 4; if (x == 5) return 1; else if (x == 4) return 1; else return 0;"));
assertEquals(3, exec(
"int x = 5;\n" +
"if (x == 5) {\n" +
" int y = 2;\n" +
" \n" +
" if (y == 2) {\n" +
" x = 3;\n" +
" }\n" +
" \n" +
"}\n" +
"\n" +
"return x;\n"));
}
public void testWhileStatement() {
assertEquals("aaaaaa", exec("String c = \"a\"; int x; while (x < 5) { c += \"a\"; ++x; } return c;"));
Object value = exec(
" byte[][] b = new byte[5][5]; \n" +
" byte x = 0, y; \n" +
" \n" +
" while (x < 5) { \n" +
" y = 0; \n" +
" \n" +
" while (y < 5) { \n" +
" b[x][y] = (byte)(x*y); \n" +
" ++y; \n" +
" } \n" +
" \n" +
" ++x; \n" +
" } \n" +
" \n" +
" return b; \n");
byte[][] b = (byte[][])value;
for (byte x = 0; x < 5; ++x) {
for (byte y = 0; y < 5; ++y) {
assertEquals(x*y, b[x][y]);
}
}
}
public void testDoWhileStatement() {
assertEquals("aaaaaa", exec("String c = \"a\"; int x; do { c += \"a\"; ++x; } while (x < 5); return c;"));
Object value = exec(
" int[][] b = new int[5][5]; \n" +
" int x = 0, y; \n" +
" \n" +
" do { \n" +
" y = 0; \n" +
" \n" +
" do { \n" +
" b[x][y] = x*y; \n" +
" ++y; \n" +
" } while (y < 5); \n" +
" \n" +
" ++x; \n" +
" } while (x < 5); \n" +
" \n" +
" return b; \n");
int[][] b = (int[][])value;
for (byte x = 0; x < 5; ++x) {
for (byte y = 0; y < 5; ++y) {
assertEquals(x*y, b[x][y]);
}
}
}
public void testForStatement() {
assertEquals("aaaaaa", exec("String c = \"a\"; for (int x = 0; x < 5; ++x) c += \"a\"; return c;"));
Object value = exec(
" int[][] b = new int[5][5]; \n" +
" for (int x = 0; x < 5; ++x) { \n" +
" for (int y = 0; y < 5; ++y) { \n" +
" b[x][y] = x*y; \n" +
" } \n" +
" } \n" +
" \n" +
" return b; \n");
int[][] b = (int[][])value;
for (byte x = 0; x < 5; ++x) {
for (byte y = 0; y < 5; ++y) {
assertEquals(x*y, b[x][y]);
}
}
}
public void testIterableForEachStatement() {
assertEquals(6, exec("List l = new ArrayList(); l.add(1); l.add(2); l.add(3); int total = 0;" +
" for (int x : l) total += x; return total"));
assertEquals(6, exec("List l = new ArrayList(); l.add(1); l.add(2); l.add(3); int total = 0;" +
" for (x in l) total += x; return total"));
assertEquals("123", exec("List l = new ArrayList(); l.add('1'); l.add('2'); l.add('3'); String cat = '';" +
" for (String x : l) cat += x; return cat"));
assertEquals("123", exec("List l = new ArrayList(); l.add('1'); l.add('2'); l.add('3'); String cat = '';" +
" for (x in l) cat += x; return cat"));
assertEquals("1236", exec("Map m = new HashMap(); m.put('1', 1); m.put('2', 2); m.put('3', 3);" +
" String cat = ''; int total = 0;" +
" for (Map.Entry e : m.entrySet()) { cat += e.getKey(); total += e.getValue(); } return cat + total"));
assertEquals("1236", exec("Map m = new HashMap(); m.put('1', 1); m.put('2', 2); m.put('3', 3);" +
" String cat = ''; int total = 0;" +
" for (e in m.entrySet()) { cat += e.getKey(); total += e.getValue(); } return cat + total"));
}
public void testIterableForEachStatementDef() {
assertEquals(6, exec("def l = new ArrayList(); l.add(1); l.add(2); l.add(3); int total = 0;" +
" for (int x : l) total += x; return total"));
assertEquals(6, exec("def l = new ArrayList(); l.add(1); l.add(2); l.add(3); int total = 0;" +
" for (x in l) total += x; return total"));
assertEquals("123", exec("def l = new ArrayList(); l.add('1'); l.add('2'); l.add('3'); String cat = '';" +
" for (String x : l) cat += x; return cat"));
assertEquals("123", exec("def l = new ArrayList(); l.add('1'); l.add('2'); l.add('3'); String cat = '';" +
" for (x in l) cat += x; return cat"));
assertEquals("1236", exec("def m = new HashMap(); m.put('1', 1); m.put('2', 2); m.put('3', 3);" +
" String cat = ''; int total = 0;" +
" for (Map.Entry e : m.entrySet()) { cat += e.getKey(); total += e.getValue(); } return cat + total"));
assertEquals("1236", exec("def m = new HashMap(); m.put('1', 1); m.put('2', 2); m.put('3', 3);" +
" String cat = ''; int total = 0;" +
" for (e in m.entrySet()) { cat += e.getKey(); total += e.getValue(); } return cat + total"));
}
public void testArrayForEachStatement() {
assertEquals(6, exec("int[] a = new int[3]; a[0] = 1; a[1] = 2; a[2] = 3; int total = 0;" +
" for (int x : a) total += x; return total"));
assertEquals(6, exec("int[] a = new int[3]; a[0] = 1; a[1] = 2; a[2] = 3; int total = 0;" +
" for (x in a) total += x; return total"));
assertEquals("123", exec("String[] a = new String[3]; a[0] = '1'; a[1] = '2'; a[2] = '3'; def total = '';" +
" for (String x : a) total += x; return total"));
assertEquals("123", exec("String[] a = new String[3]; a[0] = '1'; a[1] = '2'; a[2] = '3'; def total = '';" +
" for (x in a) total += x; return total"));
assertEquals(6, exec("int[][] i = new int[3][1]; i[0][0] = 1; i[1][0] = 2; i[2][0] = 3; int total = 0;" +
" for (int[] j : i) total += j[0]; return total"));
assertEquals(6, exec("int[][] i = new int[3][1]; i[0][0] = 1; i[1][0] = 2; i[2][0] = 3; int total = 0;" +
" for (j in i) total += j[0]; return total"));
}
public void testArrayForEachStatementDef() {
assertEquals(6, exec("def a = new int[3]; a[0] = 1; a[1] = 2; a[2] = 3; int total = 0;" +
" for (int x : a) total += x; return total"));
assertEquals(6, exec("def a = new int[3]; a[0] = 1; a[1] = 2; a[2] = 3; int total = 0;" +
" for (x in a) total += x; return total"));
assertEquals("123", exec("def a = new String[3]; a[0] = '1'; a[1] = '2'; a[2] = '3'; def total = '';" +
" for (String x : a) total += x; return total"));
assertEquals("123", exec("def a = new String[3]; a[0] = '1'; a[1] = '2'; a[2] = '3'; def total = '';" +
" for (x in a) total += x; return total"));
assertEquals(6, exec("def i = new int[3][1]; i[0][0] = 1; i[1][0] = 2; i[2][0] = 3; int total = 0;" +
" for (int[] j : i) total += j[0]; return total"));
assertEquals(6, exec("def i = new int[3][1]; i[0][0] = 1; i[1][0] = 2; i[2][0] = 3; int total = 0;" +
" for (j in i) total += j[0]; return total"));
}
public void testDeclarationStatement() {
assertEquals((byte)2, exec("byte a = 2; return a;"));
assertEquals((short)2, exec("short a = 2; return a;"));
assertEquals((char)2, exec("char a = 2; return a;"));
assertEquals(2, exec("int a = 2; return a;"));
assertEquals(2L, exec("long a = 2; return a;"));
assertEquals(2F, exec("float a = 2; return a;"));
assertEquals(2.0, exec("double a = 2; return a;"));
assertEquals(false, exec("boolean a = false; return a;"));
assertEquals("string", exec("String a = \"string\"; return a;"));
assertEquals(HashMap.class, exec("Map a = new HashMap(); return a;").getClass());
assertEquals(byte[].class, exec("byte[] a = new byte[1]; return a;").getClass());
assertEquals(short[].class, exec("short[] a = new short[1]; return a;").getClass());
assertEquals(char[].class, exec("char[] a = new char[1]; return a;").getClass());
assertEquals(int[].class, exec("int[] a = new int[1]; return a;").getClass());
assertEquals(long[].class, exec("long[] a = new long[1]; return a;").getClass());
assertEquals(float[].class, exec("float[] a = new float[1]; return a;").getClass());
assertEquals(double[].class, exec("double[] a = new double[1]; return a;").getClass());
assertEquals(boolean[].class, exec("boolean[] a = new boolean[1]; return a;").getClass());
assertEquals(String[].class, exec("String[] a = new String[1]; return a;").getClass());
assertEquals(Map[].class, exec("Map[] a = new Map[1]; return a;").getClass());
assertEquals(byte[][].class, exec("byte[][] a = new byte[1][2]; return a;").getClass());
assertEquals(short[][][].class, exec("short[][][] a = new short[1][2][3]; return a;").getClass());
assertEquals(char[][][][].class, exec("char[][][][] a = new char[1][2][3][4]; return a;").getClass());
assertEquals(int[][][][][].class, exec("int[][][][][] a = new int[1][2][3][4][5]; return a;").getClass());
assertEquals(long[][].class, exec("long[][] a = new long[1][2]; return a;").getClass());
assertEquals(float[][][].class, exec("float[][][] a = new float[1][2][3]; return a;").getClass());
assertEquals(double[][][][].class, exec("double[][][][] a = new double[1][2][3][4]; return a;").getClass());
assertEquals(boolean[][][][][].class, exec("boolean[][][][][] a = new boolean[1][2][3][4][5]; return a;").getClass());
assertEquals(String[][].class, exec("String[][] a = new String[1][2]; return a;").getClass());
assertEquals(Map[][][].class, exec("Map[][][] a = new Map[1][2][3]; return a;").getClass());
}
public void testContinueStatement() {
assertEquals(9, exec("int x = 0, y = 0; while (x < 10) { ++x; if (x == 1) continue; ++y; } return y;"));
}
public void testBreakStatement() {
assertEquals(4, exec("int x = 0, y = 0; while (x < 10) { ++x; if (x == 5) break; ++y; } return y;"));
}
@SuppressWarnings("rawtypes")
public void testReturnStatement() {
assertEquals(10, exec("return 10;"));
assertEquals(5, exec("int x = 5; return x;"));
assertEquals(4, exec("int[] x = new int[2]; x[1] = 4; return x[1];"));
assertEquals(5, ((short[])exec("short[] s = new short[3]; s[1] = 5; return s;"))[1]);
assertEquals(10, ((Map)exec("Map s = new HashMap(); s.put(\"x\", 10); return s;")).get("x"));
}
public void testLastInBlockDoesntNeedSemi() {
// One statement in the block in case that is a special case
assertEquals(10, exec("def i = 1; if (i == 1) {return 10}"));
assertEquals(10, exec("def i = 1; if (i == 1) {return 10} else {return 12}"));
// Two statements in the block, in case that is the general case
assertEquals(10, exec("def i = 1; if (i == 1) {i = 2; return 10}"));
assertEquals(10, exec("def i = 1; if (i == 1) {i = 2; return 10} else {return 12}"));
}
public void testArrayLoopWithoutCounter() {
assertEquals(6L, exec("long sum = 0; long[] array = new long[] { 1, 2, 3 };" +
"for (int i = 0; i < array.length; i++) { sum += array[i] } return sum",
Collections.emptyMap(),
Collections.singletonMap(CompilerSettings.MAX_LOOP_COUNTER, "0"),
null, true
));
assertEquals(6L, exec("long sum = 0; long[] array = new long[] { 1, 2, 3 };" +
"int i = 0; while (i < array.length) { sum += array[i++] } return sum",
Collections.emptyMap(),
Collections.singletonMap(CompilerSettings.MAX_LOOP_COUNTER, "0"),
null, true
));
assertEquals(6L, exec("long sum = 0; long[] array = new long[] { 1, 2, 3 };" +
"int i = 0; do { sum += array[i++] } while (i < array.length); return sum",
Collections.emptyMap(),
Collections.singletonMap(CompilerSettings.MAX_LOOP_COUNTER, "0"),
null, true
));
}
// tests both single break and multiple breaks used in a script
public void testForWithBreak() {
// single break test
assertEquals(1, exec(
"Map settings = ['test1' : '1'];" +
"int i = 0;" +
"List keys = ['test0', 'test1', 'test2'];" +
"for (; i < keys.size(); ++i) {" +
" if (settings.containsKey(keys[i])) {" +
" break;" +
" }" +
"}" +
"return i;"
));
List<Integer> expected = new ArrayList<>();
expected.add(1);
expected.add(0);
// multiple breaks test
assertEquals(expected, exec(
"Map outer = ['test1' : '1'];" +
"Map inner = ['test0' : '2'];" +
"boolean found = false;" +
"int i = 0, j = 0;" +
"List keys = ['test0', 'test1', 'test2'];" +
"for (; i < keys.size(); ++i) {" +
" if (outer.containsKey(keys[i])) {" +
" for (; j < keys.size(); ++j) {" +
" if (inner.containsKey(keys[j])) {" +
" found = true;" +
" break;" +
" }" +
" }" +
" if (found) {" +
" break;" +
" }" +
" }" +
"}" +
"[i, j];"
));
expected.set(1, 3);
// multiple breaks test, ignore inner break
assertEquals(expected, exec(
"Map outer = ['test1' : '1'];" +
"Map inner = ['test3' : '2'];" +
"int i = 0, j = 0;" +
"boolean found = false;" +
"List keys = ['test0', 'test1', 'test2'];" +
"for (; i < keys.size(); ++i) {" +
" if (outer.containsKey(keys[i])) {" +
" for (; j < keys.size(); ++j) {" +
" if (found) {" +
" break;" +
" }" +
" }" +
" found = true;" +
" if (found) {" +
" break;" +
" }" +
" }" +
"}" +
"[i, j];"
));
expected.set(0, 3);
expected.set(1, 1);
// multiple breaks test, ignore outer break
assertEquals(expected, exec(
"Map outer = ['test3' : '1'];" +
"Map inner = ['test1' : '2'];" +
"int i = 0, j = 0;" +
"boolean found = false;" +
"List keys = ['test0', 'test1', 'test2'];" +
"for (; i < keys.size(); ++i) {" +
" if (outer.containsKey('test3')) {" +
" for (; j < keys.size(); ++j) {" +
" if (inner.containsKey(keys[j])) {" +
" break;" +
" }" +
" }" +
" if (found) {" +
" break;" +
" }" +
" }" +
"}" +
"[i, j];"
));
}
// tests both single break and multiple breaks used in a script
public void testForEachWithBreak() {
// single break test
assertEquals(1, exec(
"Map settings = ['test1' : '1'];" +
"int i = 0;" +
"List keys = ['test0', 'test1', 'test2'];" +
"for (String key : keys) {" +
" if (settings.containsKey(key)) {" +
" break;" +
" }" +
" ++i;" +
"}" +
"return i;"
));
List<Integer> expected = new ArrayList<>();
expected.add(1);
expected.add(0);
// multiple breaks test
assertEquals(expected, exec(
"Map outer = ['test1' : '1'];" +
"Map inner = ['test0' : '2'];" +
"int i = 0, j = 0;" +
"boolean found = false;" +
"List keys = ['test0', 'test1', 'test2'];" +
"for (String okey : keys) {" +
" if (outer.containsKey(okey)) {" +
" for (String ikey : keys) {" +
" if (inner.containsKey(ikey)) {" +
" found = true;" +
" break;" +
" }" +
" ++j;" +
" }" +
" if (found) {" +
" break;" +
" }" +
" }" +
" ++i;" +
"}" +
"[i, j];"
));
expected.set(0, 3);
expected.set(1, 1);
// multiple breaks test, ignore outer break
assertEquals(expected, exec(
"Map outer = ['test1' : '1'];" +
"Map inner = ['test1' : '1'];" +
"int i = 0, j = 0;" +
"boolean found = false;" +
"List keys = ['test0', 'test1', 'test2'];" +
"for (String okey : keys) {" +
" if (outer.containsKey(okey)) {" +
" for (String ikey : keys) {" +
" if (inner.containsKey(ikey)) {" +
" break;" +
" }" +
" ++j;" +
" }" +
" if (found) {" +
" break;" +
" }" +
" }" +
" ++i;" +
"}" +
"[i, j];"
));
expected.set(0, 1);
expected.set(1, 3);
// multiple breaks test, ignore inner break
assertEquals(expected, exec(
"Map outer = ['test1' : '1'];" +
"Map inner = ['test1' : '1'];" +
"int i = 0, j = 0;" +
"boolean found = false;" +
"List keys = ['test0', 'test1', 'test2'];" +
"for (String okey : keys) {" +
" if (outer.containsKey(okey)) {" +
" for (String ikey : keys) {" +
" if (found) {" +
" break;" +
" }" +
" ++j;" +
" }" +
" found = true;" +
" if (found) {" +
" break;" +
" }" +
" }" +
" ++i;" +
"}" +
"[i, j];"
));
}
}