View Javadoc
1   package org.codehaus.plexus.interpolation;
2   
3   /*
4    * Copyright 2001-2008 Codehaus Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  import java.io.IOException;
20  import java.util.ArrayList;
21  import java.util.Collections;
22  import java.util.HashMap;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.Properties;
26  
27  import org.codehaus.plexus.interpolation.os.OperatingSystemUtils;
28  import org.junit.jupiter.api.BeforeEach;
29  import org.junit.jupiter.api.Test;
30  
31  import static org.junit.jupiter.api.Assertions.assertEquals;
32  import static org.junit.jupiter.api.Assertions.fail;
33  
34  public class StringSearchInterpolatorTest {
35  
36      @BeforeEach
37      public void setUp() {
38          EnvarBasedValueSource.resetStatics();
39      }
40  
41      @Test
42      public void testLongDelimitersInContext() throws InterpolationException {
43          String src = "This is a <expression>test.label</expression> for long delimiters in context.";
44          String result = "This is a test for long delimiters in context.";
45  
46          Properties p = new Properties();
47          p.setProperty("test.label", "test");
48  
49          StringSearchInterpolator interpolator = new StringSearchInterpolator("<expression>", "</expression>");
50          interpolator.addValueSource(new PropertiesBasedValueSource(p));
51  
52          assertEquals(result, interpolator.interpolate(src));
53      }
54  
55      @Test
56      public void testLongDelimitersWithNoStartContext() throws InterpolationException {
57          String src = "<expression>test.label</expression> for long delimiters in context.";
58          String result = "test for long delimiters in context.";
59  
60          Properties p = new Properties();
61          p.setProperty("test.label", "test");
62  
63          StringSearchInterpolator interpolator = new StringSearchInterpolator("<expression>", "</expression>");
64          interpolator.addValueSource(new PropertiesBasedValueSource(p));
65  
66          assertEquals(result, interpolator.interpolate(src));
67      }
68  
69      @Test
70      public void testLongDelimitersWithNoEndContext() throws InterpolationException {
71          String src = "This is a <expression>test.label</expression>";
72          String result = "This is a test";
73  
74          Properties p = new Properties();
75          p.setProperty("test.label", "test");
76  
77          StringSearchInterpolator interpolator = new StringSearchInterpolator("<expression>", "</expression>");
78          interpolator.addValueSource(new PropertiesBasedValueSource(p));
79  
80          assertEquals(result, interpolator.interpolate(src));
81      }
82  
83      @Test
84      public void testLongDelimitersWithNoContext() throws InterpolationException {
85          String src = "<expression>test.label</expression>";
86          String result = "test";
87  
88          Properties p = new Properties();
89          p.setProperty("test.label", "test");
90  
91          StringSearchInterpolator interpolator = new StringSearchInterpolator("<expression>", "</expression>");
92          interpolator.addValueSource(new PropertiesBasedValueSource(p));
93  
94          assertEquals(result, interpolator.interpolate(src));
95      }
96  
97      @Test
98      public void testLongDelimitersPassedToValueSource() throws InterpolationException {
99          String src = "<expression>test</expression>";
100 
101         StringSearchInterpolator interpolator = new StringSearchInterpolator("<expression>", "</expression>");
102         interpolator.addValueSource(new AbstractValueSource(false) {
103 
104             @Override
105             public Object getValue(String expression, String expressionStartDelimiter, String expressionEndDelimiter) {
106                 assertEquals("<expression>", expressionStartDelimiter);
107                 assertEquals("</expression>", expressionEndDelimiter);
108                 return expression;
109             }
110 
111             @Override
112             public Object getValue(String expression) {
113                 fail("This method is not supposed to be called");
114                 return null;
115             }
116         });
117 
118         assertEquals("test", interpolator.interpolate(src));
119     }
120 
121     @Test
122     public void testSimpleSubstitution() throws InterpolationException {
123         Properties p = new Properties();
124         p.setProperty("key", "value");
125 
126         StringSearchInterpolator interpolator = new StringSearchInterpolator();
127         interpolator.addValueSource(new PropertiesBasedValueSource(p));
128 
129         assertEquals("This is a test value.", interpolator.interpolate("This is a test ${key}."));
130     }
131 
132     @Test
133     public void testSimpleSubstitution_TwoExpressions() throws InterpolationException {
134         Properties p = new Properties();
135         p.setProperty("key", "value");
136         p.setProperty("key2", "value2");
137 
138         StringSearchInterpolator interpolator = new StringSearchInterpolator();
139         interpolator.addValueSource(new PropertiesBasedValueSource(p));
140 
141         assertEquals("value-value2", interpolator.interpolate("${key}-${key2}"));
142     }
143 
144     @Test
145     public void testBrokenExpression_LeaveItAlone() throws InterpolationException {
146         Properties p = new Properties();
147         p.setProperty("key", "value");
148 
149         StringSearchInterpolator interpolator = new StringSearchInterpolator();
150         interpolator.addValueSource(new PropertiesBasedValueSource(p));
151 
152         assertEquals("This is a test ${key.", interpolator.interpolate("This is a test ${key."));
153     }
154 
155     @Test
156     public void testShouldFailOnExpressionCycle() {
157         Properties props = new Properties();
158         props.setProperty("key1", "${key2}");
159         props.setProperty("key2", "${key1}");
160 
161         StringSearchInterpolator rbi = new StringSearchInterpolator();
162         rbi.addValueSource(new PropertiesBasedValueSource(props));
163 
164         try {
165             rbi.interpolate("${key1}", new SimpleRecursionInterceptor());
166 
167             fail("Should detect expression cycle and fail.");
168         } catch (InterpolationException e) {
169             // expected
170         }
171     }
172 
173     @Test
174     public void testShouldResolveByUsingObject_List_Map() throws InterpolationException {
175         StringSearchInterpolator rbi = new StringSearchInterpolator();
176         rbi.addValueSource(new ObjectBasedValueSource(this));
177         String result =
178                 rbi.interpolate("this is a ${var} ${list[1].name} ${anArray[2].name} ${map(Key with spaces).name}");
179 
180         assertEquals("this is a testVar testIndexedWithList testIndexedWithArray testMap", result);
181     }
182 
183     @Test
184     public void testShouldResolveByContextValue() throws InterpolationException {
185         StringSearchInterpolator rbi = new StringSearchInterpolator();
186 
187         Map context = new HashMap();
188         context.put("var", "testVar");
189 
190         rbi.addValueSource(new MapBasedValueSource(context));
191 
192         String result = rbi.interpolate("this is a ${var}");
193 
194         assertEquals("this is a testVar", result);
195     }
196 
197     @Test
198     public void testShouldResolveByEnvar() throws IOException, InterpolationException {
199         OperatingSystemUtils.setEnvVarSource(new OperatingSystemUtils.EnvVarSource() {
200             public Map<String, String> getEnvMap() {
201                 HashMap<String, String> map = new HashMap<String, String>();
202                 map.put("SOME_ENV", "variable");
203                 map.put("OTHER_ENV", "other variable");
204                 return map;
205             }
206         });
207 
208         StringSearchInterpolator rbi = new StringSearchInterpolator();
209 
210         rbi.addValueSource(new EnvarBasedValueSource(false));
211 
212         String result = rbi.interpolate("this is a ${env.SOME_ENV} ${env.OTHER_ENV}");
213 
214         assertEquals("this is a variable other variable", result);
215     }
216 
217     @Test
218     public void testUsePostProcessor_DoesNotChangeValue() throws InterpolationException {
219         StringSearchInterpolator rbi = new StringSearchInterpolator();
220 
221         Map context = new HashMap();
222         context.put("test.var", "testVar");
223 
224         rbi.addValueSource(new MapBasedValueSource(context));
225 
226         rbi.addPostProcessor(new InterpolationPostProcessor() {
227             public Object execute(String expression, Object value) {
228                 return null;
229             }
230         });
231 
232         String result = rbi.interpolate("this is a ${test.var}");
233 
234         assertEquals("this is a testVar", result);
235     }
236 
237     @Test
238     public void testUsePostProcessor_ChangesValue() throws InterpolationException {
239 
240         StringSearchInterpolator rbi = new StringSearchInterpolator();
241 
242         Map context = new HashMap();
243         context.put("test.var", "testVar");
244 
245         rbi.addValueSource(new MapBasedValueSource(context));
246 
247         rbi.addPostProcessor(new InterpolationPostProcessor() {
248             public Object execute(String expression, Object value) {
249                 return value + "2";
250             }
251         });
252 
253         String result = rbi.interpolate("this is a ${test.var}");
254 
255         assertEquals("this is a testVar2", result);
256     }
257 
258     @Test
259     public void testSimpleSubstitutionWithDefinedExpr() throws InterpolationException {
260         Properties p = new Properties();
261         p.setProperty("key", "value");
262 
263         StringSearchInterpolator interpolator = new StringSearchInterpolator("@{", "}");
264         interpolator.addValueSource(new PropertiesBasedValueSource(p));
265 
266         assertEquals("This is a test value.", interpolator.interpolate("This is a test @{key}."));
267     }
268 
269     @Test
270     public void testEscape() throws InterpolationException {
271         Properties p = new Properties();
272         p.setProperty("key", "value");
273 
274         StringSearchInterpolator interpolator = new StringSearchInterpolator("@{", "}");
275         interpolator.setEscapeString("\\");
276         interpolator.addValueSource(new PropertiesBasedValueSource(p));
277 
278         String result = interpolator.interpolate("This is a test \\@{key}.");
279 
280         assertEquals("This is a test @{key}.", result);
281     }
282 
283     @Test
284     public void testEscapeWithLongEscapeStr() throws InterpolationException {
285         Properties p = new Properties();
286         p.setProperty("key", "value");
287 
288         StringSearchInterpolator interpolator = new StringSearchInterpolator("@{", "}");
289         interpolator.setEscapeString("$$");
290         interpolator.addValueSource(new PropertiesBasedValueSource(p));
291 
292         String result = interpolator.interpolate("This is a test $$@{key}.");
293 
294         assertEquals("This is a test @{key}.", result);
295     }
296 
297     @Test
298     public void testEscapeWithLongEscapeStrAtStart() throws InterpolationException {
299         Properties p = new Properties();
300         p.setProperty("key", "value");
301 
302         StringSearchInterpolator interpolator = new StringSearchInterpolator("@{", "}");
303         interpolator.setEscapeString("$$");
304         interpolator.addValueSource(new PropertiesBasedValueSource(p));
305 
306         String result = interpolator.interpolate("$$@{key} This is a test.");
307 
308         assertEquals("@{key} This is a test.", result);
309     }
310 
311     @Test
312     public void testNotEscapeWithLongEscapeStrAtStart() throws InterpolationException {
313         Properties p = new Properties();
314         p.setProperty("key", "value");
315 
316         StringSearchInterpolator interpolator = new StringSearchInterpolator("@{", "}");
317         interpolator.setEscapeString("$$");
318         interpolator.addValueSource(new PropertiesBasedValueSource(p));
319 
320         String result = interpolator.interpolate("@{key} This is a test.");
321 
322         assertEquals("value This is a test.", result);
323     }
324 
325     @Test
326     public void testEscapeNotFailWithNullEscapeStr() throws InterpolationException {
327         Properties p = new Properties();
328         p.setProperty("key", "value");
329 
330         StringSearchInterpolator interpolator = new StringSearchInterpolator("@{", "}");
331         interpolator.setEscapeString(null);
332         interpolator.addValueSource(new PropertiesBasedValueSource(p));
333 
334         String result = interpolator.interpolate("This is a test @{key}.");
335 
336         assertEquals("This is a test value.", result);
337     }
338 
339     @Test
340     public void testOnlyEscapeExprAtStart() throws InterpolationException {
341         Properties p = new Properties();
342         p.setProperty("key", "value");
343 
344         StringSearchInterpolator interpolator = new StringSearchInterpolator("@{", "}");
345         interpolator.setEscapeString("\\");
346         interpolator.addValueSource(new PropertiesBasedValueSource(p));
347 
348         String result = interpolator.interpolate("\\@{key} This is a test.");
349 
350         assertEquals("@{key} This is a test.", result);
351     }
352 
353     @Test
354     public void testNotEscapeExprAtStart() throws InterpolationException {
355         Properties p = new Properties();
356         p.setProperty("key", "value");
357 
358         StringSearchInterpolator interpolator = new StringSearchInterpolator("@{", "}");
359         interpolator.setEscapeString("\\");
360         interpolator.addValueSource(new PropertiesBasedValueSource(p));
361 
362         String result = interpolator.interpolate("@{key} This is a test.");
363 
364         assertEquals("value This is a test.", result);
365     }
366 
367     @Test
368     public void testEscapeExprAtStart() throws InterpolationException {
369         Properties p = new Properties();
370         p.setProperty("key", "value");
371 
372         StringSearchInterpolator interpolator = new StringSearchInterpolator("@", "@");
373         interpolator.setEscapeString("\\");
374         interpolator.addValueSource(new PropertiesBasedValueSource(p));
375 
376         String result = interpolator.interpolate("\\@key@ This is a test @key@.");
377 
378         assertEquals("@key@ This is a test value.", result);
379     }
380 
381     @Test
382     public void testNPEFree() throws InterpolationException {
383         Properties p = new Properties();
384         p.setProperty("key", "value");
385 
386         StringSearchInterpolator interpolator = new StringSearchInterpolator("@{", "}");
387         interpolator.setEscapeString("\\");
388         interpolator.addValueSource(new PropertiesBasedValueSource(p));
389 
390         String result = interpolator.interpolate(null);
391 
392         assertEquals("", result);
393     }
394 
395     @Test
396     public void testInterruptedInterpolate() throws InterpolationException {
397         Interpolator interpolator = new StringSearchInterpolator();
398         RecursionInterceptor recursionInterceptor = new SimpleRecursionInterceptor();
399         final boolean[] error = new boolean[] {false};
400         interpolator.addValueSource(new ValueSource() {
401             public Object getValue(String expression) {
402                 if (expression.equals("key")) {
403                     if (error[0]) {
404                         throw new IllegalStateException("broken");
405                     }
406                     return "val";
407                 } else {
408                     return null;
409                 }
410             }
411 
412             public List getFeedback() {
413                 return Collections.EMPTY_LIST;
414             }
415 
416             public void clearFeedback() {}
417         });
418         assertEquals("-val-", interpolator.interpolate("-${key}-", recursionInterceptor), "control case");
419         error[0] = true;
420         try {
421             interpolator.interpolate("-${key}-", recursionInterceptor);
422             fail("should have thrown exception");
423         } catch (IllegalStateException x) {
424             // right
425         }
426         error[0] = false;
427         assertEquals(
428                 "-val-",
429                 interpolator.interpolate("-${key}-", recursionInterceptor),
430                 "should not believe there is a cycle here");
431     }
432 
433     @Test
434     public void testCacheAnswersTrue() throws InterpolationException {
435         Properties p = new Properties();
436         p.setProperty("key", "value");
437 
438         class CountingStringSearchInterpolator extends StringSearchInterpolator {
439             private int existingCallCount;
440 
441             @Override
442             protected Object getExistingAnswer(String key) {
443                 Object value = super.getExistingAnswer(key);
444                 if (value != null) {
445                     ++existingCallCount;
446                 }
447                 return value;
448             }
449 
450             public int getExistingCallCount() {
451                 return existingCallCount;
452             }
453         }
454 
455         CountingStringSearchInterpolator interpolator = new CountingStringSearchInterpolator();
456         interpolator.setCacheAnswers(true);
457         interpolator.addValueSource(new PropertiesBasedValueSource(p));
458 
459         String result = interpolator.interpolate("${key}-${key}-${key}-${key}");
460 
461         assertEquals("value-value-value-value", result);
462         // first value is interpolated and saved, then the 3 next answers came from existing answer Map
463         assertEquals(3, interpolator.getExistingCallCount());
464 
465         // answers are preserved between calls:
466         result = interpolator.interpolate("${key}-${key}-${key}-${key}");
467         assertEquals("value-value-value-value", result);
468         // 3 from the first call to interpolate(), plus 4 from second call
469         assertEquals(3 + 4, interpolator.getExistingCallCount());
470     }
471 
472     @Test
473     public void testCacheAnswersFalse() throws InterpolationException {
474         Properties p = new Properties();
475         p.setProperty("key", "value");
476 
477         class CountingStringSearchInterpolator extends StringSearchInterpolator {
478             private int existingCallCount;
479 
480             @Override
481             protected Object getExistingAnswer(String key) {
482                 Object value = super.getExistingAnswer(key);
483                 if (value != null) {
484                     ++existingCallCount;
485                 }
486                 return value;
487             }
488 
489             public int getExistingCallCount() {
490                 return existingCallCount;
491             }
492         }
493 
494         CountingStringSearchInterpolator interpolator = new CountingStringSearchInterpolator();
495         interpolator.addValueSource(new PropertiesBasedValueSource(p));
496 
497         String result = interpolator.interpolate("${key}-${key}-${key}-${key}");
498 
499         assertEquals("value-value-value-value", result);
500         // all values are interpolated each time
501         assertEquals(0, interpolator.getExistingCallCount());
502     }
503 
504     public String getVar() {
505         return "testVar";
506     }
507 
508     public Person[] getAnArray() {
509         Person[] array = new Person[3];
510         array[0] = new Person("Gabriel");
511         array[1] = new Person("Daniela");
512         array[2] = new Person("testIndexedWithArray");
513         return array;
514     }
515 
516     public List<Person> getList() {
517         List<Person> list = new ArrayList<Person>();
518         list.add(new Person("Gabriel"));
519         list.add(new Person("testIndexedWithList"));
520         list.add(new Person("Daniela"));
521         return list;
522     }
523 
524     public Map<String, Person> getMap() {
525         Map<String, Person> map = new HashMap<String, StringSearchInterpolatorTest.Person>();
526         map.put("Key with spaces", new Person("testMap"));
527         return map;
528     }
529 
530     public static class Person {
531         private String name;
532 
533         public Person(String name) {
534             this.name = name;
535         }
536 
537         public String getName() {
538             return name;
539         }
540     }
541 }