Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests for file snapshot state #34143

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions FileAPI/snapshot-state/content-size-manual.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<!DOCTYPE html>
<meta charset="utf-8">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<ol>
<li>
Set the file timestamp to a specific value.
<ul>
<li>On Linux: <code>touch -t 202201010000 foo.txt</code></li>
<li>On Windows (PowerShell): <code>(gci foo.txt).lastWriteTime = "2022-01-01"</code></li>
</ul>
</li>
<li><label>Select the touched file: <input type="file" id="fileInput"></label></li>
<li>
Modify the content of the selected file in various way for each test run:
<ol>
<li>Same size but different content</li>
<li>Smaller size</li>
<li>Larger size</li>
<li>Zero size</li>
</ol>
</li>
<li>Restore the file timestamp to the value used at the step 1.</li>
<li><button id="readyButton">Then click this</button></li>
</ol>
<script type="module">
import { initialState, ready, testFileAttributes, promisifiedFileReader } from "./utils.js";

setup({ explicit_timeout: true });

testFileAttributes("File attributes should not change when the native content size changes");

promise_test(async t => {
await ready;
const arrayBuffer = await fileInput.files[0].arrayBuffer();
assert_less_than_equal(arrayBuffer.byteLength, initialState.size, "buffer should be smaller than the initial file size");
}, `File#arrayBuffer() should return clipped result by File#size`);

promise_test(async t => {
await ready;
const text = await fileInput.files[0].text();
const encoded = new TextEncoder().encode(text);
assert_less_than_equal(encoded.byteLength, initialState.size, "text should be smaller than the initial file size");
}, `File#text() should return clipped result by File#size`);

promise_test(async t => {
await ready;
const arrayBuffer = await new Response(await fileInput.files[0].stream()).arrayBuffer();
assert_less_than_equal(arrayBuffer.byteLength, initialState.size, "stream should be smaller than the initial file size");
}, `File#stream() should return clipped result by File#size`);

promise_test(async t => {
await ready;
const arrayBuffer = await promisifiedFileReader(fileInput.files[0], "readAsArrayBuffer");
assert_less_than_equal(arrayBuffer.byteLength, initialState.size, "buffer should be smaller than the initial file size");
}, `FileReader#readAsArrayBuffer() return clipped result by File#size`);

promise_test(async t => {
await ready;
const str = await promisifiedFileReader(fileInput.files[0], "readAsBinaryString");
assert_less_than_equal(str.length, initialState.size, "string should be smaller than the initial file size");
}, `FileReader#readAsBinaryString() return clipped result by File#size`);

promise_test(async t => {
await ready;
const url = await promisifiedFileReader(fileInput.files[0], "readAsDataURL");
const res = await fetch(url);
const arrayBuffer = await res.arrayBuffer();
assert_less_than_equal(arrayBuffer.byteLength, initialState.size, "buffer should be smaller than the initial file size");
}, `FileReader#readAsDataURL() return clipped result by File#size`);

promise_test(async t => {
await ready;
const text = await promisifiedFileReader(fileInput.files[0], "readAsText");
const encoded = new TextEncoder().encode(text);
assert_less_than_equal(encoded.byteLength, initialState.size, "text should be smaller than the initial file size");
}, `FileReader#readAsText() return clipped result by File#size`);
</script>
41 changes: 41 additions & 0 deletions FileAPI/snapshot-state/touch-manual.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!DOCTYPE html>
<meta charset="utf-8">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<ol>
<li><label>Select a file first: <input type="file" id="fileInput"></label></li>
<li>
Update the file timestamp.
<ul>
<li>On Linux: <code>touch -t 202201010000 foo.txt</code></li>
<li>On Windows (PowerShell): <code>(gci foo.txt).lastWriteTime = "2022-01-01"</code></li>
</ul>
</li>
<li><button id="readyButton">Then click this</button></li>
</ol>
<script type="module">
import { ready, testFileAttributes, promisifiedFileReader } from "./utils.js";

setup({ explicit_timeout: true });

testFileAttributes("File attributes should not change when the native timestamp changes");

for (const method of ["text", "arrayBuffer"]) {
promise_test(async t => {
await ready;
await promise_rejects_dom(t, "NotReadableError", fileInput.files[0][method]());
}, `File#${method}() should fail if file.lastModified and the actual native timestamp is different`);
}

promise_test(async t => {
await ready;
await promise_rejects_dom(t, "NotReadableError", fileInput.files[0].stream().pipeTo(new WritableStream()));
}, `File#stream() should fail if file.lastModified and the actual native timestamp is different`);

for (const method of ["readAsArrayBuffer", "readAsBinaryString", "readAsDataURL", "readAsText"]) {
promise_test(async t => {
await ready;
await promise_rejects_dom(t, "NotReadableError", promisifiedFileReader(fileInput.files[0], method));
}, `FileReader#${method}() should fail if file.lastModified and the actual native timestamp is different`);
}
</script>
45 changes: 45 additions & 0 deletions FileAPI/snapshot-state/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* @param {Element} element
* @param {string} eventName
*/
function eventFired(element, eventName) {
return new Promise((resolve) => {
element.addEventListener(eventName, resolve, { once: true });
});
}

/**
* @param {File} file
* @param {keyof<FileReader>} method
*/
export function promisifiedFileReader(file, method) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onerror = () => reject(reader.error);
reader.onloadend = () => resolve(reader.result);
reader[method](file);
});
}

export let initialState;
export const ready = (async () => {
await eventFired(fileInput, "change");
const file = fileInput.files[0];
initialState = {
size: file.size,
lastModified: file.lastModified,
};
await eventFired(readyButton, "click");
})();

export function testFileAttributes(title) {
promise_test(async (t) => {
await ready;
assert_equals(initialState.size, fileInput.files[0].size, "File#size");
assert_equals(
initialState.lastModified,
fileInput.files[0].lastModified,
"File#lastModified"
);
}, title);
}