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  
18  package org.apache.commons.text.lookup;
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.assertInstanceOf;
23  import static org.junit.jupiter.api.Assertions.assertNotNull;
24  import static org.junit.jupiter.api.Assertions.assertNull;
25  import static org.junit.jupiter.api.Assertions.assertThrows;
26  
27  import java.nio.file.Path;
28  import java.nio.file.Paths;
29  import java.util.Collections;
30  import java.util.HashMap;
31  import java.util.Map;
32  
33  import javax.xml.XMLConstants;
34  
35  import org.apache.commons.lang3.StringUtils;
36  import org.apache.commons.text.StringSubstitutor;
37  import org.junit.jupiter.api.Test;
38  import org.junitpioneer.jupiter.SetSystemProperty;
39  
40  /**
41   * Tests {@link XmlStringLookup}.
42   */
43  class XmlStringLookupTest {
44  
45      static final String DATA = "Hello World!";
46      static final Map<String, Boolean> EMPTY_MAP = Collections.emptyMap();
47      private static final Path CURRENT_PATH = Paths.get(StringUtils.EMPTY); // NOT "."
48      private static final Path ABSENT_PATH = Paths.get("does not exist at all");
49      static final String DOC_DIR = "src/test/resources/org/apache/commons/text/";
50      private static final String DOC_RELATIVE = DOC_DIR + "document.xml";
51      private static final String DOC_ROOT = "/document.xml";
52  
53      static void assertLookup(final StringLookup xmlStringLookup) {
54          assertNotNull(xmlStringLookup);
55          assertInstanceOf(XmlStringLookup.class, xmlStringLookup);
56          assertEquals(DATA, xmlStringLookup.apply(DOC_RELATIVE + ":/root/path/to/node"));
57          assertNull(xmlStringLookup.apply(null));
58      }
59  
60      @Test
61      void testBadXPath() {
62          assertThrows(IllegalArgumentException.class, () -> XmlStringLookup.INSTANCE.apply("docName"));
63      }
64  
65      @Test
66      void testExternalEntityOff() {
67          assertThrows(IllegalArgumentException.class,
68                  () -> new XmlStringLookup(XmlStringLookup.DEFAULT_XML_FEATURES, EMPTY_MAP).apply(DOC_DIR + "document-entity-ref.xml:/document/content"));
69      }
70  
71      @Test
72      void testExternalEntityOn() {
73          final String key = DOC_DIR + "document-entity-ref.xml:/document/content";
74          assertEquals(DATA, new XmlStringLookup(EMPTY_MAP, EMPTY_MAP).apply(key).trim());
75          assertEquals(DATA, new XmlStringLookup(EMPTY_MAP, XmlStringLookup.DEFAULT_XPATH_FEATURES).apply(key).trim());
76      }
77  
78      @Test
79      void testInterpolatorExternalDtdOff() {
80          final StringSubstitutor stringSubstitutor = StringSubstitutor.createInterpolator();
81          assertThrows(IllegalArgumentException.class, () -> stringSubstitutor.replace("${xml:" + DOC_DIR + "document-external-dtd.xml:/document/content}"));
82      }
83  
84      @Test
85      @SetSystemProperty(key = "javax.xml.accessExternalDTD", value = "file")
86      void testInterpolatorExternalDtdOn() {
87          final StringSubstitutor stringSubstitutor = StringSubstitutor.createInterpolator();
88          assertEquals("This is an external entity.", stringSubstitutor.replace("${xml:" + DOC_DIR + "document-external-dtd.xml:/document/content}").trim());
89      }
90  
91      @Test
92      void testInterpolatorExternalEntityOff() {
93          final StringSubstitutor stringSubstitutor = StringSubstitutor.createInterpolator();
94          assertThrows(IllegalArgumentException.class, () -> stringSubstitutor.replace("${xml:" + DOC_DIR + "document-entity-ref.xml:/document/content}"));
95      }
96  
97      @Test
98      @SetSystemProperty(key = "javax.xml.accessExternalDTD", value = "file")
99      void testInterpolatorExternalEntityOffOverride() {
100         final StringSubstitutor stringSubstitutor = StringSubstitutor.createInterpolator();
101         assertEquals(DATA, stringSubstitutor.replace("${xml:" + DOC_DIR + "document-entity-ref.xml:/document/content}").trim());
102     }
103 
104     @Test
105     void testInterpolatorExternalEntityOn() {
106         final StringSubstitutor stringSubstitutor = StringSubstitutor.createInterpolator();
107         assertThrows(IllegalArgumentException.class, () -> stringSubstitutor.replace("${xml:" + DOC_DIR + "document-entity-ref.xml:/document/content}"));
108     }
109 
110     @Test
111     void testInterpolatorExternalEntityOnOverride() {
112         final StringSubstitutor stringSubstitutor = StringSubstitutor.createInterpolator();
113         assertThrows(IllegalArgumentException.class, () -> stringSubstitutor.replace("${xml:" + DOC_DIR + "document-entity-ref.xml:/document/content}"));
114     }
115 
116     @Test
117     void testInterpolatorSecureOnBla() {
118         final StringSubstitutor stringSubstitutor = StringSubstitutor.createInterpolator();
119         assertThrows(IllegalArgumentException.class, () -> stringSubstitutor.replace("${xml:" + DOC_DIR + "bla.xml:/document/content}"));
120         // Using XmlStringLookup.secure=false allows the BLA to occur.
121     }
122 
123     @Test
124     void testMissingXPath() {
125         assertThrows(IllegalArgumentException.class, () -> XmlStringLookup.INSTANCE.apply(DOC_RELATIVE + ":!JUNK!"));
126     }
127 
128     @Test
129     void testNoFeatures() {
130         final String xpath = "/root/path/to/node";
131         assertEquals(DATA, new XmlStringLookup(EMPTY_MAP, EMPTY_MAP).apply(DOC_RELATIVE + ":" + xpath));
132         assertEquals(DATA, new XmlStringLookup(EMPTY_MAP, EMPTY_MAP).apply(DOC_RELATIVE + ":" + xpath));
133         assertEquals(DATA, new XmlStringLookup(EMPTY_MAP, EMPTY_MAP, CURRENT_PATH, ABSENT_PATH).apply(DOC_RELATIVE + ":" + xpath));
134         assertEquals(DATA, new XmlStringLookup(EMPTY_MAP, EMPTY_MAP, ABSENT_PATH, CURRENT_PATH).apply(DOC_RELATIVE + ":" + xpath));
135         assertThrows(IllegalArgumentException.class, () -> new XmlStringLookup(EMPTY_MAP, EMPTY_MAP, ABSENT_PATH).apply(DOC_ROOT + ":" + xpath));
136         assertThrows(IllegalArgumentException.class, () -> new XmlStringLookup(EMPTY_MAP, EMPTY_MAP, CURRENT_PATH).apply(DOC_ROOT + ":" + xpath));
137         assertThrows(IllegalArgumentException.class, () -> new XmlStringLookup(EMPTY_MAP, EMPTY_MAP, ABSENT_PATH, CURRENT_PATH).apply(DOC_ROOT + ":" + xpath));
138     }
139 
140     @Test
141     void testNoFeaturesDefault() {
142         final HashMap<String, Boolean> features = new HashMap<>(1);
143         features.put(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
144         assertLookup(new XmlStringLookup(EMPTY_MAP, features));
145     }
146 
147     @Test
148     void testNull() {
149         assertNull(XmlStringLookup.INSTANCE.apply(null));
150     }
151 
152     @Test
153     void testOne() {
154         assertLookup(XmlStringLookup.INSTANCE);
155     }
156 
157     @Test
158     void testToString() {
159         // does not blow up and gives some kind of string.
160         assertFalse(XmlStringLookup.INSTANCE.toString().isEmpty());
161     }
162 }