View Javadoc
1   /**
2    *
3    * Copyright 2018 The Apache Software Foundation
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    * http://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.codehaus.plexus.archiver;
18  
19  import java.io.File;
20  import java.io.IOException;
21  import java.util.Date;
22  
23  import org.codehaus.plexus.components.io.filemappers.FileMapper;
24  import org.junit.jupiter.api.AfterEach;
25  import org.junit.jupiter.api.BeforeEach;
26  import org.junit.jupiter.api.Test;
27  import org.junit.jupiter.api.io.TempDir;
28  
29  import static org.junit.jupiter.api.Assertions.assertEquals;
30  import static org.junit.jupiter.api.Assertions.assertFalse;
31  import static org.junit.jupiter.api.Assertions.assertThrows;
32  import static org.junit.jupiter.api.Assertions.assertTrue;
33  
34  /**
35   * Unit test for {@link AbstractUnArchiver}
36   *
37   * @author <a href="mailto:karg@quipsy.de">Markus KARG</a>
38   */
39  class AbstractUnArchiverTest {
40      private AbstractUnArchiver abstractUnArchiver;
41  
42      @BeforeEach
43      void setUp() {
44          this.abstractUnArchiver = new AbstractUnArchiver() {
45              @Override
46              protected void execute(final String path, final File outputDirectory) throws ArchiverException {
47                  // unused
48              }
49  
50              @Override
51              protected void execute() throws ArchiverException {
52                  // unused
53              }
54          };
55      }
56  
57      @AfterEach
58      void tearDown() {
59          this.abstractUnArchiver = null;
60      }
61  
62      @Test
63      void shouldThrowExceptionBecauseRewrittenPathIsOutOfDirectory(@TempDir File targetFolder) throws ArchiverException {
64          // given
65  
66          // The prefix includes the target directory name to make sure we catch cases when the paths
67          // are compared as strings. For example /opt/directory starts with /opt/dir but it is
68          // sibling and not inside /opt/dir.
69          String prefix = "../" + targetFolder.getName() + "PREFIX/";
70          final FileMapper[] fileMappers = new FileMapper[] {pName -> prefix + pName, pName -> pName + ".SUFFIX"};
71  
72          // when
73          Exception exception = assertThrows(
74                  ArchiverException.class,
75                  () -> abstractUnArchiver.extractFile(
76                          null, targetFolder, null, "ENTRYNAME", null, false, null, null, fileMappers));
77          // then
78          // ArchiverException is thrown providing the rewritten path
79          assertEquals(
80                  "Entry is outside of the target directory (" + prefix + "ENTRYNAME.SUFFIX)", exception.getMessage());
81      }
82  
83      @Test
84      void shouldExtractWhenFileOnDiskDoesNotExist(@TempDir File temporaryFolder) throws IOException {
85          // given
86          File file = new File(temporaryFolder, "whatever.txt"); // does not create the file!
87          String entryname = file.getName();
88          Date entryDate = new Date();
89  
90          // when & then
91          // always extract the file if it does not exist
92          assertTrue(abstractUnArchiver.shouldExtractEntry(temporaryFolder, file, entryname, entryDate));
93          abstractUnArchiver.setOverwrite(false);
94          assertTrue(abstractUnArchiver.shouldExtractEntry(temporaryFolder, file, entryname, entryDate));
95      }
96  
97      @Test
98      void shouldExtractWhenFileOnDiskIsNewerThanEntryInArchive(@TempDir File temporaryFolder) throws IOException {
99          // given
100         File file = new File(temporaryFolder, "whatever.txt");
101         file.createNewFile();
102         file.setLastModified(System.currentTimeMillis());
103         String entryname = file.getName();
104         Date entryDate = new Date(0);
105 
106         // when & then
107         // if the file is newer than archive entry, extract only if overwrite is true (default)
108         assertTrue(this.abstractUnArchiver.shouldExtractEntry(temporaryFolder, file, entryname, entryDate));
109         abstractUnArchiver.setOverwrite(false);
110         assertFalse(this.abstractUnArchiver.shouldExtractEntry(temporaryFolder, file, entryname, entryDate));
111     }
112 
113     @Test
114     void shouldExtractWhenFileOnDiskIsNewerThanEntryInArchive_andWarnAboutDifferentCasing(@TempDir File temporaryFolder)
115             throws IOException {
116         // given
117         File file = new File(temporaryFolder, "whatever.txt");
118         file.createNewFile();
119         file.setLastModified(System.currentTimeMillis());
120         String entryname = file.getName().toUpperCase();
121         Date entryDate = new Date(0);
122 
123         // when & then
124         assertTrue(this.abstractUnArchiver.shouldExtractEntry(temporaryFolder, file, entryname, entryDate));
125         assertTrue(this.abstractUnArchiver.casingMessageEmitted.get() > 0);
126     }
127 
128     @Test
129     void shouldExtractWhenEntryInArchiveIsNewerThanFileOnDisk(@TempDir File temporaryFolder) throws IOException {
130         // given
131         File file = new File(temporaryFolder, "whatever.txt");
132         file.createNewFile();
133         file.setLastModified(0);
134         String entryname = file.getName().toUpperCase();
135         Date entryDate = new Date(System.currentTimeMillis());
136 
137         // when & then
138         // always extract the file if the archive entry is newer than the file on disk
139         assertTrue(this.abstractUnArchiver.shouldExtractEntry(temporaryFolder, file, entryname, entryDate));
140         this.abstractUnArchiver.setOverwrite(false);
141         assertTrue(this.abstractUnArchiver.shouldExtractEntry(temporaryFolder, file, entryname, entryDate));
142     }
143 
144     @Test
145     void shouldExtractWhenEntryInArchiveIsNewerThanFileOnDiskAndWarnAboutDifferentCasing(@TempDir File temporaryFolder)
146             throws IOException {
147         // given
148         File file = new File(temporaryFolder, "whatever.txt");
149         file.createNewFile();
150         file.setLastModified(0);
151         String entryname = file.getName().toUpperCase();
152         Date entryDate = new Date(System.currentTimeMillis());
153 
154         // when & then
155         this.abstractUnArchiver.setOverwrite(true);
156         assertTrue(this.abstractUnArchiver.shouldExtractEntry(temporaryFolder, file, entryname, entryDate));
157         this.abstractUnArchiver.setOverwrite(false);
158         assertTrue(this.abstractUnArchiver.shouldExtractEntry(temporaryFolder, file, entryname, entryDate));
159         assertTrue(this.abstractUnArchiver.casingMessageEmitted.get() > 0);
160     }
161 
162     @Test
163     void shouldNotWarnAboutDifferentCasingForDirectoryEntries(@TempDir File temporaryFolder) throws IOException {
164         // given
165         File file = new File(temporaryFolder, "whatever.txt");
166         file.createNewFile();
167         file.setLastModified(0);
168         String entryname = file.getName() + '/'; // archive entries for directories end with a '/'
169         Date entryDate = new Date();
170 
171         // when & then
172         this.abstractUnArchiver.setOverwrite(true);
173         assertTrue(this.abstractUnArchiver.shouldExtractEntry(temporaryFolder, file, entryname, entryDate));
174         assertEquals(0, this.abstractUnArchiver.casingMessageEmitted.get());
175     }
176 
177     @Test
178     void shouldExtractWhenCasingDifferOnlyInEntryNamePath(@TempDir File temporaryFolder) throws IOException {
179         // given
180         String entryName = "directory/whatever.txt";
181         File file = new File(temporaryFolder, entryName); // does not create the file!
182         file.mkdirs();
183         file.createNewFile();
184         Date entryDate = new Date(System.currentTimeMillis() + 5000);
185 
186         // when & then
187         abstractUnArchiver.setOverwrite(true);
188         assertTrue(abstractUnArchiver.shouldExtractEntry(temporaryFolder, file, entryName, entryDate));
189         assertEquals(0, abstractUnArchiver.casingMessageEmitted.get());
190     }
191 }