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