-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathExceptionsTest.java
More file actions
160 lines (145 loc) · 6.29 KB
/
ExceptionsTest.java
File metadata and controls
160 lines (145 loc) · 6.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package expression.exceptions;
import expression.TripleExpression;
import expression.Variable;
import expression.parser.Either;
import expression.parser.ParserTest;
import java.util.ArrayList;
import java.util.List;
import java.util.function.LongBinaryOperator;
/**
* @author Niyaz Nigmatullin
* @author Georgiy Korneev (kgeorgiy@kgeorgiy.info)
*/
public class ExceptionsTest extends ParserTest {
private final static int D = 5;
private final static List<Integer> OVERFLOW_VALUES = new ArrayList<>();
private final char[] CHARS = "AZ+-*%()[]<>".toCharArray();
public static final Variable VX = new Variable("x");
public static final Variable VY = new Variable("y");
public static final Reason OVERFLOW = new Reason("Overflow");
static {
addRange(OVERFLOW_VALUES, D, Integer.MIN_VALUE + D);
addRange(OVERFLOW_VALUES, D, Integer.MIN_VALUE / 2);
addRange(OVERFLOW_VALUES, D, (int) -Math.sqrt(Integer.MAX_VALUE));
addRange(OVERFLOW_VALUES, D, 0);
addRange(OVERFLOW_VALUES, D, (int) Math.sqrt(Integer.MAX_VALUE));
addRange(OVERFLOW_VALUES, D, Integer.MAX_VALUE / 2);
addRange(OVERFLOW_VALUES, D, Integer.MAX_VALUE - D);
}
protected final List<Op<String>> parsingTest = list(
op("No first argument", "* y * z"),
op("No middle argument", "x * * z"),
op("No last argument", "x * y * "),
op("No first argument'", "1 + (* y * z) + 2"),
op("No middle argument'", "1 + (x * / 9) + 3"),
op("No last argument'", "1 + (x * y - ) + 3"),
op("No opening parenthesis", "x * y)"),
op("No closing parenthesis", "(x * y"),
op("Start symbol", "@x * y"),
op("Middle symbol", "x @ * y"),
op("End symbol", "x * y@"),
op("Constant overflow 1", Integer.MIN_VALUE - 1L + ""),
op("Constant overflow 2", Integer.MAX_VALUE + 1L + ""),
op("Bare +", "+"),
op("Bare -", "-"),
op("Bare a", "a"),
op("(())", "(())"),
op("Spaces in numbers", "10 20")
);
public static Op<String> parseExample(final String hello) {
return op(hello, hello);
}
protected void addParsingTests(final String... examples) {
for (final String example : examples) {
parsingTest.add(parseExample(example));
}
}
public static void main(final String[] args) {
new ExceptionsTest().run();
}
private void testParsingErrors() {
for (final Op<String> op : parsingTest) {
try {
new ExpressionParser().parse(op.f);
assert false : "Successfully parsed " + op.f;
} catch (final Exception e) {
System.out.format("%-30s %s%n", op.name, e.getClass().getSimpleName() + ": " + e.getMessage());
}
}
}
protected static void testOverflow() {
//noinspection Convert2MethodRef
testOverflow((a, b) -> a + b, "+", new CheckedAdd(VX, VY));
testOverflow((a, b) -> a - b, "-", new CheckedSubtract(VX, VY));
testOverflow((a, b) -> a * b, "*", new CheckedMultiply(VX, VY));
testOverflow((a, b) -> b == 0 ? Long.MAX_VALUE : a / b, "/", new CheckedDivide(VX, VY));
testOverflow((a, b) -> -b, "<- ignore first argument, unary -", new CheckedNegate(VY));
}
protected static void testOverflow(final LongBinaryOperator f, final String op, final TripleExpression expression) {
for (final int a : OVERFLOW_VALUES) {
for (final int b : OVERFLOW_VALUES) {
final long expected = f.applyAsLong(a, b);
try {
final int actual = expression.evaluate(a, b, 0);
assert actual == expected : a + " " + op + " " + b + " == " + actual;
} catch (final Exception e) {
if (Integer.MIN_VALUE <= expected && expected <= Integer.MAX_VALUE) {
throw new AssertionError("Unexpected error in " + a + " " + op + " " + b, e);
}
}
}
}
}
@Override
protected void test() {
testOverflow();
super.test();
testParsingErrors();
}
protected TripleExpression parse(final String expression, final boolean reparse) {
final Parser parser = new ExpressionParser();
if (expression.length() > 10) {
loop: for (final char ch : CHARS) {
for (int i = 0; i < 10; i++) {
final int index = 1 + randomInt(expression.length() - 2);
int pi = index - 1;
while (Character.isWhitespace(expression.charAt(pi))) {
pi--;
}
int ni = index;
while (Character.isWhitespace(expression.charAt(ni))) {
ni++;
}
final char pc = expression.charAt(pi);
final char nc = expression.charAt(ni);
if ("-(*".indexOf(nc) < 0 && nc != ch && pc != ch && !Character.isLetterOrDigit(nc)) {
final String input = expression.substring(0, index) + ch + expression.substring(index);
try {
counter.nextTest();
parser.parse(input);
throw new AssertionError("Parsing error expected for " + expression.substring(0, index) + "<ERROR_INSERTED -->" + ch + "<-- ERROR_INSERTED>" + expression.substring(index));
} catch (final Exception e) {
// Ok
counter.passed();
}
continue loop;
}
}
}
}
counter.nextTest();
try {
final TripleExpression parse = parser.parse(expression);
counter.passed();
return parse;
} catch (final Exception e) {
throw new AssertionError("Parser failed", e);
}
}
@Override
protected Either<Reason, Integer> lift(final long value) {
return value < Integer.MIN_VALUE || Integer.MAX_VALUE < value
? Either.left(OVERFLOW)
: super.lift(value);
}
}