Refactor ExpressionParser to improve error handling
This commit is contained in:
parent
399df4d267
commit
f3b43eee9c
@ -25,6 +25,8 @@ package com.github.zafarkhaja.semver;
|
||||
|
||||
import com.github.zafarkhaja.semver.expr.Expression;
|
||||
import com.github.zafarkhaja.semver.expr.ExpressionParser;
|
||||
import com.github.zafarkhaja.semver.expr.LexerException;
|
||||
import com.github.zafarkhaja.semver.expr.UnexpectedTokenException;
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
@ -310,6 +312,9 @@ public class Version implements Comparable<Version> {
|
||||
* @param expr the SemVer Expression
|
||||
* @return {@code true} if this version satisfies the specified
|
||||
* SemVer Expression or {@code false} otherwise
|
||||
* @throws ParseException in case of a general parse error
|
||||
* @throws LexerException when encounters an illegal character
|
||||
* @throws UnexpectedTokenException when comes across an unexpected token
|
||||
* @since 0.7.0
|
||||
*/
|
||||
public boolean satisfies(String expr) {
|
||||
|
@ -78,12 +78,14 @@ public class ExpressionParser implements Parser<Expression> {
|
||||
* @param input a string representing the SemVer Expression
|
||||
* @return the AST for the SemVer Expressions
|
||||
* @throws LexerException when encounters an illegal character
|
||||
* @throws UnexpectedElementException when consumes a token of an unexpected type
|
||||
* @throws UnexpectedTokenException when consumes a token of an unexpected type
|
||||
*/
|
||||
@Override
|
||||
public Expression parse(String input) {
|
||||
tokens = lexer.tokenize(input);
|
||||
return parseSemVerExpression();
|
||||
Expression expr = parseSemVerExpression();
|
||||
consumeNextToken(EOL);
|
||||
return expr;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -104,13 +106,13 @@ public class ExpressionParser implements Parser<Expression> {
|
||||
Expression expr;
|
||||
if (tokens.positiveLookahead(NOT)) {
|
||||
tokens.consume();
|
||||
tokens.consume(LEFT_PAREN);
|
||||
consumeNextToken(LEFT_PAREN);
|
||||
expr = new Not(parseSemVerExpression());
|
||||
tokens.consume(RIGHT_PAREN);
|
||||
consumeNextToken(RIGHT_PAREN);
|
||||
} else if (tokens.positiveLookahead(LEFT_PAREN)) {
|
||||
tokens.consume(LEFT_PAREN);
|
||||
consumeNextToken(LEFT_PAREN);
|
||||
expr = parseSemVerExpression();
|
||||
tokens.consume(RIGHT_PAREN);
|
||||
consumeNextToken(RIGHT_PAREN);
|
||||
} else {
|
||||
expr = parseExpression();
|
||||
}
|
||||
@ -224,21 +226,21 @@ public class ExpressionParser implements Parser<Expression> {
|
||||
* @return the expression AST
|
||||
*/
|
||||
private Expression parseTildeExpression() {
|
||||
tokens.consume(TILDE);
|
||||
int major = intOf(tokens.consume(NUMERIC).lexeme);
|
||||
consumeNextToken(TILDE);
|
||||
int major = intOf(consumeNextToken(NUMERIC).lexeme);
|
||||
if (!tokens.positiveLookahead(DOT)) {
|
||||
return new GreaterOrEqual(versionOf(major, 0, 0));
|
||||
}
|
||||
tokens.consume(DOT);
|
||||
int minor = intOf(tokens.consume(NUMERIC).lexeme);
|
||||
consumeNextToken(DOT);
|
||||
int minor = intOf(consumeNextToken(NUMERIC).lexeme);
|
||||
if (!tokens.positiveLookahead(DOT)) {
|
||||
return new And(
|
||||
new GreaterOrEqual(versionOf(major, minor, 0)),
|
||||
new Less(versionOf(major + 1, 0, 0))
|
||||
);
|
||||
}
|
||||
tokens.consume(DOT);
|
||||
int patch = intOf(tokens.consume(NUMERIC).lexeme);
|
||||
consumeNextToken(DOT);
|
||||
int patch = intOf(consumeNextToken(NUMERIC).lexeme);
|
||||
return new And(
|
||||
new GreaterOrEqual(versionOf(major, minor, patch)),
|
||||
new Less(versionOf(major, minor + 1, 0))
|
||||
@ -270,8 +272,8 @@ public class ExpressionParser implements Parser<Expression> {
|
||||
* @return the expression AST
|
||||
*/
|
||||
private Expression parseVersionExpression() {
|
||||
int major = intOf(tokens.consume(NUMERIC).lexeme);
|
||||
tokens.consume(DOT);
|
||||
int major = intOf(consumeNextToken(NUMERIC).lexeme);
|
||||
consumeNextToken(DOT);
|
||||
if (tokens.positiveLookahead(STAR)) {
|
||||
tokens.consume();
|
||||
return new And(
|
||||
@ -279,9 +281,9 @@ public class ExpressionParser implements Parser<Expression> {
|
||||
new Less(versionOf(major + 1, 0, 0))
|
||||
);
|
||||
}
|
||||
int minor = intOf(tokens.consume(NUMERIC).lexeme);
|
||||
tokens.consume(DOT);
|
||||
tokens.consume(STAR);
|
||||
int minor = intOf(consumeNextToken(NUMERIC).lexeme);
|
||||
consumeNextToken(DOT);
|
||||
consumeNextToken(STAR);
|
||||
return new And(
|
||||
new GreaterOrEqual(versionOf(major, minor, 0)),
|
||||
new Less(versionOf(major, minor + 1, 0))
|
||||
@ -313,7 +315,7 @@ public class ExpressionParser implements Parser<Expression> {
|
||||
*/
|
||||
private Expression parseRangeExpression() {
|
||||
Expression ge = new GreaterOrEqual(parseVersion());
|
||||
tokens.consume(HYPHEN);
|
||||
consumeNextToken(HYPHEN);
|
||||
Expression le = new LessOrEqual(parseVersion());
|
||||
return new And(ge, le);
|
||||
}
|
||||
@ -332,16 +334,16 @@ public class ExpressionParser implements Parser<Expression> {
|
||||
* @return the parsed version
|
||||
*/
|
||||
private Version parseVersion() {
|
||||
int major = intOf(tokens.consume(NUMERIC).lexeme);
|
||||
int major = intOf(consumeNextToken(NUMERIC).lexeme);
|
||||
int minor = 0;
|
||||
if (tokens.positiveLookahead(DOT)) {
|
||||
tokens.consume();
|
||||
minor = intOf(tokens.consume(NUMERIC).lexeme);
|
||||
minor = intOf(consumeNextToken(NUMERIC).lexeme);
|
||||
}
|
||||
int patch = 0;
|
||||
if (tokens.positiveLookahead(DOT)) {
|
||||
tokens.consume();
|
||||
patch = intOf(tokens.consume(NUMERIC).lexeme);
|
||||
patch = intOf(consumeNextToken(NUMERIC).lexeme);
|
||||
}
|
||||
return versionOf(major, minor, patch);
|
||||
}
|
||||
@ -391,4 +393,19 @@ public class ExpressionParser implements Parser<Expression> {
|
||||
private int intOf(String value) {
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to consume the next token in the stream.
|
||||
*
|
||||
* @param expected the expected types of the next token
|
||||
* @return the next token in the stream
|
||||
* @throws UnexpectedTokenException when encounters an unexpected token type
|
||||
*/
|
||||
private Token consumeNextToken(Token.Type... expected) {
|
||||
try {
|
||||
return tokens.consume(expected);
|
||||
} catch (UnexpectedElementException e) {
|
||||
throw new UnexpectedTokenException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -64,15 +64,7 @@ class Lexer {
|
||||
LEFT_PAREN("\\("),
|
||||
RIGHT_PAREN("\\)"),
|
||||
WHITESPACE("\\s+"),
|
||||
EOL("?!") {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean isMatchedBy(Token token) {
|
||||
return token == null;
|
||||
}
|
||||
};
|
||||
EOL("?!");
|
||||
|
||||
/**
|
||||
* A pattern matching this type.
|
||||
@ -123,14 +115,22 @@ class Lexer {
|
||||
final String lexeme;
|
||||
|
||||
/**
|
||||
* Constructs a {@code Token} instance with the type and lexeme.
|
||||
* The position of this token.
|
||||
*/
|
||||
final int position;
|
||||
|
||||
/**
|
||||
* Constructs a {@code Token} instance
|
||||
* with the type, lexeme and position.
|
||||
*
|
||||
* @param type the type of this token
|
||||
* @param lexeme the lexeme of this token
|
||||
* @param position the position of this token
|
||||
*/
|
||||
Token(Type type, String lexeme) {
|
||||
Token(Type type, String lexeme, int position) {
|
||||
this.type = type;
|
||||
this.lexeme = (lexeme == null) ? "" : lexeme;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -145,7 +145,10 @@ class Lexer {
|
||||
return false;
|
||||
}
|
||||
Token token = (Token) other;
|
||||
return type.equals(token.type) && lexeme.equals(token.lexeme);
|
||||
return
|
||||
type.equals(token.type) &&
|
||||
lexeme.equals(token.lexeme) &&
|
||||
position == token.position;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -156,6 +159,7 @@ class Lexer {
|
||||
int hash = 5;
|
||||
hash = 71 * hash + type.hashCode();
|
||||
hash = 71 * hash + lexeme.hashCode();
|
||||
hash = 71 * hash + position;
|
||||
return hash;
|
||||
}
|
||||
|
||||
@ -166,7 +170,11 @@ class Lexer {
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return type.name() + "(" + lexeme + ")";
|
||||
return String.format(
|
||||
"%s(%s) at position %d",
|
||||
type.name(),
|
||||
lexeme, position
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -186,6 +194,7 @@ class Lexer {
|
||||
*/
|
||||
Stream<Token> tokenize(String input) {
|
||||
List<Token> tokens = new ArrayList<Token>();
|
||||
int tokenPos = 0;
|
||||
while (!input.isEmpty()) {
|
||||
boolean matched = false;
|
||||
for (Token.Type tokenType : Token.Type.values()) {
|
||||
@ -194,8 +203,13 @@ class Lexer {
|
||||
matched = true;
|
||||
input = matcher.replaceFirst("");
|
||||
if (tokenType != Token.Type.WHITESPACE) {
|
||||
tokens.add(new Token(tokenType, matcher.group()));
|
||||
tokens.add(new Token(
|
||||
tokenType,
|
||||
matcher.group(),
|
||||
tokenPos
|
||||
));
|
||||
}
|
||||
tokenPos += matcher.end();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -203,6 +217,7 @@ class Lexer {
|
||||
throw new LexerException(input);
|
||||
}
|
||||
}
|
||||
tokens.add(new Token(Token.Type.EOL, null, tokenPos));
|
||||
return new Stream<Token>(tokens.toArray(new Token[tokens.size()]));
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,8 @@
|
||||
package com.github.zafarkhaja.semver.expr;
|
||||
|
||||
import com.github.zafarkhaja.semver.ParseException;
|
||||
import com.github.zafarkhaja.semver.expr.Lexer.*;
|
||||
import com.github.zafarkhaja.semver.expr.Lexer.Token;
|
||||
import com.github.zafarkhaja.semver.util.UnexpectedElementException;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
@ -45,6 +46,17 @@ public class UnexpectedTokenException extends ParseException {
|
||||
*/
|
||||
private final Token.Type[] expected;
|
||||
|
||||
/**
|
||||
* Constructs a {@code UnexpectedTokenException} instance with
|
||||
* the wrapped {@code UnexpectedElementException} exception.
|
||||
*
|
||||
* @param cause the wrapped exception
|
||||
*/
|
||||
UnexpectedTokenException(UnexpectedElementException cause) {
|
||||
unexpected = (Token) cause.getUnexpectedElement();
|
||||
expected = (Token.Type[]) cause.getExpectedElementTypes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code UnexpectedTokenException} instance
|
||||
* with the unexpected token and the expected types.
|
||||
@ -57,6 +69,24 @@ public class UnexpectedTokenException extends ParseException {
|
||||
this.expected = expected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unexpected token.
|
||||
*
|
||||
* @return the unexpected token
|
||||
*/
|
||||
Token getUnexpectedToken() {
|
||||
return unexpected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expected token types.
|
||||
*
|
||||
* @return an array of expected token types
|
||||
*/
|
||||
Token.Type[] getExpectedTokenTypes() {
|
||||
return expected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string representation of this exception
|
||||
* containing the information about the unexpected
|
||||
|
@ -24,7 +24,6 @@
|
||||
package com.github.zafarkhaja.semver.expr;
|
||||
|
||||
import com.github.zafarkhaja.semver.Version;
|
||||
import com.github.zafarkhaja.semver.util.UnexpectedElementException;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
@ -197,7 +196,7 @@ public class ExpressionParserTest {
|
||||
ExpressionParser parser = new ExpressionParser(new Lexer());
|
||||
try {
|
||||
parser.parse("((>=1.0.1 & < 2)");
|
||||
} catch (UnexpectedElementException e) {
|
||||
} catch (UnexpectedTokenException e) {
|
||||
return;
|
||||
}
|
||||
fail("Should raise error if closing parenthesis is missing");
|
||||
|
@ -38,12 +38,13 @@ public class LexerTest {
|
||||
@Test
|
||||
public void shouldTokenizeVersionString() {
|
||||
Token[] expected = {
|
||||
new Token(GREATER, ">"),
|
||||
new Token(NUMERIC, "1"),
|
||||
new Token(DOT, "."),
|
||||
new Token(NUMERIC, "0"),
|
||||
new Token(DOT, "."),
|
||||
new Token(NUMERIC, "0"),
|
||||
new Token(GREATER, ">", 0),
|
||||
new Token(NUMERIC, "1", 1),
|
||||
new Token(DOT, ".", 2),
|
||||
new Token(NUMERIC, "0", 3),
|
||||
new Token(DOT, ".", 4),
|
||||
new Token(NUMERIC, "0", 5),
|
||||
new Token(EOL, null, 6),
|
||||
};
|
||||
Lexer lexer = new Lexer();
|
||||
Stream<Token> stream = lexer.tokenize(">1.0.0");
|
||||
@ -53,14 +54,30 @@ public class LexerTest {
|
||||
@Test
|
||||
public void shouldSkipWhitespaces() {
|
||||
Token[] expected = {
|
||||
new Token(GREATER, ">"),
|
||||
new Token(NUMERIC, "1"),
|
||||
new Token(GREATER, ">", 0),
|
||||
new Token(NUMERIC, "1", 2),
|
||||
new Token(EOL, null, 3),
|
||||
};
|
||||
Lexer lexer = new Lexer();
|
||||
Stream<Token> stream = lexer.tokenize("> 1");
|
||||
assertArrayEquals(expected, stream.toArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldEndWithEol() {
|
||||
Token[] expected = {
|
||||
new Token(NUMERIC, "1", 0),
|
||||
new Token(DOT, ".", 1),
|
||||
new Token(NUMERIC, "2", 2),
|
||||
new Token(DOT, ".", 3),
|
||||
new Token(NUMERIC, "3", 4),
|
||||
new Token(EOL, null, 5),
|
||||
};
|
||||
Lexer lexer = new Lexer();
|
||||
Stream<Token> stream = lexer.tokenize("1.2.3");
|
||||
assertArrayEquals(expected, stream.toArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldRaiseErrorOnIllegalCharacter() {
|
||||
Lexer lexer = new Lexer();
|
||||
|
@ -41,23 +41,23 @@ public class LexerTokenTest {
|
||||
|
||||
@Test
|
||||
public void shouldBeReflexive() {
|
||||
Token token = new Token(NUMERIC, "1");
|
||||
Token token = new Token(NUMERIC, "1", 0);
|
||||
assertTrue(token.equals(token));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBeSymmetric() {
|
||||
Token t1 = new Token(EQUAL, "=");
|
||||
Token t2 = new Token(EQUAL, "=");
|
||||
Token t1 = new Token(EQUAL, "=", 0);
|
||||
Token t2 = new Token(EQUAL, "=", 0);
|
||||
assertTrue(t1.equals(t2));
|
||||
assertTrue(t2.equals(t1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBeTransitive() {
|
||||
Token t1 = new Token(GREATER, ">");
|
||||
Token t2 = new Token(GREATER, ">");
|
||||
Token t3 = new Token(GREATER, ">");
|
||||
Token t1 = new Token(GREATER, ">", 0);
|
||||
Token t2 = new Token(GREATER, ">", 0);
|
||||
Token t3 = new Token(GREATER, ">", 0);
|
||||
assertTrue(t1.equals(t2));
|
||||
assertTrue(t2.equals(t3));
|
||||
assertTrue(t1.equals(t3));
|
||||
@ -65,8 +65,8 @@ public class LexerTokenTest {
|
||||
|
||||
@Test
|
||||
public void shouldBeConsistent() {
|
||||
Token t1 = new Token(HYPHEN, "-");
|
||||
Token t2 = new Token(HYPHEN, "-");
|
||||
Token t1 = new Token(HYPHEN, "-", 0);
|
||||
Token t2 = new Token(HYPHEN, "-", 0);
|
||||
assertTrue(t1.equals(t2));
|
||||
assertTrue(t1.equals(t2));
|
||||
assertTrue(t1.equals(t2));
|
||||
@ -74,28 +74,35 @@ public class LexerTokenTest {
|
||||
|
||||
@Test
|
||||
public void shouldReturnFalseIfOtherVersionIsOfDifferentType() {
|
||||
Token t1 = new Token(DOT, ".");
|
||||
Token t1 = new Token(DOT, ".", 0);
|
||||
assertFalse(t1.equals(new String(".")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnFalseIfOtherVersionIsNull() {
|
||||
Token t1 = new Token(AND, "&");
|
||||
Token t1 = new Token(AND, "&", 0);
|
||||
Token t2 = null;
|
||||
assertFalse(t1.equals(t2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnFalseIfTypesAreDifferent() {
|
||||
Token t1 = new Token(EQUAL, "=");
|
||||
Token t2 = new Token(NOT_EQUAL, "!=");
|
||||
Token t1 = new Token(EQUAL, "=", 0);
|
||||
Token t2 = new Token(NOT_EQUAL, "!=", 0);
|
||||
assertFalse(t1.equals(t2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnFalseIfLexemesAreDifferent() {
|
||||
Token t1 = new Token(NUMERIC, "1");
|
||||
Token t2 = new Token(NUMERIC, "2");
|
||||
Token t1 = new Token(NUMERIC, "1", 0);
|
||||
Token t2 = new Token(NUMERIC, "2", 0);
|
||||
assertFalse(t1.equals(t2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnFalseIfPositionsAreDifferent() {
|
||||
Token t1 = new Token(NUMERIC, "1", 1);
|
||||
Token t2 = new Token(NUMERIC, "1", 2);
|
||||
assertFalse(t1.equals(t2));
|
||||
}
|
||||
}
|
||||
@ -104,8 +111,8 @@ public class LexerTokenTest {
|
||||
|
||||
@Test
|
||||
public void shouldReturnSameHashCodeIfTokensAreEqual() {
|
||||
Token t1 = new Token(NUMERIC, "1");
|
||||
Token t2 = new Token(NUMERIC, "1");
|
||||
Token t1 = new Token(NUMERIC, "1", 0);
|
||||
Token t2 = new Token(NUMERIC, "1", 0);
|
||||
assertTrue(t1.equals(t2));
|
||||
assertEquals(t1.hashCode(), t2.hashCode());
|
||||
}
|
||||
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright 2014 Zafar Khaja <zafarkhaja@gmail.com>.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.github.zafarkhaja.semver.expr;
|
||||
|
||||
import com.github.zafarkhaja.semver.expr.Lexer.Token;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import static com.github.zafarkhaja.semver.expr.Lexer.Token.Type.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Zafar Khaja <zafarkhaja@gmail.com>
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class ParserErrorHandlingTest {
|
||||
|
||||
private final String invalidExpr;
|
||||
private final Token unexpected;
|
||||
private final Token.Type[] expected;
|
||||
|
||||
public ParserErrorHandlingTest(
|
||||
String invalidExpr,
|
||||
Token unexpected,
|
||||
Token.Type[] expected
|
||||
) {
|
||||
this.invalidExpr = invalidExpr;
|
||||
this.unexpected = unexpected;
|
||||
this.expected = expected;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCorrectlyHandleParseErrors() {
|
||||
try {
|
||||
ExpressionParser.newInstance().parse(invalidExpr);
|
||||
} catch (UnexpectedTokenException e) {
|
||||
assertEquals(unexpected, e.getUnexpectedToken());
|
||||
assertArrayEquals(expected, e.getExpectedTokenTypes());
|
||||
return;
|
||||
}
|
||||
fail("Uncaught exception");
|
||||
}
|
||||
|
||||
@Parameters(name = "{0}")
|
||||
public static Collection<Object[]> parameters() {
|
||||
return Arrays.asList(new Object[][] {
|
||||
{ "1)", new Token(RIGHT_PAREN, ")", 1), new Token.Type[] { EOL } },
|
||||
{ "(>1.0.1", new Token(EOL, null, 7), new Token.Type[] { RIGHT_PAREN } },
|
||||
{ "((>=1 & <2)", new Token(EOL, null, 11), new Token.Type[] { RIGHT_PAREN } },
|
||||
{ ">=1.0.0 &", new Token(EOL, null, 9), new Token.Type[] { NUMERIC } },
|
||||
{ "(>2.0 |)", new Token(RIGHT_PAREN, ")", 7), new Token.Type[] { NUMERIC } },
|
||||
{ "& 1.2", new Token(AND, "&", 0), new Token.Type[] { NUMERIC } },
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user