View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript.host.file;
16  
17  import static java.nio.charset.StandardCharsets.ISO_8859_1;
18  
19  import java.io.File;
20  import java.util.Locale;
21  import java.util.TimeZone;
22  
23  import org.apache.commons.io.FileUtils;
24  import org.htmlunit.BrowserVersion;
25  import org.htmlunit.WebDriverTestCase;
26  import org.htmlunit.junit.BrowserRunner;
27  import org.htmlunit.junit.annotation.Alerts;
28  import org.htmlunit.util.MimeType;
29  import org.junit.Test;
30  import org.junit.runner.RunWith;
31  import org.openqa.selenium.By;
32  import org.openqa.selenium.WebDriver;
33  
34  /**
35   * Tests for {@link org.htmlunit.javascript.host.file.File}.
36   *
37   * @author Ronald Brill
38   */
39  @RunWith(BrowserRunner.class)
40  public class FileTest extends WebDriverTestCase {
41  
42      /**
43       * @throws Exception if the test fails
44       */
45      @Test
46      @Alerts(DEFAULT = {"1", "ScriptExceptionTest1.txt",
47                         "Sun Jul 26 2015 10:21:47 GMT-0400 (Eastern Daylight Time)",
48                         "1437920507000", "", "14", MimeType.TEXT_PLAIN},
49              FF = {"1", "ScriptExceptionTest1.txt", "undefined",
50                    "1437920507000", "", "14", MimeType.TEXT_PLAIN},
51              FF_ESR = {"1", "ScriptExceptionTest1.txt", "undefined",
52                        "1437920507000", "", "14", MimeType.TEXT_PLAIN})
53      public void properties() throws Exception {
54          final String html = DOCTYPE_HTML
55              + "<html>\n"
56              + "<head>\n"
57              + "<script>\n"
58              + LOG_TITLE_FUNCTION
59              + "function test() {\n"
60              + "  if (document.testForm.fileupload.files) {\n"
61              + "    var files = document.testForm.fileupload.files;\n"
62              + "    log(files.length);\n"
63  
64              + "    var file = files[0];\n"
65              + "    log(file.name);\n"
66              + "    log(file.lastModifiedDate);\n"
67              + "    log(file.lastModified);\n"
68              + "    log(file.webkitRelativePath);\n"
69              + "    log(file.size);\n"
70              + "    log(file.type);\n"
71              + "  }\n"
72              + "}\n"
73              + "</script>\n"
74              + "</head>\n"
75              + "<body>\n"
76              + "  <form name='testForm'>\n"
77              + "    <input type='file' id='fileupload' name='fileupload'>\n"
78              + "  </form>\n"
79              + "  <button id='testBtn' onclick='test()'>Tester</button>\n"
80              + "</body>\n"
81              + "</html>";
82  
83          final WebDriver driver = loadPage2(html);
84  
85          final File tstFile = File.createTempFile("HtmlUnitUploadTest", ".txt");
86          try {
87              FileUtils.writeStringToFile(tstFile, "Hello HtmlUnit", ISO_8859_1);
88  
89              // do not use millis here because different file systems
90              // have different precisions
91              assertTrue(tstFile.setLastModified(1437920507000L));
92  
93              final String path = tstFile.getCanonicalPath();
94              driver.findElement(By.name("fileupload")).sendKeys(path);
95  
96              driver.findElement(By.id("testBtn")).click();
97  
98              final String[] expected = getExpectedAlerts();
99              if (expected.length > 1) {
100                 expected[1] = tstFile.getName();
101             }
102 
103             verifyTitle2(driver, getExpectedAlerts());
104         }
105         finally {
106             FileUtils.deleteQuietly(tstFile);
107         }
108     }
109 
110     /**
111      * @throws Exception if the test fails
112      */
113     @Test
114     @Alerts({"1", "function", "Hello HtmlUnit"})
115     public void text() throws Exception {
116         final String html = DOCTYPE_HTML
117             + "<html>\n"
118             + "<head>\n"
119             + "<script>\n"
120             + LOG_TITLE_FUNCTION
121             + "function test() {\n"
122             + "  if (document.testForm.fileupload.files) {\n"
123             + "    var files = document.testForm.fileupload.files;\n"
124             + "    log(files.length);\n"
125 
126             + "    var file = files[0];\n"
127             + "    log(typeof file.text);\n"
128 
129             + "    try {\n"
130             + "      file.text().then(function(text) { log(text); });\n"
131             + "    } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
132             + "  }\n"
133             + "}\n"
134             + "</script>\n"
135             + "</head>\n"
136             + "<body>\n"
137             + "  <form name='testForm'>\n"
138             + "    <input type='file' id='fileupload' name='fileupload'>\n"
139             + "  </form>\n"
140             + "  <button id='testBtn' onclick='test()'>Tester</button>\n"
141             + "</body>\n"
142             + "</html>";
143 
144         final WebDriver driver = loadPage2(html);
145 
146         final File tstFile = File.createTempFile("HtmlUnitUploadTest", ".txt");
147         try {
148             FileUtils.writeStringToFile(tstFile, "Hello HtmlUnit", ISO_8859_1);
149 
150             final String path = tstFile.getCanonicalPath();
151             driver.findElement(By.name("fileupload")).sendKeys(path);
152 
153             driver.findElement(By.id("testBtn")).click();
154 
155             verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
156         }
157         finally {
158             FileUtils.deleteQuietly(tstFile);
159         }
160     }
161 
162     /**
163      * @throws Exception if the test fails
164      */
165     @Test
166     @Alerts("text/plain")
167     public void typeTxt() throws Exception {
168         type(".txt");
169         type(".tXT");
170     }
171 
172     /**
173      * @throws Exception if the test fails
174      */
175     @Test
176     @Alerts("")
177     public void typeHtmlUnit() throws Exception {
178         type(".htmlunit");
179     }
180 
181     /**
182      * @throws Exception if the test fails
183      */
184     @Test
185     @Alerts("")
186     public void typeEmpty() throws Exception {
187         type("");
188     }
189 
190     private void type(final String extension) throws Exception {
191         final String html = DOCTYPE_HTML
192             + "<html>\n"
193             + "<head>\n"
194             + "<script>\n"
195             + LOG_TITLE_FUNCTION
196             + "function test() {\n"
197             + "  if (document.testForm.fileupload.files) {\n"
198             + "    var files = document.testForm.fileupload.files;\n"
199 
200             + "    var file = files[0];\n"
201             + "    log(file.type);\n"
202             + "  }\n"
203             + "}\n"
204             + "</script>\n"
205             + "</head>\n"
206             + "<body>\n"
207             + "  <form name='testForm'>\n"
208             + "    <input type='file' id='fileupload' name='fileupload'>\n"
209             + "  </form>\n"
210             + "  <button id='testBtn' onclick='test()'>Tester</button>\n"
211             + "</body>\n"
212             + "</html>";
213 
214         final WebDriver driver = loadPage2(html);
215 
216         final File tstFile = File.createTempFile("HtmlUnitUploadTest", extension);
217         try {
218             final String path = tstFile.getCanonicalPath();
219             driver.findElement(By.name("fileupload")).sendKeys(path);
220 
221             driver.findElement(By.id("testBtn")).click();
222 
223             verifyTitle2(driver, getExpectedAlerts());
224         }
225         finally {
226             FileUtils.deleteQuietly(tstFile);
227         }
228     }
229 
230     /**
231      * @throws Exception if the test fails
232      */
233     @Test
234     @Alerts({"false", "TypeError true"})
235     public void ctorNoArgs() throws Exception {
236         final String html = DOCTYPE_HTML
237                 + "<html>\n"
238                 + "<head>\n"
239                 + "<script>\n"
240                 + LOG_TITLE_FUNCTION
241                 + "  function test() {\n"
242                 + "    log(File in window);\n"
243 
244                 + "    try {\n"
245                 + "      log(new File());\n"
246                 + "    } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
247                 + "  }\n"
248                 + "</script>\n"
249                 + "</head>\n"
250                 + "<body onload='test()'>\n"
251                 + "</body>\n"
252                 + "</html>";
253 
254         loadPageVerifyTitle2(html);
255     }
256 
257     /**
258      * @throws Exception if the test fails
259      */
260     @Test
261     @Alerts({"[object File]", "htMluniT.txt", "", "true", "0", ""})
262     public void ctorEmpty() throws Exception {
263         final String html = DOCTYPE_HTML
264                 + "<html>\n"
265                 + "<head>\n"
266                 + "<script>\n"
267                 + LOG_TITLE_FUNCTION
268                 + "  function test() {\n"
269                 + "    try {\n"
270                 + "      var now = Date.now();\n"
271                 + "      var file = new File([], 'htMluniT.txt');\n"
272                 + "      log(file);\n"
273                 + "      log(file.name);\n"
274                 + "      log(file.type);\n"
275                 + "      log(file.lastModified >= now);\n"
276                 + "      log(file.size);\n"
277 
278                 + "      file.text().then(function(text) { log(text); });\n"
279                 + "    } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
280                 + "  }\n"
281                 + "</script>\n"
282                 + "</head>\n"
283                 + "<body onload='test()'>\n"
284                 + "</body>\n"
285                 + "</html>";
286 
287         loadPage2(html);
288         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
289     }
290 
291     /**
292      * @throws Exception if the test fails
293      */
294     @Test
295     @Alerts({"[object File]", "htMluniT.txt", "", "true", "8", "HtmlUnit"})
296     public void ctorString() throws Exception {
297         final String html = DOCTYPE_HTML
298                 + "<html>\n"
299                 + "<head>\n"
300                 + "<script>\n"
301                 + LOG_TITLE_FUNCTION
302                 + "  function test() {\n"
303                 + "    try {\n"
304                 + "      var now = Date.now();\n"
305                 + "      var file = new File(['HtmlUnit'], 'htMluniT.txt');\n"
306                 + "      log(file);\n"
307                 + "      log(file.name);\n"
308                 + "      log(file.type);\n"
309                 + "      log(file.lastModified >= now);\n"
310                 + "      log(file.size);\n"
311 
312                 + "      file.text().then(function(text) { log(text); });\n"
313                 + "    } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
314                 + "  }\n"
315                 + "</script>\n"
316                 + "</head>\n"
317                 + "<body onload='test()'>\n"
318                 + "</body>\n"
319                 + "</html>";
320 
321         loadPage2(html);
322         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
323     }
324 
325     /**
326      * @throws Exception if the test fails
327      */
328     @Test
329     @Alerts({"[object File]", "htMluniT.txt", "application/octet-stream", "1234567", "8",
330              "HtmlUnit"})
331     public void ctorStringWithOptions() throws Exception {
332         final String html = DOCTYPE_HTML
333                 + "<html>\n"
334                 + "<head>\n"
335                 + "<script>\n"
336                 + LOG_TITLE_FUNCTION
337                 + "  function test() {\n"
338                 + "    try {\n"
339                 + "      var now = Date.now();\n"
340                 + "      var file = new File(['HtmlUnit'], 'htMluniT.txt',"
341                               + "{type: 'application/octet-stream', lastModified: '1234567'});\n"
342                 + "      log(file);\n"
343                 + "      log(file.name);\n"
344                 + "      log(file.type);\n"
345                 + "      log(file.lastModified);\n"
346                 + "      log(file.size);\n"
347 
348                 + "      file.text().then(function(text) { log(text); });\n"
349                 + "    } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
350                 + "  }\n"
351                 + "</script>\n"
352                 + "</head>\n"
353                 + "<body onload='test()'>\n"
354                 + "</body>\n"
355                 + "</html>";
356 
357         loadPage2(html);
358         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
359     }
360 
361     /**
362      * @throws Exception if the test fails
363      */
364     @Test
365     @Alerts({"[object File]", "htMluniT.txt", "", "true", "16",
366              "HtmlUnitis great"})
367     public void ctorStrings() throws Exception {
368         final String html = DOCTYPE_HTML
369                 + "<html>\n"
370                 + "<head>\n"
371                 + "<script>\n"
372                 + LOG_TITLE_FUNCTION
373                 + "  function test() {\n"
374                 + "    try {\n"
375                 + "      var now = Date.now();\n"
376                 + "      var file = new File(['Html', 'Unit', 'is great'], 'htMluniT.txt');\n"
377                 + "      log(file);\n"
378                 + "      log(file.name);\n"
379                 + "      log(file.type);\n"
380                 + "      log(file.lastModified >= now);\n"
381                 + "      log(file.size);\n"
382 
383                 + "      file.text().then(function(text) { log(text); });\n"
384                 + "    } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
385                 + "  }\n"
386                 + "</script>\n"
387                 + "</head>\n"
388                 + "<body onload='test()'>\n"
389                 + "</body>\n"
390                 + "</html>";
391 
392         loadPage2(html);
393         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
394     }
395 
396     /**
397      * @throws Exception if the test fails
398      */
399     @Test
400     @Alerts({"[object File]", "htMluniT.txt", "", "true", "12", "HtmlUnitMMMK"})
401     public void ctorMixed() throws Exception {
402         final String html = DOCTYPE_HTML
403                 + "<html>\n"
404                 + "<head>\n"
405                 + "<script>\n"
406                 + LOG_TITLE_FUNCTION
407                 + "  function test() {\n"
408                 + "    try {\n"
409                 + "      var now = Date.now();\n"
410                 + "      var nab = new ArrayBuffer(2);\n"
411                 + "      var nabv = new Uint8Array(nab, 0, 2);\n"
412                 + "      nabv.set([77, 77], 0);\n"
413                 + "      var file = new File(['HtmlUnit',"
414                                       + "nab, new Int8Array([77,75])], 'htMluniT.txt');\n"
415                 + "      log(file);\n"
416                 + "      log(file.name);\n"
417                 + "      log(file.type);\n"
418                 + "      log(file.lastModified >= now);\n"
419                 + "      log(file.size);\n"
420 
421                 + "      file.text().then(function(text) { log(text); });\n"
422                 + "    } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
423                 + "  }\n"
424                 + "</script>\n"
425                 + "</head>\n"
426                 + "<body onload='test()'>\n"
427                 + "</body>\n"
428                 + "</html>";
429 
430         loadPage2(html);
431         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
432     }
433 
434     /**
435      * @throws Exception if the test fails
436      */
437     @Test
438     @Alerts(DEFAULT = "Sun Jul 26 2015 10:21:47 GMT-0400 (Eastern Daylight Time)",
439             FF = "undefined",
440             FF_ESR = "undefined")
441     public void lastModifiedDate() throws Exception {
442         lastModifiedDate(getBrowserVersion().getSystemTimezone().getID(), getBrowserVersion().getBrowserLocale());
443     }
444 
445     /**
446      * @throws Exception if the test fails
447      */
448     @Test
449     @Alerts(DEFAULT = "Sun Jul 26 2015 14:21:47 GMT+0000 (Greenwich Mean Time)",
450             FF = "undefined",
451             FF_ESR = "undefined")
452     public void lastModifiedDateGMT() throws Exception {
453         lastModifiedDate("GMT", getBrowserVersion().getBrowserLocale());
454     }
455 
456     /**
457      * @throws Exception if the test fails
458      */
459     @Test
460     @Alerts(DEFAULT = "Sun Jul 26 2015 14:21:47 GMT+0000 (Coordinated Universal Time)",
461             FF = "undefined",
462             FF_ESR = "undefined")
463     public void lastModifiedDateUTC() throws Exception {
464         lastModifiedDate("UTC", getBrowserVersion().getBrowserLocale());
465     }
466 
467     /**
468      * @throws Exception if the test fails
469      */
470     @Test
471     @Alerts(DEFAULT = "Sun Jul 26 2015 16:21:47 GMT+0200 (Mitteleuropäische Sommerzeit)",
472             FF = "undefined",
473             FF_ESR = "undefined")
474     public void lastModifiedDateBerlin() throws Exception {
475         lastModifiedDate("Europe/Berlin", Locale.GERMANY);
476     }
477 
478     /**
479      * @throws Exception if the test fails
480      */
481     @Test
482     @Alerts(DEFAULT = "Sun Jul 26 2015 23:21:47 GMT+0900 (日本標準時)",
483             FF = "undefined",
484             FF_ESR = "undefined")
485     public void lastModifiedDateJST() throws Exception {
486         lastModifiedDate("JST", Locale.JAPAN);
487     }
488 
489     private void lastModifiedDate(final String tz, final Locale locale) throws Exception {
490         final String html = DOCTYPE_HTML
491             + "<html>\n"
492             + "<head>\n"
493             + "<script>\n"
494             + LOG_TITLE_FUNCTION
495             + "function test() {\n"
496             + "  if (document.testForm.fileupload.files) {\n"
497             + "    var files = document.testForm.fileupload.files;\n"
498             + "    var file = files[0];\n"
499             + "    log(file.lastModifiedDate);\n"
500             + "  }\n"
501             + "}\n"
502             + "</script>\n"
503             + "</head>\n"
504             + "<body>\n"
505             + "  <form name='testForm'>\n"
506             + "    <input type='file' id='fileupload' name='fileupload'>\n"
507             + "  </form>\n"
508             + "  <button id='testBtn' onclick='test()'>Tester</button>\n"
509             + "</body>\n"
510             + "</html>";
511 
512         final File tstFile = File.createTempFile("HtmlUnitUploadTest", ".txt");
513         try {
514             FileUtils.writeStringToFile(tstFile, "Hello HtmlUnit", ISO_8859_1);
515 
516             // do not use millis here because different file systems
517             // have different precisions
518             assertTrue(tstFile.setLastModified(1437920507000L));
519 
520             final String path = tstFile.getCanonicalPath();
521 
522             shutDownAll();
523             try {
524                 final BrowserVersion.BrowserVersionBuilder builder
525                     = new BrowserVersion.BrowserVersionBuilder(getBrowserVersion());
526                 builder.setSystemTimezone(TimeZone.getTimeZone(tz));
527                 builder.setBrowserLanguage(locale.toLanguageTag());
528                 setBrowserVersion(builder.build());
529 
530                 final WebDriver driver = loadPage2(html);
531                 driver.findElement(By.name("fileupload")).sendKeys(path);
532 
533                 driver.findElement(By.id("testBtn")).click();
534 
535                 final String[] expected = getExpectedAlerts();
536                 if (expected.length > 1) {
537                     expected[1] = tstFile.getName();
538                 }
539 
540                 verifyTitle2(driver, getExpectedAlerts());
541             }
542             finally {
543                 shutDownAll();
544             }
545         }
546         finally {
547             FileUtils.deleteQuietly(tstFile);
548         }
549     }
550 }