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.net.ftp.parser;
18  
19  import static org.junit.jupiter.api.Assertions.assertFalse;
20  import static org.junit.jupiter.api.Assertions.assertNotNull;
21  import static org.junit.jupiter.api.Assertions.assertNull;
22  import static org.junit.jupiter.api.Assertions.assertTrue;
23  
24  import java.text.SimpleDateFormat;
25  import java.time.Instant;
26  import java.util.Calendar;
27  import java.util.Locale;
28  
29  import org.apache.commons.net.ftp.FTPFile;
30  import org.apache.commons.net.ftp.FTPFileEntryParser;
31  import org.junit.jupiter.api.BeforeEach;
32  import org.junit.jupiter.api.Test;
33  
34  /**
35   */
36  public abstract class AbstractFTPParseTest {
37      // associate Calendar unit ints with a readable string
38      // MUST be listed least significant first, as the routine needs to
39      // find the previous - less significant - entry
40      protected enum CalendarUnit {
41          MILLISECOND(Calendar.MILLISECOND), SECOND(Calendar.SECOND), MINUTE(Calendar.MINUTE), HOUR_OF_DAY(Calendar.HOUR_OF_DAY),
42          DAY_OF_MONTH(Calendar.DAY_OF_MONTH), MONTH(Calendar.MONTH), YEAR(Calendar.YEAR);
43  
44          final int unit;
45  
46          CalendarUnit(final int calUnit) {
47              unit = calUnit;
48          }
49      }
50  
51      private FTPFileEntryParser parser;
52  
53      protected SimpleDateFormat df;
54  
55      /**
56       * during processing you could hook here to do additional tests
57       *
58       * @param test raw entry
59       * @param f    parsed entry
60       */
61      protected void doAdditionalBadTests(final String test, final FTPFile f) {
62      }
63  
64      /**
65       * during processing you could hook here to do additional tests
66       *
67       * @param test raw entry
68       * @param f    parsed entry
69       */
70      protected void doAdditionalGoodTests(final String test, final FTPFile f) {
71      }
72  
73      /**
74       * Method getBadListing. Implementors must provide a listing that contains failures.
75       *
76       * @return String[]
77       */
78      protected abstract String[] getBadListing();
79  
80      /**
81       * Method getGoodListing. Implementors must provide a listing that passes.
82       *
83       * @return String[]
84       */
85      protected abstract String[] getGoodListing();
86  
87      /**
88       * Method getParser. Provide the parser to use for testing.
89       *
90       * @return FTPFileEntryParser
91       */
92      protected abstract FTPFileEntryParser getParser();
93  
94      /**
95       * Check if FTPFile entry parsing failed; i.e. if entry is null or date is null.
96       *
97       * @param f FTPFile entry - may be null
98       * @return null if f is null or the date is null
99       */
100     protected FTPFile nullFileOrNullDate(final FTPFile f) {
101         if (f == null || f.getTimestamp() == null) {
102             return null;
103         }
104         return f;
105     }
106 
107     @BeforeEach
108     protected void setUp() throws Exception {
109         parser = getParser();
110         df = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy", Locale.US);
111     }
112 
113     @Test
114     void testBadListing() {
115 
116         final String[] badsamples = getBadListing();
117         for (final String test : badsamples) {
118 
119             final FTPFile f = parser.parseFTPEntry(test);
120             assertNull(nullFileOrNullDate(f), "Should have Failed to parse <" + test + ">");
121 
122             doAdditionalBadTests(test, f);
123         }
124     }
125 
126     // Force subclasses to test precision
127     abstract void testDefaultPrecision();
128 
129     @Test
130     void testGoodListing() {
131 
132         final String[] goodsamples = getGoodListing();
133         for (final String test : goodsamples) {
134 
135             final FTPFile f = parser.parseFTPEntry(test);
136             assertNotNull(f, "Failed to parse " + test);
137 
138             doAdditionalGoodTests(test, f);
139         }
140     }
141 
142     /**
143      * Method testParseFieldsOnDirectory. Provide a test to show that fields on a directory entry are parsed correctly.
144      *
145      * @throws Exception on error
146      */
147     abstract void testParseFieldsOnDirectory() throws Exception;
148 
149     /**
150      * Method testParseFieldsOnFile. Provide a test to show that fields on a file entry are parsed correctly.
151      *
152      * @throws Exception on error
153      */
154     abstract void testParseFieldsOnFile() throws Exception;
155 
156     protected void testPrecision(final String listEntry, final CalendarUnit expectedPrecision) {
157         final FTPFile file = getParser().parseFTPEntry(listEntry);
158         assertNotNull(file, "Could not parse " + listEntry);
159         final Calendar stamp = file.getTimestamp();
160         assertNotNull(stamp, "Failed to parse time in " + listEntry);
161         final Instant instant = file.getTimestampInstant();
162         assertNotNull(instant, "Failed to parse time in " + listEntry);
163         final int ordinal = expectedPrecision.ordinal();
164         final CalendarUnit[] values = CalendarUnit.values();
165         // Check expected unit and all more significant ones are set
166         // This is needed for FTPFile.toFormattedString() to work correctly
167         for (int i = ordinal; i < values.length; i++) {
168             final CalendarUnit unit = values[i];
169             assertTrue(stamp.isSet(unit.unit), "Expected set " + unit + " in " + listEntry);
170         }
171         // Check previous entry (if any) is not set
172         // This is also needed for FTPFile.toFormattedString() to work correctly
173         if (ordinal > 0) {
174             final CalendarUnit prevUnit = values[ordinal - 1];
175             assertFalse(stamp.isSet(prevUnit.unit), "Expected not set " + prevUnit + " in " + listEntry);
176         }
177     }
178 
179     abstract void testRecentPrecision();
180 }