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    *      http://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  
18  package org.apache.commons.lang3.text;
19  
20  import static org.junit.jupiter.api.Assertions.assertEquals;
21  import static org.junit.jupiter.api.Assertions.assertFalse;
22  import static org.junit.jupiter.api.Assertions.assertNull;
23  import static org.junit.jupiter.api.Assertions.assertSame;
24  import static org.junit.jupiter.api.Assertions.assertThrows;
25  import static org.junit.jupiter.api.Assertions.assertTrue;
26  
27  import java.util.HashMap;
28  import java.util.Map;
29  import java.util.Properties;
30  
31  import org.apache.commons.lang3.AbstractLangTest;
32  import org.apache.commons.lang3.mutable.MutableObject;
33  import org.junit.jupiter.api.AfterEach;
34  import org.junit.jupiter.api.BeforeEach;
35  import org.junit.jupiter.api.Test;
36  
37  /**
38   * Test class for StrSubstitutor.
39   */
40  @Deprecated
41  public class StrSubstitutorTest extends AbstractLangTest {
42  
43      private Map<String, String> values;
44  
45      private void doTestNoReplace(final String replaceTemplate) {
46          final StrSubstitutor sub = new StrSubstitutor(values);
47  
48          if (replaceTemplate == null) {
49              assertNull(sub.replace((String) null));
50              assertNull(sub.replace((String) null, 0, 100));
51              assertNull(sub.replace((char[]) null));
52              assertNull(sub.replace((char[]) null, 0, 100));
53              assertNull(sub.replace((StringBuffer) null));
54              assertNull(sub.replace((StringBuffer) null, 0, 100));
55              assertNull(sub.replace((StrBuilder) null));
56              assertNull(sub.replace((StrBuilder) null, 0, 100));
57              assertNull(sub.replace((Object) null));
58              assertFalse(sub.replaceIn((StringBuffer) null));
59              assertFalse(sub.replaceIn((StringBuffer) null, 0, 100));
60              assertFalse(sub.replaceIn((StrBuilder) null));
61              assertFalse(sub.replaceIn((StrBuilder) null, 0, 100));
62          } else {
63              assertEquals(replaceTemplate, sub.replace(replaceTemplate));
64              final StrBuilder bld = new StrBuilder(replaceTemplate);
65              assertFalse(sub.replaceIn(bld));
66              assertEquals(replaceTemplate, bld.toString());
67          }
68      }
69  
70      private void doTestReplace(final String expectedResult, final String replaceTemplate, final boolean substring) {
71          final String expectedShortResult = expectedResult.substring(1, expectedResult.length() - 1);
72          final StrSubstitutor sub = new StrSubstitutor(values);
73  
74          // replace using String
75          assertEquals(expectedResult, sub.replace(replaceTemplate));
76          if (substring) {
77              assertEquals(expectedShortResult, sub.replace(replaceTemplate, 1, replaceTemplate.length() - 2));
78          }
79  
80          // replace using char[]
81          final char[] chars = replaceTemplate.toCharArray();
82          assertEquals(expectedResult, sub.replace(chars));
83          if (substring) {
84              assertEquals(expectedShortResult, sub.replace(chars, 1, chars.length - 2));
85          }
86  
87          // replace using StringBuffer
88          StringBuffer buf = new StringBuffer(replaceTemplate);
89          assertEquals(expectedResult, sub.replace(buf));
90          if (substring) {
91              assertEquals(expectedShortResult, sub.replace(buf, 1, buf.length() - 2));
92          }
93  
94          // replace using StringBuilder
95          StringBuilder builder = new StringBuilder(replaceTemplate);
96          assertEquals(expectedResult, sub.replace(builder));
97          if (substring) {
98              assertEquals(expectedShortResult, sub.replace(builder, 1, builder.length() - 2));
99          }
100 
101         // replace using StrBuilder
102         StrBuilder bld = new StrBuilder(replaceTemplate);
103         assertEquals(expectedResult, sub.replace(bld));
104         if (substring) {
105             assertEquals(expectedShortResult, sub.replace(bld, 1, bld.length() - 2));
106         }
107 
108         // replace using object
109         final MutableObject<String> obj = new MutableObject<>(replaceTemplate);  // toString returns template
110         assertEquals(expectedResult, sub.replace(obj));
111 
112         // replace in StringBuffer
113         buf = new StringBuffer(replaceTemplate);
114         assertTrue(sub.replaceIn(buf));
115         assertEquals(expectedResult, buf.toString());
116         if (substring) {
117             buf = new StringBuffer(replaceTemplate);
118             assertTrue(sub.replaceIn(buf, 1, buf.length() - 2));
119             assertEquals(expectedResult, buf.toString());  // expect full result as remainder is untouched
120         }
121 
122         // replace in StringBuilder
123         builder = new StringBuilder(replaceTemplate);
124         assertTrue(sub.replaceIn(builder));
125         assertEquals(expectedResult, builder.toString());
126         if (substring) {
127             builder = new StringBuilder(replaceTemplate);
128             assertTrue(sub.replaceIn(builder, 1, builder.length() - 2));
129             assertEquals(expectedResult, builder.toString());  // expect full result as remainder is untouched
130         }
131 
132         // replace in StrBuilder
133         bld = new StrBuilder(replaceTemplate);
134         assertTrue(sub.replaceIn(bld));
135         assertEquals(expectedResult, bld.toString());
136         if (substring) {
137             bld = new StrBuilder(replaceTemplate);
138             assertTrue(sub.replaceIn(bld, 1, bld.length() - 2));
139             assertEquals(expectedResult, bld.toString());  // expect full result as remainder is untouched
140         }
141     }
142 
143     @BeforeEach
144     public void setUp() {
145         values = new HashMap<>();
146         values.put("animal", "quick brown fox");
147         values.put("target", "lazy dog");
148     }
149 
150     @AfterEach
151     public void tearDown() {
152         values = null;
153     }
154 
155     /**
156      * Tests constructor.
157      */
158     @Test
159     public void testConstructorMapFull() {
160         final Map<String, String> map = new HashMap<>();
161         map.put("name", "commons");
162         StrSubstitutor sub = new StrSubstitutor(map, "<", ">", '!');
163         assertEquals("Hi < commons", sub.replace("Hi !< <name>"));
164         sub = new StrSubstitutor(map, "<", ">", '!', "||");
165         assertEquals("Hi < commons", sub.replace("Hi !< <name2||commons>"));
166     }
167 
168     /**
169      * Tests constructor.
170      */
171     @Test
172     public void testConstructorMapPrefixSuffix() {
173         final Map<String, String> map = new HashMap<>();
174         map.put("name", "commons");
175         final StrSubstitutor sub = new StrSubstitutor(map, "<", ">");
176         assertEquals("Hi < commons", sub.replace("Hi $< <name>"));
177     }
178 
179     /**
180      * Tests constructor.
181      */
182     @Test
183     public void testConstructorNoArgs() {
184         final StrSubstitutor sub = new StrSubstitutor();
185         assertEquals("Hi ${name}", sub.replace("Hi ${name}"));
186     }
187 
188     /**
189      * Tests a cyclic replace operation.
190      * The cycle should be detected and cause an exception to be thrown.
191      */
192     @Test
193     public void testCyclicReplacement() {
194         final Map<String, String> map = new HashMap<>();
195         map.put("animal", "${critter}");
196         map.put("target", "${pet}");
197         map.put("pet", "${petCharacteristic} dog");
198         map.put("petCharacteristic", "lazy");
199         map.put("critter", "${critterSpeed} ${critterColor} ${critterType}");
200         map.put("critterSpeed", "quick");
201         map.put("critterColor", "brown");
202         map.put("critterType", "${animal}");
203         final StrSubstitutor sub = new StrSubstitutor(map);
204         assertThrows(
205                 IllegalStateException.class,
206                 () -> sub.replace("The ${animal} jumps over the ${target}."),
207                 "Cyclic replacement was not detected!");
208 
209         // also check even when default value is set.
210         map.put("critterType", "${animal:-fox}");
211         final StrSubstitutor sub2 = new StrSubstitutor(map);
212         assertThrows(
213                 IllegalStateException.class,
214                 () -> sub2.replace("The ${animal} jumps over the ${target}."),
215                 "Cyclic replacement was not detected!");
216     }
217 
218     @Test
219     public void testDefaultValueDelimiters() {
220         final Map<String, String> map = new HashMap<>();
221         map.put("animal", "fox");
222         map.put("target", "dog");
223 
224         StrSubstitutor sub = new StrSubstitutor(map, "${", "}", '$');
225         assertEquals("The fox jumps over the lazy dog. 1234567890.",
226                 sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number:-1234567890}."));
227 
228         sub = new StrSubstitutor(map, "${", "}", '$', "?:");
229         assertEquals("The fox jumps over the lazy dog. 1234567890.",
230                 sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number?:1234567890}."));
231 
232         sub = new StrSubstitutor(map, "${", "}", '$', "||");
233         assertEquals("The fox jumps over the lazy dog. 1234567890.",
234                 sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number||1234567890}."));
235 
236         sub = new StrSubstitutor(map, "${", "}", '$', "!");
237         assertEquals("The fox jumps over the lazy dog. 1234567890.",
238                 sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number!1234567890}."));
239 
240         sub = new StrSubstitutor(map, "${", "}", '$', "");
241         sub.setValueDelimiterMatcher(null);
242         assertEquals("The fox jumps over the lazy dog. ${undefined.number!1234567890}.",
243                 sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number!1234567890}."));
244 
245         sub = new StrSubstitutor(map, "${", "}", '$');
246         sub.setValueDelimiterMatcher(null);
247         assertEquals("The fox jumps over the lazy dog. ${undefined.number!1234567890}.",
248                 sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number!1234567890}."));
249     }
250 
251     /**
252      * Tests get set.
253      */
254     @Test
255     public void testGetSetEscape() {
256         final StrSubstitutor sub = new StrSubstitutor();
257         assertEquals('$', sub.getEscapeChar());
258         sub.setEscapeChar('<');
259         assertEquals('<', sub.getEscapeChar());
260     }
261 
262     /**
263      * Tests get set.
264      */
265     @Test
266     public void testGetSetPrefix() {
267         final StrSubstitutor sub = new StrSubstitutor();
268         assertTrue(sub.getVariablePrefixMatcher() instanceof StrMatcher.StringMatcher);
269         sub.setVariablePrefix('<');
270         assertTrue(sub.getVariablePrefixMatcher() instanceof StrMatcher.CharMatcher);
271 
272         sub.setVariablePrefix("<<");
273         assertTrue(sub.getVariablePrefixMatcher() instanceof StrMatcher.StringMatcher);
274         assertThrows(NullPointerException.class, () -> sub.setVariablePrefix(null));
275         assertTrue(sub.getVariablePrefixMatcher() instanceof StrMatcher.StringMatcher);
276 
277         final StrMatcher matcher = StrMatcher.commaMatcher();
278         sub.setVariablePrefixMatcher(matcher);
279         assertSame(matcher, sub.getVariablePrefixMatcher());
280         assertThrows(NullPointerException.class, () -> sub.setVariablePrefixMatcher(null));
281         assertSame(matcher, sub.getVariablePrefixMatcher());
282     }
283 
284     /**
285      * Tests get set.
286      */
287     @Test
288     public void testGetSetSuffix() {
289         final StrSubstitutor sub = new StrSubstitutor();
290         assertTrue(sub.getVariableSuffixMatcher() instanceof StrMatcher.StringMatcher);
291         sub.setVariableSuffix('<');
292         assertTrue(sub.getVariableSuffixMatcher() instanceof StrMatcher.CharMatcher);
293 
294         sub.setVariableSuffix("<<");
295         assertTrue(sub.getVariableSuffixMatcher() instanceof StrMatcher.StringMatcher);
296         assertThrows(NullPointerException.class, () -> sub.setVariableSuffix(null));
297         assertTrue(sub.getVariableSuffixMatcher() instanceof StrMatcher.StringMatcher);
298 
299         final StrMatcher matcher = StrMatcher.commaMatcher();
300         sub.setVariableSuffixMatcher(matcher);
301         assertSame(matcher, sub.getVariableSuffixMatcher());
302         assertThrows(NullPointerException.class, () -> sub.setVariableSuffixMatcher(null));
303         assertSame(matcher, sub.getVariableSuffixMatcher());
304     }
305 
306     /**
307      * Tests get set.
308      */
309     @Test
310     public void testGetSetValueDelimiter() {
311         final StrSubstitutor sub = new StrSubstitutor();
312         assertTrue(sub.getValueDelimiterMatcher() instanceof StrMatcher.StringMatcher);
313         sub.setValueDelimiter(':');
314         assertTrue(sub.getValueDelimiterMatcher() instanceof StrMatcher.CharMatcher);
315 
316         sub.setValueDelimiter("||");
317         assertTrue(sub.getValueDelimiterMatcher() instanceof StrMatcher.StringMatcher);
318         sub.setValueDelimiter(null);
319         assertNull(sub.getValueDelimiterMatcher());
320 
321         final StrMatcher matcher = StrMatcher.commaMatcher();
322         sub.setValueDelimiterMatcher(matcher);
323         assertSame(matcher, sub.getValueDelimiterMatcher());
324         sub.setValueDelimiterMatcher(null);
325         assertNull(sub.getValueDelimiterMatcher());
326     }
327 
328     /**
329      * Test for LANG-1055: StrSubstitutor.replaceSystemProperties does not work consistently
330      */
331     @Test
332     public void testLANG1055() {
333         System.setProperty("test_key",  "test_value");
334 
335         final String expected = StrSubstitutor.replace("test_key=${test_key}", System.getProperties());
336         final String actual = StrSubstitutor.replaceSystemProperties("test_key=${test_key}");
337         assertEquals(expected, actual);
338     }
339 
340     /**
341      * Tests adjacent keys.
342      */
343     @Test
344     public void testReplaceAdjacentAtEnd() {
345         values.put("code", "GBP");
346         values.put("amount", "12.50");
347         final StrSubstitutor sub = new StrSubstitutor(values);
348         assertEquals("Amount is GBP12.50", sub.replace("Amount is ${code}${amount}"));
349     }
350 
351     /**
352      * Tests adjacent keys.
353      */
354     @Test
355     public void testReplaceAdjacentAtStart() {
356         values.put("code", "GBP");
357         values.put("amount", "12.50");
358         final StrSubstitutor sub = new StrSubstitutor(values);
359         assertEquals("GBP12.50 charged", sub.replace("${code}${amount} charged"));
360     }
361 
362     /**
363      * Tests key replace changing map after initialization (not recommended).
364      */
365     @Test
366     public void testReplaceChangedMap() {
367         final StrSubstitutor sub = new StrSubstitutor(values);
368         values.put("target", "moon");
369         assertEquals("The quick brown fox jumps over the moon.", sub.replace("The ${animal} jumps over the ${target}."));
370     }
371 
372     /**
373      * Tests complex escaping.
374      */
375     @Test
376     public void testReplaceComplexEscaping() {
377         doTestReplace("The ${quick brown fox} jumps over the lazy dog.", "The $${${animal}} jumps over the ${target}.", true);
378         doTestReplace("The ${quick brown fox} jumps over the lazy dog. ${1234567890}.", "The $${${animal}} jumps over the ${target}. $${${undefined.number:-1234567890}}.", true);
379     }
380 
381     /**
382      * Tests replace with null.
383      */
384     @Test
385     public void testReplaceEmpty() {
386         doTestNoReplace("");
387     }
388 
389     /**
390      * Tests when no variable name.
391      */
392     @Test
393     public void testReplaceEmptyKeys() {
394         doTestReplace("The ${} jumps over the lazy dog.", "The ${} jumps over the ${target}.", true);
395         doTestReplace("The animal jumps over the lazy dog.", "The ${:-animal} jumps over the ${target}.", true);
396     }
397 
398     /**
399      * Tests escaping.
400      */
401     @Test
402     public void testReplaceEscaping() {
403         doTestReplace("The ${animal} jumps over the lazy dog.", "The $${animal} jumps over the ${target}.", true);
404     }
405 
406     /**
407      * Tests when no incomplete prefix.
408      */
409     @Test
410     public void testReplaceIncompletePrefix() {
411         doTestReplace("The {animal} jumps over the lazy dog.", "The {animal} jumps over the ${target}.", true);
412     }
413 
414     /**
415      * Tests whether a variable can be replaced in a variable name.
416      */
417     @Test
418     public void testReplaceInVariable() {
419         values.put("animal.1", "fox");
420         values.put("animal.2", "mouse");
421         values.put("species", "2");
422         final StrSubstitutor sub = new StrSubstitutor(values);
423         sub.setEnableSubstitutionInVariables(true);
424         assertEquals(
425                 "The mouse jumps over the lazy dog.",
426                 sub.replace("The ${animal.${species}} jumps over the ${target}."),
427                 "Wrong result (1)");
428         values.put("species", "1");
429         assertEquals(
430                 "The fox jumps over the lazy dog.",
431                 sub.replace("The ${animal.${species}} jumps over the ${target}."),
432                 "Wrong result (2)");
433         assertEquals(
434                 "The fox jumps over the lazy dog.",
435                 sub.replace("The ${unknown.animal.${unknown.species:-1}:-fox} jumps over the ${unknown.target:-lazy dog}."),
436                 "Wrong result (3)");
437     }
438 
439     /**
440      * Tests whether substitution in variable names is disabled per default.
441      */
442     @Test
443     public void testReplaceInVariableDisabled() {
444         values.put("animal.1", "fox");
445         values.put("animal.2", "mouse");
446         values.put("species", "2");
447         final StrSubstitutor sub = new StrSubstitutor(values);
448         assertEquals(
449                 "The ${animal.${species}} jumps over the lazy dog.",
450                 sub.replace("The ${animal.${species}} jumps over the ${target}."),
451                 "Wrong result (1)");
452         assertEquals(
453                 "The ${animal.${species:-1}} jumps over the lazy dog.",
454                 sub.replace("The ${animal.${species:-1}} jumps over the ${target}."),
455                 "Wrong result (2)");
456     }
457 
458     /**
459      * Tests complex and recursive substitution in variable names.
460      */
461     @Test
462     public void testReplaceInVariableRecursive() {
463         values.put("animal.2", "brown fox");
464         values.put("animal.1", "white mouse");
465         values.put("color", "white");
466         values.put("species.white", "1");
467         values.put("species.brown", "2");
468         final StrSubstitutor sub = new StrSubstitutor(values);
469         sub.setEnableSubstitutionInVariables(true);
470         assertEquals(
471                 "The white mouse jumps over the lazy dog.",
472                 sub.replace("The ${animal.${species.${color}}} jumps over the ${target}."),
473                 "Wrong result (1)");
474         assertEquals(
475                 "The brown fox jumps over the lazy dog.",
476                 sub.replace("The ${animal.${species.${unknownColor:-brown}}} jumps over the ${target}."),
477                 "Wrong result (2)");
478     }
479 
480     /**
481      * Tests when no prefix or suffix.
482      */
483     @Test
484     public void testReplaceNoPrefixNoSuffix() {
485         doTestReplace("The animal jumps over the lazy dog.", "The animal jumps over the ${target}.", true);
486     }
487 
488     /**
489      * Tests when suffix but no prefix.
490      */
491     @Test
492     public void testReplaceNoPrefixSuffix() {
493         doTestReplace("The animal} jumps over the lazy dog.", "The animal} jumps over the ${target}.", true);
494     }
495 
496     /**
497      * Tests replace with no variables.
498      */
499     @Test
500     public void testReplaceNoVariables() {
501         doTestNoReplace("The balloon arrived.");
502     }
503 
504     /**
505      * Tests replace with null.
506      */
507     @Test
508     public void testReplaceNull() {
509         doTestNoReplace(null);
510     }
511 
512     /**
513      * Tests simple key replace.
514      */
515     @Test
516     public void testReplacePartialString_noReplace() {
517         final StrSubstitutor sub = new StrSubstitutor();
518         assertEquals("${animal} jumps", sub.replace("The ${animal} jumps over the ${target}.", 4, 15));
519     }
520 
521     /**
522      * Tests when prefix but no suffix.
523      */
524     @Test
525     public void testReplacePrefixNoSuffix() {
526         doTestReplace("The ${animal jumps over the ${target} lazy dog.", "The ${animal jumps over the ${target} ${target}.", true);
527     }
528 
529     /**
530      * Tests simple recursive replace.
531      */
532     @Test
533     public void testReplaceRecursive() {
534         values.put("animal", "${critter}");
535         values.put("target", "${pet}");
536         values.put("pet", "${petCharacteristic} dog");
537         values.put("petCharacteristic", "lazy");
538         values.put("critter", "${critterSpeed} ${critterColor} ${critterType}");
539         values.put("critterSpeed", "quick");
540         values.put("critterColor", "brown");
541         values.put("critterType", "fox");
542         doTestReplace("The quick brown fox jumps over the lazy dog.", "The ${animal} jumps over the ${target}.", true);
543 
544         values.put("pet", "${petCharacteristicUnknown:-lazy} dog");
545         doTestReplace("The quick brown fox jumps over the lazy dog.", "The ${animal} jumps over the ${target}.", true);
546     }
547 
548     /**
549      * Tests simple key replace.
550      */
551     @Test
552     public void testReplaceSimple() {
553         doTestReplace("The quick brown fox jumps over the lazy dog.", "The ${animal} jumps over the ${target}.", true);
554     }
555 
556     /**
557      * Tests simple key replace.
558      */
559     @Test
560     public void testReplaceSolo() {
561         doTestReplace("quick brown fox", "${animal}", false);
562     }
563 
564     /**
565      * Tests escaping.
566      */
567     @Test
568     public void testReplaceSoloEscaping() {
569         doTestReplace("${animal}", "$${animal}", false);
570     }
571 
572     /**
573      * Tests replace creates output same as input.
574      */
575     @Test
576     public void testReplaceToIdentical() {
577         values.put("animal", "$${${thing}}");
578         values.put("thing", "animal");
579         doTestReplace("The ${animal} jumps.", "The ${animal} jumps.", true);
580     }
581 
582     /**
583      * Tests unknown key replace.
584      */
585     @Test
586     public void testReplaceUnknownKey() {
587         doTestReplace("The ${person} jumps over the lazy dog.", "The ${person} jumps over the ${target}.", true);
588         doTestReplace("The ${person} jumps over the lazy dog. 1234567890.", "The ${person} jumps over the ${target}. ${undefined.number:-1234567890}.", true);
589     }
590 
591     /**
592      * Tests interpolation with weird boundary patterns.
593      */
594     @Test
595     public void testReplaceWeirdPattens() {
596         doTestNoReplace("");
597         doTestNoReplace("${}");
598         doTestNoReplace("${ }");
599         doTestNoReplace("${\t}");
600         doTestNoReplace("${\n}");
601         doTestNoReplace("${\b}");
602         doTestNoReplace("${");
603         doTestNoReplace("$}");
604         doTestNoReplace("}");
605         doTestNoReplace("${}$");
606         doTestNoReplace("${${");
607         doTestNoReplace("${${}}");
608         doTestNoReplace("${$${}}");
609         doTestNoReplace("${$$${}}");
610         doTestNoReplace("${$$${$}}");
611         doTestNoReplace("${${}}");
612         doTestNoReplace("${${ }}");
613     }
614 
615     /**
616      * Tests protected.
617      */
618     @Test
619     public void testResolveVariable() {
620         final StrBuilder builder = new StrBuilder("Hi ${name}!");
621         final Map<String, String> map = new HashMap<>();
622         map.put("name", "commons");
623         final StrSubstitutor sub = new StrSubstitutor(map) {
624             @Override
625             protected String resolveVariable(final String variableName, final StrBuilder buf, final int startPos, final int endPos) {
626                 assertEquals("name", variableName);
627                 assertSame(builder, buf);
628                 assertEquals(3, startPos);
629                 assertEquals(10, endPos);
630                 return "jakarta";
631             }
632         };
633         sub.replaceIn(builder);
634         assertEquals("Hi jakarta!", builder.toString());
635     }
636 
637     @Test
638     public void testSamePrefixAndSuffix() {
639         final Map<String, String> map = new HashMap<>();
640         map.put("greeting", "Hello");
641         map.put(" there ", "XXX");
642         map.put("name", "commons");
643         assertEquals("Hi commons!", StrSubstitutor.replace("Hi @name@!", map, "@", "@"));
644         assertEquals("Hello there commons!", StrSubstitutor.replace("@greeting@ there @name@!", map, "@", "@"));
645     }
646 
647     /**
648      * Tests static.
649      */
650     @Test
651     public void testStaticReplace() {
652         final Map<String, String> map = new HashMap<>();
653         map.put("name", "commons");
654         assertEquals("Hi commons!", StrSubstitutor.replace("Hi ${name}!", map));
655     }
656 
657     /**
658      * Tests static.
659      */
660     @Test
661     public void testStaticReplacePrefixSuffix() {
662         final Map<String, String> map = new HashMap<>();
663         map.put("name", "commons");
664         assertEquals("Hi commons!", StrSubstitutor.replace("Hi <name>!", map, "<", ">"));
665     }
666 
667     /**
668      * Tests interpolation with system properties.
669      */
670     @Test
671     public void testStaticReplaceSystemProperties() {
672         final StrBuilder buf = new StrBuilder();
673         buf.append("Hi ").append(System.getProperty("user.name"));
674         buf.append(", you are working with ");
675         buf.append(System.getProperty("os.name"));
676         buf.append(", your home directory is ");
677         buf.append(System.getProperty("user.home")).append('.');
678         assertEquals(buf.toString(), StrSubstitutor.replaceSystemProperties("Hi ${user.name}, you are "
679             + "working with ${os.name}, your home "
680             + "directory is ${user.home}."));
681     }
682 
683     /**
684      * Test the replace of a properties object
685      */
686     @Test
687     public void testSubstituteDefaultProperties() {
688         final String org = "${doesnotwork}";
689         System.setProperty("doesnotwork", "It works!");
690 
691         // create a new Properties object with the System.getProperties as default
692         final Properties props = new Properties(System.getProperties());
693 
694         assertEquals("It works!", StrSubstitutor.replace(org, props));
695     }
696 
697     @Test
698     public void testSubstitutePreserveEscape() {
699         final String org = "${not-escaped} $${escaped}";
700         final Map<String, String> map = new HashMap<>();
701         map.put("not-escaped", "value");
702 
703         final StrSubstitutor sub = new StrSubstitutor(map, "${", "}", '$');
704         assertFalse(sub.isPreserveEscapes());
705         assertEquals("value ${escaped}", sub.replace(org));
706 
707         sub.setPreserveEscapes(true);
708         assertTrue(sub.isPreserveEscapes());
709         assertEquals("value $${escaped}", sub.replace(org));
710     }
711 
712 }