You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ch...@apache.org on 2015/11/12 16:34:06 UTC

olingo-odata4 git commit: [OLINGO-568] second parser draft

Repository: olingo-odata4
Updated Branches:
  refs/head/OLINGO-568_SearchParserPoC [created] 193ebc150


[OLINGO-568] second parser draft


Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/193ebc15
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/193ebc15
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/193ebc15

Branch: refs/head/OLINGO-568_SearchParserPoC
Commit: 193ebc1506e7a75925cad587653e42fddc0dee85
Parents: a8d63fb
Author: Christian Amend <ch...@sap.com>
Authored: Thu Nov 12 16:32:43 2015 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Thu Nov 12 16:32:43 2015 +0100

----------------------------------------------------------------------
 .../api/uri/queryoption/search/SearchUnary.java |   6 +-
 .../uri/parser/search/SearchBinaryImpl.java     |  14 +-
 .../core/uri/parser/search/SearchParser.java    | 176 +++++++++++--------
 .../parser/search/SearchParserException.java    |  31 ++++
 .../core/uri/parser/search/SearchTokenizer.java |   5 +-
 .../parser/search/SearchTokenizerException.java |   7 +-
 .../core/uri/parser/search/SearchUnaryImpl.java |  18 +-
 .../search/SearchParserAndTokenizerTest.java    |  17 +-
 .../uri/parser/search/SearchParserTest.java     | 114 ++++++------
 9 files changed, 240 insertions(+), 148 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/193ebc15/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/search/SearchUnary.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/search/SearchUnary.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/search/SearchUnary.java
index c266308..b01094d 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/search/SearchUnary.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/search/SearchUnary.java
@@ -6,9 +6,9 @@
  * 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
