You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by rj...@apache.org on 2014/07/10 01:18:58 UTC

svn commit: r1609337 [2/2] - in /lucene/dev/trunk/lucene: ./ expressions/src/java/org/apache/lucene/expressions/ expressions/src/java/org/apache/lucene/expressions/js/ expressions/src/test/org/apache/lucene/expressions/ expressions/src/test/org/apache/...

Modified: lucene/dev/trunk/lucene/expressions/src/test/org/apache/lucene/expressions/TestDemoExpressions.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/expressions/src/test/org/apache/lucene/expressions/TestDemoExpressions.java?rev=1609337&r1=1609336&r2=1609337&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/expressions/src/test/org/apache/lucene/expressions/TestDemoExpressions.java (original)
+++ lucene/dev/trunk/lucene/expressions/src/test/org/apache/lucene/expressions/TestDemoExpressions.java Wed Jul  9 23:18:58 2014
@@ -4,9 +4,13 @@ import org.apache.lucene.document.Docume
 import org.apache.lucene.document.Field;
 import org.apache.lucene.document.NumericDocValuesField;
 import org.apache.lucene.expressions.js.JavascriptCompiler;
+import org.apache.lucene.expressions.js.VariableContext;
 import org.apache.lucene.index.DirectoryReader;
 import org.apache.lucene.index.RandomIndexWriter;
 import org.apache.lucene.index.Term;
+import org.apache.lucene.queries.function.ValueSource;
+import org.apache.lucene.queries.function.valuesource.DoubleConstValueSource;
+import org.apache.lucene.queries.function.valuesource.IntFieldSource;
 import org.apache.lucene.search.CheckHits;
 import org.apache.lucene.search.FieldDoc;
 import org.apache.lucene.search.IndexSearcher;
@@ -19,6 +23,10 @@ import org.apache.lucene.search.TopField
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.util.LuceneTestCase;
 
+import static org.apache.lucene.expressions.js.VariableContext.Type.MEMBER;
+import static org.apache.lucene.expressions.js.VariableContext.Type.STR_INDEX;
+import static org.apache.lucene.expressions.js.VariableContext.Type.INT_INDEX;
+
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -224,4 +232,71 @@ public class  TestDemoExpressions extend
     d = (FieldDoc) td.scoreDocs[2];
     assertEquals(5.2842D, (Double)d.fields[0], 1E-4);
   }
+
+  public void testStaticExtendedVariableExample() throws Exception {
+    Expression popularity = JavascriptCompiler.compile("doc[\"popularity\"].value");
+    SimpleBindings bindings = new SimpleBindings();
+    bindings.add("doc['popularity'].value", new IntFieldSource("popularity"));
+    Sort sort = new Sort(popularity.getSortField(bindings, true));
+    TopFieldDocs td = searcher.search(new MatchAllDocsQuery(), null, 3, sort);
+
+    FieldDoc d = (FieldDoc)td.scoreDocs[0];
+    assertEquals(20D, (Double)d.fields[0], 1E-4);
+
+    d = (FieldDoc)td.scoreDocs[1];
+    assertEquals(5D, (Double)d.fields[0], 1E-4);
+
+    d = (FieldDoc)td.scoreDocs[2];
+    assertEquals(2D, (Double)d.fields[0], 1E-4);
+  }
+
+  public void testDynamicExtendedVariableExample() throws Exception {
+    Expression popularity = JavascriptCompiler.compile("doc['popularity'].value + magicarray[0] + fourtytwo");
+
+    // The following is an example of how to write bindings which parse the variable name into pieces.
+    // Note, however, that this requires a lot of error checking.  Each "error case" below should be
+    // filled in with proper error messages for a real use case.
+    Bindings bindings = new Bindings() {
+      @Override
+      public ValueSource getValueSource(String name) {
+        VariableContext[] var = VariableContext.parse(name);
+        assert var[0].type == MEMBER;
+        String base = var[0].text;
+        if (base.equals("doc")) {
+          if (var.length > 1 && var[1].type == STR_INDEX) {
+            String field = var[1].text;
+            if (var.length > 2 && var[2].type == MEMBER && var[2].text.equals("value")) {
+              return new IntFieldSource(field);
+            } else {
+              fail("member: " + var[2].text);// error case, non/missing "value" member access
+            }
+          } else {
+            fail();// error case, doc should be a str indexed array
+          }
+        } else if (base.equals("magicarray")) {
+          if (var.length > 1 && var[1].type == INT_INDEX) {
+            return new DoubleConstValueSource(2048);
+          } else {
+            fail();// error case, magic array isn't an array
+          }
+        } else if (base.equals("fourtytwo")) {
+          return new DoubleConstValueSource(42);
+        } else {
+          fail();// error case (variable doesn't exist)
+        }
+        throw new IllegalArgumentException("Illegal reference '" + name + "'");
+      }
+    };
+    Sort sort = new Sort(popularity.getSortField(bindings, false));
+    TopFieldDocs td = searcher.search(new MatchAllDocsQuery(), null, 3, sort);
+
+    FieldDoc d = (FieldDoc)td.scoreDocs[0];
+    assertEquals(2092D, (Double)d.fields[0], 1E-4);
+
+    d = (FieldDoc)td.scoreDocs[1];
+    assertEquals(2095D, (Double)d.fields[0], 1E-4);
+
+    d = (FieldDoc)td.scoreDocs[2];
+    assertEquals(2110D, (Double)d.fields[0], 1E-4);
+  }
 }

