/*
* 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.
*/
package org.elasticsearch.painless;
import static org.hamcrest.Matchers.containsString;
public class FunctionTests extends ScriptTestCase {
public void testBasic() {
assertEquals(5, exec("int get() {5;} get()"));
}
public void testReference() {
assertEquals(5, exec("void get(int[] x) {x[0] = 5;} int[] y = new int[1]; y[0] = 1; get(y); y[0]"));
}
public void testConcat() {
assertEquals("xyxy", exec("String catcat(String single) {single + single;} catcat('xy')"));
}
public void testMultiArgs() {
assertEquals(5, exec("int add(int x, int y) {return x + y;} int x = 1, y = 2; add(add(x, x), add(x, y))"));
}
public void testMultiFuncs() {
assertEquals(1, exec("int add(int x, int y) {return x + y;} int sub(int x, int y) {return x - y;} add(2, sub(3, 4))"));
assertEquals(3, exec("int sub2(int x, int y) {sub(x, y) - y;} int sub(int x, int y) {return x - y;} sub2(5, 1)"));
}
public void testRecursion() {
assertEquals(55, exec("int fib(int n) {if (n <= 1) return n; else return fib(n-1) + fib(n-2);} fib(10)"));
}
public void testEmpty() {
Exception expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("void test(int x) {} test()");
});
assertThat(expected.getMessage(), containsString("Cannot generate an empty function"));
}
public void testReturnsAreUnboxedIfNeeded() {
assertEquals((byte) 5, exec("byte get() {Byte.valueOf(5)} get()"));
assertEquals((short) 5, exec("short get() {Byte.valueOf(5)} get()"));
assertEquals(5, exec("int get() {Byte.valueOf(5)} get()"));
assertEquals((short) 5, exec("short get() {Short.valueOf(5)} get()"));
assertEquals(5, exec("int get() {Integer.valueOf(5)} get()"));
assertEquals(5.0f, exec("float get() {Float.valueOf(5)} get()"));
assertEquals(5.0d, exec("double get() {Float.valueOf(5)} get()"));
assertEquals(5.0d, exec("double get() {Double.valueOf(5)} get()"));
assertEquals(true, exec("boolean get() {Boolean.TRUE} get()"));
}
public void testDuplicates() {
Exception expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("void test(int x) {x = 2;} void test(def y) {y = 3;} test()");
});
assertThat(expected.getMessage(), containsString("Duplicate functions"));
}
public void testBadCastFromMethod() {
Exception e = expectScriptThrows(ClassCastException.class, () -> exec("int get() {5L} get()"));
assertEquals("Cannot cast from [long] to [int].", e.getMessage());
e = expectScriptThrows(ClassCastException.class, () -> exec("int get() {5.1f} get()"));
assertEquals("Cannot cast from [float] to [int].", e.getMessage());
e = expectScriptThrows(ClassCastException.class, () -> exec("int get() {5.1d} get()"));
assertEquals("Cannot cast from [double] to [int].", e.getMessage());
}
public void testInfiniteLoop() {
Error expected = expectScriptThrows(PainlessError.class, () -> {
exec("void test() {boolean x = true; while (x) {}} test()");
});
assertThat(expected.getMessage(),
containsString("The maximum number of statements that can be executed in a loop has been reached."));
}
public void testReturnVoid() {
assertEquals(null, exec("void test(StringBuilder b, int i) {b.setLength(i)} test(new StringBuilder(), 1)"));
Exception expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("int test(StringBuilder b, int i) {b.setLength(i)} test(new StringBuilder(), 1)");
});
assertEquals("Not all paths provide a return value for method [test].", expected.getMessage());
expected = expectScriptThrows(ClassCastException.class, () -> {
exec("int test(StringBuilder b, int i) {return b.setLength(i)} test(new StringBuilder(), 1)");
});
assertEquals("Cannot cast from [void] to [int].", expected.getMessage());
expected = expectScriptThrows(ClassCastException.class, () -> {
exec("def test(StringBuilder b, int i) {return b.setLength(i)} test(new StringBuilder(), 1)");
});
assertEquals("Cannot cast from [void] to [def].", expected.getMessage());
}
}