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.text.lookup;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertNotNull;
21  import static org.junit.jupiter.api.Assertions.assertSame;
22  import static org.junit.jupiter.api.Assertions.assertThrows;
23  import static org.junit.jupiter.api.Assertions.assertTrue;
24  
25  import java.util.HashMap;
26  import java.util.HashSet;
27  import java.util.Locale;
28  import java.util.Map;
29  import java.util.Properties;
30  import java.util.Set;
31  
32  import javax.xml.XMLConstants;
33  
34  import org.junit.jupiter.api.Test;
35  import org.junitpioneer.jupiter.SetSystemProperty;
36  
37  /**
38   * Tests {@link StringLookupFactory}.
39   */
40  class StringLookupFactoryTest {
41  
42      public static void assertDefaultKeys(final Map<String, StringLookup> stringLookupMap) {
43          // included
44          assertMappedLookups(stringLookupMap,
45                  "base64",
46                  StringLookupFactory.KEY_BASE64_DECODER,
47                  StringLookupFactory.KEY_BASE64_ENCODER,
48                  StringLookupFactory.KEY_CONST,
49                  StringLookupFactory.KEY_DATE,
50                  StringLookupFactory.KEY_ENV,
51                  StringLookupFactory.KEY_FILE,
52                  StringLookupFactory.KEY_JAVA,
53                  StringLookupFactory.KEY_LOCALHOST,
54                  StringLookupFactory.KEY_LOOPBACK_ADDRESS,
55                  StringLookupFactory.KEY_PROPERTIES,
56                  StringLookupFactory.KEY_RESOURCE_BUNDLE,
57                  StringLookupFactory.KEY_SYS,
58                  StringLookupFactory.KEY_URL_DECODER,
59                  StringLookupFactory.KEY_URL_ENCODER,
60                  StringLookupFactory.KEY_XML,
61                  StringLookupFactory.KEY_XML_DECODER,
62                  StringLookupFactory.KEY_XML_ENCODER);
63      }
64  
65      private static void assertMappedLookups(final Map<String, StringLookup> lookupMap, final String... keys) {
66          final Set<String> remainingKeys = new HashSet<>(lookupMap.keySet());
67          for (final String key : keys) {
68              final String normalizedKey = StringLookupFactory.toKey(key);
69              assertNotNull(normalizedKey, () -> "Expected map to contain string lookup for key " + key);
70              remainingKeys.remove(normalizedKey);
71          }
72          assertTrue(remainingKeys.isEmpty(), () -> "Unexpected keys in lookup map: " + remainingKeys);
73      }
74  
75      private static void checkDefaultStringLookupsHolder(final Properties props, final String... keys) {
76          final StringLookupFactory.DefaultStringLookupsHolder holder = new StringLookupFactory.DefaultStringLookupsHolder(props);
77          final Map<String, StringLookup> lookupMap = holder.getDefaultStringLookups();
78          assertMappedLookups(lookupMap, keys);
79      }
80  
81      /**
82       * Main method used to verify the default string lookups resolved during JVM execution.
83       * @param args
84       */
85      public static void main(final String[] args) {
86          final Map<String, StringLookup> lookupMap = new HashMap<>();
87          StringLookupFactory.INSTANCE.addDefaultStringLookups(lookupMap);
88          System.out.println("Default string lookups");
89          for (final String key : lookupMap.keySet()) {
90              System.out.println("- " + key);
91          }
92      }
93  
94      @Test
95      void testAddDefaultStringLookupsMap() {
96          final Map<String, StringLookup> stringLookupMap = new HashMap<>();
97          StringLookupFactory.INSTANCE.addDefaultStringLookups(stringLookupMap);
98          assertDefaultKeys(stringLookupMap);
99      }
100 
101     @Test
102     void testAddDefaultStringLookupsNull() {
103         StringLookupFactory.INSTANCE.addDefaultStringLookups(null);
104     }
105 
106     /**
107      * Tests that we return the singleton.
108      */
109     @Test
110     void testDefault() {
111         final StringLookupFactory stringLookupFactory = StringLookupFactory.INSTANCE;
112         final Map<String, StringLookup> stringLookupMap = new HashMap<>();
113         stringLookupFactory.addDefaultStringLookups(stringLookupMap);
114         assertTrue(stringLookupMap.containsKey("base64"));
115         assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_BASE64_ENCODER.toLowerCase(Locale.ROOT)));
116         assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_CONST.toLowerCase(Locale.ROOT)));
117         assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_DATE));
118         assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_ENV.toLowerCase(Locale.ROOT)));
119         assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_FILE.toLowerCase(Locale.ROOT)));
120         assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_JAVA.toLowerCase(Locale.ROOT)));
121         assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_LOCALHOST.toLowerCase(Locale.ROOT)));
122         assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_LOOPBACK_ADDRESS.toLowerCase(Locale.ROOT)));
123         assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_PROPERTIES.toLowerCase(Locale.ROOT)));
124         assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_RESOURCE_BUNDLE.toLowerCase(Locale.ROOT)));
125         assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_SYS.toLowerCase(Locale.ROOT)));
126         assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_URL_DECODER.toLowerCase(Locale.ROOT)));
127         assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_URL_ENCODER.toLowerCase(Locale.ROOT)));
128         assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_XML.toLowerCase(Locale.ROOT)));
129         assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_XML_DECODER.toLowerCase(Locale.ROOT)));
130         assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_XML_ENCODER.toLowerCase(Locale.ROOT)));
131     }
132 
133     @Test
134     void testDefaultStringLookupsHolder_allLookups() {
135         final Properties props = new Properties();
136         props.setProperty(StringLookupFactory.DEFAULT_STRING_LOOKUPS_PROPERTY, "BASE64_DECODER BASE64_ENCODER const, date, dns, environment "
137                 + "file ,java, local_host properties, resource_bundle,script,system_properties url url_decoder  , url_encoder, xml");
138         // @formatter:off
139         checkDefaultStringLookupsHolder(props,
140                 "base64",
141                 StringLookupFactory.KEY_BASE64_DECODER,
142                 StringLookupFactory.KEY_BASE64_ENCODER,
143                 StringLookupFactory.KEY_CONST,
144                 StringLookupFactory.KEY_DATE,
145                 StringLookupFactory.KEY_ENV,
146                 StringLookupFactory.KEY_FILE,
147                 StringLookupFactory.KEY_JAVA,
148                 StringLookupFactory.KEY_LOCALHOST,
149                 StringLookupFactory.KEY_LOOPBACK_ADDRESS,
150                 StringLookupFactory.KEY_PROPERTIES,
151                 StringLookupFactory.KEY_RESOURCE_BUNDLE,
152                 StringLookupFactory.KEY_SYS,
153                 StringLookupFactory.KEY_URL_DECODER,
154                 StringLookupFactory.KEY_URL_ENCODER,
155                 StringLookupFactory.KEY_XML,
156 
157                 StringLookupFactory.KEY_DNS,
158                 StringLookupFactory.KEY_URL,
159                 StringLookupFactory.KEY_SCRIPT);
160         // @formatter:on
161     }
162 
163     @Test
164     void testDefaultStringLookupsHolder_givenSingleLookup() {
165         final Properties props = new Properties();
166         props.setProperty(StringLookupFactory.DEFAULT_STRING_LOOKUPS_PROPERTY, "base64_encoder");
167         checkDefaultStringLookupsHolder(props, "base64", StringLookupFactory.KEY_BASE64_ENCODER);
168     }
169 
170     @Test
171     void testDefaultStringLookupsHolder_givenSingleLookup_weirdString() {
172         final Properties props = new Properties();
173         props.setProperty(StringLookupFactory.DEFAULT_STRING_LOOKUPS_PROPERTY, " \n \t  ,, DnS , , ");
174         checkDefaultStringLookupsHolder(props, StringLookupFactory.KEY_DNS);
175     }
176 
177     @Test
178     void testDefaultStringLookupsHolder_invalidLookupsDefinition() {
179         final Properties props = new Properties();
180         props.setProperty(StringLookupFactory.DEFAULT_STRING_LOOKUPS_PROPERTY, "base64_encoder nope");
181         final Exception exc = assertThrows(IllegalArgumentException.class, () -> new StringLookupFactory.DefaultStringLookupsHolder(props));
182         assertEquals("Invalid default string lookups definition: base64_encoder nope", exc.getMessage());
183     }
184 
185     @Test
186     void testDefaultStringLookupsHolder_lookupsPropertyEmptyAndBlank() {
187         final Properties propsWithNull = new Properties();
188         propsWithNull.setProperty(StringLookupFactory.DEFAULT_STRING_LOOKUPS_PROPERTY, "");
189         checkDefaultStringLookupsHolder(propsWithNull);
190         final Properties propsWithBlank = new Properties();
191         propsWithBlank.setProperty(StringLookupFactory.DEFAULT_STRING_LOOKUPS_PROPERTY, " ");
192         checkDefaultStringLookupsHolder(propsWithBlank);
193     }
194 
195     @Test
196     void testDefaultStringLookupsHolder_lookupsPropertyNotPresent() {
197         // @formatter:off
198         checkDefaultStringLookupsHolder(new Properties(),
199                 "base64",
200                 StringLookupFactory.KEY_BASE64_DECODER,
201                 StringLookupFactory.KEY_BASE64_ENCODER,
202                 StringLookupFactory.KEY_CONST,
203                 StringLookupFactory.KEY_DATE,
204                 StringLookupFactory.KEY_ENV,
205                 StringLookupFactory.KEY_FILE,
206                 StringLookupFactory.KEY_JAVA,
207                 StringLookupFactory.KEY_LOCALHOST,
208                 StringLookupFactory.KEY_LOOPBACK_ADDRESS,
209                 StringLookupFactory.KEY_PROPERTIES,
210                 StringLookupFactory.KEY_RESOURCE_BUNDLE,
211                 StringLookupFactory.KEY_SYS,
212                 StringLookupFactory.KEY_URL_DECODER,
213                 StringLookupFactory.KEY_URL_ENCODER,
214                 StringLookupFactory.KEY_XML,
215                 StringLookupFactory.KEY_XML_DECODER,
216                 StringLookupFactory.KEY_XML_ENCODER);
217         // @formatter:on
218     }
219 
220     @Test
221     void testDefaultStringLookupsHolder_multipleLookups() {
222         final Properties props = new Properties();
223         props.setProperty(StringLookupFactory.DEFAULT_STRING_LOOKUPS_PROPERTY, "dns, url script ");
224         // @formatter:off
225         checkDefaultStringLookupsHolder(props,
226                 StringLookupFactory.KEY_DNS,
227                 StringLookupFactory.KEY_URL,
228                 StringLookupFactory.KEY_SCRIPT);
229         // @formatter:on
230     }
231 
232     /**
233      * Tests that we return the singleton.
234      */
235     @Test
236     void testSingletons() {
237         final StringLookupFactory stringLookupFactory = StringLookupFactory.INSTANCE;
238         assertSame(StringLookupFactory.INSTANCE_BASE64_DECODER, stringLookupFactory.base64DecoderStringLookup());
239         assertSame(StringLookupFactory.INSTANCE_BASE64_ENCODER, stringLookupFactory.base64EncoderStringLookup());
240         assertSame(ConstantStringLookup.INSTANCE, stringLookupFactory.constantStringLookup());
241         assertSame(DateStringLookup.INSTANCE, stringLookupFactory.dateStringLookup());
242         assertSame(DnsStringLookup.INSTANCE, stringLookupFactory.dnsStringLookup());
243         assertSame(StringLookupFactory.INSTANCE_ENVIRONMENT_VARIABLES, stringLookupFactory.environmentVariableStringLookup());
244         assertSame(InterpolatorStringLookup.INSTANCE, stringLookupFactory.interpolatorStringLookup());
245         assertSame(JavaPlatformStringLookup.INSTANCE, stringLookupFactory.javaPlatformStringLookup());
246         assertSame(InetAddressStringLookup.LOCAL_HOST, stringLookupFactory.localHostStringLookup());
247         assertSame(InetAddressStringLookup.LOOPACK_ADDRESS, stringLookupFactory.loopbackAddressStringLookup());
248         assertSame(StringLookupFactory.INSTANCE_NULL, stringLookupFactory.nullStringLookup());
249         assertSame(ResourceBundleStringLookup.INSTANCE, stringLookupFactory.resourceBundleStringLookup());
250         assertSame(ScriptStringLookup.INSTANCE, stringLookupFactory.scriptStringLookup());
251         assertSame(StringLookupFactory.INSTANCE_SYSTEM_PROPERTIES, stringLookupFactory.systemPropertyStringLookup());
252         assertSame(UrlDecoderStringLookup.INSTANCE, stringLookupFactory.urlDecoderStringLookup());
253         assertSame(UrlEncoderStringLookup.INSTANCE, stringLookupFactory.urlEncoderStringLookup());
254         assertSame(UrlStringLookup.INSTANCE, stringLookupFactory.urlStringLookup());
255         assertSame(XmlStringLookup.INSTANCE, stringLookupFactory.xmlStringLookup());
256         assertSame(XmlDecoderStringLookup.INSTANCE, stringLookupFactory.xmlDecoderStringLookup());
257         assertSame(XmlEncoderStringLookup.INSTANCE, stringLookupFactory.xmlEncoderStringLookup());
258     }
259 
260     @Test
261     void testXmlStringLookup() {
262         final StringLookupFactory stringLookupFactory = StringLookupFactory.INSTANCE;
263         final HashMap<String, Boolean> features = new HashMap<>(1);
264         features.put(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
265         XmlStringLookupTest.assertLookup(stringLookupFactory.xmlStringLookup(features));
266         XmlStringLookupTest.assertLookup(stringLookupFactory.xmlStringLookup(new HashMap<>()));
267     }
268 
269     @Test
270     void testXmlStringLookupExternalEntityOff() {
271         assertThrows(IllegalArgumentException.class,
272                 () -> StringLookupFactory.INSTANCE.xmlStringLookup().apply(XmlStringLookupTest.DOC_DIR + "document-entity-ref.xml:/document/content"));
273     }
274 
275     @Test
276     @SetSystemProperty(key = "XmlStringLookup.secure", value = "false")
277     void testXmlStringLookupExternalEntityOn() {
278         final String key = XmlStringLookupTest.DOC_DIR + "document-entity-ref.xml:/document/content";
279         assertEquals(XmlStringLookupTest.DATA, StringLookupFactory.INSTANCE.xmlStringLookup(XmlStringLookupTest.EMPTY_MAP).apply(key).trim());
280     }
281 
282 }