Modified: lucene/dev/trunk/lucene/expressions/src/test/org/apache/lucene/expressions/js/TestJavascriptCompiler.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/expressions/src/test/org/apache/lucene/expressions/js/TestJavascriptCompiler.java?rev=1609337&r1=1609336&r2=1609337&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/expressions/src/test/org/apache/lucene/expressions/js/TestJavascriptCompiler.java (original)
+++ lucene/dev/trunk/lucene/expressions/src/test/org/apache/lucene/expressions/js/TestJavascriptCompiler.java Wed Jul  9 23:18:58 2014
@@ -18,6 +18,7 @@ package org.apache.lucene.expressions.js
 
 import java.text.ParseException;
 
+import org.apache.lucene.expressions.Expression;
 import org.apache.lucene.util.LuceneTestCase;
 
 public class TestJavascriptCompiler extends LuceneTestCase {
@@ -29,39 +30,60 @@ public class TestJavascriptCompiler exte
     assertNotNull(JavascriptCompiler.compile("logn(2, 20+10-5.0)"));
   }
 
-  public void testValidNamespaces() throws Exception {
-    assertNotNull(JavascriptCompiler.compile("object.valid0"));
-    assertNotNull(JavascriptCompiler.compile("object0.object1.valid1"));
+  public void testValidVariables() throws Exception {
+    doTestValidVariable("object.valid0");
+    doTestValidVariable("object0.object1.valid1");
+    doTestValidVariable("array0[1]");
+    doTestValidVariable("array0[1].x");
+    doTestValidVariable("multiarray[0][0]");
+    doTestValidVariable("multiarray[0][0].x");
+    doTestValidVariable("strindex['hello']");
+    doTestValidVariable("strindex[\"hello\"]", "strindex['hello']");
+    doTestValidVariable("empty['']");
+    doTestValidVariable("empty[\"\"]", "empty['']");
+    doTestValidVariable("strindex['\u304A\u65E9\u3046\u3054\u3056\u3044\u307E\u3059']");
+    doTestValidVariable("strindex[\"\u304A\u65E9\u3046\u3054\u3056\u3044\u307E\u3059\"]",
+                        "strindex['\u304A\u65E9\u3046\u3054\u3056\u3044\u307E\u3059']");
+    doTestValidVariable("escapes['\\\\\\'']");
+    doTestValidVariable("escapes[\"\\\\\\\"\"]", "escapes['\\\\\"']");
+    doTestValidVariable("mixed[23]['key'].sub.sub");
+    doTestValidVariable("mixed[23]['key'].sub.sub[1]");
+    doTestValidVariable("mixed[23]['key'].sub.sub[1].sub");
+    doTestValidVariable("mixed[23]['key'].sub.sub[1].sub['abc']");
+  }
+
+  void doTestValidVariable(String variable) throws Exception {
+    doTestValidVariable(variable, variable);
+  }
+
+  void doTestValidVariable(String variable, String output) throws Exception {
+    Expression e = JavascriptCompiler.compile(variable);
+    assertNotNull(e);
+    assertEquals(1, e.variables.length);
+    assertEquals(output, e.variables[0]);
+  }
+
+  public void testInvalidVariables() throws Exception {
+    doTestInvalidVariable("object.0invalid");
+    doTestInvalidVariable("0.invalid");
+    doTestInvalidVariable("object..invalid");
+    doTestInvalidVariable(".invalid");
+    doTestInvalidVariable("negative[-1]");
+    doTestInvalidVariable("float[1.0]");
+    doTestInvalidVariable("missing_end['abc]");
+    doTestInvalidVariable("missing_end[\"abc]");
+    doTestInvalidVariable("missing_begin[abc']");
+    doTestInvalidVariable("missing_begin[abc\"]");
+    doTestInvalidVariable("dot_needed[1]sub");
+    doTestInvalidVariable("dot_needed[1]sub");
+    doTestInvalidVariable("opposite_escape['\\\"']");
+    doTestInvalidVariable("opposite_escape[\"\\'\"]");
   }
 
-  public void testInvalidNamespaces() throws Exception {
+  void doTestInvalidVariable(String variable) {
     try {
-      JavascriptCompiler.compile("object.0invalid");
-      fail();
-    }
-    catch (ParseException expected) {
-      //expected
-    }
-
-    try {
-      JavascriptCompiler.compile("0.invalid");
-      fail();
-    }
-    catch (ParseException expected) {
-      //expected
-    }
-
-    try {
-      JavascriptCompiler.compile("object..invalid");
-      fail();
-    }
-    catch (ParseException expected) {
-      //expected
-    }
-
-    try {
-      JavascriptCompiler.compile(".invalid");
-      fail();
+      JavascriptCompiler.compile(variable);
+      fail("\"" + variable + " should have failed to compile");
     }
     catch (ParseException expected) {
       //expected
@@ -152,4 +174,30 @@ public class TestJavascriptCompiler exte
       assertTrue(expected.getMessage().contains("arguments for method call"));
     }
   }
+
+  public void testVariableNormalization() throws Exception {
+    // multiple double quotes
+    Expression x = JavascriptCompiler.compile("foo[\"a\"][\"b\"]");
+    assertEquals("foo['a']['b']", x.variables[0]);
+
+    // single and double in the same var
+    x = JavascriptCompiler.compile("foo['a'][\"b\"]");
+    assertEquals("foo['a']['b']", x.variables[0]);
+
+    // escapes remain the same in single quoted strings
+    x = JavascriptCompiler.compile("foo['\\\\\\'\"']");
+    assertEquals("foo['\\\\\\'\"']", x.variables[0]);
+
+    // single quotes are escaped
+    x = JavascriptCompiler.compile("foo[\"'\"]");
+    assertEquals("foo['\\'']", x.variables[0]);
+
+    // double quotes are unescaped
+    x = JavascriptCompiler.compile("foo[\"\\\"\"]");
+    assertEquals("foo['\"']", x.variables[0]);
+
+    // backslash escapes are kept the same
+    x = JavascriptCompiler.compile("foo['\\\\'][\"\\\\\"]");
+    assertEquals("foo['\\\\']['\\\\']", x.variables[0]);
+  }
 }

Added: lucene/dev/trunk/lucene/expressions/src/test/org/apache/lucene/expressions/js/TestVariableContext.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/expressions/src/test/org/apache/lucene/expressions/js/TestVariableContext.java?rev=1609337&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/expressions/src/test/org/apache/lucene/expressions/js/TestVariableContext.java (added)
+++ lucene/dev/trunk/lucene/expressions/src/test/org/apache/lucene/expressions/js/TestVariableContext.java Wed Jul  9 23:18:58 2014
@@ -0,0 +1,69 @@
+package org.apache.lucene.expressions.js;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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 org.apache.lucene.util.LuceneTestCase;
+
+import static org.apache.lucene.expressions.js.VariableContext.Type.MEMBER;
+import static org.apache.lucene.expressions.js.VariableContext.Type.STR_INDEX;
+import static org.apache.lucene.expressions.js.VariableContext.Type.INT_INDEX;
+
+public class TestVariableContext extends LuceneTestCase {
+
+  public void testSimpleVar() {
+    VariableContext[] x = VariableContext.parse("foo");
+    assertEquals(1, x.length);
+    assertEquals(x[0].type, MEMBER);
+    assertEquals(x[0].text, "foo");
+  }
+
+  public void testEmptyString() {
+    VariableContext[] x = VariableContext.parse("foo['']");
+    assertEquals(2, x.length);
+    assertEquals(x[1].type, STR_INDEX);
+    assertEquals(x[1].text, "");
+  }
+
+  public void testUnescapeString() {
+    VariableContext[] x = VariableContext.parse("foo['\\'\\\\']");
+    assertEquals(2, x.length);
+    assertEquals(x[1].type, STR_INDEX);
+    assertEquals(x[1].text, "'\\");
+  }
+
+  public void testMember() {
+    VariableContext[] x = VariableContext.parse("foo.bar");
+    assertEquals(2, x.length);
+    assertEquals(x[1].type, MEMBER);
+    assertEquals(x[1].text, "bar");
+  }
+
+  public void testMemberFollowedByMember() {
+    VariableContext[] x = VariableContext.parse("foo.bar.baz");
+    assertEquals(3, x.length);
+    assertEquals(x[2].type, MEMBER);
+    assertEquals(x[2].text, "baz");
+  }
+
+  public void testMemberFollowedByIntArray() {
+    VariableContext[] x = VariableContext.parse("foo.bar[1]");
+    assertEquals(3, x.length);
+    assertEquals(x[2].type, INT_INDEX);
+    assertEquals(x[2].integer, 1);
+  }
+}