@@ -21,6 +21,6 @@ package org.apache.olingo.server.api.uri.queryoption.search;
 public interface SearchUnary extends SearchExpression {
 
   SearchUnaryOperatorKind getOperator();
-  SearchTerm getOperand();
 
+  SearchExpression getOperand();
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/193ebc15/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchBinaryImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchBinaryImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchBinaryImpl.java
index 418d9e7..ed0a697 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchBinaryImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchBinaryImpl.java
@@ -25,12 +25,18 @@ import org.apache.olingo.server.api.uri.queryoption.search.SearchExpression;
 public class SearchBinaryImpl extends SearchExpressionImpl implements SearchBinary {
 
   private final SearchBinaryOperatorKind operator;
-  private final SearchExpression left;
-  private final SearchExpression right;
+  private SearchExpression left;
+  private SearchExpression right;
 
-  public SearchBinaryImpl(SearchExpression left, SearchBinaryOperatorKind operator, SearchExpression right) {
-    this.left = left;
+  public SearchBinaryImpl(SearchBinaryOperatorKind operator) {
     this.operator = operator;
+  }
+
+  public void setLeft(SearchExpression left) {
+    this.left = left;
+  }
+
+  public void setRight(SearchExpression right) {
     this.right = right;
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/193ebc15/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
index 5e26c35..8321b6c 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
@@ -6,9 +6,9 @@
  * 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
@@ -18,109 +18,141 @@
  */
 package org.apache.olingo.server.core.uri.parser.search;
 
+import java.util.ArrayList;
+
 import org.apache.olingo.server.api.uri.queryoption.SearchOption;
 import org.apache.olingo.server.api.uri.queryoption.search.SearchBinaryOperatorKind;
 import org.apache.olingo.server.api.uri.queryoption.search.SearchExpression;
 import org.apache.olingo.server.api.uri.queryoption.search.SearchTerm;
 import org.apache.olingo.server.core.uri.queryoption.SearchOptionImpl;
 
-import java.util.Iterator;
-
 public class SearchParser {
 
-  protected Iterator<SearchQueryToken> tokens;
-  protected SearchExpression root;
-//  private SearchQueryToken currentToken;
+  protected ArrayList<SearchQueryToken> tokens;
+  private int size;
+  private int currentPosition = -1;
 
-  public SearchOption parse(String path, String value) {
+  public SearchOption parse(String path, String value) throws SearchTokenizerException, SearchParserException {
     SearchTokenizer tokenizer = new SearchTokenizer();
-    try {
-      tokens = tokenizer.tokenize(value).iterator();
-//      currentToken = tokens.next();
-      root = processTokens();
-    } catch (SearchTokenizerException e) {
-      return null;
-    }
+    tokens = tokenizer.tokenize(value);
+    SearchExpression root = processTokens();
     final SearchOptionImpl searchOption = new SearchOptionImpl();
     searchOption.setSearchExpression(root);
     return searchOption;
   }
 
-  protected SearchExpression processTokens() {
-    SearchQueryToken token = nextToken();
-    
-    
-    if(token.getToken() == SearchQueryToken.Token.OPEN) {
-      throw illegalState();
-    } else if(token.getToken() == SearchQueryToken.Token.NOT) {
-      return processNot();
-    } else if(token.getToken() == SearchQueryToken.Token.PHRASE ||
-        token.getToken() == SearchQueryToken.Token.WORD) {
-      return processTerm(token);
-//    } else if(token.getToken() == SearchQueryToken.Token.AND) {
-//      return processAnd();
-    } else {
-      throw illegalState();
+  protected SearchExpression processTokens() throws SearchParserException {
+    size = tokens.size();
+    SearchExpression root = null;
+    SearchQueryToken nextToken = next();
+    switch (nextToken.getToken()) {
+    case WORD:
+    case PHRASE:
+      root = processWord(null, nextToken.getLiteral());
+      break;
+    case NOT:
+      root = processNot();
+    case OPEN:
+      // TODO: implement
+    default:
+      break;
     }
-  }
 
-  private SearchExpression processAnd(SearchExpression se) {
-    SearchQueryToken token = nextToken();
-    if(token.getToken() == SearchQueryToken.Token.PHRASE ||
-        token.getToken() == SearchQueryToken.Token.WORD) {
-//      SearchExpression t = processTerm(token);
-      return new SearchBinaryImpl(se, SearchBinaryOperatorKind.AND, processTerm(token));
+    if (hasNext()) {
+      throw new SearchParserException();
     }
-    throw illegalState();
+
+    return root;
   }
 
-  private SearchExpression processOr(SearchExpression se) {
-    SearchQueryToken token = nextToken();
-    if(token.getToken() == SearchQueryToken.Token.PHRASE ||
-        token.getToken() == SearchQueryToken.Token.WORD) {
-      return new SearchBinaryImpl(se, SearchBinaryOperatorKind.OR, processTerm(token));
+  private SearchExpression processNot() throws SearchParserException {
+    SearchUnaryImpl not = new SearchUnaryImpl();
+    SearchQueryToken nextToken = next();
+    switch (nextToken.getToken()) {
+    case WORD:
+    case PHRASE:
+      processWord(not, nextToken.getLiteral());
+    case OPEN:
+    default:
+      break;
     }
-    throw illegalState();
+    return not;
   }
 
-  private RuntimeException illegalState() {
-    return new RuntimeException();
+  private SearchExpression processWord(SearchUnaryImpl not, String literal) throws SearchParserException {
+    SearchExpression exp = new SearchTermImpl(literal);
+    if (not != null) {
+      not.setOperand(exp);
+      exp = not;
+    }
+    if (hasNext()) {
+      SearchQueryToken nextToken = next();
+      switch (nextToken.getToken()) {
+      case WORD:
+      case PHRASE:
+        exp = processImplicitAnd(exp, nextToken);
+        break;
+      case AND:
+        exp = processAnd(exp);
+        break;
+      case OR:
+        exp = processOr(exp);
+        break;
+      default:
+        break;
+      }
+    }
+    return exp;
   }
 
-  private SearchUnaryImpl processNot() {
-    SearchQueryToken token = nextToken();
-    if(token.getToken() == SearchQueryToken.Token.PHRASE ||
-        token.getToken() == SearchQueryToken.Token.WORD) {
-      throw illegalState();
-//      return new SearchUnaryImpl(processTerm(token));
+  private SearchExpression processOr(SearchExpression left) throws SearchParserException {
+    SearchBinaryImpl or = new SearchBinaryImpl(SearchBinaryOperatorKind.OR);
+    or.setLeft(left);
+    SearchQueryToken nextToken = next();
+    switch (nextToken.getToken()) {
+    case WORD:
+    case PHRASE:
+      or.setRight(processWord(null, nextToken.getLiteral()));
+      break;
+    default:
+      break;
     }
-    throw illegalState();
+    return or;
   }
 
-  private SearchQueryToken nextToken() {
-//    if(tokens.hasNext()) {
-    return tokens.next();
-//    }
-//    return null;
+  private SearchExpression processAnd(SearchExpression left) throws SearchParserException {
+    SearchBinaryImpl and = new SearchBinaryImpl(SearchBinaryOperatorKind.AND);
+    and.setLeft(left);
+    SearchQueryToken nextToken = next();
+    switch (nextToken.getToken()) {
+    case WORD:
+    case PHRASE:
+      and.setRight(processWord(null, nextToken.getLiteral()));
+      break;
+    default:
+      break;
+    }
+    return and;
   }
 
-  private SearchExpression processTerm(SearchQueryToken token) {
-    SearchTerm searchTerm = new SearchTermImpl(token.getLiteral());
-    if(isEof()) {
-      return searchTerm;
-    }
+  private SearchExpression processImplicitAnd(SearchExpression left, SearchQueryToken nextToken)
+      throws SearchParserException {
+    SearchBinaryImpl and = new SearchBinaryImpl(SearchBinaryOperatorKind.AND);
+    and.setLeft(left);
+    and.setRight(new SearchTermImpl(nextToken.getLiteral()));
+    return and;
+  }
 
-    SearchQueryToken next = nextToken();
-    if(next.getToken() == SearchQueryToken.Token.AND) {
-      return processAnd(searchTerm);
-    } else if(next.getToken() == SearchQueryToken.Token.OR) {
-      return processOr(searchTerm);
+  private SearchQueryToken next() throws SearchParserException {
+    currentPosition++;
+    if (currentPosition < size) {
+      return tokens.get(currentPosition);
+    } else {
+      throw new SearchParserException();
     }
-
-    throw illegalState();
   }
 
-  private boolean isEof() {
-    return !tokens.hasNext();
+  private boolean hasNext() {
+    return currentPosition + 1 < size;
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/193ebc15/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParserException.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParserException.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParserException.java
new file mode 100644
index 0000000..be22620
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParserException.java
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+package org.apache.olingo.server.core.uri.parser.search;
+
+import org.apache.olingo.server.core.uri.parser.UriParserSemanticException;
+
+public class SearchParserException extends UriParserSemanticException {
+  private static final long serialVersionUID = 5781553037561337795L;
+
+  //TODO: message keys
+  public SearchParserException() {
+    super(null, null);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/193ebc15/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
index 9288981..78936bd 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
@@ -19,7 +19,6 @@
 package org.apache.olingo.server.core.uri.parser.search;
 
 import java.util.ArrayList;
-import java.util.List;
 
 /**
  * <code>
@@ -440,13 +439,13 @@ public class SearchTokenizer {
    * @throws SearchTokenizerException if something in query is not valid
    *                                  (based on OData search query ABNF)
    */
-  public List<SearchQueryToken> tokenize(final String searchQuery)
+  public ArrayList<SearchQueryToken> tokenize(final String searchQuery)
         throws SearchTokenizerException {
     
     char[] chars = searchQuery.trim().toCharArray();
 
     State state = new SearchExpressionState();
-    List<SearchQueryToken> states = new ArrayList<SearchQueryToken>();
+    ArrayList<SearchQueryToken> states = new ArrayList<SearchQueryToken>();
     for (char aChar : chars) {
       State next = state.nextChar(aChar);
       if (state.isFinished()) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/193ebc15/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerException.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerException.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerException.java
index 451632b..6abf6cc 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerException.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerException.java
@@ -18,11 +18,14 @@
  */
 package org.apache.olingo.server.core.uri.parser.search;
 
-public class SearchTokenizerException extends Exception {
+import org.apache.olingo.server.core.uri.parser.UriParserSyntaxException;
+
+public class SearchTokenizerException extends UriParserSyntaxException {
 
   private static final long serialVersionUID = -8295456415309640166L;
 
+  //TODO: Translation texts
   public SearchTokenizerException(String message) {
-    super(message);
+    super(message, null);
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/193ebc15/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchUnaryImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchUnaryImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchUnaryImpl.java
index 51e3a24..f82d478 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchUnaryImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchUnaryImpl.java
@@ -6,9 +6,9 @@
  * 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
@@ -18,24 +18,24 @@
  */
 package org.apache.olingo.server.core.uri.parser.search;
 
-import org.apache.olingo.server.api.uri.queryoption.search.SearchTerm;
+import org.apache.olingo.server.api.uri.queryoption.search.SearchExpression;
 import org.apache.olingo.server.api.uri.queryoption.search.SearchUnary;
 import org.apache.olingo.server.api.uri.queryoption.search.SearchUnaryOperatorKind;
 
 public class SearchUnaryImpl extends SearchExpressionImpl implements SearchUnary {
-  private final SearchTerm operand;
-
-  public SearchUnaryImpl(SearchTerm operand) {
-    this.operand = operand;
-  }
+  private SearchExpression operand;
 
   @Override
   public SearchUnaryOperatorKind getOperator() {
     return SearchUnaryOperatorKind.NOT;
   }
 
+  public void setOperand(SearchExpression operand) {
+    this.operand = operand;
+  }
+
   @Override
-  public SearchTerm getOperand() {
+  public SearchExpression getOperand() {
     return operand;
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/193ebc15/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
index 43b63c3..af21e7a 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
@@ -33,7 +33,7 @@ import org.junit.Test;
 public class SearchParserAndTokenizerTest {
 
   @Test
-  public void basicParsing() throws SearchTokenizerException {
+  public void basicParsing() throws Exception {
     SearchExpressionValidator.init("a")
         .validate(with("a"));
     SearchExpressionValidator.init("a AND b")
@@ -91,11 +91,15 @@ public class SearchParserAndTokenizerTest {
   }
 
   private static SearchExpression or(SearchExpression right) {
-    return new SearchBinaryImpl(null, OR, right);
+    SearchBinaryImpl impl = new SearchBinaryImpl(OR);
+    impl.setRight(right);
+    return impl;
   }
 
   private static SearchExpression and(SearchExpression right) {
-    return new SearchBinaryImpl(null, AND, right);
+    SearchBinaryImpl impl = new SearchBinaryImpl(AND);
+    impl.setRight(right);
+    return impl;
   }
 
   private static SearchExpression and(String right) {
@@ -107,7 +111,9 @@ public class SearchParserAndTokenizerTest {
   }
 
   private static SearchUnary not(String term) {
-    return new SearchUnaryImpl(new SearchTermImpl(term));
+    SearchUnaryImpl unary = new SearchUnaryImpl();
+    unary.setOperand(new SearchTermImpl(term));
+    return unary;
   }
 
   private static void setLeftField(String left, SearchExpression se) {
@@ -155,7 +161,8 @@ public class SearchParserAndTokenizerTest {
       Assert.fail("Expected exception " + exception.getClass().getSimpleName() + " was not thrown.");
     }
 
-    private void validate(SearchExpression expectedSearchExpression) throws SearchTokenizerException {
+    private void validate(SearchExpression expectedSearchExpression) throws SearchTokenizerException,
+        SearchParserException {
       SearchParser tokenizer = new SearchParser();
       SearchOption result = tokenizer.parse(null, searchQuery);
       Assert.assertNotNull(result);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/193ebc15/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
index 961663c..383c0d1 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
@@ -25,7 +25,6 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import java.util.ArrayList;
-import java.util.List;
 
 import org.apache.olingo.server.api.uri.queryoption.search.SearchBinaryOperatorKind;
 import org.apache.olingo.server.api.uri.queryoption.search.SearchExpression;
@@ -33,31 +32,31 @@ import org.apache.olingo.server.core.uri.parser.search.SearchQueryToken.Token;
 import org.junit.Ignore;
 import org.junit.Test;
 
-public class SearchParserTest extends SearchParser {
+public class SearchParserTest {
 
   @Test
-  public void simple() {
+  public void simple() throws Exception {
     SearchExpression se = run(Token.WORD);
     assertEquals("'word1'", se.toString());
     assertTrue(se.isSearchTerm());
     assertEquals("word1", se.asSearchTerm().getSearchTerm());
-    
+
     se = run(Token.PHRASE);
     assertEquals("'phrase1'", se.toString());
     assertTrue(se.isSearchTerm());
-    //TODO: Check if quotation marks should be part of the string we deliver
+    // TODO: Check if quotation marks should be part of the string we deliver
     assertEquals("phrase1", se.asSearchTerm().getSearchTerm());
   }
 
   @Test
-  public void simpleAnd() {
+  public void simpleAnd() throws Exception {
     SearchExpression se = run(Token.WORD, Token.AND, Token.WORD);
     assertEquals("{'word1' AND 'word2'}", se.toString());
     assertTrue(se.isSearchBinary());
     assertEquals(SearchBinaryOperatorKind.AND, se.asSearchBinary().getOperator());
     assertEquals("word1", se.asSearchBinary().getLeftOperand().asSearchTerm().getSearchTerm());
     assertEquals("word2", se.asSearchBinary().getRightOperand().asSearchTerm().getSearchTerm());
-    
+
     se = run(Token.PHRASE, Token.AND, Token.PHRASE);
     assertEquals("{'phrase1' AND 'phrase2'}", se.toString());
     assertTrue(se.isSearchBinary());
@@ -65,16 +64,16 @@ public class SearchParserTest extends SearchParser {
     assertEquals("phrase1", se.asSearchBinary().getLeftOperand().asSearchTerm().getSearchTerm());
     assertEquals("phrase2", se.asSearchBinary().getRightOperand().asSearchTerm().getSearchTerm());
   }
-  
+
   @Test
-  public void simpleOr() {
+  public void simpleOr() throws Exception {
     SearchExpression se = run(Token.WORD, Token.OR, Token.WORD);
     assertEquals("{'word1' OR 'word2'}", se.toString());
     assertTrue(se.isSearchBinary());
     assertEquals(SearchBinaryOperatorKind.OR, se.asSearchBinary().getOperator());
     assertEquals("word1", se.asSearchBinary().getLeftOperand().asSearchTerm().getSearchTerm());
     assertEquals("word2", se.asSearchBinary().getRightOperand().asSearchTerm().getSearchTerm());
-    
+
     se = run(Token.PHRASE, Token.OR, Token.PHRASE);
     assertEquals("{'phrase1' OR 'phrase2'}", se.toString());
     assertTrue(se.isSearchBinary());
@@ -82,17 +81,16 @@ public class SearchParserTest extends SearchParser {
     assertEquals("phrase1", se.asSearchBinary().getLeftOperand().asSearchTerm().getSearchTerm());
     assertEquals("phrase2", se.asSearchBinary().getRightOperand().asSearchTerm().getSearchTerm());
   }
-  
-  @Ignore
+
   @Test
-  public void simpleImplicitAnd() {
+  public void simpleImplicitAnd() throws Exception {
     SearchExpression se = run(Token.WORD, Token.WORD);
     assertEquals("{'word1' AND 'word2'}", se.toString());
     assertTrue(se.isSearchBinary());
     assertEquals(SearchBinaryOperatorKind.AND, se.asSearchBinary().getOperator());
     assertEquals("word1", se.asSearchBinary().getLeftOperand().asSearchTerm().getSearchTerm());
     assertEquals("word2", se.asSearchBinary().getRightOperand().asSearchTerm().getSearchTerm());
-    
+
     se = run(Token.PHRASE, Token.PHRASE);
     assertEquals("{'phrase1' AND 'phrase2'}", se.toString());
     assertTrue(se.isSearchBinary());
@@ -100,77 +98,93 @@ public class SearchParserTest extends SearchParser {
     assertEquals("phrase1", se.asSearchBinary().getLeftOperand().asSearchTerm().getSearchTerm());
     assertEquals("phrase2", se.asSearchBinary().getRightOperand().asSearchTerm().getSearchTerm());
   }
-  
+
   @Ignore
   @Test
-  public void simpleBrackets() {
+  public void simpleBrackets() throws Exception {
     SearchExpression se = run(Token.OPEN, Token.WORD, Token.CLOSE);
     assertEquals("'word1'", se.toString());
     assertTrue(se.isSearchTerm());
     assertEquals("word1", se.asSearchTerm().getSearchTerm());
-    
+
     se = run(Token.OPEN, Token.PHRASE, Token.CLOSE);
     assertEquals("'phrase1'", se.toString());
     assertTrue(se.isSearchTerm());
     assertEquals("phrase1", se.asSearchTerm().getSearchTerm());
   }
-  
-  @Ignore
+
   @Test
-  public void simpleNot() {
+  public void simpleNot() throws Exception {
     SearchExpression se = run(Token.NOT, Token.WORD);
     assertEquals("{NOT 'word1'}", se.toString());
     assertTrue(se.isSearchUnary());
     assertEquals("word1", se.asSearchUnary().getOperand().asSearchTerm().getSearchTerm());
-    
-    se = run(Token.NOT, Token.WORD);
-    assertEquals("'phrase1'", se.toString());
+
+    se = run(Token.NOT, Token.PHRASE);
+    assertEquals("{NOT 'phrase1'}", se.toString());
     assertTrue(se.isSearchUnary());
     assertEquals("phrase1", se.asSearchUnary().getOperand().asSearchTerm().getSearchTerm());
   }
-  
+
   @Ignore
   @Test
-  public void precedenceLast() {
-    //word1 AND (word2 AND word3) 
+  public void precedenceLast() throws Exception {
+    // word1 AND (word2 AND word3)
     SearchExpression se = run(Token.WORD, Token.AND, Token.OPEN, Token.WORD, Token.AND, Token.WORD, Token.CLOSE);
     assertEquals("{'word1' AND {'word2' AND 'word3'}}", se.toString());
   }
-  
+
   @Ignore
   @Test
-  public void precedenceFirst() {
-    //(word1 AND word2) AND word3 
+  public void precedenceFirst() throws Exception {
+    // (word1 AND word2) AND word3
     SearchExpression se = run(Token.OPEN, Token.WORD, Token.AND, Token.WORD, Token.CLOSE, Token.AND, Token.WORD);
     assertEquals("{{'word1' AND 'word2'} AND 'word3'}", se.toString());
   }
-  
 
-  private SearchExpression run(SearchQueryToken.Token... tokenArray) {
-    List<SearchQueryToken> tokenList = prepareTokens(tokenArray);
-    tokens = tokenList.iterator();
-    SearchExpression se = processTokens();
+  @Ignore
+  @Test
+  public void baseCases() throws Exception {
+    // word1 AND (word2 OR word3)
+    SearchExpression se = run(Token.WORD, Token.AND, Token.OPEN, Token.WORD, Token.OR, Token.WORD, Token.CLOSE);
+    assertEquals("{'word1' AND {'word2' OR 'word3'}}", se.toString());
+
+    // word1 AND word2 OR word3
+    se = run(Token.WORD, Token.AND, Token.WORD, Token.OR, Token.WORD);
+    assertEquals("{{'word1' AND 'word2'} OR 'word3'}", se.toString());
+
+    // word1 OR word2 AND word3
+    se = run(Token.WORD, Token.OR, Token.WORD, Token.AND, Token.WORD);
+    assertEquals("{'word1' OR {'word2' AND 'word3'}}", se.toString());
+  }
+
+  private SearchExpression run(SearchQueryToken.Token... tokenArray) throws SearchParserException {
+    LocalTestParser parser = new LocalTestParser();
+    parser.prepareTokens(tokenArray);
+    SearchExpression se = parser.processTokens();
     assertNotNull(se);
     return se;
   }
 
-  public List<SearchQueryToken> prepareTokens(SearchQueryToken.Token... tokenArray) {
-    ArrayList<SearchQueryToken> tokenList = new ArrayList<SearchQueryToken>();
-    int wordNumber = 1;
-    int phraseNumber = 1;
-    for (int i = 0; i < tokenArray.length; i++) {
-      SearchQueryToken token = mock(SearchQueryToken.class);
-      when(token.getToken()).thenReturn(tokenArray[i]);
-      if (tokenArray[i] == Token.WORD) {
-        when(token.getLiteral()).thenReturn("word" + wordNumber);
-        wordNumber++;
-      } else if (tokenArray[i] == Token.PHRASE) {
-        when(token.getLiteral()).thenReturn("phrase" + phraseNumber);
-        phraseNumber++;
+  private class LocalTestParser extends SearchParser {
+
+    public void prepareTokens(SearchQueryToken.Token... tokenArray) {
+      ArrayList<SearchQueryToken> tokenList = new ArrayList<SearchQueryToken>();
+      int wordNumber = 1;
+      int phraseNumber = 1;
+      for (int i = 0; i < tokenArray.length; i++) {
+        SearchQueryToken token = mock(SearchQueryToken.class);
+        when(token.getToken()).thenReturn(tokenArray[i]);
+        if (tokenArray[i] == Token.WORD) {
+          when(token.getLiteral()).thenReturn("word" + wordNumber);
+          wordNumber++;
+        } else if (tokenArray[i] == Token.PHRASE) {
+          when(token.getLiteral()).thenReturn("phrase" + phraseNumber);
+          phraseNumber++;
+        }
+        tokenList.add(token);
       }
-      tokenList.add(token);
+      tokens = tokenList;
     }
-    return tokenList;
   }
-
 }
\ No newline at end of file