Branch data Line data Source code
1 [ + ]: 1 : import assert from 'node:assert/strict';
2 : 1 : import { File as FilePolyfill } from '../../../../lib/helper/file-polyfill.js';
3 : 1 :
4 : 1 : globalThis.File = FilePolyfill;
5 : 1 :
6 [ + ]: 1 : export default (activeURL) => {
7 : 1 :
8 : 1 : /* Test the existance of of File interface */
9 [ + ]: 1 : (function test(){
10 : 1 : assert('File' in globalThis, 'globalThis should have a File property.');
11 : 1 : })('File interface object exists');
12 : 1 :
13 : 1 : /* Test the number of arguments */
14 [ + ]: 1 : (function test(){
15 : 1 : assert.throws(
16 [ + ]: 1 : () => {
17 : 1 : new File();
18 : 1 : },
19 [ + ]: 1 : (err) => {
20 : 1 : assert(err instanceof TypeError, 'Bits argument is required');
21 : 1 : return true;
22 : 1 : }
23 : 1 : );
24 : 1 :
25 : 1 : assert.throws(
26 [ + ]: 1 : () => {
27 : 1 : new File([]);
28 : 1 : },
29 [ + ]: 1 : (err) => {
30 : 1 : assert(err instanceof TypeError, 'Name argument is required');
31 : 1 : return true;
32 : 1 : }
33 : 1 : );
34 : 1 :
35 : 1 : })('Required arguments');
36 : 1 :
37 : 1 : /* Test first argument */
38 [ + ]: 1 : const to_string_obj = { toString: () => 'a string' };
39 [ + ]: 1 : const to_string_throws = { toString: () => { throw new Error('expected'); } };
40 : 1 :
41 : 1 : test_first_argument([], 0, 'empty fileBits');
42 : 1 : test_first_argument(['bits'], 4, 'DOMString fileBits');
43 : 1 : test_first_argument(['𝓽𝓮𝔁𝓽'], 16, 'Unicode DOMString fileBits');
44 : 1 : test_first_argument([new String('string object')], 13, 'String object fileBits');
45 : 1 : test_first_argument([new Blob()], 0, 'Empty Blob fileBits');
46 : 1 : test_first_argument([new Blob(['bits'])], 4, 'Blob fileBits');
47 : 1 : test_first_argument([new File([], 'world.txt')], 0, 'Empty File fileBits');
48 : 1 : test_first_argument([new File(['bits'], 'world.txt')], 4, 'File fileBits');
49 : 1 : test_first_argument([new ArrayBuffer(8)], 8, 'ArrayBuffer fileBits');
50 : 1 : test_first_argument([new Uint8Array([0x50, 0x41, 0x53, 0x53])], 4, 'Typed array fileBits');
51 : 1 : test_first_argument([
52 : 1 : 'bits',
53 : 1 : new Blob(['bits']), new Blob(),
54 : 1 : new Uint8Array([0x50, 0x41]),
55 : 1 : new Uint16Array([0x5353]),
56 : 1 : new Uint32Array([0x53534150])
57 : 1 : ], 16, 'Various fileBits');
58 : 1 : test_first_argument([12], 2, 'Number in fileBits');
59 : 1 : test_first_argument([[1,2,3]], 5, 'Array in fileBits');
60 : 1 : test_first_argument([{}], 15, 'Object in fileBits'); // '[object Object]'
61 : 1 :
62 : 1 : test_first_argument([to_string_obj], 8, "Object with toString in fileBits");
63 [ + ]: 1 : test_first_argument({[Symbol.iterator](){
64 : 1 : let i = 0;
65 : 1 : return {
66 [ + ]: 1 : next: () => [
67 : 3 : {done:false, value:'ab'},
68 : 3 : {done:false, value:'cde'},
69 : 3 : {done:true}
70 : 1 : ][i++]};
71 : 1 : }}, 5, 'Custom @@iterator');
72 : 1 :
73 [ + ]: 1 : ['hello', 0, null].forEach(arg => {
74 : 3 :
75 : 3 : assert.throws(
76 [ + ]: 3 : () => {
77 : 3 : new File(arg, 'world.html');
78 : 3 : },
79 [ + ]: 3 : (err) => {
80 : 3 : assert(err instanceof TypeError, 'Constructor should throw for invalid bits argument');
81 : 3 : return true;
82 : 3 : }
83 : 3 : );
84 : 1 : });
85 : 1 :
86 [ + ]: 1 : (function test(){
87 : 1 : assert.throws(
88 [ + ]: 1 : () => {
89 : 1 : new File([to_string_throws], 'name.txt');
90 : 1 : },
91 [ + ]: 1 : (err) => {
92 : 1 : assert(err instanceof Error, 'Constructor should propagate exceptions');
93 : 1 : return true;
94 : 1 : }
95 : 1 : );
96 : 1 : })('Bits argument: object that throws');
97 : 1 :
98 [ + ]: 1 : function test_first_argument(arg1, expectedSize, testName){
99 : 16 :
100 : 16 : const file = new File(arg1, 'dummy');
101 : 16 :
102 : 16 : assert(file instanceof File);
103 : 16 :
104 : 16 : assert.strictEqual(file.name, 'dummy');
105 : 16 : assert.strictEqual(file.size, expectedSize);
106 : 16 : assert.strictEqual(file.type, '');
107 : 16 :
108 : 16 : // assert_false(file.isClosed); XXX: File.isClosed doesn't seem to be implemented
109 : 16 : assert.notEqual(file.lastModified, '');
110 : 16 : }
111 : 1 :
112 : 1 : /* Test second argument */
113 : 1 :
114 : 1 : test_second_argument('dummy', 'dummy', 'Using fileName');
115 : 1 : test_second_argument('dummy/foo', 'dummy/foo', 'No replacement when using special character in fileName');
116 : 1 : test_second_argument(null, 'null', 'Using null fileName');
117 : 1 : test_second_argument(1, '1', 'Using number fileName');
118 : 1 : test_second_argument('', '', 'Using empty string fileName');
119 : 1 :
120 [ + ]: 1 : function test_second_argument(arg2, expectedFileName, testName){
121 : 5 :
122 : 5 : const file = new File(['bits'], arg2);
123 : 5 :
124 : 5 : assert(file instanceof File);
125 : 5 : assert.strictEqual(file.name, expectedFileName);
126 : 5 : }
127 : 1 :
128 : 1 : /* Test third argument */
129 : 1 :
130 : 1 : [
131 : 1 : {type: 'text/plain', expected: 'text/plain'},
132 : 1 : {type: 'text/plain;charset=UTF-8', expected: 'text/plain;charset=utf-8'},
133 : 1 : {type: 'TEXT/PLAIN', expected: 'text/plain'},
134 : 1 : {type: '𝓽𝓮𝔁𝓽/𝔭𝔩𝔞𝔦𝔫', expected: ''},
135 : 1 : {type: 'ascii/nonprintable\u001F', expected: ''},
136 : 1 : {type: 'ascii/nonprintable\u007F', expected: ''},
137 : 1 : {type: 'nonascii\u00EE', expected: ''},
138 : 1 : {type: 'nonascii\u1234', expected: ''},
139 : 1 : {type: 'nonparsable', expected: 'nonparsable'}
140 [ + ]: 1 : ].forEach(testCase => {
141 : 9 : const file = new File(['bits'], 'dummy', { type: testCase.type});
142 : 9 :
143 : 9 : assert(file instanceof File);
144 : 9 : assert.strictEqual(file.type, testCase.expected);
145 : 1 : });
146 : 1 :
147 [ + ]: 1 : (function test(){
148 : 1 : const file = new File(['bits'], 'dummy', { lastModified: 42 });
149 : 1 :
150 : 1 : assert(file instanceof File);
151 : 1 : assert.strictEqual(file.lastModified, 42);
152 : 1 : })('Using lastModified');
153 : 1 :
154 [ + ]: 1 : (function test(){
155 : 1 : const file = new File(['bits'], 'dummy', { name: 'foo' });
156 : 1 :
157 : 1 : assert(file instanceof File);
158 : 1 : assert.strictEqual(file.name, 'dummy');
159 : 1 : })('Misusing name');
160 : 1 :
161 [ + ]: 1 : (function test(){
162 : 1 : const file = new File(['bits'], 'dummy', { unknownKey: 'value' });
163 : 1 :
164 : 1 : assert(file instanceof File);
165 : 1 : assert.strictEqual(file.name, 'dummy');
166 : 1 : })('Unknown properties are ignored');
167 : 1 :
168 : 1 : [
169 : 1 : 123,
170 : 1 : 123.4,
171 : 1 : true,
172 : 1 : 'abc'
173 [ + ]: 1 : ].forEach(arg => {
174 : 4 : assert.throws(
175 [ + ]: 4 : () => {
176 : 4 : new File(['bits'], 'name.txt', arg);
177 : 4 : },
178 [ + ]: 4 : (err) => {
179 : 4 : assert(err instanceof TypeError, 'Constructor should throw for invalid property bag type');
180 : 4 : return true;
181 : 4 : }
182 : 4 : );
183 : 1 : });
184 : 1 :
185 : 1 : [
186 : 1 : null,
187 : 1 : undefined,
188 : 1 : [1,2,3],
189 : 1 : /regex/,
190 : 1 : function() {}
191 [ + ]: 1 : ].forEach(arg => {
192 : 5 : assert.strictEqual(new File(['bits'], 'name.txt', arg).size, 4, 'Constructor should accept object-ish property bag type');
193 : 1 : });
194 : 1 :
195 [ + ]: 1 : (function test(){
196 : 1 : assert.throws(
197 [ + ]: 1 : () => {
198 : 1 : new File(['bits'], 'name.txt', {type: to_string_throws});
199 : 1 : },
200 [ + ]: 1 : (err) => {
201 : 1 : assert(err instanceof Error, 'Constructor should propagate exceptions');
202 : 1 : return true;
203 : 1 : }
204 : 1 : );
205 : 1 : })('Property bag propagates exceptions');
206 : 1 :
207 : 1 : }
208 : 1 :
209 : 1 : /*
210 : 1 : * File-constructor.any.js
211 : 1 : *
212 : 1 :
213 : 1 : const to_string_obj = { toString: () => 'a string' };
214 : 1 : const to_string_throws = { toString: () => { throw new Error('expected'); } };
215 : 1 :
216 : 1 : test(function() {
217 : 1 : assert_true("File" in globalThis, "globalThis should have a File property.");
218 : 1 : }, "File interface object exists");
219 : 1 :
220 : 1 : test(t => {
221 : 1 : assert_throws_js(TypeError, () => new File(),
222 : 1 : 'Bits argument is required');
223 : 1 : assert_throws_js(TypeError, () => new File([]),
224 : 1 : 'Name argument is required');
225 : 1 : }, 'Required arguments');
226 : 1 :
227 : 1 : function test_first_argument(arg1, expectedSize, testName) {
228 : 1 : test(function() {
229 : 1 : var file = new File(arg1, "dummy");
230 : 1 : assert_true(file instanceof File);
231 : 1 : assert_equals(file.name, "dummy");
232 : 1 : assert_equals(file.size, expectedSize);
233 : 1 : assert_equals(file.type, "");
234 : 1 : // assert_false(file.isClosed); XXX: File.isClosed doesn't seem to be implemented
235 : 1 : assert_not_equals(file.lastModified, "");
236 : 1 : }, testName);
237 : 1 : }
238 : 1 :
239 : 1 : test_first_argument([], 0, "empty fileBits");
240 : 1 : test_first_argument(["bits"], 4, "DOMString fileBits");
241 : 1 : test_first_argument(["𝓽𝓮𝔁𝓽"], 16, "Unicode DOMString fileBits");
242 : 1 : test_first_argument([new String('string object')], 13, "String object fileBits");
243 : 1 : test_first_argument([new Blob()], 0, "Empty Blob fileBits");
244 : 1 : test_first_argument([new Blob(["bits"])], 4, "Blob fileBits");
245 : 1 : test_first_argument([new File([], 'world.txt')], 0, "Empty File fileBits");
246 : 1 : test_first_argument([new File(["bits"], 'world.txt')], 4, "File fileBits");
247 : 1 : test_first_argument([new ArrayBuffer(8)], 8, "ArrayBuffer fileBits");
248 : 1 : test_first_argument([new Uint8Array([0x50, 0x41, 0x53, 0x53])], 4, "Typed array fileBits");
249 : 1 : test_first_argument(["bits", new Blob(["bits"]), new Blob(), new Uint8Array([0x50, 0x41]),
250 : 1 : new Uint16Array([0x5353]), new Uint32Array([0x53534150])], 16, "Various fileBits");
251 : 1 : test_first_argument([12], 2, "Number in fileBits");
252 : 1 : test_first_argument([[1,2,3]], 5, "Array in fileBits");
253 : 1 : test_first_argument([{}], 15, "Object in fileBits"); // "[object Object]"
254 : 1 : if (globalThis.document !== undefined) {
255 : 1 : test_first_argument([document.body], 24, "HTMLBodyElement in fileBits"); // "[object HTMLBodyElement]"
256 : 1 : }
257 : 1 : test_first_argument([to_string_obj], 8, "Object with toString in fileBits");
258 : 1 : test_first_argument({[Symbol.iterator]() {
259 : 1 : let i = 0;
260 : 1 : return {next: () => [
261 : 1 : {done:false, value:'ab'},
262 : 1 : {done:false, value:'cde'},
263 : 1 : {done:true}
264 : 1 : ][i++]};
265 : 1 : }}, 5, 'Custom @@iterator');
266 : 1 :
267 : 1 : [
268 : 1 : 'hello',
269 : 1 : 0,
270 : 1 : null
271 : 1 : ].forEach(arg => {
272 : 1 : test(t => {
273 : 1 : assert_throws_js(TypeError, () => new File(arg, 'world.html'),
274 : 1 : 'Constructor should throw for invalid bits argument');
275 : 1 : }, `Invalid bits argument: ${JSON.stringify(arg)}`);
276 : 1 : });
277 : 1 :
278 : 1 : test(t => {
279 : 1 : assert_throws_js(Error, () => new File([to_string_throws], 'name.txt'),
280 : 1 : 'Constructor should propagate exceptions');
281 : 1 : }, 'Bits argument: object that throws');
282 : 1 :
283 : 1 :
284 : 1 : function test_second_argument(arg2, expectedFileName, testName) {
285 : 1 : test(function() {
286 : 1 : var file = new File(["bits"], arg2);
287 : 1 : assert_true(file instanceof File);
288 : 1 : assert_equals(file.name, expectedFileName);
289 : 1 : }, testName);
290 : 1 : }
291 : 1 :
292 : 1 : test_second_argument("dummy", "dummy", "Using fileName");
293 : 1 : test_second_argument("dummy/foo", "dummy/foo",
294 : 1 : "No replacement when using special character in fileName");
295 : 1 : test_second_argument(null, "null", "Using null fileName");
296 : 1 : test_second_argument(1, "1", "Using number fileName");
297 : 1 : test_second_argument('', '', "Using empty string fileName");
298 : 1 : if (globalThis.document !== undefined) {
299 : 1 : test_second_argument(document.body, '[object HTMLBodyElement]', "Using object fileName");
300 : 1 : }
301 : 1 :
302 : 1 : // testing the third argument
303 : 1 : [
304 : 1 : {type: 'text/plain', expected: 'text/plain'},
305 : 1 : {type: 'text/plain;charset=UTF-8', expected: 'text/plain;charset=utf-8'},
306 : 1 : {type: 'TEXT/PLAIN', expected: 'text/plain'},
307 : 1 : {type: '𝓽𝓮𝔁𝓽/𝔭𝔩𝔞𝔦𝔫', expected: ''},
308 : 1 : {type: 'ascii/nonprintable\u001F', expected: ''},
309 : 1 : {type: 'ascii/nonprintable\u007F', expected: ''},
310 : 1 : {type: 'nonascii\u00EE', expected: ''},
311 : 1 : {type: 'nonascii\u1234', expected: ''},
312 : 1 : {type: 'nonparsable', expected: 'nonparsable'}
313 : 1 : ].forEach(testCase => {
314 : 1 : test(t => {
315 : 1 : var file = new File(["bits"], "dummy", { type: testCase.type});
316 : 1 : assert_true(file instanceof File);
317 : 1 : assert_equals(file.type, testCase.expected);
318 : 1 : }, `Using type in File constructor: ${testCase.type}`);
319 : 1 : });
320 : 1 : test(function() {
321 : 1 : var file = new File(["bits"], "dummy", { lastModified: 42 });
322 : 1 : assert_true(file instanceof File);
323 : 1 : assert_equals(file.lastModified, 42);
324 : 1 : }, "Using lastModified");
325 : 1 : test(function() {
326 : 1 : var file = new File(["bits"], "dummy", { name: "foo" });
327 : 1 : assert_true(file instanceof File);
328 : 1 : assert_equals(file.name, "dummy");
329 : 1 : }, "Misusing name");
330 : 1 : test(function() {
331 : 1 : var file = new File(["bits"], "dummy", { unknownKey: "value" });
332 : 1 : assert_true(file instanceof File);
333 : 1 : assert_equals(file.name, "dummy");
334 : 1 : }, "Unknown properties are ignored");
335 : 1 :
336 : 1 : [
337 : 1 : 123,
338 : 1 : 123.4,
339 : 1 : true,
340 : 1 : 'abc'
341 : 1 : ].forEach(arg => {
342 : 1 : test(t => {
343 : 1 : assert_throws_js(TypeError, () => new File(['bits'], 'name.txt', arg),
344 : 1 : 'Constructor should throw for invalid property bag type');
345 : 1 : }, `Invalid property bag: ${JSON.stringify(arg)}`);
346 : 1 : });
347 : 1 :
348 : 1 : [
349 : 1 : null,
350 : 1 : undefined,
351 : 1 : [1,2,3],
352 : 1 : /regex/,
353 : 1 : function() {}
354 : 1 : ].forEach(arg => {
355 : 1 : test(t => {
356 : 1 : assert_equals(new File(['bits'], 'name.txt', arg).size, 4,
357 : 1 : 'Constructor should accept object-ish property bag type');
358 : 1 : }, `Unusual but valid property bag: ${arg}`);
359 : 1 : });
360 : 1 :
361 : 1 : test(t => {
362 : 1 : assert_throws_js(Error,
363 : 1 : () => new File(['bits'], 'name.txt', {type: to_string_throws}),
364 : 1 : 'Constructor should propagate exceptions');
365 : 1 : }, 'Property bag propagates exceptions');
366 : 1 :
367 : 1 : *
368 : 1 : *
369 : 1 : */
|