View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.jexl3.internal;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertFalse;
21  import static org.junit.jupiter.api.Assertions.assertNotEquals;
22  import static org.junit.jupiter.api.Assertions.assertNotNull;
23  import static org.junit.jupiter.api.Assertions.assertNull;
24  import static org.junit.jupiter.api.Assertions.assertTrue;
25  
26  import java.util.HashMap;
27  import java.util.Map;
28  
29  import org.apache.commons.jexl3.ConcurrentCache;
30  import org.apache.commons.jexl3.JexlBuilder;
31  import org.apache.commons.jexl3.JexlCache;
32  import org.apache.commons.jexl3.JexlEngine;
33  import org.apache.commons.jexl3.JexlFeatures;
34  import org.apache.commons.jexl3.JexlScript;
35  import org.junit.jupiter.api.Test;
36  
37  public class SourceCacheTest {
38  
39      @Test
40      void testSource() {
41          final JexlFeatures features = JexlFeatures.createDefault();
42          final Source src0 = new Source(features, null,"x -> -x");
43          final Source src0b = new Source(features, null,"x -> -x");
44          final Source src1 = new Source(features, null,"x -> +x");
45          assertEquals(7, src0.length());
46          assertEquals(src0, src0b);
47          assertNotEquals(src0, src1);
48          assertEquals(src0.hashCode(), src0b.hashCode());
49          assertNotEquals(src0.hashCode(), src1.hashCode());
50          assertEquals(0, src0.compareTo(src0b));
51          assertTrue(src0.compareTo(src1) > 0);
52          assertTrue(src1.compareTo(src0) < 0);
53      }
54  
55      @Test
56      void testSourceCache() {
57          final JexlFeatures features = JexlFeatures.createDefault();
58          // source objects differ when symbol maps differ
59          final Map<String, Integer> symbols0 = new HashMap<>();
60          symbols0.put("x", 0);
61          symbols0.put("y", 1);
62          final Source src0 = new Source(features, symbols0,"x + y");
63          assertFalse(src0.equals(null));
64          assertFalse(src0.equals("x + y"));
65          final Map<String, Integer> symbols1 = new HashMap<>();
66          symbols0.put("x", 0);
67          symbols0.put("y", 2);
68          final Source src1 = new Source(features, symbols1,"x + y");
69          assertNotEquals(src0, src1);
70          assertNotEquals(0, src0.compareTo(src1));
71          final Source src2 = new Source(features, null,"x + y");
72          assertNotEquals(src0, src2);
73          assertNotEquals(0, src0.compareTo(src2));
74          final Source src3 = new Source(JexlFeatures.createNone(), symbols1,"x + y");
75          assertNotEquals(src0, src3);
76          assertNotEquals(0, src0.compareTo(src3));
77  
78          final JexlEngine jexl = new JexlBuilder().cache(4).create();
79          final JexlCache<Source, Object> cache = ((Engine) jexl).getCache();
80          // order of declaration of variables matters
81          JexlScript script0 = jexl.createScript("x + y", "x", "y");
82          assertNotNull(script0);
83          JexlScript script1 = jexl.createScript("x + y", "y", "x");
84          assertNotNull(script1);
85          assertEquals(2, cache.size());
86          cache.clear();
87          script0 = jexl.createScript("x + y", "x", "y");
88          assertNotNull(script0);
89          script1 = jexl.createScript("x + y", "x", "y");
90          assertNotNull(script1);
91          assertEquals(1, cache.size());
92      }
93  
94      @Test
95      void testInterpolationCache() {
96          final JexlEngine jexl = new JexlBuilder().strictInterpolation(true).cache(4).create();
97          final JexlCache<Source, Object> cache = ((Engine) jexl).getCache();
98          // order of declaration of variables matters
99          JexlScript script0;
100         for (int i = 0; i < 2; ++i) {
101             script0 = jexl.createScript("`${x}` + `${x}`", "x");
102             assertNotNull(script0);
103             final Object result = script0.execute(null, 42);
104             assertEquals("4242", result);
105             // the '+' and the two '`${x}`' should lead to only 2 cached sources
106             assertEquals(2, cache.size());
107         }
108     }
109 
110     @Test
111     void testMetaCache() {
112         final MetaCache mc = new MetaCache(ConcurrentCache::new);
113         JexlCache<Integer, String> cache1 = mc.createCache(3);
114         cache1.put(1, "one");
115         cache1.put(2, "two");
116         cache1.put(3, "three");
117         assertEquals(3, cache1.size());
118         assertEquals("one", cache1.get(1));
119         assertEquals("two", cache1.get(2));
120         assertEquals("three", cache1.get(3));
121         cache1.put(4, "four");
122         assertEquals(3, cache1.size());
123         assertNull(cache1.get(1)); // evicted
124         assertEquals("two", cache1.get(2));
125         assertEquals("three", cache1.get(3));
126         assertEquals("four", cache1.get(4));
127 
128         JexlCache<String, String> cache2 = mc.createCache(2);
129         cache2.put("a", "A");
130         cache2.put("b", "B");
131         assertEquals(2, cache2.size());
132         assertEquals("A", cache2.get("a"));
133         assertEquals("B", cache2.get("b"));
134         cache2.put("c", "C");
135         assertEquals(2, cache2.size());
136         assertNull(cache2.get("a")); // evicted
137         assertEquals("B", cache2.get("b"));
138         assertEquals("C", cache2.get("c"));
139 
140         // metacache weak references test
141         assertEquals(2, mc.size());
142         // drop the strong references to the caches
143         cache1 = null;
144         assertNull(cache1);
145         cache2 = null;
146         assertNull(cache2);
147         // trigger garbage collection
148         System.gc();
149         // wait for the garbage collector to do its work
150         for(int i = 0; i < 5 && mc.size() != 0; ++i) {
151             try {
152                 Thread.sleep(100);
153             } catch(final InterruptedException xint) {
154                 // ignore
155             }
156         }
157         // the caches should have been removed from the metacache
158         assertEquals(0, mc.size(), "metacache should have no more cache references");
159     }
160 }