diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /dom/system/tests/ioutils/test_ioutils_read_write_utf8.html | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/system/tests/ioutils/test_ioutils_read_write_utf8.html')
-rw-r--r-- | dom/system/tests/ioutils/test_ioutils_read_write_utf8.html | 384 |
1 files changed, 384 insertions, 0 deletions
diff --git a/dom/system/tests/ioutils/test_ioutils_read_write_utf8.html b/dom/system/tests/ioutils/test_ioutils_read_write_utf8.html new file mode 100644 index 0000000000..cdea016732 --- /dev/null +++ b/dom/system/tests/ioutils/test_ioutils_read_write_utf8.html @@ -0,0 +1,384 @@ +<!-- Any copyright is dedicated to the Public Domain. +- http://creativecommons.org/publicdomain/zero/1.0/ --> +<!DOCTYPE HTML> +<html> + +<head> + <meta charset="utf-8"> + <title>Test the IOUtils file I/O API</title> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + <script src="file_ioutils_test_fixtures.js"></script> + <script> + "use strict"; + + const { Assert } = ChromeUtils.importESModule( + "resource://testing-common/Assert.sys.mjs" + ); + + // This is an impossible sequence of bytes in an UTF-8 encoded file. + // See section 3.5.3 of this text: + // https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt + const invalidUTF8 = Uint8Array.of(0xfe, 0xfe, 0xff, 0xff); + + add_task(async function test_read_utf8_failure() { + info("Test attempt to read non-existent file (UTF8)"); + const doesNotExist = PathUtils.join(PathUtils.tempDir, "does_not_exist.tmp"); + await Assert.rejects( + IOUtils.readUTF8(doesNotExist), + /Could not open the file at .*/, + "IOUtils::readUTF8 rejects when file does not exist" + ); + + info("Test attempt to read invalid UTF-8"); + const invalidUTF8File = PathUtils.join(PathUtils.tempDir, "invalid_utf8.tmp"); + + // Deliberately write the invalid byte sequence to file. + await IOUtils.write(invalidUTF8File, invalidUTF8); + + await Assert.rejects( + IOUtils.readUTF8(invalidUTF8File), + /Could not read file\(.*\) because it is not UTF-8 encoded/, + "IOUtils::readUTF8 will reject when reading a file that is not valid UTF-8" + ); + + await cleanup(invalidUTF8File); + }); + + add_task(async function test_write_utf8_no_overwrite() { + // Make a new file, and try to write to it with overwrites disabled. + const tmpFileName = PathUtils.join(PathUtils.tempDir, "test_ioutils_write_utf8_overwrite.tmp"); + const untouchableContents = "Can't touch this!\n"; + await IOUtils.writeUTF8(tmpFileName, untouchableContents); + + const newContents = "Nah nah nah!\n"; + await Assert.rejects( + IOUtils.writeUTF8(tmpFileName, newContents, { + mode: "create", + }), + /Refusing to overwrite the file at */, + "IOUtils::writeUTF8 rejects writing to existing file if overwrites are disabled" + ); + ok( + await fileHasTextContents(tmpFileName, untouchableContents), + "IOUtils::writeUTF8 doesn't change target file when overwrite is refused" + ); + + const bytesWritten = await IOUtils.writeUTF8( + tmpFileName, + newContents, + { mode: "overwrite" } + ); + is( + bytesWritten, + newContents.length, + "IOUtils::writeUTF8 can overwrite files if specified" + ); + ok( + await fileHasTextContents(tmpFileName, newContents), + "IOUtils::writeUTF8 overwrites with the expected contents" + ); + + await cleanup(tmpFileName); + }); + + add_task(async function test_write_with_backup() { + info("Test backup file option with non-existing file"); + let fileContents = "Original file contents"; + let destFileName = PathUtils.join(PathUtils.tempDir, "test_write_utf8_with_backup_option.tmp"); + let backupFileName = destFileName + ".backup"; + let bytesWritten = + await IOUtils.writeUTF8(destFileName, fileContents, { + backupFile: backupFileName, + }); + ok( + await fileHasTextContents(destFileName, "Original file contents"), + "IOUtils::writeUTF8 creates a new file with the correct contents" + ); + ok( + !await fileExists(backupFileName), + "IOUtils::writeUTF8 does not create a backup if the target file does not exist" + ); + is( + bytesWritten, + fileContents.length, + "IOUtils::write correctly writes to a new file without performing a backup" + ); + + info("Test backup file option with existing destination"); + let newFileContents = "New file contents"; + ok(await fileExists(destFileName), `Expected ${destFileName} to exist`); + bytesWritten = + await IOUtils.writeUTF8(destFileName, newFileContents, { + backupFile: backupFileName, + }); + ok( + await fileHasTextContents(backupFileName, "Original file contents"), + "IOUtils::writeUTF8 can backup an existing file before writing" + ); + ok( + await fileHasTextContents(destFileName, "New file contents"), + "IOUtils::writeUTF8 can create the target with the correct contents" + ); + is( + bytesWritten, + newFileContents.length, + "IOUtils::writeUTF8 correctly writes to the target after taking a backup" + ); + + await cleanup(destFileName, backupFileName); + }); + + add_task(async function test_write_with_backup_and_tmp() { + info("Test backup with tmp and backup file options, non-existing destination"); + let fileContents = "Original file contents"; + let destFileName = PathUtils.join(PathUtils.tempDir, "test_write_utf8_with_backup_and_tmp_options.tmp"); + let backupFileName = destFileName + ".backup"; + let tmpFileName = PathUtils.join(PathUtils.tempDir, "temp_file.tmp"); + let bytesWritten = + await IOUtils.writeUTF8(destFileName, fileContents, { + backupFile: backupFileName, + tmpPath: tmpFileName, + }); + ok(!await fileExists(tmpFileName), "IOUtils::writeUTF8 cleans up the tmpFile"); + ok( + !await fileExists(backupFileName), + "IOUtils::writeUTF8 does not create a backup if the target file does not exist" + ); + ok( + await fileHasTextContents(destFileName, "Original file contents"), + "IOUtils::writeUTF8 can write to the destination when a temporary file is used" + ); + is( + bytesWritten, + fileContents.length, + "IOUtils::writeUTF8 can copy tmp file to destination without performing a backup" + ); + + info("Test backup with tmp and backup file options, existing destination"); + let newFileContents = "New file contents"; + bytesWritten = + await IOUtils.writeUTF8(destFileName, newFileContents, { + backupFile: backupFileName, + tmpPath: tmpFileName, + }); + + ok(!await fileExists(tmpFileName), "IOUtils::writeUTF8 cleans up the tmpFile"); + ok( + await fileHasTextContents(backupFileName, "Original file contents"), + "IOUtils::writeUTF8 can create a backup if the target file exists" + ); + ok( + await fileHasTextContents(destFileName, "New file contents"), + "IOUtils::writeUTF8 can write to the destination when a temporary file is used" + ); + is( + bytesWritten, + newFileContents.length, + "IOUtils::writeUTF8 can move tmp file to destination after performing a backup" + ); + + await cleanup(destFileName, backupFileName); + }); + + add_task(async function test_empty_read_and_write_utf8() { + const tmpFileName = PathUtils.join(PathUtils.tempDir, "test_ioutils_empty_utf8.tmp"); + const emptyString = "" + const bytesWritten = await IOUtils.writeUTF8( + tmpFileName, + emptyString + ); + is(bytesWritten, 0, "IOUtils::writeUTF8 can create an empty file"); + + const nothing = await IOUtils.readUTF8(tmpFileName); + is(nothing.length, 0, "IOUtils::readUTF8 can read empty files"); + + await cleanup(tmpFileName); + }); + + add_task(async function test_full_read_and_write_utf8() { + // Write a file. + info("Test writing emoji file"); + const tmpFileName = PathUtils.join(PathUtils.tempDir, "test_ioutils_emoji.tmp"); + + // Make sure non-ASCII text is supported for writing and reading back. + // For fun, a sampling of space-separated emoji characters from different + // Unicode versions, including multi-byte glyphs that are rendered using + // ZWJ sequences. + const emoji = "☕️ ⚧️ 😀 🖖🏿 🤠 🏳️🌈 🥠 🏴☠️ 🪐"; + const expectedBytes = 71; + const bytesWritten = await IOUtils.writeUTF8(tmpFileName, emoji); + is( + bytesWritten, + expectedBytes, + "IOUtils::writeUTF8 can write emoji to file" + ); + + // Read it back. + info("Test reading emoji from file"); + let fileContents = await IOUtils.readUTF8(tmpFileName); + ok( + emoji == fileContents && + emoji.length == fileContents.length, + "IOUtils::readUTF8 can read back entire file" + ); + + // Clean up. + await cleanup(tmpFileName); + }); + + add_task(async function test_write_utf8_relative_path() { + const tmpFileName = "test_ioutils_write_utf8_relative_path.tmp"; + + info("Test writing a file at a relative destination"); + await Assert.rejects( + IOUtils.writeUTF8(tmpFileName, "foo"), + /Could not parse path/, + "IOUtils::writeUTF8 only works with absolute paths" + ); + }); + + add_task(async function test_read_utf8_relative_path() { + const tmpFileName = "test_ioutils_read_utf8_relative_path.tmp"; + + info("Test reading a file at a relative destination"); + await Assert.rejects( + IOUtils.readUTF8(tmpFileName), + /Could not parse path/, + "IOUtils::readUTF8 only works with absolute paths" + ); + }); + + + add_task(async function test_utf8_lz4() { + const tmpFileName = PathUtils.join(PathUtils.tempDir, "test_ioutils_utf8_lz4.tmp"); + + info("Test writing lz4 encoded UTF-8 string"); + const emoji = "☕️ ⚧️ 😀 🖖🏿 🤠 🏳️🌈 🥠 🏴☠️ 🪐"; + let bytesWritten = await IOUtils.writeUTF8(tmpFileName, emoji, { compress: true }); + is(bytesWritten, 83, "Expected to write 64 bytes"); + + info("Test reading lz4 encoded UTF-8 string"); + let readData = await IOUtils.readUTF8(tmpFileName, { decompress: true }); + is(readData, emoji, "IOUtils can write and read back UTF-8 LZ4 encoded data"); + + info("Test writing lz4 compressed UTF-8 string"); + const lotsOfCoffee = new Array(24).fill("☕️").join(""); // ☕️ is 3 bytes in UTF-8: \0xe2 \0x98 \0x95 + bytesWritten = await IOUtils.writeUTF8(tmpFileName, lotsOfCoffee, { compress: true }); + console.log(bytesWritten); + is(bytesWritten, 28, "Expected 72 bytes to compress to 28 bytes"); + + info("Test reading lz4 encoded UTF-8 string"); + readData = await IOUtils.readUTF8(tmpFileName, { decompress: true }); + is(readData, lotsOfCoffee, "IOUtils can write and read back UTF-8 LZ4 compressed data"); + + info("Test writing empty lz4 compressed UTF-8 string") + const empty = ""; + bytesWritten = await IOUtils.writeUTF8(tmpFileName, empty, { compress: true }); + is(bytesWritten, 12, "Expected to write just the LZ4 header"); + + info("Test reading empty lz4 compressed UTF-8 string") + const readEmpty = await IOUtils.readUTF8(tmpFileName, { decompress: true }); + is(readEmpty, empty, "IOUtils can write and read back empty buffers with LZ4"); + const readEmptyRaw = await IOUtils.readUTF8(tmpFileName, { decompress: false }); + is(readEmptyRaw.length, 12, "Expected to read back just the LZ4 header"); + + await cleanup(tmpFileName); + }); + + add_task(async function test_utf8_lz4_bad_call() { + const tmpFileName = PathUtils.join(PathUtils.tempDir, "test_ioutils_utf8_lz4_bad_call.tmp"); + + info("readUTF8 ignores the maxBytes option if provided"); + const emoji = "☕️ ⚧️ 😀 🖖🏿 🤠 🏳️🌈 🥠 🏴☠️ 🪐"; + let bytesWritten = await IOUtils.writeUTF8(tmpFileName, emoji, { compress: true }); + is(bytesWritten, 83, "Expected to write 83 bytes"); + + let readData = await IOUtils.readUTF8(tmpFileName, { maxBytes: 4, decompress: true }); + is(readData, emoji, "IOUtils can write and read back UTF-8 LZ4 encoded data"); + + await cleanup(tmpFileName) + }); + + add_task(async function test_utf8_lz4_failure() { + const tmpFileName = PathUtils.join(PathUtils.tempDir, "test_ioutils_utf8_lz4_fail.tmp"); + + info("Test decompression of non-lz4 UTF-8 string"); + const repeatedBytes = Uint8Array.of(...new Array(50).fill(1)); + await IOUtils.write(tmpFileName, repeatedBytes, { compress: false }); + + await Assert.rejects( + IOUtils.readUTF8(tmpFileName, { decompress: true }), + /Could not decompress file because it has an invalid LZ4 header \(wrong magic number: .*\)/, + "IOUtils::readUTF8 fails to decompress LZ4 data with a bad header" + ); + + info("Test UTF-8 decompression of short byte buffer"); + const elevenBytes = Uint8Array.of(...new Array(11).fill(1)); + await IOUtils.write(tmpFileName, elevenBytes, { compress: false }); + + await Assert.rejects( + IOUtils.readUTF8(tmpFileName, { decompress: true }), + /Could not decompress file because the buffer is too short/, + "IOUtils::readUTF8 fails to decompress LZ4 data with missing header" + ); + + info("Test UTF-8 decompression of valid header, but corrupt contents"); + const headerFor10bytes = [109, 111, 122, 76, 122, 52, 48, 0, 10, 0, 0, 0] // "mozlz40\0" + 4 byte length + const badContents = new Array(11).fill(255); // Bad leading byte, followed by uncompressed stream. + const goodHeaderBadContents = Uint8Array.of(...headerFor10bytes, ...badContents); + await IOUtils.write(tmpFileName, goodHeaderBadContents, { compress: false }); + + await Assert.rejects( + IOUtils.readUTF8(tmpFileName, { decompress: true }), + /Could not decompress file contents, the file may be corrupt/, + "IOUtils::readUTF8 fails to read corrupt LZ4 contents with a correct header" + ); + + info("Testing decompression of an empty file (no header)"); + { + const n = await IOUtils.writeUTF8(tmpFileName, ""); + ok(n === 0, "Overwrote with empty file"); + } + await Assert.rejects( + IOUtils.readUTF8(tmpFileName, { decompress: true }), + /Could not decompress file because the buffer is too short/, + "IOUtils::readUTF8 fails to decompress empty files" + ); + + await cleanup(tmpFileName); + }); + + add_task(async function test_skipBOM() { + const tmpFileName = PathUtils.join(PathUtils.tempDir, "test_ioutils_readutf8_bom.tmp"); + + const raw = `\uFEFFstring`; + + await IOUtils.writeUTF8(tmpFileName, raw); + + is( + await IOUtils.readUTF8(tmpFileName), + "string", + "IOUtils.readUTF8 should skip BOM by default" + ); + + await IOUtils.writeUTF8(tmpFileName, raw, { compress: true }); + + is( + await IOUtils.readUTF8(tmpFileName, { decompress: true }), + "string", + "IOUtils.readUTF8 should skip BOM by default for compressed files" + ); + + await cleanup(tmpFileName); + }); + </script> +</head> + +<body> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> + +</html> |