File: TestELEvaluation.java

package info (click to toggle)
tomcat11 11.0.18-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 47,520 kB
  • sloc: java: 370,500; xml: 56,763; jsp: 4,787; sh: 1,304; perl: 324; makefile: 25; ansic: 14
file content (257 lines) | stat: -rw-r--r-- 10,301 bytes parent folder | download | duplicates (3)
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
/*
 * 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.el;

import java.io.File;
import java.util.Date;

import jakarta.el.ELException;
import jakarta.el.ValueExpression;

import org.junit.Assert;
import org.junit.Test;

import org.apache.el.lang.ELSupport;
import org.apache.jasper.el.ELContextImpl;

/**
 * Tests the EL engine directly. Similar tests may be found in {@link org.apache.jasper.compiler.TestAttributeParser}
 * and {@link TestELInJsp}.
 */
public class TestELEvaluation {

    /**
     * Test use of spaces in ternary expressions. This was primarily an EL parser bug.
     */
    @Test
    public void testBug42565() {
        Assert.assertEquals("false", evaluateExpression("${false?true:false}"));
        Assert.assertEquals("false", evaluateExpression("${false?true: false}"));
        Assert.assertEquals("false", evaluateExpression("${false?true :false}"));
        Assert.assertEquals("false", evaluateExpression("${false?true : false}"));
        Assert.assertEquals("false", evaluateExpression("${false? true:false}"));
        Assert.assertEquals("false", evaluateExpression("${false? true: false}"));
        Assert.assertEquals("false", evaluateExpression("${false? true :false}"));
        Assert.assertEquals("false", evaluateExpression("${false? true : false}"));
        Assert.assertEquals("false", evaluateExpression("${false ?true:false}"));
        Assert.assertEquals("false", evaluateExpression("${false ?true: false}"));
        Assert.assertEquals("false", evaluateExpression("${false ?true :false}"));
        Assert.assertEquals("false", evaluateExpression("${false ?true : false}"));
        Assert.assertEquals("false", evaluateExpression("${false ? true:false}"));
        Assert.assertEquals("false", evaluateExpression("${false ? true: false}"));
        Assert.assertEquals("false", evaluateExpression("${false ? true :false}"));
        Assert.assertEquals("false", evaluateExpression("${false ? true : false}"));
    }


    /**
     * Test use nested ternary expressions. This was primarily an EL parser bug.
     */
    @Test
    public void testBug44994() {
        Assert.assertEquals("none", evaluateExpression("${0 lt 0 ? 1 lt 0 ? 'many': 'one': 'none'}"));
        Assert.assertEquals("one", evaluateExpression("${0 lt 1 ? 1 lt 1 ? 'many': 'one': 'none'}"));
        Assert.assertEquals("many", evaluateExpression("${0 lt 2 ? 1 lt 2 ? 'many': 'one': 'none'}"));
    }

    @Test
    public void testParserBug45511() {
        // Test cases provided by OP
        Assert.assertEquals("true", evaluateExpression("${empty ('')}"));
        Assert.assertEquals("true", evaluateExpression("${empty('')}"));
        Assert.assertEquals("false", evaluateExpression("${(true) and (false)}"));
        Assert.assertEquals("false", evaluateExpression("${(true)and(false)}"));
    }

    @Test
    public void testBug48112() {
        // bug 48112
        Assert.assertEquals("{world}", evaluateExpression("${fn:trim('{world}')}"));
    }

    @Test
    public void testParserLiteralExpression() {
        // Inspired by work on bug 45451, comments from kkolinko on the dev
        // list and looking at the spec to find some edge cases

        // '\' is only an escape character inside a StringLiteral
        Assert.assertEquals("\\\\", evaluateExpression("\\\\"));

        /*
         * LiteralExpressions can only contain ${ or #{ if escaped with \ \ is not an escape character in any other
         * circumstances including \\
         */
        Assert.assertEquals("\\", evaluateExpression("\\"));
        Assert.assertEquals("$", evaluateExpression("$"));
        Assert.assertEquals("#", evaluateExpression("#"));
        Assert.assertEquals("\\$", evaluateExpression("\\$"));
        Assert.assertEquals("\\#", evaluateExpression("\\#"));
        Assert.assertEquals("\\\\$", evaluateExpression("\\\\$"));
        Assert.assertEquals("\\\\#", evaluateExpression("\\\\#"));
        Assert.assertEquals("${", evaluateExpression("\\${"));
        Assert.assertEquals("#{", evaluateExpression("\\#{"));
        Assert.assertEquals("\\${", evaluateExpression("\\\\${"));
        Assert.assertEquals("\\#{", evaluateExpression("\\\\#{"));

        // '\' is only an escape for '${' and '#{'.
        Assert.assertEquals("\\$", evaluateExpression("\\$"));
        Assert.assertEquals("${", evaluateExpression("\\${"));
        Assert.assertEquals("\\$a", evaluateExpression("\\$a"));
        Assert.assertEquals("\\a", evaluateExpression("\\a"));
        Assert.assertEquals("\\\\", evaluateExpression("\\\\"));
    }

