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.configuration2.io;
18  
19  import static org.apache.commons.configuration2.TempDirUtils.newFile;
20  import static org.apache.commons.configuration2.TempDirUtils.newFolder;
21  import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
22  import static org.junit.jupiter.api.Assertions.assertEquals;
23  import static org.junit.jupiter.api.Assertions.assertFalse;
24  import static org.junit.jupiter.api.Assertions.assertNotNull;
25  import static org.junit.jupiter.api.Assertions.assertNull;
26  import static org.junit.jupiter.api.Assertions.assertSame;
27  import static org.junit.jupiter.api.Assertions.assertThrows;
28  import static org.junit.jupiter.api.Assertions.assertTrue;
29  import static org.mockito.Mockito.doThrow;
30  import static org.mockito.Mockito.mock;
31  import static org.mockito.Mockito.verify;
32  import static org.mockito.Mockito.verifyNoMoreInteractions;
33  import static org.mockito.Mockito.when;
34  
35  import java.io.ByteArrayInputStream;
36  import java.io.ByteArrayOutputStream;
37  import java.io.File;
38  import java.io.FileOutputStream;
39  import java.io.FileReader;
40  import java.io.FileWriter;
41  import java.io.IOException;
42  import java.io.InputStream;
43  import java.io.Reader;
44  import java.io.StringReader;
45  import java.io.StringWriter;
46  import java.io.Writer;
47  import java.net.MalformedURLException;
48  import java.net.URI;
49  import java.net.URL;
50  import java.nio.charset.StandardCharsets;
51  import java.nio.file.Files;
52  import java.nio.file.Path;
53  import java.util.Arrays;
54  import java.util.HashMap;
55  import java.util.List;
56  import java.util.Map;
57  
58  import org.apache.commons.configuration2.ConfigurationAssert;
59  import org.apache.commons.configuration2.PropertiesConfiguration;
60  import org.apache.commons.configuration2.SynchronizerTestImpl;
61  import org.apache.commons.configuration2.SynchronizerTestImpl.Methods;
62  import org.apache.commons.configuration2.ex.ConfigurationException;
63  import org.junit.jupiter.api.Test;
64  import org.junit.jupiter.api.io.TempDir;
65  
66  /**
67   * Test class for {@code FileHandler}.
68   */
69  public class TestFileHandler {
70  
71      /**
72       * A FileBased implementation which also implements FileLocatorAware. This class adds information about the current file
73       * locator to the content read and written.
74       */
75      private static final class FileBasedFileLocatorAwareTestImpl extends FileBasedTestImpl implements FileLocatorAware {
76  
77          /** Stores the passed in file locator. */
78          private FileLocator locator;
79  
80          /**
81           * Returns the locator.
82           *
83           * @return the file locator
84           */
85          public FileLocator getLocator() {
86              return locator;
87          }
88  
89          @Override
90          public void initFileLocator(final FileLocator loc) {
91              this.locator = loc;
92          }
93  
94          @Override
95          public void read(final Reader in) throws ConfigurationException, IOException {
96              super.read(in);
97              setContent(String.valueOf(locator.getSourceURL()) + ": " + getContent());
98          }
99  
100         @Override
101         public void write(final Writer out) throws ConfigurationException, IOException {
102             out.write(String.valueOf(locator.getSourceURL()) + ": ");
103             super.write(out);
104         }
105     }
106 
107     /**
108      * A test implementation of FileBased which can also read from input streams.
109      * <p>
110      * Cannot be final for Mockito.
111      * </p>
112      */
113     private static class FileBasedInputStreamSupportTestImpl extends FileBasedTestImpl implements InputStreamSupport {
114         @Override
115         public void read(final InputStream in) throws ConfigurationException, IOException {
116             final ByteArrayOutputStream bos = new ByteArrayOutputStream();
117             int c;
118             while ((c = in.read()) != -1) {
119                 bos.write(c);
120             }
121             setContent("InputStream = " + bos.toString());
122         }
123     }
124 
125     /**
126      * An implementation of the FileBased interface used for test purposes.
127      */
128     private static class FileBasedTestImpl implements FileBased {
129 
130         /** The content read from a reader. */
131         private String content = CONTENT;
132 
133         /**
134          * Returns the content read from a reader.
135          *
136          * @return the read content
137          */
138         public String getContent() {
139             return content;
140         }
141 
142         @Override
143         public void read(final Reader in) throws ConfigurationException, IOException {
144             content = readReader(in);
145         }
146 
147         /**
148          * Sets the content.
149          *
150          * @param content the content
151          */
152         public void setContent(final String content) {
153             this.content = content;
154         }
155 
156         @Override
157         public void write(final Writer out) throws ConfigurationException, IOException {
158             out.write(getContent());
159             out.flush();
160         }
161     }
162 
163     /**
164      * A test listener implementation.
165      */
166     private static final class FileHandlerListenerTestImpl extends FileHandlerListenerAdapter {
167 
168         /** The expected file handler. */
169         private final FileHandler expHandler;
170 
171         /** A buffer for recording method invocations. */
172         private final StringBuilder methods;
173 
174         public FileHandlerListenerTestImpl(final FileHandler fh) {
175             expHandler = fh;
176             methods = new StringBuilder();
177         }
178 
179         /**
180          * Tests whether the expected listener methods have been called.
181          *
182          * @param expMethods the expected methods as plain string
183          */
184         public void checkMethods(final String expMethods) {
185             assertEquals(expMethods, methods.toString());
186         }
187 
188         @Override
189         public void loaded(final FileHandler handler) {
190             super.loaded(handler);
191             methodCalled(handler, "loaded");
192         }
193 
194         @Override
195         public void loading(final FileHandler handler) {
196             super.loading(handler);
197             methodCalled(handler, "loading");
198         }
199 
200         @Override
201         public void locationChanged(final FileHandler handler) {
202             super.locationChanged(handler);
203             methodCalled(handler, "locationChanged");
204         }
205 
206         /**
207          * One of the listener methods was called. Records this invocation.
208          *
209          * @param handler the file handler
210          * @param method the called method
211          */
212         private void methodCalled(final FileHandler handler, final String method) {
213             assertEquals(expHandler, handler);
214             methods.append(method);
215         }
216 
217         @Override
218         public void saved(final FileHandler handler) {
219             super.saved(handler);
220             methodCalled(handler, "saved");
221         }
222 
223         @Override
224         public void saving(final FileHandler handler) {
225             super.saving(handler);
226             methodCalled(handler, "saving");
227         }
228     }
229 
230     /** Constant for the name of a test file. */
231     private static final String TEST_FILENAME = "test.properties";
232 
233     /** Constant for content of the test file. */
234     private static final String CONTENT = "TestFileHandler: This is test content.";
235 
236     /**
237      * Checks a FileLocator which is expected to contain no data.
238      *
239      * @param content the data object which was passed the locator
240      */
241     private static void checkEmptyLocator(final FileBasedFileLocatorAwareTestImpl content) {
242         assertNull(content.getLocator().getSourceURL());
243         assertNull(content.getLocator().getBasePath());
244         assertNull(content.getLocator().getFileName());
245     }
246 
247     /**
248      * Reads the content of the specified file into a string
249      *
250      * @param f the file to be read
251      * @return the content of this file
252      */
253     private static String readFile(final File f) {
254         return assertDoesNotThrow(() -> {
255             try (Reader in = new FileReader(f)) {
256                 return readReader(in);
257             }
258         });
259     }
260 
261     /**
262      * Reads the content of the specified reader into a string.
263      *
264      * @param in the reader
265      * @return the read content
266      * @throws IOException if an error occurs
267      */
268     private static String readReader(final Reader in) throws IOException {
269         final StringBuilder buf = new StringBuilder();
270         int c;
271         while ((c = in.read()) != -1) {
272             buf.append((char) c);
273         }
274         return buf.toString();
275     }
276 
277     /** A folder for temporary files. */
278     @TempDir
279     public File tempFolder;
280 
281     /**
282      * Creates a test file with the test content.
283      *
284      * @return the File object pointing to the test file
285      */
286     private File createTestFile() {
287         return createTestFile(null);
288     }
289 
290     /**
291      * Creates a test file with test content and allows specifying a file name.
292      *
293      * @param f the file to be created (may be <strong>null</strong>)
294      * @return the File object pointing to the test file
295      */
296     private File createTestFile(final File f) {
297         return assertDoesNotThrow(() -> {
298             File file = f;
299             if (file == null) {
300                 file = newFile(tempFolder);
301             }
302             try (Writer out = new FileWriter(file)) {
303                 out.write(CONTENT);
304             }
305             return file;
306         });
307     }
308 
309     private Path createTestPath() {
310         return createTestFile().toPath();
311     }
312 
313     private URI createTestURI() {
314         return createTestFile().toURI();
315     }
316 
317     private URL createTestURL() throws MalformedURLException {
318         return createTestURI().toURL();
319     }
320 
321     /**
322      * Tries to add a null listener.
323      */
324     @Test
325     void testAddFileHandlerListenerNull() {
326         final FileHandler fileHandler = new FileHandler();
327         assertThrows(IllegalArgumentException.class, () -> fileHandler.addFileHandlerListener(null));
328     }
329 
330     /**
331      * Tries to invoke the assignment constructor with a null handler.
332      */
333     @Test
334     void testAssignNullHandler() {
335         final FileBased obj = new FileBasedTestImpl();
336         assertThrows(IllegalArgumentException.class, () -> new FileHandler(obj, null));
337     }
338 
339     /**
340      * Tests whether a FileHandler object can be used to specify a location and later be assigned to a FileBased object.
341      */
342     @Test
343     void testAssignWithFileBased() {
344         final FileHandler h1 = new FileHandler();
345         final File f = new File("testfile.txt");
346         h1.setFile(f);
347         final FileBased content = new FileBasedTestImpl();
348         final FileHandler h2 = new FileHandler(content, h1);
349         h1.setFileName("someOtherFile.txt");
350         assertSame(content, h2.getContent());
351         assertEquals(f, h2.getFile());
352     }
353 
354     /**
355      * Tests whether the location can be cleared.
356      */
357     @Test
358     void testClearLocation() {
359         final FileHandler handler = new FileHandler();
360         handler.setFile(createTestFile());
361         handler.clearLocation();
362         assertFalse(handler.isLocationDefined());
363         assertNull(handler.getFile());
364         assertNull(handler.getURL());
365         assertNull(handler.getBasePath());
366         assertNull(handler.getPath());
367     }
368 
369     /**
370      * Tests getBasePath() if no information is available.
371      */
372     @Test
373     void testGetBasePathUndefined() {
374         assertNull(new FileHandler().getBasePath());
375     }
376 
377     /**
378      * Tests getFileName() if no information is set.
379      */
380     @Test
381     void testGetFileNameUndefined() {
382         assertNull(new FileHandler().getFileName());
383     }
384 
385     /**
386      * Tests whether a newly created instance has a default file system.
387      */
388     @Test
389     void testGetFileSystemDefault() {
390         final FileHandler handler = new FileHandler(new FileBasedTestImpl());
391         assertEquals(FileLocatorUtils.DEFAULT_FILE_SYSTEM, handler.getFileSystem());
392     }
393 
394     /**
395      * Tests whether a newly created instance uses the default location strategy.
396      */
397     @Test
398     void testGetLocationStrategyDefault() {
399         final FileHandler handler = new FileHandler();
400         assertNull(handler.getFileLocator().getLocationStrategy());
401         assertSame(FileLocatorUtils.DEFAULT_LOCATION_STRATEGY, handler.getLocationStrategy());
402     }
403 
404     /**
405      * Tests whether an instance can be created from a map with the properties of a FileLocator.
406      */
407     @Test
408     void testInitFromMap() {
409         final FileLocator locator = FileLocatorUtils.fileLocator().fileName(TEST_FILENAME).basePath("someBasePath").encoding("someEncoding").create();
410         final Map<String, Object> map = new HashMap<>();
411         FileLocatorUtils.put(locator, map);
412         final FileHandler handler = FileHandler.fromMap(map);
413         assertEquals(locator, handler.getFileLocator());
414     }
415 
416     /**
417      * Tests whether the initialization of properties is safe even if performed in multiple threads.
418      */
419     @Test
420     void testInitPropertiesMultiThreaded() throws InterruptedException {
421         final String encoding = "TestEncoding";
422         final FileSystem fileSystem = new DefaultFileSystem();
423         final FileLocationStrategy locationStrategy = new ProvidedURLLocationStrategy();
424         final int loops = 8;
425 
426         for (int i = 0; i < loops; i++) {
427             final FileHandler handler = new FileHandler();
428             final Thread t1 = new Thread(() -> handler.setFileSystem(fileSystem));
429             final Thread t2 = new Thread(() -> handler.setFileName(TEST_FILENAME));
430             final Thread t3 = new Thread(() -> handler.setEncoding(encoding));
431             final Thread t4 = new Thread(() -> handler.setLocationStrategy(locationStrategy));
432             final List<Thread> threads = Arrays.asList(t1, t2, t3, t4);
433             for (final Thread t : threads) {
434                 t.start();
435             }
436             for (final Thread t : threads) {
437                 t.join();
438             }
439             final FileLocator locator = handler.getFileLocator();
440             assertEquals(TEST_FILENAME, locator.getFileName());
441             assertNull(locator.getSourceURL());
442             assertEquals(encoding, locator.getEncoding());
443             assertSame(fileSystem, locator.getFileSystem());
444             assertSame(locationStrategy, locator.getLocationStrategy());
445         }
446     }
447 
448     /**
449      * Tests isLocationDefined() if only a base path is set.
450      */
451     @Test
452     void testIsLocationDefinedBasePathOnly() {
453         final FileHandler handler = new FileHandler();
454         handler.setBasePath(createTestFile().getParent());
455         assertFalse(handler.isLocationDefined());
456     }
457 
458     /**
459      * Tests whether an undefined location can be queried.
460      */
461     @Test
462     void testIsLocationDefinedFalse() {
463         final FileHandler handler = new FileHandler();
464         assertFalse(handler.isLocationDefined());
465     }
466 
467     /**
468      * Tests isLocationDefined() if a File has been set.
469      */
470     @Test
471     void testIsLocationDefinedFile() {
472         final FileHandler handler = new FileHandler();
473         handler.setFile(createTestFile());
474         assertTrue(handler.isLocationDefined());
475     }
476 
477     /**
478      * Tests isLocationDefined() if a file name has been set.
479      */
480     @Test
481     void testIsLocationDefinedFileName() {
482         final FileHandler handler = new FileHandler();
483         handler.setFileName(createTestFile().getName());
484         assertTrue(handler.isLocationDefined());
485     }
486 
487     /**
488      * Tests isLocationDefined() if a path has been set.
489      */
490     @Test
491     void testIsLocationDefinedPath() {
492         final FileHandler handler = new FileHandler();
493         handler.setPath(createTestFile().getAbsolutePath());
494         assertTrue(handler.isLocationDefined());
495     }
496 
497     /**
498      * Tests isLocationDefined() if a URL has been set.
499      */
500     @Test
501     void testIsLocationDefinedURL() throws IOException {
502         final FileHandler handler = new FileHandler();
503         handler.setURL(createTestURL());
504         assertTrue(handler.isLocationDefined());
505     }
506 
507     /**
508      * Tests that it is not possible to load a directory using the load() method which expects a File.
509      */
510     @Test
511     void testLoadDirectoryFile() {
512         final FileHandler handler = new FileHandler(new FileBasedTestImpl());
513         assertThrows(ConfigurationException.class, () -> handler.load(ConfigurationAssert.TEST_DIR));
514     }
515 
516     /**
517      * Checks that loading a directory instead of a file throws an exception.
518      */
519     @Test
520     void testLoadDirectoryString() {
521         final FileHandler handler = new FileHandler(new FileBasedTestImpl());
522         final String fileName = ConfigurationAssert.TEST_DIR.getAbsolutePath();
523         assertThrows(ConfigurationException.class, () -> handler.load(fileName));
524     }
525 
526     /**
527      * Tests notifications about load operations.
528      */
529     @Test
530     void testLoadEvents() throws ConfigurationException {
531         final FileHandler handler = new FileHandler(new FileBasedTestImpl());
532         final FileHandlerListenerTestImpl listener = new FileHandlerListenerTestImpl(handler);
533         handler.addFileHandlerListener(listener);
534         handler.load(createTestFile());
535         listener.checkMethods("loadingloaded");
536     }
537 
538     /**
539      * Tests whether a FileLocatorAware object is initialized correctly when loading data.
540      */
541     @Test
542     void testLoadFileLocatorAware() throws IOException, ConfigurationException {
543         final File file = createTestFile();
544         final FileBasedFileLocatorAwareTestImpl content = new FileBasedFileLocatorAwareTestImpl();
545         final FileHandler handler = new FileHandler(content);
546         handler.setFile(file);
547         handler.load();
548         assertEquals(file.toURI().toURL().toString() + ": " + CONTENT, content.getContent());
549     }
550 
551     /**
552      * Tests a load operation with a FileLocatorAware object if data is loaded from a reader.
553      */
554     @Test
555     void testLoadFileLocatorAwareReader() throws ConfigurationException {
556         final FileBasedFileLocatorAwareTestImpl content = new FileBasedFileLocatorAwareTestImpl();
557         final FileHandler handler = new FileHandler(content);
558         handler.load(new StringReader(CONTENT));
559         checkEmptyLocator(content);
560     }
561 
562     /**
563      * Tests loading with a FileLocatorAware object if data is loaded from a stream.
564      */
565     @Test
566     void testLoadFileLocatorAwareStream() throws ConfigurationException {
567         final FileBasedFileLocatorAwareTestImpl content = new FileBasedFileLocatorAwareTestImpl();
568         final FileHandler handler = new FileHandler(content);
569         final ByteArrayInputStream bos = new ByteArrayInputStream(CONTENT.getBytes());
570         handler.load(bos);
571         checkEmptyLocator(content);
572     }
573 
574     /**
575      * Tests whether whether data can be loaded from class path.
576      */
577     @Test
578     void testLoadFromClassPath() throws ConfigurationException {
579         final FileBasedTestImpl content = new FileBasedTestImpl();
580         final FileHandler config1 = new FileHandler(content);
581         config1.setFileName("config/deep/deeptest.properties");
582         config1.load();
583         assertFalse(content.getContent().isEmpty());
584     }
585 
586     /**
587      * Tests whether data from a File can be loaded.
588      */
589     @Test
590     void testLoadFromFile() throws ConfigurationException {
591         final FileBasedTestImpl content = new FileBasedTestImpl();
592         final File file = createTestFile();
593         final FileHandler handler = new FileHandler(content);
594         handler.load(file);
595         assertEquals(CONTENT, content.getContent());
596     }
597 
598     /**
599      * Tests a load operation using the current location which is a file name.
600      */
601     @Test
602     void testLoadFromFileNameLocation() throws ConfigurationException {
603         final File file = createTestFile();
604         final FileBasedTestImpl content = new FileBasedTestImpl();
605         final FileHandler handler = new FileHandler(content);
606         handler.setBasePath(file.getParentFile().getAbsolutePath());
607         handler.setFileName(file.getName());
608         handler.load();
609         assertEquals(CONTENT, content.getContent());
610     }
611 
612     /**
613      * Tries to load data from a File if no content object was set.
614      */
615     @Test
616     void testLoadFromFileNoContent() {
617         final FileHandler handler = new FileHandler();
618         final File file = createTestFile();
619         final ConfigurationException cex = assertThrows(ConfigurationException.class, () -> handler.load(file));
620         assertEquals("No content available.", cex.getMessage());
621     }
622 
623     /**
624      * Tests whether data from an absolute path can be loaded.
625      */
626     @Test
627     void testLoadFromFilePath() throws ConfigurationException {
628         final File file = createTestFile();
629         final FileBasedTestImpl content = new FileBasedTestImpl();
630         final FileHandler handler = new FileHandler(content);
631         handler.load(file.getAbsolutePath());
632         assertEquals(CONTENT, content.getContent());
633     }
634 
635     /**
636      * Tests that a load() operation with a file path overrides a URL which might have been set.
637      */
638     @Test
639     void testLoadFromFilePathWithURLDefined() throws ConfigurationException {
640         final File file = createTestFile();
641         final FileBasedTestImpl content = new FileBasedTestImpl();
642         final FileHandler handler = new FileHandler(content);
643         handler.setURL(ConfigurationAssert.getTestURL("test.xml"));
644         handler.load(file.getAbsolutePath());
645         assertEquals(CONTENT, content.getContent());
646     }
647 
648     /**
649      * Tests whether data from a reader can be read.
650      */
651     @Test
652     void testLoadFromReader() throws Exception {
653         final FileBasedTestImpl content = new FileBasedTestImpl();
654         final FileHandler handler = new FileHandler(content);
655         try (Reader in = new FileReader(createTestFile())) {
656             handler.load(in);
657         }
658         assertEquals(CONTENT, content.getContent());
659     }
660 
661     /**
662      * Tests whether an IOException is handled when loading data from a reader.
663      */
664     @Test
665     void testLoadFromReaderIOException() throws IOException, ConfigurationException {
666         final FileBased content = mock(FileBased.class);
667         final Reader in = new StringReader(CONTENT);
668         final IOException ioex = new IOException("Test exception");
669 
670         doThrow(ioex).when(content).read(in);
671 
672         final FileHandler handler = new FileHandler(content);
673         final ConfigurationException cex = assertThrows(ConfigurationException.class, () -> handler.load(in));
674         assertEquals(ioex, cex.getCause());
675 
676         verify(content).read(in);
677         verifyNoMoreInteractions(content);
678     }
679 
680     /**
681      * Tests whether data from an input stream can be read.
682      */
683     @Test
684     void testLoadFromStream() throws Exception {
685         final FileBasedTestImpl content = new FileBasedTestImpl();
686         final FileHandler handler = new FileHandler(content);
687         try (InputStream in = Files.newInputStream(createTestPath())) {
688             handler.load(in);
689         }
690         assertEquals(CONTENT, content.getContent());
691     }
692 
693     /**
694      * Tests whether data from a URL can be loaded.
695      */
696     @Test
697     void testLoadFromURL() throws Exception {
698         final FileBasedTestImpl content = new FileBasedTestImpl();
699         final FileHandler handler = new FileHandler(content);
700         handler.load(createTestURL());
701         assertEquals(CONTENT, content.getContent());
702     }
703 
704     /**
705      * Tests a load operation using the current location which is a URL.
706      */
707     @Test
708     void testLoadFromURLLocation() throws Exception {
709         final FileBasedTestImpl content = new FileBasedTestImpl();
710         final FileHandler handler = new FileHandler(content);
711         handler.setURL(createTestURL());
712         handler.load();
713         assertEquals(CONTENT, content.getContent());
714     }
715 
716     /**
717      * Tests whether data can be read from an input stream.
718      */
719     @Test
720     void testLoadInputStreamSupport() throws ConfigurationException {
721         final FileBasedInputStreamSupportTestImpl content = new FileBasedInputStreamSupportTestImpl();
722         final FileHandler handler = new FileHandler(content);
723         final ByteArrayInputStream bin = new ByteArrayInputStream(CONTENT.getBytes());
724         handler.load(bin);
725         assertEquals("InputStream = " + CONTENT, content.getContent());
726     }
727 
728     /**
729      * Tests whether an IOException is handled when reading from an input stream.
730      */
731     @Test
732     void testLoadInputStreamSupportIOException() throws ConfigurationException, IOException {
733         final FileBasedInputStreamSupportTestImpl content = mock(FileBasedInputStreamSupportTestImpl.class);
734         final ByteArrayInputStream bin = new ByteArrayInputStream(CONTENT.getBytes());
735         final IOException ioex = new IOException();
736 
737         doThrow(ioex).when(content).read(bin);
738 
739         final FileHandler handler = new FileHandler(content);
740         final ConfigurationException cex = assertThrows(ConfigurationException.class, () -> handler.load(bin));
741         assertEquals(ioex, cex.getCause());
742 
743         verify(content).read(bin);
744         verifyNoMoreInteractions(content);
745     }
746 
747     /**
748      * Tries to call a load() method if no content object is available.
749      */
750     @Test
751     void testLoadNoContent() {
752         final FileHandler handler = new FileHandler();
753         final StringReader reader = new StringReader(CONTENT);
754         assertThrows(ConfigurationException.class, () -> handler.load(reader));
755     }
756 
757     /**
758      * Tries to load data if no location has been set.
759      */
760     @Test
761     void testLoadNoLocation() {
762         final FileBasedTestImpl content = new FileBasedTestImpl();
763         final FileHandler handler = new FileHandler(content);
764         assertThrows(ConfigurationException.class, handler::load);
765     }
766 
767     /**
768      * Tests whether a load() operation is correctly synchronized.
769      */
770     @Test
771     void testLoadSynchronized() throws ConfigurationException {
772         final PropertiesConfiguration config = new PropertiesConfiguration();
773         final SynchronizerTestImpl sync = new SynchronizerTestImpl();
774         config.setSynchronizer(sync);
775         final FileHandler handler = new FileHandler(config);
776         handler.load(ConfigurationAssert.getTestFile("test.properties"));
777         sync.verifyStart(Methods.BEGIN_WRITE);
778         sync.verifyEnd(Methods.END_WRITE);
779     }
780 
781     /**
782      * Tests a successful locate() operation.
783      */
784     @Test
785     void testLocateSuccess() throws ConfigurationException {
786         final FileHandler handler = new FileHandler();
787         handler.setFileName(TEST_FILENAME);
788         assertTrue(handler.locate());
789         final FileLocator locator = handler.getFileLocator();
790         assertNotNull(locator.getSourceURL());
791         assertNotNull(locator.getBasePath());
792         assertEquals(TEST_FILENAME, locator.getFileName());
793 
794         // check whether the correct URL was obtained
795         final PropertiesConfiguration config = new PropertiesConfiguration();
796         final FileHandler h2 = new FileHandler(config);
797         h2.setURL(locator.getSourceURL());
798         h2.load();
799         assertTrue(config.getBoolean("configuration.loaded"));
800     }
801 
802     /**
803      * Tests a locate() operation if there is not enough information.
804      */
805     @Test
806     void testLocateUndefinedLocator() {
807         final FileHandler handler = new FileHandler();
808         handler.setBasePath("only/a/base/path");
809         final FileLocator locator = handler.getFileLocator();
810         assertFalse(handler.locate());
811         assertSame(locator, handler.getFileLocator());
812     }
813 
814     /**
815      * Tests a locate() operation if the specified file cannot be resolved.
816      */
817     @Test
818     void testLocateUnknownFile() {
819         final FileHandler handler = new FileHandler();
820         handler.setFileName("unknown file");
821         final FileLocator locator = handler.getFileLocator();
822         assertFalse(handler.locate());
823         assertSame(locator, handler.getFileLocator());
824     }
825 
826     /**
827      * Tests a notification about a changed base path.
828      */
829     @Test
830     void testLocationChangedBasePath() {
831         final FileHandler handler = new FileHandler();
832         final FileHandlerListenerTestImpl listener = new FileHandlerListenerTestImpl(handler);
833         handler.addFileHandlerListener(listener);
834         handler.setBasePath(TEST_FILENAME);
835         listener.checkMethods("locationChanged");
836     }
837 
838     /**
839      * Tests a notification about a changed encoding.
840      */
841     @Test
842     void testLocationChangedEncoding() {
843         final FileHandler handler = new FileHandler();
844         final FileHandlerListenerTestImpl listener = new FileHandlerListenerTestImpl(handler);
845         handler.addFileHandlerListener(listener);
846         handler.setEncoding(StandardCharsets.UTF_8.name());
847         listener.checkMethods("locationChanged");
848     }
849 
850     /**
851      * Tests a notification about a changed file.
852      */
853     @Test
854     void testLocationChangedFile() throws IOException {
855         final FileHandler handler = new FileHandler();
856         final FileHandlerListenerTestImpl listener = new FileHandlerListenerTestImpl(handler);
857         handler.addFileHandlerListener(listener);
858         handler.setFile(newFile(tempFolder));
859         listener.checkMethods("locationChanged");
860     }
861 
862     /**
863      * Tests a notification about a changed file name.
864      */
865     @Test
866     void testLocationChangedFileName() {
867         final FileHandler handler = new FileHandler();
868         final FileHandlerListenerTestImpl listener = new FileHandlerListenerTestImpl(handler);
869         handler.addFileHandlerListener(listener);
870         handler.setFileName(TEST_FILENAME);
871         listener.checkMethods("locationChanged");
872     }
873 
874     /**
875      * Tests a notification about a changed file system.
876      */
877     @Test
878     void testLocationChangedFileSystem() {
879         final FileSystem fs = mock(FileSystem.class);
880         final FileHandler handler = new FileHandler();
881         final FileHandlerListenerTestImpl listener = new FileHandlerListenerTestImpl(handler);
882         handler.addFileHandlerListener(listener);
883         handler.setFileSystem(fs);
884         listener.checkMethods("locationChanged");
885     }
886 
887     /**
888      * Tests whether a notification is sent if the whole locator was changed.
889      */
890     @Test
891     void testLocationChangedLocator() {
892         final FileHandler handler = new FileHandler();
893         final FileHandlerListenerTestImpl listener = new FileHandlerListenerTestImpl(handler);
894         handler.addFileHandlerListener(listener);
895         handler.setFileLocator(FileLocatorUtils.fileLocator().fileName(TEST_FILENAME).create());
896         listener.checkMethods("locationChanged");
897     }
898 
899     /**
900      * Tests a notification about a changed path.
901      */
902     @Test
903     void testLocationChangedPath() {
904         final FileHandler handler = new FileHandler();
905         final FileHandlerListenerTestImpl listener = new FileHandlerListenerTestImpl(handler);
906         handler.addFileHandlerListener(listener);
907         handler.setPath(TEST_FILENAME);
908         listener.checkMethods("locationChanged");
909     }
910 
911     /**
912      * Tests a notification about a changed URL.
913      */
914     @Test
915     void testLocationChangedURL() throws IOException {
916         final FileHandler handler = new FileHandler();
917         final FileHandlerListenerTestImpl listener = new FileHandlerListenerTestImpl(handler);
918         handler.addFileHandlerListener(listener);
919         final URL url = newFile(tempFolder).toURI().toURL();
920         handler.setURL(url);
921         listener.checkMethods("locationChanged");
922     }
923 
924     /**
925      * Tests that the locator injected into the content object has an encoding set.
926      */
927     @Test
928     void testLocatorAwareEncoding() throws ConfigurationException {
929         final FileBasedFileLocatorAwareTestImpl content = new FileBasedFileLocatorAwareTestImpl();
930         final FileHandler handler = new FileHandler(content);
931         final String encoding = "testEncoding";
932         handler.setEncoding(encoding);
933         handler.save(new StringWriter());
934         assertEquals(encoding, content.getLocator().getEncoding());
935     }
936 
937     /**
938      * Tests whether file names containing a "+" character are handled correctly. This test is related to CONFIGURATION-415.
939      */
940     @Test
941     void testPathWithPlus() throws ConfigurationException, IOException {
942         final File saveFile = newFile("test+config.properties", tempFolder);
943         final FileHandler handler = new FileHandler(new FileBasedTestImpl());
944         handler.setFile(saveFile);
945         handler.save();
946         assertEquals(CONTENT, readFile(saveFile));
947     }
948 
949     /**
950      * Tests loading and saving a configuration file with a complicated path name including spaces. (related to issue 35210)
951      */
952     @Test
953     void testPathWithSpaces() throws ConfigurationException, IOException {
954         final File path = newFolder("path with spaces", tempFolder);
955         final File confFile = new File(path, "config-test.properties");
956         final File testFile = createTestFile(confFile);
957         final URL url = testFile.toURI().toURL();
958         final FileBasedTestImpl content = new FileBasedTestImpl();
959         final FileHandler handler = new FileHandler(content);
960         handler.setURL(url);
961         handler.load();
962         assertEquals(CONTENT, content.getContent());
963         final File out = new File(path, "out.txt");
964         handler.save(out);
965         assertEquals(CONTENT, readFile(out));
966     }
967 
968     /**
969      * Tests whether the file system can be reset.
970      */
971     @Test
972     void testResetFileSystem() {
973         final FileSystem sys = mock(FileSystem.class);
974         final FileHandler handler = new FileHandler(new FileBasedTestImpl());
975         handler.setFileSystem(sys);
976         handler.resetFileSystem();
977         assertEquals(FileLocatorUtils.DEFAULT_FILE_SYSTEM, handler.getFileSystem());
978     }
979 
980     /**
981      * Tests notifications about save operations.
982      */
983     @Test
984     void testSaveEvents() throws IOException, ConfigurationException {
985         final FileHandler handler = new FileHandler(new FileBasedTestImpl());
986         final FileHandlerListenerTestImpl listener = new FileHandlerListenerTestImpl(handler);
987         handler.addFileHandlerListener(listener);
988         final File f = newFile(tempFolder);
989         handler.save(f);
990         listener.checkMethods("savingsaved");
991     }
992 
993     /**
994      * Tests whether a FileLocatorAware is correctly handled when saving data.
995      */
996     @Test
997     void testSaveFileLocatorAware() throws ConfigurationException, IOException {
998         final File file = newFile(tempFolder);
999         final FileBasedFileLocatorAwareTestImpl content = new FileBasedFileLocatorAwareTestImpl();
1000         final FileHandler handler = new FileHandler(content);
1001         handler.save(file);
1002         assertEquals(file.toURI().toURL() + ": " + CONTENT, readFile(file));
1003     }
1004 
1005     /**
1006      * Tests a save operation with a FileLocatorAware object if the target is a stream.
1007      */
1008     @Test
1009     void testSaveFileLocatorAwareToStream() throws ConfigurationException {
1010         final FileBasedFileLocatorAwareTestImpl content = new FileBasedFileLocatorAwareTestImpl();
1011         final FileHandler handler = new FileHandler(content);
1012         handler.save(new ByteArrayOutputStream());
1013         checkEmptyLocator(content);
1014     }
1015 
1016     /**
1017      * Tests a save operation with a FileLocatorAware object if the target is a writer.
1018      */
1019     @Test
1020     void testSaveFileLocatorAwareToWriter() throws ConfigurationException {
1021         final FileBasedFileLocatorAwareTestImpl content = new FileBasedFileLocatorAwareTestImpl();
1022         final FileHandler handler = new FileHandler(content);
1023         handler.save(new StringWriter());
1024         checkEmptyLocator(content);
1025     }
1026 
1027     /**
1028      * Tries to save the locator if no location has been set.
1029      */
1030     @Test
1031     void testSaveNoLocation() {
1032         final FileHandler handler = new FileHandler(new FileBasedTestImpl());
1033         assertThrows(ConfigurationException.class, handler::save);
1034     }
1035 
1036     /**
1037      * Tests whether a save() operation is correctly synchronized.
1038      */
1039     @Test
1040     void testSaveSynchronized() throws ConfigurationException, IOException {
1041         final PropertiesConfiguration config = new PropertiesConfiguration();
1042         config.addProperty("test.synchronized", Boolean.TRUE);
1043         final SynchronizerTestImpl sync = new SynchronizerTestImpl();
1044         config.setSynchronizer(sync);
1045         final FileHandler handler = new FileHandler(config);
1046         final File f = newFile(tempFolder);
1047         handler.save(f);
1048         sync.verify(Methods.BEGIN_WRITE, Methods.END_WRITE);
1049     }
1050 
1051     /**
1052      * Tests whether data can be saved to a file.
1053      */
1054     @Test
1055     void testSaveToFile() throws ConfigurationException, IOException {
1056         final File file = newFile(tempFolder);
1057         final FileHandler handler = new FileHandler(new FileBasedTestImpl());
1058         handler.save(file);
1059         assertEquals(CONTENT, readFile(file));
1060     }
1061 
1062     /**
1063      * Tests whether data can be saved to a file name.
1064      */
1065     @Test
1066     void testSaveToFileName() throws ConfigurationException, IOException {
1067         final File file = newFile(tempFolder);
1068         final FileHandler handler = new FileHandler(new FileBasedTestImpl());
1069         handler.save(file.getAbsolutePath());
1070         assertEquals(CONTENT, readFile(file));
1071     }
1072 
1073     /**
1074      * Tests whether data can be saved to the internal location if it is a file name.
1075      */
1076     @Test
1077     void testSaveToFileNameLocation() throws ConfigurationException, IOException {
1078         final File file = newFile(tempFolder);
1079         final FileHandler handler = new FileHandler(new FileBasedTestImpl());
1080         handler.setFileName(file.getAbsolutePath());
1081         handler.save();
1082         assertEquals(CONTENT, readFile(file));
1083     }
1084 
1085     /**
1086      * Tests whether a URL exception is handled when saving a file to a file name.
1087      */
1088     @Test
1089     void testSaveToFileNameURLException() throws IOException {
1090         final FileSystem fs = mock(FileSystem.class);
1091         final File file = newFile(tempFolder);
1092         final String basePath = "some base path";
1093         final MalformedURLException urlex = new MalformedURLException("Test exception");
1094         final String fileName = file.getName();
1095 
1096         when(fs.getURL(basePath, fileName)).thenThrow(urlex);
1097 
1098         final FileHandler handler = new FileHandler(new FileBasedTestImpl());
1099         handler.setBasePath(basePath);
1100         handler.setFileSystem(fs);
1101         final ConfigurationException cex = assertThrows(ConfigurationException.class, () -> handler.save(fileName));
1102         assertEquals(urlex, cex.getCause());
1103 
1104         verify(fs).getURL(basePath, fileName);
1105         verifyNoMoreInteractions(fs);
1106     }
1107 
1108     /**
1109      * Tries to save data to a file name if the name cannot be located.
1110      */
1111     @Test
1112     void testSaveToFileNameURLNotResolved() throws IOException {
1113         final FileSystem fs = mock(FileSystem.class);
1114         final File file = newFile(tempFolder);
1115         final String fileName = file.getName();
1116 
1117         when(fs.getURL(null, fileName)).thenReturn(null);
1118 
1119         final FileHandler handler = new FileHandler(new FileBasedTestImpl());
1120         handler.setFileSystem(fs);
1121         assertThrows(ConfigurationException.class, () -> handler.save(fileName));
1122 
1123         verify(fs).getURL(null, fileName);
1124         verifyNoMoreInteractions(fs);
1125     }
1126 
1127     /**
1128      * Tests whether data can be saved to a stream.
1129      */
1130     @Test
1131     void testSaveToStream() throws ConfigurationException, IOException {
1132         final File file = newFile(tempFolder);
1133         try (FileOutputStream out = new FileOutputStream(file)) {
1134             final FileHandler handler = new FileHandler(new FileBasedTestImpl());
1135             handler.save(out);
1136         }
1137         assertEquals(CONTENT, readFile(file));
1138     }
1139 
1140     /**
1141      * Tests whether data can be saved to a URL.
1142      */
1143     @Test
1144     void testSaveToURL() throws Exception {
1145         final File file = newFile(tempFolder);
1146         final URL url = file.toURI().toURL();
1147         final FileHandler handler = new FileHandler(new FileBasedTestImpl());
1148         handler.save(url);
1149         assertEquals(CONTENT, readFile(file));
1150     }
1151 
1152     /**
1153      * Tests whether data can be saved to the internal location if it is a URL.
1154      */
1155     @Test
1156     void testSaveToURLLocation() throws ConfigurationException, IOException {
1157         final File file = newFile(tempFolder);
1158         final FileHandler handler = new FileHandler(new FileBasedTestImpl());
1159         handler.setURL(file.toURI().toURL());
1160         handler.save();
1161         assertEquals(CONTENT, readFile(file));
1162     }
1163 
1164     /**
1165      * Tests whether data can be saved into a Writer.
1166      */
1167     @Test
1168     void testSaveToWriter() throws ConfigurationException {
1169         final FileBasedTestImpl content = new FileBasedTestImpl();
1170         final FileHandler handler = new FileHandler(content);
1171         final StringWriter out = new StringWriter();
1172         handler.save(out);
1173         assertEquals(CONTENT, out.toString());
1174     }
1175 
1176     /**
1177      * Tests whether an I/O exception during a save operation to a Writer is handled correctly.
1178      */
1179     @Test
1180     void testSaveToWriterIOException() throws ConfigurationException, IOException {
1181         final FileBased content = mock(FileBased.class);
1182         final StringWriter out = new StringWriter();
1183         final IOException ioex = new IOException("Test exception.");
1184 
1185         doThrow(ioex).when(content).write(out);
1186 
1187         final FileHandler handler = new FileHandler(content);
1188         final ConfigurationException cex = assertThrows(ConfigurationException.class, () -> handler.save(out));
1189         assertEquals(ioex, cex.getCause());
1190 
1191         verify(content).write(out);
1192         verifyNoMoreInteractions(content);
1193     }
1194 
1195     /**
1196      * Tries to save something to a Writer if no content is set.
1197      */
1198     @Test
1199     void testSaveToWriterNoContent() {
1200         final FileHandler handler = new FileHandler();
1201         final StringWriter writer = new StringWriter();
1202         assertThrows(ConfigurationException.class, () -> handler.save(writer));
1203     }
1204 
1205     /**
1206      * Tests whether a base path can be set and whether this removes an already set URL.
1207      */
1208     @Test
1209     void testSetBasePath() {
1210         final FileHandler handler = new FileHandler();
1211         handler.setURL(ConfigurationAssert.getTestURL(TEST_FILENAME));
1212         final String basePath = ConfigurationAssert.TEST_DIR_NAME;
1213         handler.setBasePath(basePath);
1214         final FileLocator locator = handler.getFileLocator();
1215         assertEquals(basePath, locator.getBasePath());
1216         assertNull(locator.getSourceURL());
1217         assertNull(locator.getFileName());
1218     }
1219 
1220     /**
1221      * Tests whether the file scheme is corrected when setting the base path.
1222      */
1223     @Test
1224     void testSetBasePathFileScheme() {
1225         final FileHandler handler = new FileHandler();
1226         handler.setBasePath("file:/test/path/");
1227         assertEquals("file:///test/path/", handler.getFileLocator().getBasePath());
1228     }
1229 
1230     /**
1231      * Tests whether the location can be set as a file.
1232      */
1233     @Test
1234     void testSetFile() {
1235         final FileHandler handler = new FileHandler();
1236         final File directory = ConfigurationAssert.TEST_DIR;
1237         final File file = ConfigurationAssert.getTestFile(TEST_FILENAME);
1238         handler.setFile(file);
1239         assertEquals(directory.getAbsolutePath(), handler.getBasePath());
1240         assertEquals(TEST_FILENAME, handler.getFileName());
1241         assertEquals(file.getAbsolutePath(), handler.getPath());
1242     }
1243 
1244     /**
1245      * Tests whether the handler can be initialized using a FileLocator.
1246      */
1247     @Test
1248     void testSetFileLocator() {
1249         final FileLocator locator = FileLocatorUtils.fileLocator().fileName(TEST_FILENAME).create();
1250         final FileHandler handler = new FileHandler();
1251         handler.setFileLocator(locator);
1252         assertEquals(TEST_FILENAME, handler.getFileName());
1253     }
1254 
1255     /**
1256      * Tries to set the FileLocator to null.
1257      */
1258     @Test
1259     void testSetFileLocatorNull() {
1260         final FileHandler handler = new FileHandler();
1261         assertThrows(IllegalArgumentException.class, () -> handler.setFileLocator(null));
1262     }
1263 
1264     /**
1265      * Tests whether the location can be set using file name and base path.
1266      */
1267     @Test
1268     void testSetFileName() {
1269         final FileHandler handler = new FileHandler();
1270         handler.setURL(ConfigurationAssert.getTestURL(TEST_FILENAME));
1271         handler.setFileName(TEST_FILENAME);
1272         assertNull(handler.getBasePath());
1273         assertEquals(TEST_FILENAME, handler.getFileName());
1274         assertEquals(TEST_FILENAME, handler.getFileLocator().getFileName());
1275         assertNull(handler.getFileLocator().getSourceURL());
1276     }
1277 
1278     /**
1279      * Tests whether the file scheme is corrected when setting the file name.
1280      */
1281     @Test
1282     void testSetFileNameFileScheme() {
1283         final FileHandler handler = new FileHandler();
1284         handler.setFileName("file:/test/path/test.txt");
1285         assertEquals("file:///test/path/test.txt", handler.getFileLocator().getFileName());
1286     }
1287 
1288     /**
1289      * Tests whether a null file system can be set to reset this property.
1290      */
1291     @Test
1292     void testSetFileSystemNull() {
1293         final FileSystem sys = mock(FileSystem.class);
1294         final FileHandler handler = new FileHandler(new FileBasedTestImpl());
1295         handler.setFileSystem(sys);
1296         assertSame(sys, handler.getFileSystem());
1297         handler.setFileSystem(null);
1298         assertEquals(FileLocatorUtils.DEFAULT_FILE_SYSTEM, handler.getFileSystem());
1299     }
1300 
1301     /**
1302      * Tests whether the location strategy can be changed.
1303      */
1304     @Test
1305     void testSetLocationStrategy() {
1306         final FileLocationStrategy strategy = mock(FileLocationStrategy.class);
1307         final FileHandler handler = new FileHandler();
1308         handler.setLocationStrategy(strategy);
1309         assertSame(strategy, handler.getFileLocator().getLocationStrategy());
1310         assertSame(strategy, handler.getLocationStrategy());
1311     }
1312 
1313     /**
1314      * Tests whether the location can be set as a file.
1315      */
1316     @Test
1317     void testSetPath() throws MalformedURLException {
1318         final FileHandler handler = new FileHandler();
1319         handler.setPath(ConfigurationAssert.TEST_DIR_NAME + File.separator + TEST_FILENAME);
1320         assertEquals(TEST_FILENAME, handler.getFileName());
1321         assertEquals(ConfigurationAssert.TEST_DIR.getAbsolutePath(), handler.getBasePath());
1322         final File file = ConfigurationAssert.getTestFile(TEST_FILENAME);
1323         assertEquals(file.getAbsolutePath(), handler.getPath());
1324         assertEquals(file.toURI().toURL(), handler.getURL());
1325         assertNull(handler.getFileLocator().getSourceURL());
1326     }
1327 
1328     /**
1329      * Additional tests for setting file names in various ways. (Copied from the test for XMLConfiguration)
1330      */
1331     @Test
1332     void testSettingFileNames() {
1333         final String testProperties = ConfigurationAssert.getTestFile("test.xml").getAbsolutePath();
1334         final String testBasePath = ConfigurationAssert.TEST_DIR.getAbsolutePath();
1335 
1336         final FileHandler handler = new FileHandler();
1337         handler.setFileName(testProperties);
1338         assertEquals(testProperties.toString(), handler.getFileName());
1339 
1340         handler.setBasePath(testBasePath);
1341         handler.setFileName("hello.xml");
1342         assertEquals("hello.xml", handler.getFileName());
1343         assertEquals(testBasePath.toString(), handler.getBasePath());
1344         assertEquals(new File(testBasePath, "hello.xml"), handler.getFile());
1345 
1346         handler.setBasePath(testBasePath);
1347         handler.setFileName("subdir/hello.xml");
1348         assertEquals("subdir/hello.xml", handler.getFileName());
1349         assertEquals(testBasePath.toString(), handler.getBasePath());
1350         assertEquals(new File(testBasePath, "subdir/hello.xml"), handler.getFile());
1351     }
1352 
1353     /**
1354      * Tests whether a URL can be set.
1355      */
1356     @Test
1357     void testSetURL() throws Exception {
1358         final FileHandler handler = new FileHandler();
1359         handler.setURL(new URL("https://commons.apache.org/configuration/index.html"));
1360 
1361         assertEquals("https://commons.apache.org/configuration/", handler.getBasePath());
1362         assertEquals("index.html", handler.getFileName());
1363         assertNull(handler.getFileLocator().getFileName());
1364     }
1365 
1366     /**
1367      * Tests whether the correct file scheme is applied.
1368      */
1369     @Test
1370     void testSetURLFileScheme() throws MalformedURLException {
1371         final FileHandler handler = new FileHandler();
1372         // file URL - This url is invalid, a valid url would be
1373         // file:///temp/test.properties.
1374         handler.setURL(new URL("file:/temp/test.properties"));
1375         assertEquals("file:///temp/", handler.getBasePath());
1376         assertEquals(TEST_FILENAME, handler.getFileName());
1377     }
1378 
1379     /**
1380      * Tests whether a null URL can be set.
1381      */
1382     @Test
1383     void testSetURLNull() {
1384         final FileHandler handler = new FileHandler();
1385         handler.setURL(ConfigurationAssert.getTestURL(TEST_FILENAME));
1386         handler.setURL(null);
1387         final FileLocator locator = handler.getFileLocator();
1388         assertNull(locator.getBasePath());
1389         assertNull(locator.getFileName());
1390         assertNull(locator.getSourceURL());
1391     }
1392 
1393     /**
1394      * Tests whether a URL with parameters can be set.
1395      */
1396     @Test
1397     void testSetURLWithParams() throws Exception {
1398         final FileHandler handler = new FileHandler();
1399         final URL url = new URL("https://issues.apache.org/bugzilla/show_bug.cgi?id=37886");
1400         handler.setURL(url);
1401         assertEquals("https://issues.apache.org/bugzilla/", handler.getBasePath());
1402         assertEquals("show_bug.cgi", handler.getFileName());
1403         assertEquals(url, handler.getURL());
1404     }
1405 }