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 org.htmlunit.WebDriverTestCase;
18  import org.htmlunit.junit.annotation.Alerts;
19  import org.htmlunit.util.MimeType;
20  import org.junit.jupiter.api.Test;
21  
22  /**
23   * Tests for {@link org.htmlunit.javascript.host.file.Blob}.
24   *
25   * @author Ronald Brill
26   * @author Lai Quang Duong
27   */
28  public class BlobTest extends WebDriverTestCase {
29  
30      /**
31       * @throws Exception if the test fails
32       */
33      @Test
34      @Alerts({"3", MimeType.TEXT_HTML})
35      public void properties() throws Exception {
36          final String html = DOCTYPE_HTML
37              + "<html>\n"
38              + "<head>\n"
39              + "<script>\n"
40              + LOG_TITLE_FUNCTION
41              + "function test() {\n"
42              + "  var blob = new Blob(['abc'], {type : 'text/html'});\n"
43  
44              + "  log(blob.size);\n"
45              + "  log(blob.type);\n"
46              + "}\n"
47              + "</script>\n"
48              + "</head>\n"
49              + "<body onload='test()'>\n"
50              + "</body>\n"
51              + "</html>";
52  
53          loadPageVerifyTitle2(html);
54      }
55  
56      /**
57       * @throws Exception if the test fails
58       */
59      @Test
60      @Alerts({"function", "Hello HtmlUnit"})
61      public void text() throws Exception {
62          final String html = DOCTYPE_HTML
63                  + "<html>\n"
64                  + "<head>\n"
65                  + "<script>\n"
66                  + LOG_TITLE_FUNCTION
67                  + "function test() {\n"
68                  + "  var blob = new Blob(['Hello HtmlUnit'], {type : 'text/html'});\n"
69  
70                  + "  log(typeof blob.text);\n"
71                  + "  try {\n"
72                  + "    blob.text().then(function(text) { log(text); });\n"
73                  + "  } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
74                  + "}\n"
75                  + "</script>\n"
76                  + "</head>\n"
77                  + "<body onload='test()'>\n"
78                  + "</body>\n"
79                  + "</html>";
80  
81          loadPage2(html);
82          verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
83      }
84  
85      /**
86       * @throws Exception if the test fails
87       */
88      @Test
89      @Alerts("text/plain")
90      public void typeTxt() throws Exception {
91          type(MimeType.TEXT_PLAIN);
92      }
93  
94      /**
95       * @throws Exception if the test fails
96       */
97      @Test
98      @Alerts("htmlunit")
99      public void typeHtmlUnit() throws Exception {
100         type("htmlunit");
101     }
102 
103     /**
104      * @throws Exception if the test fails
105      */
106     @Test
107     @Alerts("")
108     public void typeEmpty() throws Exception {
109         type("");
110     }
111 
112     private void type(final String type) throws Exception {
113         final String html = DOCTYPE_HTML
114             + "<html>\n"
115             + "<head>\n"
116             + "<script>\n"
117             + LOG_TITLE_FUNCTION
118             + "function test() {\n"
119             + "  var blob = new Blob(['Hello HtmlUnit'], {type : '" + type + "'});\n"
120             + "  log(blob.type);\n"
121             + "}\n"
122             + "</script>\n"
123             + "</head>\n"
124             + "<body onload='test()'>\n"
125             + "</body>\n"
126             + "</html>";
127 
128         loadPageVerifyTitle2(html);
129     }
130 
131     /**
132      * @throws Exception if the test fails
133      */
134     @Test
135     @Alerts("")
136     public void typeDefault() throws Exception {
137         final String html = DOCTYPE_HTML
138             + "<html>\n"
139             + "<head>\n"
140             + "<script>\n"
141             + LOG_TITLE_FUNCTION
142             + "function test() {\n"
143             + "  var blob = new Blob(['Hello HtmlUnit']);\n"
144             + "  log(blob.type);\n"
145             + "}\n"
146             + "</script>\n"
147             + "</head>\n"
148             + "<body onload='test()'>\n"
149             + "</body>\n"
150             + "</html>";
151 
152         loadPageVerifyTitle2(html);
153     }
154 
155     /**
156      * @throws Exception if the test fails
157      */
158     @Test
159     @Alerts({"0", "", ""})
160     public void ctorNoArgs() throws Exception {
161         final String html = DOCTYPE_HTML
162                 + "<html>\n"
163                 + "<head>\n"
164                 + "<script>\n"
165                 + LOG_TITLE_FUNCTION
166                 + "  function test() {\n"
167                 + "    var blob = new Blob();\n"
168 
169                 + "    log(blob.size);\n"
170                 + "    log(blob.type);\n"
171                 + "    try {\n"
172                 + "      blob.text().then(function(text) { log(text); });\n"
173                 + "    } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
174                 + "  }\n"
175                 + "</script>\n"
176                 + "</head>\n"
177                 + "<body onload='test()'>\n"
178                 + "</body>\n"
179                 + "</html>";
180 
181         loadPage2(html);
182         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
183     }
184 
185     /**
186      * @throws Exception if the test fails
187      */
188     @Test
189     @Alerts({"0", "", ""})
190     public void ctorEmpty() 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                 + "    var blob = new Blob([]);\n"
198 
199                 + "    log(blob.size);\n"
200                 + "    log(blob.type);\n"
201                 + "    try {\n"
202                 + "      blob.text().then(function(text) { log(text); });\n"
203                 + "    } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
204                 + "  }\n"
205                 + "</script>\n"
206                 + "</head>\n"
207                 + "<body onload='test()'>\n"
208                 + "</body>\n"
209                 + "</html>";
210 
211         loadPage2(html);
212         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
213     }
214 
215     /**
216      * @throws Exception if the test fails
217      */
218     @Test
219     @Alerts({"8", "", "HtmlUnit"})
220     public void ctorString() throws Exception {
221         final String html = DOCTYPE_HTML
222                 + "<html>\n"
223                 + "<head>\n"
224                 + "<script>\n"
225                 + LOG_TITLE_FUNCTION
226                 + "  function test() {\n"
227                 + "    var blob = new Blob(['HtmlUnit']);\n"
228 
229                 + "    log(blob.size);\n"
230                 + "    log(blob.type);\n"
231                 + "    try {\n"
232                 + "      blob.text().then(function(text) { log(text); });\n"
233                 + "    } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
234                 + "  }\n"
235                 + "</script>\n"
236                 + "</head>\n"
237                 + "<body onload='test()'>\n"
238                 + "</body>\n"
239                 + "</html>";
240 
241         loadPage2(html);
242         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
243     }
244 
245     /**
246      * @throws Exception if the test fails
247      */
248     @Test
249     @Alerts({"8", "application/octet-stream", "HtmlUnit"})
250     public void ctorStringWithOptions() throws Exception {
251         final String html = DOCTYPE_HTML
252                 + "<html>\n"
253                 + "<head>\n"
254                 + "<script>\n"
255                 + LOG_TITLE_FUNCTION
256                 + "  function test() {\n"
257                 + "    var blob = new Blob(['Html', 'Unit'], {type: 'application/octet-stream'});\n"
258 
259                 + "    log(blob.size);\n"
260                 + "    log(blob.type);\n"
261                 + "    try {\n"
262                 + "      blob.text().then(function(text) { log(text); });\n"
263                 + "    } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
264                 + "  }\n"
265                 + "</script>\n"
266                 + "</head>\n"
267                 + "<body onload='test()'>\n"
268                 + "</body>\n"
269                 + "</html>";
270 
271         loadPage2(html);
272         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
273     }
274 
275     /**
276      * @throws Exception if the test fails
277      */
278     @Test
279     @Alerts({"16", "", "HtmlUnitis great"})
280     public void ctorStrings() throws Exception {
281         final String html = DOCTYPE_HTML
282                 + "<html>\n"
283                 + "<head>\n"
284                 + "<script>\n"
285                 + LOG_TITLE_FUNCTION
286                 + "  function test() {\n"
287                 + "    var blob = new Blob(['Html', 'Unit', 'is great']);\n"
288 
289                 + "    log(blob.size);\n"
290                 + "    log(blob.type);\n"
291                 + "    try {\n"
292                 + "      blob.text().then(function(text) { log(text); });\n"
293                 + "    } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
294                 + "  }\n"
295                 + "</script>\n"
296                 + "</head>\n"
297                 + "<body onload='test()'>\n"
298                 + "</body>\n"
299                 + "</html>";
300 
301         loadPage2(html);
302         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
303     }
304 
305     /**
306      * @throws Exception if the test fails
307      */
308     @Test
309     @Alerts({"12", "", "HtmlUnitMMMK"})
310     public void ctorMixed() throws Exception {
311         final String html = DOCTYPE_HTML
312                 + "<html>\n"
313                 + "<head>\n"
314                 + "<script>\n"
315                 + LOG_TITLE_FUNCTION
316                 + "  function test() {\n"
317                 + "    var nab = new ArrayBuffer(2);\n"
318                 + "    var nabv = new Uint8Array(nab, 0, 2);\n"
319                 + "    nabv.set([77, 77], 0);\n"
320                 + "    var blob = new Blob(['HtmlUnit',"
321                                         + "nab, new Int8Array([77,75])]);\n"
322 
323                 + "    log(blob.size);\n"
324                 + "    log(blob.type);\n"
325                 + "    try {\n"
326                 + "      blob.text().then(function(text) { log(text); });\n"
327                 + "    } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
328                 + "  }\n"
329                 + "</script>\n"
330                 + "</head>\n"
331                 + "<body onload='test()'>\n"
332                 + "</body>\n"
333                 + "</html>";
334 
335         loadPage2(html);
336         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
337     }
338 
339     /**
340      * @throws Exception if the test fails
341      */
342     @Test
343     @Alerts({"34", "", "HtmlUnitHtmlUnitMMMKMKHtmlUnitMMMK"})
344     public void ctorMixedBlobs() throws Exception {
345         final String html = DOCTYPE_HTML
346                 + "<html>\n"
347                 + "<head>\n"
348                 + "<script>\n"
349                 + LOG_TITLE_FUNCTION
350                 + "  function test() {\n"
351                 + "    var nab = new ArrayBuffer(2);\n"
352                 + "    var nabv = new Uint8Array(nab, 0, 2);\n"
353                 + "    nabv.set([77, 77], 0);\n"
354                 + "    var blob = new Blob(['HtmlUnit',"
355                                         + "nab, new Int8Array([77,75])]);\n"
356                 + "    blob = new Blob(['HtmlUnit',"
357                                     + "blob, new Int8Array([77,75]), blob]);\n"
358                 + "    log(blob.size);\n"
359                 + "    log(blob.type);\n"
360                 + "    try {\n"
361                 + "      blob.text().then(function(text) { log(text); });\n"
362                 + "    } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
363                 + "  }\n"
364                 + "</script>\n"
365                 + "</head>\n"
366                 + "<body onload='test()'>\n"
367                 + "</body>\n"
368                 + "</html>";
369 
370         loadPage2(html);
371         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
372     }
373 
374     /**
375      * @throws Exception if the test fails
376      */
377     @Test
378     @Alerts({"function", "Hello HtmlUnit"})
379     public void arrayBuffer() throws Exception {
380         final String html = DOCTYPE_HTML
381                 + "<html>\n"
382                 + "<head>\n"
383                 + "<script>\n"
384                 + LOG_TITLE_FUNCTION
385                 + "function test() {\n"
386                 + "  var blob = new Blob(['Hello HtmlUnit'], {type : 'text/html'});\n"
387                 + "  log(typeof blob.arrayBuffer);\n"
388                 + "  try {\n"
389                 + "    blob.arrayBuffer().then(function(buf) {\n"
390                 + "      var arr = new Uint8Array(buf);\n"
391                 + "      log(String.fromCharCode.apply(String, arr));\n"
392                 + "    })\n"
393                 + "  } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
394                 + "}\n"
395                 + "</script>\n"
396                 + "</head>\n"
397                 + "<body onload='test()'>\n"
398                 + "</body>\n"
399                 + "</html>";
400 
401         loadPage2(html);
402         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
403     }
404 
405     /**
406      * @throws Exception if the test fails
407      */
408     @Test
409     @Alerts({"12", "", "function", "3", "", "tml"})
410     public void slice() throws Exception {
411         final String html = DOCTYPE_HTML
412                 + "<html>\n"
413                 + "<head>\n"
414                 + "<script>\n"
415                 + LOG_TITLE_FUNCTION
416                 + "  function test() {\n"
417                 + "    var nab = new ArrayBuffer(2);\n"
418                 + "    var nabv = new Uint8Array(nab, 0, 2);\n"
419                 + "    nabv.set([77, 77], 0);\n"
420                 + "    var blob = new Blob(['HtmlUnit',"
421                                         + "nab, new Int8Array([77,75])]);\n"
422 
423                 + "    log(blob.size);\n"
424                 + "    log(blob.type);\n"
425 
426                 + "    log(typeof blob.slice);\n"
427 
428                 + "    var sliced = blob.slice(1,4);\n"
429                 + "    log(sliced.size);\n"
430                 + "    log(sliced.type);\n"
431 
432                 + "    try {\n"
433                 + "      sliced.text().then(function(text) { log(text); });\n"
434                 + "    } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
435                 + "  }\n"
436                 + "</script>\n"
437                 + "</head>\n"
438                 + "<body onload='test()'>\n"
439                 + "</body>\n"
440                 + "</html>";
441 
442         loadPage2(html);
443         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
444     }
445 
446     /**
447      * @throws Exception if the test fails
448      */
449     @Test
450     @Alerts({"12", "", "12", "", "HtmlUnitMMMK"})
451     public void sliceWhole() throws Exception {
452         slice("blob.slice();");
453     }
454 
455     /**
456      * @throws Exception if the test fails
457      */
458     @Test
459     @Alerts({"12", "", "9", "", "lUnitMMMK"})
460     public void sliceStartOnly() throws Exception {
461         slice("blob.slice(3);");
462     }
463 
464     /**
465      * @throws Exception if the test fails
466      */
467     @Test
468     @Alerts({"12", "", "7", "", "nitMMMK"})
469     public void sliceStartOnlyNegative() throws Exception {
470         slice("blob.slice(-7);");
471     }
472 
473     /**
474      * @throws Exception if the test fails
475      */
476     @Test
477     @Alerts({"12", "", "12", "", "HtmlUnitMMMK"})
478     public void sliceStartOnlyNegativeOutside() throws Exception {
479         slice("blob.slice(-123);");
480     }
481 
482     /**
483      * @throws Exception if the test fails
484      */
485     @Test
486     @Alerts({"12", "", "3", "", "mlU"})
487     public void sliceEndNegative() throws Exception {
488         slice("blob.slice(2, -7);");
489     }
490 
491     /**
492      * @throws Exception if the test fails
493      */
494     @Test
495     @Alerts({"12", "", "10", "", "mlUnitMMMK"})
496     public void sliceEndOutside() throws Exception {
497         slice("blob.slice(2, 1234);");
498     }
499 
500     /**
501      * @throws Exception if the test fails
502      */
503     @Test
504     @Alerts({"12", "", "0", "", ""})
505     public void sliceBothOutside() throws Exception {
506         slice("blob.slice(123, 1234);");
507     }
508 
509     /**
510      * @throws Exception if the test fails
511      */
512     @Test
513     @Alerts({"12", "", "0", "", ""})
514     public void sliceNoIntersection() throws Exception {
515         slice("blob.slice(5, 4);");
516     }
517 
518     /**
519      * @throws Exception if the test fails
520      */
521     @Test
522     @Alerts({"12", "", "1", "", "U"})
523     public void sliceEmptyIntersection() throws Exception {
524         slice("blob.slice(4, 5);");
525     }
526 
527     /**
528      * @throws Exception if the test fails
529      */
530     @Test
531     @Alerts({"12", "", "12", "", "HtmlUnitMMMK"})
532     public void sliceWrongStart() throws Exception {
533         slice("blob.slice('four');");
534     }
535 
536     /**
537      * @throws Exception if the test fails
538      */
539     @Test
540     @Alerts({"12", "", "0", "", ""})
541     public void sliceWrongEnd() throws Exception {
542         slice("blob.slice(1, 'four');");
543     }
544 
545     /**
546      * @throws Exception if the test fails
547      */
548     @Test
549     @Alerts({"12", "", "1", "type", "t"})
550     public void sliceContentType() throws Exception {
551         slice("blob.slice(1, 2, 'tyPE');");
552     }
553 
554     /**
555      * @throws Exception if the test fails
556      */
557     @Test
558     @Alerts({"12", "", "1", "7", "t"})
559     public void sliceContentTypeNotString() throws Exception {
560         slice("blob.slice(1, 2, 7);");
561     }
562 
563     private void slice(final String slice) throws Exception {
564         final String html = DOCTYPE_HTML
565                 + "<html>\n"
566                 + "<head>\n"
567                 + "<script>\n"
568                 + LOG_TITLE_FUNCTION
569                 + "  function test() {\n"
570                 + "    var nab = new ArrayBuffer(2);\n"
571                 + "    var nabv = new Uint8Array(nab, 0, 2);\n"
572                 + "    nabv.set([77, 77], 0);\n"
573                 + "    var blob = new Blob(['HtmlUnit',"
574                                         + "nab, new Int8Array([77,75])]);\n"
575 
576                 + "    log(blob.size);\n"
577                 + "    log(blob.type);\n"
578 
579                 + "    var sliced = " + slice + "\n"
580                 + "    log(sliced.size);\n"
581                 + "    log(sliced.type);\n"
582 
583                 + "    try {\n"
584                 + "      sliced.text().then(function(text) { log(text); });\n"
585                 + "    } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
586                 + "  }\n"
587                 + "</script>\n"
588                 + "</head>\n"
589                 + "<body onload='test()'>\n"
590                 + "</body>\n"
591                 + "</html>";
592 
593         loadPage2(html);
594         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
595     }
596 }