1+ /**
2+ * Licensed to the Apache Software Foundation (ASF) under one
3+ * or more contributor license agreements. See the NOTICE file
4+ * distributed with this work for additional information
5+ * regarding copyright ownership. The ASF licenses this file
6+ * to you under the Apache License, Version 2.0 (the
7+ * "License"); you may not use this file except in compliance
8+ * with the License. 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,
13+ * software distributed under the License is distributed on an
14+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+ * KIND, either express or implied. See the License for the
16+ * specific language governing permissions and limitations
17+ * under the License.
18+ */
119package org .apache .xml .security .utils ;
220
321import org .junit .jupiter .api .AfterEach ;
1634import static org .hamcrest .Matchers .*;
1735import static org .junit .jupiter .api .Assertions .*;
1836
37+ /**
38+ * This test checks {@link XMLUtils} class methods, responsible for Base64 values formatting in XML documents.
39+ * Since it is a utility class with static methods, and it is configured with system properties,
40+ * we need to reload the class after system properties are set in each test case.
41+ * This test uses a special implementation of {@link ClassLoader} to achieve this and calls {@code XMLUtils} methods
42+ * using reflection.
43+ *
44+ * There are three methods producing Base64-encoded data in {@code XMLUtils}:
45+ * <ul>
46+ * <li>{@link XMLUtils#encodeToString(byte[])}</li>
47+ * <li>{@link XMLUtils#encodeElementValue(byte[])}</li>
48+ * <li>{@link XMLUtils#encodeStream(OutputStream)}</li> (creates a wrapper stream, which applies the same encoding
49+ * as {@code encodeToString(byte[])})
50+ * </ul>
51+ * In the tests, formatting of the outputs of these methods is checked.
52+ */
1953public class XMLUtilsTest {
2054 private static final byte [] data = new byte [60 ]; // long enough for a line break in MIME encoding
2155
@@ -24,14 +58,19 @@ public class XMLUtilsTest {
2458
2559 @ BeforeEach
2660 public void createClassLoader () {
27- /* create custom classloader to reload class in each test */
61+ /* create custom classloader to reload XMLUtils class and its nested classes in each test */
2862 ClassLoader parent = getClass ().getClassLoader ();
2963 Collection <Class <?>> classesToReload = List .of (
3064 XMLUtils .class ,
3165 XMLUtils .Base64FormattingOptions .class ,
3266 XMLUtils .Base64LineSeparator .class
3367 );
3468 classLoader = new ReloadingClassLoader (parent , classesToReload );
69+
70+ /*
71+ * XMLUtils instantiates XMLParserImpl, but its package is not exported,
72+ * thus unavailable for the new classloader.
73+ */
3574 ModuleLayer .boot ().findModule ("org.apache.santuario.xmlsec" ).orElseThrow ()
3675 .addOpens ("org.apache.xml.security.parser" , classLoader .getUnnamedModule ());
3776 }
@@ -221,10 +260,19 @@ private String encodeUsingStream(Class<?> xmlUtilsClass, byte[] bytes) throws Re
221260 }
222261 }
223262
263+ /**
264+ * This implementation of {@code ClassLoader} reloads given classes from bytecode,
265+ * even if they are already loaded by the parent class loader.
266+ */
224267 private static class ReloadingClassLoader extends ClassLoader {
225268 private Collection <String > classNames ;
226269
227- public ReloadingClassLoader (ClassLoader parent , Collection <Class <?>> classes ) {
270+ /**
271+ * Creates new class loader.
272+ * @param parent Parent class loader.
273+ * @param classes Set of classes to be forcefully reloaded
274+ */
275+ private ReloadingClassLoader (ClassLoader parent , Collection <Class <?>> classes ) {
228276 super ("TestClassLoader" , parent );
229277 this .classNames = classes .stream ().map (Class ::getName ).collect (Collectors .toSet ());
230278 }
0 commit comments