    @Test
    public void testParserStringLiteral() {
        // Inspired by work on bug 45451, comments from kkolinko on the dev
        // list and looking at the spec to find some edge cases

        // The only characters that can be escaped inside a String literal
        // are \ " and '. # and $ are not escaped inside a String literal.
        Assert.assertEquals("\\", evaluateExpression("${'\\\\'}"));
        Assert.assertEquals("\\", evaluateExpression("${\"\\\\\"}"));
        Assert.assertEquals("\\\"'$#", evaluateExpression("${'\\\\\\\"\\'$#'}"));
        Assert.assertEquals("\\\"'$#", evaluateExpression("${\"\\\\\\\"\\'$#\"}"));

        // Trying to quote # or $ should throw an error
        Exception e = null;
        try {
            evaluateExpression("${'\\$'}");
        } catch (ELException el) {
            e = el;
        }
        Assert.assertNotNull(e);

        Assert.assertEquals("\\$", evaluateExpression("${'\\\\$'}"));
        Assert.assertEquals("\\\\$", evaluateExpression("${'\\\\\\\\$'}"));


        // Can use ''' inside '"' when quoting with '"' and vice versa without
        // escaping
        Assert.assertEquals("\\\"", evaluateExpression("${'\\\\\"'}"));
        Assert.assertEquals("\"\\", evaluateExpression("${'\"\\\\'}"));
        Assert.assertEquals("\\'", evaluateExpression("${'\\\\\\''}"));
        Assert.assertEquals("'\\", evaluateExpression("${'\\'\\\\'}"));
        Assert.assertEquals("\\'", evaluateExpression("${\"\\\\'\"}"));
        Assert.assertEquals("'\\", evaluateExpression("${\"'\\\\\"}"));
        Assert.assertEquals("\\\"", evaluateExpression("${\"\\\\\\\"\"}"));
        Assert.assertEquals("\"\\", evaluateExpression("${\"\\\"\\\\\"}"));
    }

    @Test
    public void testMultipleEscaping() throws Exception {
        Assert.assertEquals("''", evaluateExpression("${\"\'\'\"}"));
    }

    private void compareBoth(String msg, int expected, Object o1, Object o2) {
        int i1 = ELSupport.compare(null, o1, o2);
        int i2 = ELSupport.compare(null, o2, o1);
        Assert.assertEquals(msg, expected, i1);
        Assert.assertEquals(msg, expected, -i2);
    }

    @Test
    public void testElSupportCompare() {
        compareBoth("Nulls should compare equal", 0, null, null);
        compareBoth("Null should compare equal to \"\"", 0, "", null);
        compareBoth("Null should be less than File()", -1, null, new File(""));
        compareBoth("Null should be less than Date()", -1, null, new Date());
        compareBoth("Date(0) should be less than Date(1)", -1, new Date(0), new Date(1));
        try {
            compareBoth("Should not compare", 0, new Date(), new File(""));
            Assert.fail("Expecting ClassCastException");
        } catch (ClassCastException expected) {
            // Expected
        }
        Assert.assertTrue(null == null);
    }

    /**
     * Test mixing ${...} and #{...} in the same expression.
     */
    @Test
    public void testMixedTypes() {
        // Mixing types should throw an error
        Exception e = null;
        try {
            evaluateExpression("${1+1}#{1+1}");
        } catch (ELException el) {
            e = el;
        }
        Assert.assertNotNull(e);
    }

    @Test
    public void testEscape01() {
        Assert.assertEquals("$${", evaluateExpression("$\\${"));
    }

    @Test
    public void testBug49081a() {
        Assert.assertEquals("$2", evaluateExpression("$${1+1}"));
    }

    @Test
    public void testBug49081b() {
        Assert.assertEquals("#2", evaluateExpression("##{1+1}"));
    }

    @Test
    public void testBug49081c() {
        Assert.assertEquals("#2", evaluateExpression("#${1+1}"));
    }

    @Test
    public void testBug49081d() {
        Assert.assertEquals("$2", evaluateExpression("$#{1+1}"));
    }

    @Test
    public void testBug60431a() {
        Assert.assertEquals("OK", evaluateExpression("${fn:concat('O','K')}"));
    }

    @Test
    public void testBug60431b() {
        Assert.assertEquals("OK", evaluateExpression("${fn:concat(fn:toArray('O','K'))}"));
    }

    @Test
    public void testBug60431c() {
        Assert.assertEquals("", evaluateExpression("${fn:concat()}"));
    }

    @Test
    public void testBug60431d() {
        Assert.assertEquals("OK", evaluateExpression("${fn:concat2('OK')}"));
    }

    @Test
    public void testBug60431e() {
        Assert.assertEquals("RUOK", evaluateExpression("${fn:concat2('RU', fn:toArray('O','K'))}"));
    }

    // ************************************************************************

    private String evaluateExpression(String expression) {
        ExpressionFactoryImpl exprFactory = new ExpressionFactoryImpl();
        ELContextImpl ctx = new ELContextImpl();
        ctx.setFunctionMapper(new TesterFunctions.FMapper());
        ValueExpression ve = exprFactory.createValueExpression(ctx, expression, String.class);
        return (String) ve.getValue(ctx);
    }
}