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.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertFalse;
21  import static org.junit.jupiter.api.Assertions.assertNotNull;
22  import static org.junit.jupiter.api.Assertions.assertTrue;
23  
24  import java.util.Calendar;
25  
26  import org.apache.commons.net.ftp.FTPFile;
27  import org.apache.commons.net.ftp.FTPFileEntryParser;
28  import org.junit.jupiter.api.Test;
29  
30  /**
31   */
32  class UnixFTPEntryParserTest extends AbstractFTPParseTest {
33  
34      private static final String[] badsamples = { "zrwxr-xr-x   2 root     root         4096 Mar  2 15:13 zxbox",
35              "dxrwr-xr-x   2 root     root         4096 Aug 24  2001 zxjdbc", "drwxr-xr-x   2 root     root         4096 Jam  4 00:03 zziplib",
36              "drwxr-xr-x   2 root     99           4096 Feb 23 30:01 zzplayer", "drwxr-xr-x   2 root     root         4096 Aug 36  2001 zztpp",
37              "-rw-r--r--   1 14       staff       80284 Aug 22  zxJDBC-1.2.3.tar.gz", "-rw-r--r--   1 14       staff      119:26 Aug 22  2000 zxJDBC-1.2.3.zip",
38              /* "-rw-r--r--   1 ftp      no group    83853 Jan 22  2001 zxJDBC-1.2.4.tar.gz", */
39              "-rw-r--r--   1ftp       nogroup    126552 Jan 22  2001 zxJDBC-1.2.4.zip",
40              "-rw-r--r--   1 root     root       190144 2001-04-27 zxJDBC-2.0.1b1.zip",
41              "-rw-r--r--   1 root     root       111325 Apr -7 18:79 zxJDBC-2.0.1b1.tar.gz" };
42  
43      private static final String[] goodsamples = { "-rw-r--r--   1 500      500            21 Aug  8 14:14 JB3-TES1.gz",
44              "-rwxr-xr-x   2 root     root         4096 Mar  2 15:13 zxbox", "drwxr-xr-x   2 root     root         4096 Aug 24  2001 zxjdbc",
45              "drwxr-xr-x   2 root     root         4096 Jan  4 00:03 zziplib", "drwxr-xr-x   2 root     99           4096 Feb 23  2001 zzplayer",
46              "drwxr-xr-x   2 root     root         4096 Aug  6  2001 zztpp", "drwxr-xr-x 1 usernameftp 512 Jan 29 23:32 prog",
47              "lrw-r--r--   1 14       14          80284 Aug 22  2000 zxJDBC-1.2.3.tar.gz",
48              "frw-r--r--   1 14       staff      119926 Aug 22  2000 zxJDBC-1.2.3.zip",
49              "crw-r--r--   1 ftp      nogroup     83853 Jan 22  2001 zxJDBC-1.2.4.tar.gz",
50              "brw-r--r--   1 ftp      nogroup    126552 Jan 22  2001 zxJDBC-1.2.4.zip",
51              "-rw-r--r--   1 root     root       111325 Apr 27  2001 zxJDBC-2.0.1b1.tar.gz",
52              "-rw-r--r--   1 root     root       190144 Apr 27  2001 zxJDBC-2.0.1b1.zip",
53              "-rwxr-xr-x   2 500      500           166 Nov  2  2001 73131-testtes1.afp",
54              "-rw-r--r--   1 500      500           166 Nov  9  2001 73131-testtes1.AFP",
55              "-rw-r--r--   1 500      500           166 Nov 12  2001 73131-testtes2.afp",
56              "-rw-r--r--   1 500      500           166 Nov 12  2001 73131-testtes2.AFP",
57              "-rw-r--r--   1 500      500       2040000 Aug  5 07:35 testRemoteUPCopyNIX",
58              "-rw-r--r--   1 500      500       2040000 Aug  5 07:31 testRemoteUPDCopyNIX",
59              "-rw-r--r--   1 500      500       2040000 Aug  5 07:31 testRemoteUPVCopyNIX", "-rw-r--r-T   1 500      500             0 Mar 25 08:20 testSticky",
60              "-rwxr-xr-t   1 500      500             0 Mar 25 08:21 testStickyExec", "-rwSr-Sr--   1 500      500             0 Mar 25 08:22 testSuid",
61              "-rwsr-sr--   1 500      500             0 Mar 25 08:23 testSuidExec", "-rwsr-sr--   1 500      500             0 Mar 25 0:23 testSuidExec2",
62              "drwxrwx---+ 23 500     500    0 Jan 10 13:09 testACL", "-rw-r--r--   1 1        3518644 May 25 12:12 std",
63              "lrwxrwxrwx   1 neeme neeme             23 Mar  2 18:06 macros -> ./../../global/macros/.",
64              "-rw-r--r--   1 ftp      group with spaces in it as allowed in cygwin see bug 38634" + "   83853 Jan 22  2001 zxJDBC-1.2.4.tar.gz",
65              // Bug 38634 => NET-16
66              "crw-r----- 1 root kmem 0, 27 Jan 30 11:42 kmem", // FreeBSD device
67              "crw-------   1 root     sys      109,767 Jul  2  2004 pci@1c,600000:devctl", // Solaris device
68              "-rwxrwx---   1 ftp      ftp-admin 816026400 Oct  5  2008 bloplab 7 cd1.img", // NET-294
69  
70              // https://mail-archives.apache.org/mod_mbox/commons-dev/200408.mbox/%3c4122F3C1.9090402@tanukisoftware.com%3e
71              "-rw-r--r-- 1 1 3518644 May 25 12:12 std", "-rw-rw---- 1 ep1adm sapsys 0 6\u6708 3\u65e5 2003\u5e74 \u8a66\u9a13\u30d5\u30a1\u30a4\u30eb.csv",
72              "-rw-rw---- 1 ep1adm sapsys 0 8\u6708 17\u65e5 20:10 caerrinf",
73  
74              "-rw-r--r-- 1 1 3518644 May 25 12:12 std", "-rw-rw---- 1 ep1adm sapsys 0 6\u6708 3 2003 \u8a66\u9a13\u30d5\u30a1\u30a4\u30eb.csv",
75              "-rw-rw---- 1 ep1adm sapsys 0 8\u6708 17 20:10 caerrinf",
76  
77      };
78  
79      private void checkPermissions(final FTPFile f) {
80          assertTrue(f.hasPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION), "Should have user read permission.");
81          assertTrue(f.hasPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION), "Should have user write permission.");
82          assertTrue(f.hasPermission(FTPFile.USER_ACCESS, FTPFile.EXECUTE_PERMISSION), "Should have user execute permission.");
83          assertTrue(f.hasPermission(FTPFile.GROUP_ACCESS, FTPFile.READ_PERMISSION), "Should have group read permission.");
84          assertFalse(f.hasPermission(FTPFile.GROUP_ACCESS, FTPFile.WRITE_PERMISSION), "Should NOT have group write permission.");
85          assertTrue(f.hasPermission(FTPFile.GROUP_ACCESS, FTPFile.EXECUTE_PERMISSION), "Should have group execute permission.");
86          assertTrue(f.hasPermission(FTPFile.WORLD_ACCESS, FTPFile.READ_PERMISSION), "Should have world read permission.");
87          assertFalse(f.hasPermission(FTPFile.WORLD_ACCESS, FTPFile.WRITE_PERMISSION), "Should NOT have world write permission.");
88          assertTrue(f.hasPermission(FTPFile.WORLD_ACCESS, FTPFile.EXECUTE_PERMISSION), "Should have world execute permission.");
89      }
90  
91      @Override
92      protected void doAdditionalGoodTests(final String test, final FTPFile f) {
93          final String link = f.getLink();
94          if (null != link) {
95              final int linklen = link.length();
96              if (linklen > 0) {
97                  assertEquals(link, test.substring(test.length() - linklen));
98                  assertEquals(FTPFile.SYMBOLIC_LINK_TYPE, f.getType());
99              }
100         }
101         final int type = f.getType();
102         switch (test.charAt(0)) {
103         case 'd':
104             assertEquals(FTPFile.DIRECTORY_TYPE, type, "Type of " + test);
105             break;
106         case 'l':
107             assertEquals(FTPFile.SYMBOLIC_LINK_TYPE, type, "Type of " + test);
108             break;
109         case 'b':
110         case 'c':
111             assertEquals(0, f.getHardLinkCount());
112             // falls through$ TODO this needs to be fixed if a device type is introduced
113         case 'f':
114         case '-':
115             assertEquals(FTPFile.FILE_TYPE, type, "Type of " + test);
116             break;
117         default:
118             assertEquals(FTPFile.UNKNOWN_TYPE, type, "Type of " + test);
119         }
120 
121         for (int access = FTPFile.USER_ACCESS; access <= FTPFile.WORLD_ACCESS; access++) {
122             for (int perm = FTPFile.READ_PERMISSION; perm <= FTPFile.EXECUTE_PERMISSION; perm++) {
123                 final int pos = 3 * access + perm + 1;
124                 final char permchar = test.charAt(pos);
125                 assertEquals(Boolean.valueOf(f.hasPermission(access, perm)),
126                         Boolean.valueOf(permchar != '-' && !Character.isUpperCase(permchar)), "Permission " + test.substring(1, 10));
127             }
128         }
129 
130         assertNotNull(f.getTimestamp(), "Expected to find a timestamp");
131 // Perhaps check date range (need to ensure all good examples qualify)
132 //        assertTrue(test,f.getTimestamp().get(Calendar.YEAR)>=2000);
133     }
134 
135     @Override
136     protected String[] getBadListing() {
137         return badsamples;
138     }
139 
140     @Override
141     protected String[] getGoodListing() {
142         return goodsamples;
143     }
144 
145     @Override
146     protected FTPFileEntryParser getParser() {
147         return new UnixFTPEntryParser();
148     }
149 
150     @Test
151     void testCorrectGroupNameParsing() {
152         final FTPFile f = getParser().parseFTPEntry("-rw-r--r--   1 ftpuser  ftpusers 12414535 Mar 17 11:07 test 1999 abc.pdf");
153         assertNotNull(f);
154         assertEquals(1, f.getHardLinkCount());
155         assertEquals("ftpuser", f.getUser());
156         assertEquals("ftpusers", f.getGroup());
157         assertEquals(12414535, f.getSize());
158         assertEquals("test 1999 abc.pdf", f.getName());
159 
160         final Calendar cal = Calendar.getInstance();
161         cal.set(Calendar.MONTH, Calendar.MARCH);
162         cal.set(Calendar.DAY_OF_MONTH, 17);
163         cal.set(Calendar.HOUR_OF_DAY, 11);
164         cal.set(Calendar.MINUTE, 7);
165         cal.set(Calendar.SECOND, 0);
166         cal.set(Calendar.MILLISECOND, 0);
167 
168         assertEquals(f.getTimestamp().get(Calendar.MONTH), cal.get(Calendar.MONTH));
169         assertEquals(f.getTimestamp().get(Calendar.DAY_OF_MONTH), cal.get(Calendar.DAY_OF_MONTH));
170         assertEquals(f.getTimestamp().get(Calendar.HOUR_OF_DAY), cal.get(Calendar.HOUR_OF_DAY));
171         assertEquals(f.getTimestamp().get(Calendar.MINUTE), cal.get(Calendar.MINUTE));
172         assertEquals(f.getTimestamp().get(Calendar.SECOND), cal.get(Calendar.SECOND));
173     }
174 
175     @Override
176     @Test
177     void testDefaultPrecision() {
178         testPrecision("drwxr-xr-x   2 user     group         4096 Mar  2 2014 zxbox", CalendarUnit.DAY_OF_MONTH);
179     }
180 
181     @Test
182     void testFilenamesWithEmbeddedNumbers() {
183         final FTPFile f = getParser().parseFTPEntry("-rw-rw-rw-   1 user group 5840 Mar 19 09:34 123 456 abc.csv");
184         assertEquals("123 456 abc.csv", f.getName());
185         assertEquals(5840, f.getSize());
186         assertEquals("user", f.getUser());
187         assertEquals("group", f.getGroup());
188     }
189 
190     @Test
191     void testGroupNameWithSpaces() {
192         final FTPFile f = getParser().parseFTPEntry("drwx------ 4 maxm Domain Users 512 Oct 2 10:59 .metadata");
193         assertNotNull(f);
194         assertEquals("maxm", f.getUser());
195         assertEquals("Domain Users", f.getGroup());
196     }
197 
198     @Test
199     void testLeadingSpacesDefault() { // the default has been changed to keep spaces
200         final FTPFile f = getParser().parseFTPEntry("drwxr-xr-x   2 john smith     group         4096 Mar  2 15:13   zxbox");
201         assertNotNull(f);
202         assertEquals("  zxbox", f.getName()); // leading spaces retained
203     }
204 
205     @Test
206     void testLeadingSpacesNET566() { // check new behavior
207         final FTPFile f = new UnixFTPEntryParser(null, false).parseFTPEntry("drwxr-xr-x   2 john smith     group         4096 Mar  2 15:13   zxbox");
208         assertNotNull(f);
209         assertEquals("  zxbox", f.getName()); // leading spaces retained
210     }
211 
212     @Test
213     void testNameWIthPunctuation() {
214         final FTPFile f = getParser().parseFTPEntry("drwx------ 4 maxm Domain Users 512 Oct 2 10:59 abc(test)123.pdf");
215         assertNotNull(f);
216         assertEquals("abc(test)123.pdf", f.getName());
217     }
218 
219     @Test
220     void testNET294() {
221         final FTPFile f = getParser().parseFTPEntry("-rwxrwx---   1 ftp      ftp-admin 816026400 Oct  5  2008 bloplab 7 cd1.img");
222         assertNotNull(f);
223         assertEquals("ftp", f.getUser());
224         assertEquals("ftp-admin", f.getGroup());
225         assertEquals(816026400L, f.getSize());
226         assertNotNull(f.getTimestamp(), "Timestamp should not be null");
227         assertEquals(2008, f.getTimestamp().get(Calendar.YEAR));
228         assertEquals("bloplab 7 cd1.img", f.getName());
229     }
230 
231     @Test
232     void testNoSpacesBeforeFileSize() {
233         final FTPFile f = getParser().parseFTPEntry("drwxr-x---+1464 chrism   chrism     41472 Feb 25 13:17 20090225");
234         assertNotNull(f);
235         assertEquals(41472, f.getSize());
236         assertEquals(FTPFile.DIRECTORY_TYPE, f.getType());
237         assertEquals("chrism", f.getUser());
238         assertEquals("chrism", f.getGroup());
239         assertEquals(1464, f.getHardLinkCount());
240     }
241 
242     @Test
243     void testNumericDateFormat() {
244         final String testNumericDF = "-rw-r-----   1 neeme neeme   346 2005-04-08 11:22 services.vsp";
245         final String testNumericDF2 = "lrwxrwxrwx   1 neeme neeme    23 2005-03-02 18:06 macros -> ./../../global/macros/.";
246 
247         final UnixFTPEntryParser parser = new UnixFTPEntryParser(UnixFTPEntryParser.NUMERIC_DATE_CONFIG);
248 
249         final FTPFile f = parser.parseFTPEntry(testNumericDF);
250         assertNotNull(f, "Failed to parse " + testNumericDF);
251 
252         final Calendar cal = Calendar.getInstance();
253         cal.clear();
254         cal.set(Calendar.YEAR, 2005);
255         cal.set(Calendar.MONTH, Calendar.APRIL);
256 
257         cal.set(Calendar.DAY_OF_MONTH, 8);
258         cal.set(Calendar.HOUR_OF_DAY, 11);
259         cal.set(Calendar.MINUTE, 22);
260         assertEquals(cal.getTime(), f.getTimestamp().getTime());
261 
262         final FTPFile f2 = parser.parseFTPEntry(testNumericDF2);
263         assertNotNull(f2, "Failed to parse " + testNumericDF2);
264         assertEquals("./../../global/macros/.", f2.getLink(), "symbolic link");
265 
266     }
267 
268     @Test
269     void testOwnerAndGroupNameWithSpaces() {
270         final FTPFile f = getParser().parseFTPEntry("drwxr-xr-x   2 john smith     test group         4096 Mar  2 15:13 zxbox");
271         assertNotNull(f);
272         assertEquals("john smith", f.getUser());
273         assertEquals("test group", f.getGroup());
274     }
275 
276     @Test
277     void testOwnerNameWithSpaces() {
278         final FTPFile f = getParser().parseFTPEntry("drwxr-xr-x   2 john smith     group         4096 Mar  2 15:13 zxbox");
279         assertNotNull(f);
280         assertEquals("john smith", f.getUser());
281     }
282 
283     @Override
284     @Test
285     void testParseFieldsOnDirectory() throws Exception {
286         final FTPFile f = getParser().parseFTPEntry("drwxr-xr-x   2 user     group         4096 Mar  2 15:13 zxbox");
287         assertNotNull(f, "Could not parse entry.");
288         assertTrue(f.isDirectory(), "Should have been a directory.");
289         checkPermissions(f);
290         assertEquals(2, f.getHardLinkCount());
291         assertEquals("user", f.getUser());
292         assertEquals("group", f.getGroup());
293         assertEquals("zxbox", f.getName());
294         assertEquals(4096, f.getSize());
295 
296         final Calendar cal = Calendar.getInstance();
297         cal.set(Calendar.MONTH, Calendar.MARCH);
298 
299         cal.set(Calendar.DAY_OF_MONTH, 1);
300         cal.set(Calendar.HOUR_OF_DAY, 0);
301         cal.set(Calendar.MINUTE, 0);
302         cal.set(Calendar.SECOND, 0);
303         if (f.getTimestamp().getTime().before(cal.getTime())) {
304             cal.add(Calendar.YEAR, -1);
305         }
306         cal.set(Calendar.DAY_OF_MONTH, 2);
307         cal.set(Calendar.HOUR_OF_DAY, 15);
308         cal.set(Calendar.MINUTE, 13);
309 
310         assertEquals(df.format(cal.getTime()), df.format(f.getTimestamp().getTime()));
311     }
312 
313     @Override
314     @Test
315     void testParseFieldsOnFile() throws Exception {
316         final FTPFile f = getParser().parseFTPEntry("-rwxr-xr-x   2 user     my group 500        5000000000 Mar  2 15:13 zxbox");
317         assertNotNull(f, "Could not parse entry.");
318         assertTrue(f.isFile(), "Should have been a file.");
319         checkPermissions(f);
320         assertEquals(2, f.getHardLinkCount());
321         assertEquals("user", f.getUser());
322         assertEquals("my group 500", f.getGroup());
323         assertEquals("zxbox", f.getName());
324         assertEquals(5000000000L, f.getSize());
325 
326         final Calendar cal = Calendar.getInstance();
327         cal.set(Calendar.MONTH, Calendar.MARCH);
328 
329         cal.set(Calendar.DAY_OF_MONTH, 1);
330         cal.set(Calendar.HOUR_OF_DAY, 0);
331         cal.set(Calendar.MINUTE, 0);
332         cal.set(Calendar.SECOND, 0);
333         if (f.getTimestamp().getTime().before(cal.getTime())) {
334             cal.add(Calendar.YEAR, -1);
335         }
336         cal.set(Calendar.DAY_OF_MONTH, 2);
337         cal.set(Calendar.HOUR_OF_DAY, 15);
338         cal.set(Calendar.MINUTE, 13);
339         assertEquals(df.format(cal.getTime()), df.format(f.getTimestamp().getTime()));
340     }
341 
342     @Test
343     void testParseFieldsOnFileChineseTime() {
344         final FTPFile f = getParser().parseFTPEntry("-rwxr-xr-x 2 user group 4096 3\u6708 2 15:13 zxbox");
345         assertNotNull(f, "Could not parse entry.");
346         assertTrue(f.isFile(), "Should have been a file.");
347         checkPermissions(f);
348         assertEquals(2, f.getHardLinkCount());
349         assertEquals("user", f.getUser());
350         assertEquals("group", f.getGroup());
351         assertEquals("zxbox", f.getName());
352         assertEquals(4096, f.getSize());
353 
354         assertNotNull(f.getTimestamp(), "Timestamp not null");
355         final Calendar cal = Calendar.getInstance();
356         cal.set(Calendar.MONTH, Calendar.MARCH);
357         cal.set(Calendar.DATE, 1);
358         cal.set(Calendar.HOUR_OF_DAY, 0);
359         cal.set(Calendar.MINUTE, 0);
360         cal.set(Calendar.SECOND, 0);
361         if (f.getTimestamp().getTime().before(cal.getTime())) {
362             cal.add(Calendar.YEAR, -1);
363         }
364         cal.set(Calendar.DATE, 2);
365         cal.set(Calendar.HOUR_OF_DAY, 15);
366         cal.set(Calendar.MINUTE, 13);
367         assertEquals(df.format(cal.getTime()), df.format(f.getTimestamp().getTime()));
368     }
369 
370     @Test
371     void testParseFieldsOnFileChineseYear() {
372         final FTPFile f = getParser().parseFTPEntry("-rwxr-xr-x 2 user group 4096 3\u6708 2 2003 \u8a66\u9a13\u30d5\u30a1\u30a4\u30eb.csv");
373         assertNotNull(f, "Could not parse entry.");
374         assertTrue(f.isFile(), "Should have been a file.");
375         checkPermissions(f);
376         assertEquals(2, f.getHardLinkCount());
377         assertEquals("user", f.getUser());
378         assertEquals("group", f.getGroup());
379         assertEquals("\u8a66\u9a13\u30d5\u30a1\u30a4\u30eb.csv", f.getName());
380         assertEquals(4096, f.getSize());
381 
382         assertNotNull(f.getTimestamp(), "Timestamp not null");
383         final Calendar cal = Calendar.getInstance();
384         cal.set(Calendar.YEAR, 2003);
385         cal.set(Calendar.MONTH, Calendar.MARCH);
386         cal.set(Calendar.DATE, 2);
387         cal.set(Calendar.HOUR_OF_DAY, 0);
388         cal.set(Calendar.MINUTE, 0);
389         cal.set(Calendar.SECOND, 0);
390         assertEquals(df.format(cal.getTime()), df.format(f.getTimestamp().getTime()));
391     }
392 
393     // https://mail-archives.apache.org/mod_mbox/commons-dev/200408.mbox/%3c4122F3C1.9090402@tanukisoftware.com%3e
394     @Test
395     void testParseFieldsOnFileJapaneseTime() {
396         final FTPFile f = getParser().parseFTPEntry("-rwxr-xr-x 2 user group 4096 3\u6708 2\u65e5 15:13 zxbox");
397         assertNotNull(f, "Could not parse entry.");
398         assertTrue(f.isFile(), "Should have been a file.");
399         checkPermissions(f);
400         assertEquals(2, f.getHardLinkCount());
401         assertEquals("user", f.getUser());
402         assertEquals("group", f.getGroup());
403         assertEquals("zxbox", f.getName());
404         assertEquals(4096, f.getSize());
405 
406         assertNotNull(f.getTimestamp(), "Timestamp not null");
407         final Calendar cal = Calendar.getInstance();
408         cal.set(Calendar.MONTH, Calendar.MARCH);
409         cal.set(Calendar.DATE, 1);
410         cal.set(Calendar.HOUR_OF_DAY, 0);
411         cal.set(Calendar.MINUTE, 0);
412         cal.set(Calendar.SECOND, 0);
413         if (f.getTimestamp().getTime().before(cal.getTime())) {
414             cal.add(Calendar.YEAR, -1);
415         }
416         cal.set(Calendar.DATE, 2);
417         cal.set(Calendar.HOUR_OF_DAY, 15);
418         cal.set(Calendar.MINUTE, 13);
419         assertEquals(df.format(cal.getTime()), df.format(f.getTimestamp().getTime()));
420     }
421 
422     // https://mail-archives.apache.org/mod_mbox/commons-dev/200408.mbox/%3c4122F3C1.9090402@tanukisoftware.com%3e
423     @Test
424     void testParseFieldsOnFileJapaneseYear() {
425         final FTPFile f = getParser().parseFTPEntry("-rwxr-xr-x 2 user group 4096 3\u6708 2\u65e5 2003\u5e74 \u8a66\u9a13\u30d5\u30a1\u30a4\u30eb.csv");
426         assertNotNull(f, "Could not parse entry.");
427         assertTrue(f.isFile(), "Should have been a file.");
428         checkPermissions(f);
429         assertEquals(2, f.getHardLinkCount());
430         assertEquals("user", f.getUser());
431         assertEquals("group", f.getGroup());
432         assertEquals("\u8a66\u9a13\u30d5\u30a1\u30a4\u30eb.csv", f.getName());
433         assertEquals(4096, f.getSize());
434 
435         assertNotNull(f.getTimestamp(), "Timestamp not null");
436         final Calendar cal = Calendar.getInstance();
437         cal.set(Calendar.YEAR, 2003);
438         cal.set(Calendar.MONTH, Calendar.MARCH);
439         cal.set(Calendar.DATE, 2);
440         cal.set(Calendar.HOUR_OF_DAY, 0);
441         cal.set(Calendar.MINUTE, 0);
442         cal.set(Calendar.SECOND, 0);
443         assertEquals(df.format(cal.getTime()), df.format(f.getTimestamp().getTime()));
444     }
445 
446     @Override
447     @Test
448     void testRecentPrecision() {
449         testPrecision("drwxr-xr-x   2 user     group         4096 Mar  2 15:13 zxbox", CalendarUnit.MINUTE);
450     }
451 
452     @Test
453     void testTrailingSpaces() {
454         final FTPFile f = getParser().parseFTPEntry("drwxr-xr-x   2 john smith     group         4096 Mar  2 15:13 zxbox     ");
455         assertNotNull(f);
456         assertEquals("zxbox     ", f.getName());
457     }
458 
459     @Test
460     void testTrimLeadingSpacesNET566() { // check can trim spaces as before
461         final FTPFile f = new UnixFTPEntryParser(null, true).parseFTPEntry("drwxr-xr-x   2 john smith     group         4096 Mar  2 15:13   zxbox");
462         assertNotNull(f);
463         assertEquals("zxbox", f.getName()); // leading spaces trimmed
464     }
465 }