|
@@ -0,0 +1,105 @@
|
|
|
+/*
|
|
|
+ * 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 org.elasticsearch.common.Nullable;
|
|
|
+import org.hamcrest.Matcher;
|
|
|
+
|
|
|
+import static java.util.Collections.singletonMap;
|
|
|
+
|
|
|
+/**
|
|
|
+ * Superclass for testing array-like objects (arrays and lists).
|
|
|
+ */
|
|
|
+public abstract class ArrayLikeObjectTestCase extends ScriptTestCase {
|
|
|
+ /**
|
|
|
+ * Build the string for declaring the variable holding the array-like-object to test. So {@code int[]} for arrays and {@code List} for
|
|
|
+ * lists.
|
|
|
+ */
|
|
|
+ protected abstract String declType(String valueType);
|
|
|
+ /**
|
|
|
+ * Build the string for calling the constructor for the array-like-object to test. So {@code new int[5]} for arrays and
|
|
|
+ * {@code [0, 0, 0, 0, 0]} or {@code [null, null, null, null, null]} for lists.
|
|
|
+ */
|
|
|
+ protected abstract String valueCtorCall(String valueType, int size);
|
|
|
+ /**
|
|
|
+ * The type of the exception thrown by out of bounds accesses;
|
|
|
+ */
|
|
|
+ protected abstract Matcher<? super IndexOutOfBoundsException> outOfBoundsExceptionMatcher(int index, int size);
|
|
|
+
|
|
|
+ private void arrayLoadStoreTestCase(boolean declareAsDef, String valueType, Object val, @Nullable Number valPlusOne) {
|
|
|
+ String declType = declareAsDef ? "def" : declType(valueType);
|
|
|
+ String valueCtorCall = valueCtorCall(valueType, 5);
|
|
|
+ String decl = declType + " x = " + valueCtorCall;
|
|
|
+ assertEquals(5, exec(decl + "; return x.length", true));
|
|
|
+ assertEquals(val, exec(decl + "; x[ 0] = params.val; return x[ 0];", singletonMap("val", val), true));
|
|
|
+ assertEquals(val, exec(decl + "; x[ 0] = params.val; return x[-5];", singletonMap("val", val), true));
|
|
|
+ assertEquals(val, exec(decl + "; x[-5] = params.val; return x[-5];", singletonMap("val", val), true));
|
|
|
+
|
|
|
+ expectOutOfBounds( 6, decl + "; return x[ 6]", val);
|
|
|
+ expectOutOfBounds(-1, decl + "; return x[-6]", val);
|
|
|
+ expectOutOfBounds( 6, decl + "; x[ 6] = params.val; return 0", val);
|
|
|
+ expectOutOfBounds(-1, decl + "; x[-6] = params.val; return 0", val);
|
|
|
+
|
|
|
+ if (valPlusOne != null) {
|
|
|
+ assertEquals(val, exec(decl + "; x[0] = params.val; x[ 0] = x[ 0]++; return x[0];", singletonMap("val", val), true));
|
|
|
+ assertEquals(val, exec(decl + "; x[0] = params.val; x[ 0] = x[-5]++; return x[0];", singletonMap("val", val), true));
|
|
|
+ assertEquals(valPlusOne, exec(decl + "; x[0] = params.val; x[ 0] = ++x[ 0]; return x[0];", singletonMap("val", val), true));
|
|
|
+ assertEquals(valPlusOne, exec(decl + "; x[0] = params.val; x[ 0] = ++x[-5]; return x[0];", singletonMap("val", val), true));
|
|
|
+ assertEquals(valPlusOne, exec(decl + "; x[0] = params.val; x[ 0]++ ; return x[0];", singletonMap("val", val), true));
|
|
|
+ assertEquals(valPlusOne, exec(decl + "; x[0] = params.val; x[-5]++ ; return x[0];", singletonMap("val", val), true));
|
|
|
+ assertEquals(valPlusOne, exec(decl + "; x[0] = params.val; x[ 0] += 1 ; return x[0];", singletonMap("val", val), true));
|
|
|
+ assertEquals(valPlusOne, exec(decl + "; x[0] = params.val; x[-5] += 1 ; return x[0];", singletonMap("val", val), true));
|
|
|
+
|
|
|
+ expectOutOfBounds( 6, decl + "; return x[ 6]++", val);
|
|
|
+ expectOutOfBounds(-1, decl + "; return x[-6]++", val);
|
|
|
+ expectOutOfBounds( 6, decl + "; return ++x[ 6]", val);
|
|
|
+ expectOutOfBounds(-1, decl + "; return ++x[-6]", val);
|
|
|
+ expectOutOfBounds( 6, decl + "; x[ 6] += 1; return 0", val);
|
|
|
+ expectOutOfBounds(-1, decl + "; x[-6] += 1; return 0", val);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void expectOutOfBounds(int index, String script, Object val) {
|
|
|
+ IndexOutOfBoundsException e = expectScriptThrows(IndexOutOfBoundsException.class,
|
|
|
+ () -> exec(script, singletonMap("val", val), true));
|
|
|
+ try {
|
|
|
+ assertThat(e, outOfBoundsExceptionMatcher(index, 5));
|
|
|
+ } catch (AssertionError ae) {
|
|
|
+ ae.addSuppressed(e); // Mark the exception we are testing as suppressed so we get its stack trace. If it has one :(
|
|
|
+ throw ae;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testInts() { arrayLoadStoreTestCase(false, "int", 5, 6); }
|
|
|
+ public void testIntsInDef() { arrayLoadStoreTestCase(true, "int", 5, 6); }
|
|
|
+ public void testLongs() { arrayLoadStoreTestCase(false, "long", 5L, 6L); }
|
|
|
+ public void testLongsInDef() { arrayLoadStoreTestCase(true, "long", 5L, 6L); }
|
|
|
+ public void testShorts() { arrayLoadStoreTestCase(false, "short", (short) 5, (short) 6); }
|
|
|
+ public void testShortsInDef() { arrayLoadStoreTestCase(true, "short", (short) 5, (short) 6); }
|
|
|
+ public void testBytes() { arrayLoadStoreTestCase(false, "byte", (byte) 5, (byte) 6); }
|
|
|
+ public void testBytesInDef() { arrayLoadStoreTestCase(true, "byte", (byte) 5, (byte) 6); }
|
|
|
+ public void testFloats() { arrayLoadStoreTestCase(false, "float", 5.0f, 6.0f); }
|
|
|
+ public void testFloatsInDef() { arrayLoadStoreTestCase(true, "float", 5.0f, 6.0f); }
|
|
|
+ public void testDoubles() { arrayLoadStoreTestCase(false, "double", 5.0d, 6.0d); }
|
|
|
+ public void testDoublesInDef() { arrayLoadStoreTestCase(true, "double", 5.0d, 6.0d); }
|
|
|
+ public void testStrings() { arrayLoadStoreTestCase(false, "String", "cat", null); }
|
|
|
+ public void testStringsInDef() { arrayLoadStoreTestCase(true, "String", "cat", null); }
|
|
|
+ public void testDef() { arrayLoadStoreTestCase(true, "def", 5, null); }
|
|
|
+}
|