/*
* ModeShape (http://www.modeshape.org)
*
* Licensed 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.modeshape.common.text;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import java.util.Arrays;
import org.junit.Before;
import org.junit.Test;
import org.modeshape.common.FixFor;
import org.modeshape.common.text.TokenStream.BasicTokenizer;
import org.modeshape.common.text.TokenStream.Tokenizer;
public class TokenStreamTest {
public static final int WORD = TokenStream.BasicTokenizer.WORD;
public static final int SYMBOL = TokenStream.BasicTokenizer.SYMBOL;
public static final int DECIMAL = TokenStream.BasicTokenizer.DECIMAL;
public static final int SINGLE_QUOTED_STRING = TokenStream.BasicTokenizer.SINGLE_QUOTED_STRING;
public static final int DOUBLE_QUOTED_STRING = TokenStream.BasicTokenizer.DOUBLE_QUOTED_STRING;
public static final int COMMENT = TokenStream.BasicTokenizer.COMMENT;
private Tokenizer tokenizer;
private String content;
private TokenStream tokens;
@Before
public void beforeEach() {
tokenizer = TokenStream.basicTokenizer(false);
content = "Select all columns from this table";
makeCaseInsensitive();
}
public void makeCaseSensitive() {
tokens = new TokenStream(content, tokenizer, true);
tokens.start();
}
public void makeCaseInsensitive() {
tokens = new TokenStream(content, tokenizer, false);
tokens.start();
}
@Test( expected = IllegalStateException.class )
public void shouldNotAllowConsumeBeforeStartIsCalled() {
tokens = new TokenStream(content, TokenStream.basicTokenizer(false), false);
tokens.consume("Select");
}
@Test( expected = IllegalStateException.class )
public void shouldNotAllowHasNextBeforeStartIsCalled() {
tokens = new TokenStream(content, TokenStream.basicTokenizer(false), false);
tokens.hasNext();
}
@Test( expected = IllegalStateException.class )
public void shouldNotAllowMatchesBeforeStartIsCalled() {
tokens = new TokenStream(content, TokenStream.basicTokenizer(false), false);
tokens.matches("Select");
}
@Test( expected = IllegalStateException.class )
public void shouldNotAllowCanConsumeBeforeStartIsCalled() {
tokens = new TokenStream(content, TokenStream.basicTokenizer(false), false);
tokens.canConsume("Select");
}
@Test
public void shouldReturnTrueFromHasNextIfThereIsACurrentToken() {
content = "word";
makeCaseSensitive();
assertThat(tokens.currentToken().matches("word"), is(true));
assertThat(tokens.hasNext(), is(true));
}
@Test
public void shouldConsumeInCaseSensitiveMannerWithExpectedValuesWhenMatchingExactCase() {
makeCaseSensitive();
tokens.consume("Select");
tokens.consume("all");
tokens.consume("columns");
tokens.consume("from");
tokens.consume("this");
tokens.consume("table");
assertThat(tokens.hasNext(), is(false));
}
@Test( expected = ParsingException.class )
public void shouldFailToConsumeInCaseSensitiveMannerWithExpectedValuesWhenMatchingIncorrectCase() {
makeCaseSensitive();
tokens.consume("Select");
tokens.consume("all");
tokens.consume("Columns");
}
@Test
public void shouldConsumeInCaseInsensitiveMannerWithExpectedValuesWhenMatchingNonExactCase() {
makeCaseInsensitive();
tokens.consume("SELECT");
tokens.consume("ALL");
tokens.consume("COLUMNS");
tokens.consume("FROM");
tokens.consume("THIS");
tokens.consume("TABLE");
assertThat(tokens.hasNext(), is(false));
}
@Test( expected = ParsingException.class )
public void shouldFailToConsumeInCaseInsensitiveMannerWithExpectedValuesWhenMatchingStringIsInLowerCase() {
makeCaseInsensitive();
tokens.consume("SELECT");
tokens.consume("ALL");
tokens.consume("columns");
}
@FixFor( "MODE-2497" )
@Test
public void shouldHandleNonAsciiCharactersWhenCaseSensitive() {
content = "ü and";
makeCaseSensitive();
tokens.consume("ü");
tokens.consume("and");
assertThat(tokens.hasNext(), is(false));
}
@FixFor( "MODE-2497" )
@Test
public void shouldHandleßCharacterWhenCaseSensitive() {
content = "ß and";
makeCaseSensitive();
tokens.consume("ß");
tokens.consume("and");
assertThat(tokens.hasNext(), is(false));
}
@FixFor( "MODE-2497" )
@Test
public void shouldConsumeCaseInsensitiveStringInOriginalCase() {
makeCaseInsensitive();
String firstToken = tokens.consume();
assertThat(firstToken, is("Select"));
}
@FixFor( "MODE-2497" )
@Test
public void shouldMatchUpperCaseVersionOfßCharacterWhenCaseInsensitive() {
content = "ß";
makeCaseInsensitive();
tokens.consume("SS");
assertThat(tokens.hasNext(), is(false));
}
@FixFor( "MODE-2497" )
@Test
public void shouldHandleTokensAfterßCharacterWhenCaseInsensitive() {
content = "ß and";
makeCaseInsensitive();
tokens.consume(TokenStream.ANY_VALUE);
tokens.consume("AND");
assertThat(tokens.hasNext(), is(false));
}
@Test
public void shouldReturnTrueFromCanConsumeWithCaseSensitiveTokenStreamIfMatchStringDoesMatchCaseExactly() {
makeCaseSensitive();
assertThat(tokens.canConsume("Select"), is(true));
assertThat(tokens.canConsume("all"), is(true));
assertThat(tokens.canConsume("columns"), is(true));
assertThat(tokens.canConsume("from"), is(true));
assertThat(tokens.canConsume("this"), is(true));
assertThat(tokens.canConsume("table"), is(true));
assertThat(tokens.hasNext(), is(false));
}
@Test
public void shouldReturnFalseFromCanConsumeWithCaseSensitiveTokenStreamIfMatchStringDoesNotMatchCaseExactly() {
makeCaseSensitive();
assertThat(tokens.canConsume("Select"), is(true));
assertThat(tokens.canConsume("all"), is(true));
assertThat(tokens.canConsume("Columns"), is(false));
assertThat(tokens.canConsume("COLUMNS"), is(false));
assertThat(tokens.canConsume("columns"), is(true));
assertThat(tokens.canConsume("from"), is(true));
assertThat(tokens.canConsume("THIS"), is(false));
assertThat(tokens.canConsume("table"), is(false));
assertThat(tokens.canConsume("this"), is(true));
assertThat(tokens.canConsume("table"), is(true));
assertThat(tokens.hasNext(), is(false));
}
@Test
public void shouldReturnTrueFromCanConsumeWithCaseSensitiveTokenStreamIfSuppliedTypeDoesMatch() {
makeCaseSensitive();
assertThat(tokens.canConsume(WORD), is(true));
assertThat(tokens.canConsume(WORD), is(true));
assertThat(tokens.canConsume(WORD), is(true));
assertThat(tokens.canConsume(WORD), is(true));
assertThat(tokens.canConsume(WORD), is(true));
assertThat(tokens.canConsume(WORD), is(true));
assertThat(tokens.hasNext(), is(false));
}
@Test
public void shouldReturnFalseFromCanConsumeWithCaseSensitiveTokenStreamIfSuppliedTypeDoesMatch() {
makeCaseSensitive();
assertThat(tokens.canConsume(WORD), is(true));
assertThat(tokens.canConsume(WORD), is(true));
assertThat(tokens.canConsume(COMMENT), is(false));
assertThat(tokens.canConsume(SINGLE_QUOTED_STRING), is(false));
assertThat(tokens.canConsume(DOUBLE_QUOTED_STRING), is(false));
assertThat(tokens.canConsume(DECIMAL), is(false));
assertThat(tokens.canConsume(SYMBOL), is(false));
assertThat(tokens.canConsume(WORD), is(true));
assertThat(tokens.canConsume(WORD), is(true));
assertThat(tokens.canConsume(WORD), is(true));
assertThat(tokens.canConsume(WORD), is(true));
assertThat(tokens.hasNext(), is(false));
}
@Test
public void shouldReturnTrueFromMatchesWithCaseSensitiveTokenStreamIfMatchStringDoesMatchCaseExactly() {
makeCaseSensitive();
assertThat(tokens.matches("Select"), is(true));
assertThat(tokens.matches("select"), is(false));
assertThat(tokens.canConsume("Select"), is(true));
assertThat(tokens.matches("all"), is(true));
assertThat(tokens.canConsume("all"), is(true));
}
@Test
public void shouldReturnFalseFromMatchesWithCaseSensitiveTokenStreamIfMatchStringDoesMatchCaseExactly() {
makeCaseSensitive();
assertThat(tokens.matches("select"), is(false));
assertThat(tokens.matches("SElect"), is(false));
assertThat(tokens.matches("Select"), is(true));
}
@Test
public void shouldReturnFalseFromCanConsumeWithCaseInsensitiveTokenStreamIfMatchStringIsNotUppercase() {
makeCaseInsensitive();
assertThat(tokens.canConsume("Select"), is(false));
assertThat(tokens.canConsume("SELECT"), is(true));
assertThat(tokens.canConsume("aLL"), is(false));
assertThat(tokens.canConsume("all"), is(false));
assertThat(tokens.canConsume("ALL"), is(true));
}
@Test
public void shouldReturnTrueFromCanConsumeWithCaseInsensitiveTokenStreamIfMatchStringDoesNotMatchCaseExactly() {
makeCaseInsensitive();
assertThat(tokens.canConsume("SELECT"), is(true));
assertThat(tokens.canConsume("ALL"), is(true));
assertThat(tokens.canConsume("COLUMNS"), is(true));
assertThat(tokens.canConsume("FROM"), is(true));
assertThat(tokens.canConsume("THIS"), is(true));
assertThat(tokens.canConsume("TABLE"), is(true));
assertThat(tokens.hasNext(), is(false));
}
@Test
public void shouldReturnTrueFromCanConsumeWithCaseInsensitiveTokenStreamIfSuppliedTypeDoesMatch() {
makeCaseInsensitive();
assertThat(tokens.canConsume(WORD), is(true));
assertThat(tokens.canConsume(WORD), is(true));
assertThat(tokens.canConsume(WORD), is(true));
assertThat(tokens.canConsume(WORD), is(true));
assertThat(tokens.canConsume(WORD), is(true));
assertThat(tokens.canConsume(WORD), is(true));
assertThat(tokens.hasNext(), is(false));
}
@Test
public void shouldReturnFalseFromCanConsumeWithCaseInsensitiveTokenStreamIfSuppliedTypeDoesMatch() {
makeCaseInsensitive();
assertThat(tokens.canConsume(WORD), is(true));
assertThat(tokens.canConsume(WORD), is(true));
assertThat(tokens.canConsume(COMMENT), is(false));
assertThat(tokens.canConsume(SINGLE_QUOTED_STRING), is(false));
assertThat(tokens.canConsume(DOUBLE_QUOTED_STRING), is(false));
assertThat(tokens.canConsume(DECIMAL), is(false));
assertThat(tokens.canConsume(SYMBOL), is(false));
assertThat(tokens.canConsume(WORD), is(true));
assertThat(tokens.canConsume(WORD), is(true));
assertThat(tokens.canConsume(WORD), is(true));
assertThat(tokens.canConsume(WORD), is(true));
assertThat(tokens.hasNext(), is(false));
}
@Test
public void shouldReturnTrueFromMatchesWithCaseInsensitiveTokenStreamIfMatchStringIsUppercaseAndMatches() {
makeCaseInsensitive();
assertThat(tokens.matches("SELECT"), is(true));
assertThat(tokens.canConsume("SELECT"), is(true));
assertThat(tokens.matches("ALL"), is(true));
assertThat(tokens.canConsume("ALL"), is(true));
}
@Test
public void shouldReturnFalseFromMatchesWithCaseInsensitiveTokenStreamIfMatchStringIsUppercaseAndDoesNotMatch() {
makeCaseInsensitive();
assertThat(tokens.matches("ALL"), is(false));
assertThat(tokens.matches("SElect"), is(false));
assertThat(tokens.matches("SELECT"), is(true));
}
@Test
public void shouldConsumeMultipleTokensIfTheyMatch() {
makeCaseInsensitive();
tokens.consume("SELECT", "ALL", "COLUMNS", "FROM", "THIS", "TABLE");
assertThat(tokens.hasNext(), is(false));
}
@Test( expected = ParsingException.class )
public void shouldFailToConsumeMultipleTokensIfTheyDoNotMatch() {
makeCaseInsensitive();
tokens.consume("SELECT", "ALL", "COLUMNS", "FROM", "TABLE");
}
@Test
public void shouldReturnTrueFromCanConsumeMultipleTokensIfTheyAllMatch() {
makeCaseInsensitive();
assertThat(tokens.canConsume("SELECT", "ALL", "COLUMNS", "FROM", "THIS", "TABLE"), is(true));
assertThat(tokens.hasNext(), is(false));
}
@Test
public void shouldReturnTrueFromCanConsumeArrayOfTokensIfTheyAllMatch() {
makeCaseInsensitive();
assertThat(tokens.matches(new String[] {"SELECT", "ALL", "COLUMNS", "FROM", "THIS", "TABLE"}), is(true));
assertThat(tokens.canConsume(new String[] {"SELECT", "ALL", "COLUMNS", "FROM", "THIS", "TABLE"}), is(true));
assertThat(tokens.hasNext(), is(false));
}
@Test
public void shouldReturnTrueFromCanConsumeMultipleTokensIfTheyDoNotAllMatch() {
makeCaseInsensitive();
// Unable to consume unless they all match ...
assertThat(tokens.canConsume("SELECT", "ALL", "COLUMNS", "FRM", "THIS", "TABLE"), is(false));
assertThat(tokens.canConsume("SELECT", "ALL", "COLUMNS", "FROM", "THIS", "TABLE", "EXTRA"), is(false));
assertThat(tokens.canConsume("SELECT", "ALL", "COLUMNS", "FROM", "EXTRA", "THIS", "TABLE"), is(false));
assertThat(tokens.hasNext(), is(true));
// Should have consumed nothing so far ...
assertThat(tokens.canConsume("SELECT", "ALL", "COLUMNS"), is(true));
assertThat(tokens.canConsume("FROM", "THIS", "TABLE"), is(true));
assertThat(tokens.hasNext(), is(false));
}
@Test
public void shouldReturnTrueFromMatchAnyOfIfAnyOfTheTokenValuesMatch() {
makeCaseInsensitive();
// Unable to consume unless they all match ...
assertThat(tokens.matchesAnyOf("ALL", "COLUMNS"), is(false));
assertThat(tokens.matchesAnyOf("ALL", "COLUMNS", "SELECT"), is(true));
tokens.consume("SELECT");
assertThat(tokens.matchesAnyOf("ALL", "COLUMNS", "SELECT"), is(true));
tokens.consume("ALL");
assertThat(tokens.matchesAnyOf("ALL", "COLUMNS", "SELECT"), is(true));
tokens.consume("COLUMNS");
assertThat(tokens.canConsume("FROM", "THIS", "TABLE"), is(true));
assertThat(tokens.hasNext(), is(false));
}
@Test
public void shouldReturnTrueFromMatchIfAllTypeValuesMatch() {
makeCaseInsensitive();
assertThat(tokens.matches(BasicTokenizer.WORD, BasicTokenizer.WORD), is(true));
}
@Test
public void shouldReturnFalseFromMatchIfAllTypeValuesDoNotMatch() {
makeCaseInsensitive();
assertThat(tokens.matches(BasicTokenizer.WORD, BasicTokenizer.DECIMAL), is(false));
assertThat(tokens.matches(BasicTokenizer.DECIMAL, BasicTokenizer.WORD), is(false));
}
@Test
public void shouldConsumeMultipleTokensWithAnyValueConstant() {
makeCaseInsensitive();
// Unable to consume unless they all match ...
tokens.consume("SELECT", "ALL", TokenStream.ANY_VALUE);
tokens.consume("FROM", "THIS", "TABLE");
assertThat(tokens.hasNext(), is(false));
}
@Test
public void shouldConsumeTokenWithAnyValueConstant() {
makeCaseInsensitive();
// Unable to consume unless they all match ...
tokens.consume("SELECT", "ALL");
tokens.consume(TokenStream.ANY_VALUE);
tokens.consume("FROM", "THIS", "TABLE");
assertThat(tokens.hasNext(), is(false));
}
@Test
public void shouldReturnTrueFromCanConsumeMultipleTokensWithAnyValueConstant() {
makeCaseInsensitive();
// Unable to consume unless they all match ...
assertThat(tokens.canConsume("SELECT", "ALL", TokenStream.ANY_VALUE, "FRM", "THIS", "TABLE"), is(false));
assertThat(tokens.canConsume("SELECT", "ALL", "COLUMNS", "FROM", TokenStream.ANY_VALUE, "TABLE"), is(true));
assertThat(tokens.hasNext(), is(false));
}
@Test
public void shouldCanConsumeSingleAfterTokensCompleteFromCanConsumeStringList() {
makeCaseInsensitive();
// consume ALL the tokens using canConsume()
tokens.canConsume("SELECT", "ALL", "COLUMNS", "FROM", "THIS", "TABLE");
// try to canConsume() single word
assertThat(tokens.canConsume("SELECT"), is(false));
assertThat(tokens.canConsume(TokenStream.ANY_VALUE), is(false));
assertThat(tokens.canConsume(BasicTokenizer.SYMBOL), is(false));
}
@Test
public void shouldCanConsumeStringAfterTokensCompleteFromCanConsumeStringArray() {
makeCaseInsensitive();
// consume ALL the tokens using canConsume()
tokens.canConsume(new String[] {"SELECT", "ALL", "COLUMNS", "FROM", "THIS", "TABLE"});
// try to canConsume() single word
assertThat(tokens.canConsume("SELECT"), is(false));
assertThat(tokens.canConsume(TokenStream.ANY_VALUE), is(false));
assertThat(tokens.canConsume(BasicTokenizer.SYMBOL), is(false));
}
@Test
public void shouldCanConsumeStringAfterTokensCompleteFromCanConsumeStringIterator() {
makeCaseInsensitive();
// consume ALL the tokens using canConsume()
tokens.canConsume(Arrays.asList(new String[] {"SELECT", "ALL", "COLUMNS", "FROM", "THIS", "TABLE"}));
// try to canConsume() single word
assertThat(tokens.canConsume("SELECT"), is(false));
assertThat(tokens.canConsume(TokenStream.ANY_VALUE), is(false));
assertThat(tokens.canConsume(BasicTokenizer.SYMBOL), is(false));
}
@Test
public void shouldFindNextPositionStartIndex() {
makeCaseInsensitive();
// "Select all columns from this table";
tokens.consume();
// Next position should be line 1, column 8
assertThat(tokens.nextPosition().getIndexInContent(), is(7));
assertThat(tokens.nextPosition().getColumn(), is(8));
assertThat(tokens.nextPosition().getLine(), is(1));
}
@Test
public void shouldFindPreviousPositionStartIndex() {
makeCaseInsensitive();
// "Select all columns from this table";
tokens.consume();
tokens.consume();
// previous position should be line 1, column 8
assertThat(tokens.previousPosition().getIndexInContent(), is(7));
assertThat(tokens.previousPosition().getColumn(), is(8));
assertThat(tokens.previousPosition().getLine(), is(1));
}
@Test
public void shouldParseMultiLineString() {
makeCaseInsensitive();
String content = "ALTER DATABASE \n" + "DO SOMETHING; \n" + "ALTER DATABASE \n" + " SET DEFAULT BIGFILE TABLESPACE;";
tokens = new TokenStream(content, tokenizer, true);
tokens.start();
tokens.consume(); // LINE
tokens.consume(); // ONE
tokens.consume(); // DO
tokens.consume(); // SOMETHING
tokens.consume(); // ;
assertThat(tokens.nextPosition().getIndexInContent(), is(31));
assertThat(tokens.nextPosition().getColumn(), is(1));
tokens.consume(); // ALTER
assertThat(tokens.nextPosition().getIndexInContent(), is(37));
assertThat(tokens.nextPosition().getColumn(), is(7));
}
}