From 0f777c8c167a7bd2cb5914aee5a0fcb467f5daf9 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Sun, 6 Sep 2026 14:19:04 +0200 Subject: [PATCH 1/2] refactor(api)!: one way to open a file odr::open was six one-line forwards to six DecodedFile constructors, and the split had already reached the bindings: jni exposed both, apple went through the constructors, python bound each. The bodies move to open and the constructors go; DecodedFile keeps only the one that wraps a decoded impl. DocumentFile loses its factories and its decoding constructors with them. It was never a second kind of open - open_document_file repeated open_file's cascade engine for engine for zip and cfb, and both ends threw NoDocumentFile, which as_document_file() throws too. open(...).as_document_file() is the same call, so 73 lines of open_strategy go as well. Java gains Odr.open(File), which is what the removed DecodedFile(File) constructor was. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_016hxDa2rev11eLUEJZJ5nmz --- CHANGELOG.md | 4 + apple/src/ODRFile.mm | 22 ++- cli/src/back_translate.cpp | 3 +- cli/src/meta.cpp | 3 +- cli/src/server.cpp | 3 +- cli/src/translate.cpp | 3 +- .../app/opendocument/core/DecodedFile.java | 22 +-- .../app/opendocument/core/DocumentFile.java | 6 - jni/java/app/opendocument/core/Odr.java | 9 + jni/src/jni_file.cpp | 27 +-- jni/tests/app/opendocument/core/FileTest.java | 2 +- python/src/bind_file.cpp | 34 +--- python/tests/test_file.py | 27 +-- python/tests/test_logger.py | 2 +- src/odr/file.cpp | 41 ----- src/odr/file.hpp | 26 +-- src/odr/internal/html/image_file.cpp | 2 +- src/odr/internal/open_strategy.cpp | 73 --------- src/odr/internal/open_strategy.hpp | 4 - src/odr/odr.cpp | 15 +- test/src/document_list_test.cpp | 5 +- test/src/document_test.cpp | 91 +++++++---- test/src/file_test.cpp | 58 ++++--- test/src/html_test.cpp | 89 +++++----- test/src/internal/csv/csv_file_test.cpp | 4 +- test/src/internal/html/image_file_test.cpp | 10 +- test/src/internal/html/media_file_test.cpp | 15 +- test/src/internal/iwork/keynote_test.cpp | 25 +-- test/src/internal/iwork/numbers_test.cpp | 49 +++--- test/src/internal/iwork/pages_test.cpp | 21 ++- .../internal/markdown/markdown_file_test.cpp | 12 +- test/src/internal/odf/odf_flat_file_test.cpp | 154 ++++++++++-------- .../internal/odf/odf_sheet_repeat_test.cpp | 9 +- test/src/internal/oldms/ppt_test.cpp | 11 +- test/src/internal/oldms/xls_test.cpp | 19 ++- .../ooxml/ooxml_spreadsheet_merge_test.cpp | 5 +- test/src/internal/rtf/rtf_document_test.cpp | 12 +- test/src/internal/svg/svg_file_test.cpp | 3 +- test/src/internal/text/text_file_test.cpp | 4 +- test/src/internal/xml/xml_file_test.cpp | 11 +- test/src/odr_test.cpp | 5 +- 41 files changed, 410 insertions(+), 530 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca88a2c93..3056203ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,10 @@ The release run heads these entries with the version and opens a fresh ## Unreleased +- **Breaking**: `odr::open` is the only way to decode a file. The `DecodedFile` + and `DocumentFile` constructors and `DocumentFile::from_disk`/`::from_memory` + are gone, in every binding; narrow with `open(...).as_document_file()`. + - **Breaking**: `DecodedFile::list_file_types`/`::mimetype` and `DocumentFile::type`/`::meta` are gone, in every binding. Use the free `odr::list_file_types`/`odr::mimetype`, or `odr::open(...).file_type()`. diff --git a/apple/src/ODRFile.mm b/apple/src/ODRFile.mm index 68c145012..918c54739 100644 --- a/apple/src/ODRFile.mm +++ b/apple/src/ODRFile.mm @@ -313,8 +313,7 @@ + (instancetype)decodedFileWithHandle:(odr::DecodedFile)handle { + (nullable instancetype)decodePath:(NSString *)path error:(NSError **)error { return guarded(error, [&]() -> ODRDecodedFile * { - return [ODRDecodedFile - decodedFileWithHandle:odr::DecodedFile(to_string(path))]; + return [ODRDecodedFile decodedFileWithHandle:odr::open(to_string(path))]; }); } @@ -323,9 +322,8 @@ + (nullable instancetype)decodePath:(NSString *)path error:(NSError **)error { return guarded(error, [&]() -> ODRDecodedFile * { return [ODRDecodedFile - decodedFileWithHandle:odr::DecodedFile( - to_string(path), - static_cast(type))]; + decodedFileWithHandle:odr::open(to_string(path), + static_cast(type))]; }); } @@ -340,13 +338,13 @@ + (nullable instancetype)decodePath:(NSString *)path } native.file_type_priority = to_file_types(preference.fileTypePriority); return [ODRDecodedFile - decodedFileWithHandle:odr::DecodedFile(to_string(path), native)]; + decodedFileWithHandle:odr::open(to_string(path), native)]; }); } + (nullable instancetype)decodeFile:(ODRFile *)file error:(NSError **)error { return guarded(error, [&]() -> ODRDecodedFile * { - return [ODRDecodedFile decodedFileWithHandle:odr::DecodedFile(file.handle)]; + return [ODRDecodedFile decodedFileWithHandle:odr::open(file.handle)]; }); } @@ -355,7 +353,7 @@ + (nullable instancetype)decodePath:(NSString *)path error:(NSError **)error { return guarded(error, [&]() -> ODRDecodedFile * { return [ODRDecodedFile - decodedFileWithHandle:odr::DecodedFile(to_string(path), logger.handle)]; + decodedFileWithHandle:odr::open(to_string(path), logger.handle)]; }); } @@ -365,9 +363,9 @@ + (nullable instancetype)decodePath:(NSString *)path error:(NSError **)error { return guarded(error, [&]() -> ODRDecodedFile * { return [ODRDecodedFile - decodedFileWithHandle:odr::DecodedFile(to_string(path), - static_cast(type), - logger.handle)]; + decodedFileWithHandle:odr::open(to_string(path), + static_cast(type), + logger.handle)]; }); } @@ -376,7 +374,7 @@ + (nullable instancetype)decodeFile:(ODRFile *)file error:(NSError **)error { return guarded(error, [&]() -> ODRDecodedFile * { return [ODRDecodedFile - decodedFileWithHandle:odr::DecodedFile(file.handle, logger.handle)]; + decodedFileWithHandle:odr::open(file.handle, logger.handle)]; }); } diff --git a/cli/src/back_translate.cpp b/cli/src/back_translate.cpp index 656ada4d3..d9af40e87 100644 --- a/cli/src/back_translate.cpp +++ b/cli/src/back_translate.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include @@ -23,7 +24,7 @@ int main(const int argc, char **argv) { const std::string diff_path{argv[2]}; const std::string output{argv[3]}; - const DocumentFile document_file{input}; + const DocumentFile document_file = open(input).as_document_file(); if (document_file.password_encrypted()) { ODR_FATAL(logger, "encrypted documents are not supported"); diff --git a/cli/src/meta.cpp b/cli/src/meta.cpp index 579c85fd1..14d7d29b6 100644 --- a/cli/src/meta.cpp +++ b/cli/src/meta.cpp @@ -1,4 +1,5 @@ #include +#include #include @@ -25,7 +26,7 @@ int main(const int argc, char **argv) { password = argv[2]; } - DocumentFile document_file{input}; + DocumentFile document_file = open(input).as_document_file(); if (document_file.password_encrypted()) { if (!password) { diff --git a/cli/src/server.cpp b/cli/src/server.cpp index 93fc89f1a..2da1b5112 100644 --- a/cli/src/server.cpp +++ b/cli/src/server.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -30,7 +31,7 @@ int main(const int argc, char **argv) { DecodePreference decode_preference; decode_preference.as_file_type = FileType::zip; - DecodedFile decoded_file{input, decode_preference, logger}; + DecodedFile decoded_file = open(input, decode_preference, logger); if (decoded_file.password_encrypted()) { if (!password) { diff --git a/cli/src/translate.cpp b/cli/src/translate.cpp index 32e2695fc..134bdc77e 100644 --- a/cli/src/translate.cpp +++ b/cli/src/translate.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -26,7 +27,7 @@ int main(const int argc, char **argv) { password = argv[3]; } - DecodedFile decoded_file{input}; + DecodedFile decoded_file = open(input); if (decoded_file.password_encrypted()) { if (!password) { diff --git a/jni/java/app/opendocument/core/DecodedFile.java b/jni/java/app/opendocument/core/DecodedFile.java index 2bdf4d179..b1ba8f2eb 100644 --- a/jni/java/app/opendocument/core/DecodedFile.java +++ b/jni/java/app/opendocument/core/DecodedFile.java @@ -1,9 +1,9 @@ package app.opendocument.core; /** - * A decoded file. Mirrors {@code odr::DecodedFile}. Obtain via - * {@link Odr#open} or the constructors; {@code as*} accessors return typed - * views and throw when the file is not of that kind (check {@code is*} first). + * A decoded file. Mirrors {@code odr::DecodedFile}. Obtain via {@link Odr#open}; + * {@code as*} accessors return typed views and throw when the file is not of + * that kind (check {@code is*} first). */ public class DecodedFile extends NativeResource { static { @@ -14,18 +14,6 @@ public class DecodedFile extends NativeResource { super(handle, null, DecodedFile::destroy); } - public DecodedFile(String path) { - this(create(path)); - } - - public DecodedFile(String path, FileType as) { - this(createAs(path, as.toNative())); - } - - public DecodedFile(File file) { - this(file.decode()); - } - public File file() { return new File(fileNative(handle())); } @@ -116,10 +104,6 @@ public FontFile asFontFile() { return new FontFile(asFontFileNative(handle())); } - private static native long create(String path); - - private static native long createAs(String path, int as); - static native void destroy(long handle); private native long fileNative(long handle); diff --git a/jni/java/app/opendocument/core/DocumentFile.java b/jni/java/app/opendocument/core/DocumentFile.java index 2add96060..4cb97f4a1 100644 --- a/jni/java/app/opendocument/core/DocumentFile.java +++ b/jni/java/app/opendocument/core/DocumentFile.java @@ -6,10 +6,6 @@ public final class DocumentFile extends DecodedFile { super(handle); } - public DocumentFile(String path) { - this(create(path)); - } - public DocumentType documentType() { return DocumentType.fromNative(documentTypeNative(handle())); } @@ -33,8 +29,6 @@ public Document document() { return new Document(documentNative(handle())); } - private static native long create(String path); - private native int documentTypeNative(long handle); private native long decryptDocumentFileNative(long handle, String password); diff --git a/jni/java/app/opendocument/core/Odr.java b/jni/java/app/opendocument/core/Odr.java index 0e497aaad..153e82341 100644 --- a/jni/java/app/opendocument/core/Odr.java +++ b/jni/java/app/opendocument/core/Odr.java @@ -100,6 +100,15 @@ public static List listFileTypes(String path) { /** Determines the MIME type of a file. */ public static native String mimetype(String path); + /** Decodes an already-opened file. */ + public static DecodedFile open(File file) { + try { + return new DecodedFile(file.decode()); + } finally { + file.keepAlive(); + } + } + /** Opens and decodes a file. */ public static DecodedFile open(String path) { return new DecodedFile(openNative(path)); diff --git a/jni/src/jni_file.cpp b/jni/src/jni_file.cpp index 5db8a9700..8e836122a 100644 --- a/jni/src/jni_file.cpp +++ b/jni/src/jni_file.cpp @@ -90,7 +90,7 @@ extern "C" JNIEXPORT void JNICALL Java_app_opendocument_core_File_copyNative( extern "C" JNIEXPORT jlong JNICALL Java_app_opendocument_core_File_decodeNative( JNIEnv *env, jobject, jlong handle) { return guarded(env, [&] { - return make_handle(odr::DecodedFile(*from_handle(handle))); + return make_handle(odr::open(*from_handle(handle))); }); } @@ -99,22 +99,6 @@ extern "C" JNIEXPORT jlong JNICALL Java_app_opendocument_core_File_decodeNative( // Handles hold a heap `odr::DecodedFile` (the typed C++ subclasses are sliced // away); typed accessors re-derive the typed view per call via `as_*`. -extern "C" JNIEXPORT jlong JNICALL -Java_app_opendocument_core_DecodedFile_create(JNIEnv *env, jclass, - jstring path) { - return guarded( - env, [&] { return make_handle(odr::DecodedFile(to_string(env, path))); }); -} - -extern "C" JNIEXPORT jlong JNICALL -Java_app_opendocument_core_DecodedFile_createAs(JNIEnv *env, jclass, - jstring path, jint as) { - return guarded(env, [&] { - return make_handle( - odr::DecodedFile(to_string(env, path), static_cast(as))); - }); -} - extern "C" JNIEXPORT void JNICALL Java_app_opendocument_core_DecodedFile_destroy(JNIEnv *env, jclass, jlong handle) { @@ -338,15 +322,6 @@ Java_app_opendocument_core_ArchiveFile_archiveNative(JNIEnv *env, jobject, // app.opendocument.core.DocumentFile -extern "C" JNIEXPORT jlong JNICALL -Java_app_opendocument_core_DocumentFile_create(JNIEnv *env, jclass, - jstring path) { - return guarded(env, [&] { - return make_handle( - odr::DecodedFile(odr::DocumentFile(to_string(env, path)))); - }); -} - extern "C" JNIEXPORT jint JNICALL Java_app_opendocument_core_DocumentFile_documentTypeNative(JNIEnv *env, jobject, jlong handle) { diff --git a/jni/tests/app/opendocument/core/FileTest.java b/jni/tests/app/opendocument/core/FileTest.java index c3ea2832a..c399632d4 100644 --- a/jni/tests/app/opendocument/core/FileTest.java +++ b/jni/tests/app/opendocument/core/FileTest.java @@ -95,7 +95,7 @@ void archiveEntryName() throws IOException { void decodeAnOpenFile() throws IOException { Path odt = TestFiles.odtFile(tempDir); try (File file = new File(odt.toString()); - DecodedFile decoded = new DecodedFile(file)) { + DecodedFile decoded = Odr.open(file)) { assertEquals(FileType.OPENDOCUMENT_TEXT, decoded.fileType()); } } diff --git a/python/src/bind_file.cpp b/python/src/bind_file.cpp index 9679d1fd5..af713efb4 100644 --- a/python/src/bind_file.cpp +++ b/python/src/bind_file.cpp @@ -185,21 +185,8 @@ void odr_python::bind_file(py::module_ &m) { "Read the whole file into bytes.") .def("copy", &odr::File::copy, py::arg("path")); + // no constructor: `pyodr.open(...)` decodes, this is what it hands back py::class_(m, "DecodedFile") - .def(py::init(), py::arg("file"), - py::arg("logger") = odr::Logger::null()) - .def(py::init(), - py::arg("file"), py::arg("as_type"), - py::arg("logger") = odr::Logger::null()) - .def(py::init(), - py::arg("file"), py::arg("preference"), - py::arg("logger") = odr::Logger::null()) - .def(py::init(), - py::arg("path"), py::arg("logger") = odr::Logger::null()) - .def(py::init(), - py::arg("path"), py::arg("as_type"), - py::arg("logger") = odr::Logger::null()) .def("file", &odr::DecodedFile::file) .def("file_type", &odr::DecodedFile::file_type) .def("file_category", &odr::DecodedFile::file_category) @@ -246,25 +233,8 @@ void odr_python::bind_file(py::module_ &m) { py::class_(m, "ArchiveFile") .def("archive", &odr::ArchiveFile::archive); + // no constructor either: `pyodr.open(...).as_document_file()` narrows py::class_(m, "DocumentFile") - .def(py::init(), py::arg("file"), - py::arg("logger") = odr::Logger::null()) - .def(py::init(), py::arg("path")) - .def_static("from_disk", &odr::DocumentFile::from_disk, py::arg("path"), - py::arg("logger") = odr::Logger::null(), - py::call_guard(), - "Decode the document file at `path` on disk.") - .def_static( - "from_memory", - [](const py::bytes &data, const odr::Logger &logger) { - // the bytes have to be copied out under the GIL; only the decode - // that follows is long-running - std::string bytes(data); - const py::gil_scoped_release release; - return odr::DocumentFile::from_memory(std::move(bytes), logger); - }, - py::arg("data"), py::arg("logger") = odr::Logger::null(), - "Decode a document file held in memory; `data` is its bytes.") .def("document_type", &odr::DocumentFile::document_type) .def("decrypt", &odr::DocumentFile::decrypt, py::arg("password"), py::call_guard()) diff --git a/python/tests/test_file.py b/python/tests/test_file.py index 37a190b74..b28c6310c 100644 --- a/python/tests/test_file.py +++ b/python/tests/test_file.py @@ -54,10 +54,10 @@ def test_file_name_of_an_archive_entry(odt_path): def test_named_bytes_decode_as_markdown(): # markdown has no signature, so only the name can offer it named = pyodr.File.from_memory(b"# heading\n", "notes.md") - assert pyodr.DecodedFile(named).file_type() == pyodr.FileType.markdown + assert pyodr.open(named).file_type() == pyodr.FileType.markdown unnamed = pyodr.File.from_memory(b"# heading\n") - assert pyodr.DecodedFile(unnamed).file_type() == pyodr.FileType.text_file + assert pyodr.open(unnamed).file_type() == pyodr.FileType.text_file def test_open_missing_file(tmp_path): @@ -152,18 +152,18 @@ def test_open_from_memory_as_type(odt_path): def test_decoded_file_from_file(odt_path): file = pyodr.File.from_memory(odt_path.read_bytes()) - assert pyodr.DecodedFile(file).file_type() == pyodr.FileType.opendocument_text - assert pyodr.DecodedFile(file, pyodr.FileType.zip).is_archive_file() + assert pyodr.open(file).file_type() == pyodr.FileType.opendocument_text + assert pyodr.open(file, pyodr.FileType.zip).is_archive_file() preference = pyodr.DecodePreference() preference.as_file_type = pyodr.FileType.zip - assert pyodr.DecodedFile(file, preference).is_archive_file() + assert pyodr.open(file, preference).is_archive_file() def test_document_file_from_file(odt_path): file = pyodr.File.from_memory(odt_path.read_bytes()) - document_file = pyodr.DocumentFile(file) + document_file = pyodr.open(file).as_document_file() assert document_file.file_type() == pyodr.FileType.opendocument_text assert document_file.file_meta().type == pyodr.FileType.opendocument_text @@ -171,8 +171,8 @@ def test_document_file_from_file(odt_path): def test_document_file_from_disk_and_from_memory(odt_path): - from_disk = pyodr.DocumentFile.from_disk(str(odt_path)) - from_memory = pyodr.DocumentFile.from_memory(odt_path.read_bytes()) + from_disk = pyodr.open(str(odt_path)).as_document_file() + from_memory = pyodr.open(pyodr.File.from_memory(odt_path.read_bytes())).as_document_file() assert from_disk.file_type() == pyodr.FileType.opendocument_text assert from_memory.file_type() == from_disk.file_type() @@ -184,7 +184,7 @@ def test_document_file_from_disk_and_from_memory(odt_path): def test_document_file_thumbnail(tmp_path, odt_path): # The minimal odt the fixture builds carries none. - assert pyodr.DocumentFile.from_disk(str(odt_path)).thumbnail() is None + assert pyodr.open(str(odt_path)).as_document_file().thumbnail() is None with_thumbnail = tmp_path / "with-thumbnail.odt" with zipfile.ZipFile(odt_path) as source: @@ -194,14 +194,14 @@ def test_document_file_thumbnail(tmp_path, odt_path): for name, content in entries.items(): archive.writestr(name, content) - thumbnail = pyodr.DocumentFile.from_disk(str(with_thumbnail)).thumbnail() + thumbnail = pyodr.open(str(with_thumbnail)).as_document_file().thumbnail() assert thumbnail is not None assert thumbnail.read() == b"not really a png" def test_document_file_from_memory_rejects_a_non_document(): with pytest.raises(pyodr.Error): - pyodr.DocumentFile.from_memory(b"not a document") + pyodr.open(pyodr.File.from_memory(b"not a document")).as_document_file() def test_file_and_path_entry_points_agree(odt_path): @@ -211,4 +211,7 @@ def test_file_and_path_entry_points_agree(odt_path): assert pyodr.mimetype(file) == pyodr.mimetype(path) assert pyodr.list_file_types(file) == pyodr.list_file_types(path) assert pyodr.open(file).file_type() == pyodr.open(path).file_type() - assert pyodr.DocumentFile(file).file_type() == pyodr.DocumentFile(path).file_type() + assert ( + pyodr.open(file).as_document_file().file_type() + == pyodr.open(path).as_document_file().file_type() + ) diff --git a/python/tests/test_logger.py b/python/tests/test_logger.py index d25f896e8..744ee4d18 100644 --- a/python/tests/test_logger.py +++ b/python/tests/test_logger.py @@ -65,4 +65,4 @@ def test_logger_accepted_by_entry_points(odt_path): logger = pyodr.Logger(CollectingLogger()) assert pyodr.list_file_types(str(odt_path), logger=logger) assert pyodr.mimetype(str(odt_path), logger=logger) - assert pyodr.DecodedFile(str(odt_path), logger=logger).is_document_file() + assert pyodr.open(str(odt_path), logger=logger).is_document_file() diff --git a/src/odr/file.cpp b/src/odr/file.cpp index eb2db84e9..a202d2539 100644 --- a/src/odr/file.cpp +++ b/src/odr/file.cpp @@ -94,31 +94,6 @@ DecodedFile::DecodedFile(std::shared_ptr impl) } } -DecodedFile::DecodedFile(const File &file, const Logger &logger) - : DecodedFile(internal::open_strategy::open_file(file.impl(), logger)) {} - -DecodedFile::DecodedFile(const File &file, const FileType as, - const Logger &logger) - : DecodedFile(internal::open_strategy::open_file(file.impl(), as, logger)) { -} - -DecodedFile::DecodedFile(const File &file, const DecodePreference &preference, - const Logger &logger) - : DecodedFile(internal::open_strategy::open_file(file.impl(), preference, - logger)) {} - -DecodedFile::DecodedFile(const std::string &path, const Logger &logger) - : DecodedFile(File::from_disk(path), logger) {} - -DecodedFile::DecodedFile(const std::string &path, const FileType as, - const Logger &logger) - : DecodedFile(File::from_disk(path), as, logger) {} - -DecodedFile::DecodedFile(const std::string &path, - const DecodePreference &preference, - const Logger &logger) - : DecodedFile(File::from_disk(path), preference, logger) {} - File DecodedFile::file() const { return File(m_impl->file()); } FileType DecodedFile::file_type() const noexcept { return m_impl->file_type(); } @@ -345,26 +320,10 @@ ArchiveFile::ArchiveFile(std::shared_ptr impl) Archive ArchiveFile::archive() const { return Archive(m_impl->archive()); } -DocumentFile DocumentFile::from_disk(const std::string &path, - const Logger &logger) { - return DocumentFile(File::from_disk(path), logger); -} - -DocumentFile DocumentFile::from_memory(std::string data, const Logger &logger) { - return DocumentFile(File::from_memory(std::move(data)), logger); -} - DocumentFile::DocumentFile( std::shared_ptr impl) : DecodedFile(impl), m_impl{std::move(impl)} {} -DocumentFile::DocumentFile(const File &file, const Logger &logger) - : DocumentFile( - internal::open_strategy::open_document_file(file.impl(), logger)) {} - -DocumentFile::DocumentFile(const std::string &path, const Logger &logger) - : DocumentFile(File::from_disk(path), logger) {} - DocumentType DocumentFile::document_type() const { return m_impl->document_type(); } diff --git a/src/odr/file.hpp b/src/odr/file.hpp index f248494fb..79daf5409 100644 --- a/src/odr/file.hpp +++ b/src/odr/file.hpp @@ -352,18 +352,8 @@ class File final { /// @brief Represents a decoded file. class DecodedFile { public: + /// Decoding is @ref odr::open; this wraps what it produced. explicit DecodedFile(std::shared_ptr impl); - explicit DecodedFile(const File &file, const Logger &logger = Logger::null()); - DecodedFile(const File &file, FileType as, - const Logger &logger = Logger::null()); - DecodedFile(const File &file, const DecodePreference &preference, - const Logger &logger = Logger::null()); - explicit DecodedFile(const std::string &path, - const Logger &logger = Logger::null()); - DecodedFile(const std::string &path, FileType as, - const Logger &logger = Logger::null()); - DecodedFile(const std::string &path, const DecodePreference &preference, - const Logger &logger = Logger::null()); [[nodiscard]] File file() const; @@ -507,19 +497,9 @@ class ArchiveFile final : public DecodedFile { /// @brief Represents a document file. class DocumentFile final : public DecodedFile { public: - /// @brief Decodes the document file at @p path on disk. - [[nodiscard]] static DocumentFile - from_disk(const std::string &path, const Logger &logger = Logger::null()); - /// @brief Decodes a document file held in memory; @p data is its bytes, - /// moved in. - [[nodiscard]] static DocumentFile - from_memory(std::string data, const Logger &logger = Logger::null()); - + /// Reached through @ref DecodedFile::as_document_file, on what @ref + /// odr::open produced; this wraps what that narrowed to. explicit DocumentFile(std::shared_ptr); - explicit DocumentFile(const File &file, - const Logger &logger = Logger::null()); - explicit DocumentFile(const std::string &path, - const Logger &logger = Logger::null()); [[nodiscard]] DocumentType document_type() const; diff --git a/src/odr/internal/html/image_file.cpp b/src/odr/internal/html/image_file.cpp index c578c746c..ba74e4ba3 100644 --- a/src/odr/internal/html/image_file.cpp +++ b/src/odr/internal/html/image_file.cpp @@ -186,7 +186,7 @@ namespace odr::internal { void html::translate_image_src(const File &file, std::ostream &out, const HtmlConfig &config, const Logger &logger) { try { - translate_image_src(DecodedFile(file).as_image_file(), out, config, logger); + translate_image_src(odr::open(file).as_image_file(), out, config, logger); } catch (...) { // nothing named it, so the label is a guess - browsers sniff `` and // `image/jpg` is what they have been handed here for years diff --git a/src/odr/internal/open_strategy.cpp b/src/odr/internal/open_strategy.cpp index 95ea1eb4b..b5d6b7c62 100644 --- a/src/odr/internal/open_strategy.cpp +++ b/src/odr/internal/open_strategy.cpp @@ -661,77 +661,4 @@ open_strategy::open_file(const std::shared_ptr &file, throw UnknownFileType(); } -std::unique_ptr -open_strategy::open_document_file(const std::shared_ptr &file, - const Logger &logger) { - auto file_type = magic::file_type(*file); - ODR_VERBOSE(logger, - "magic determined file type " << file_type_to_string(file_type)); - - if (file_type == FileType::zip) { - ODR_VERBOSE(logger, "open as zip"); - - auto zip_file = std::make_unique(file); - - auto filesystem = zip_file->archive()->as_filesystem(); - - try { - ODR_VERBOSE(logger, "try open as odf"); - return std::make_unique(filesystem); - } catch (...) { - ODR_VERBOSE(logger, "failed to open as odf"); - } - - try { - ODR_VERBOSE(logger, "try open as ooxml"); - return std::make_unique(filesystem); - } catch (...) { - ODR_VERBOSE(logger, "failed to open as ooxml"); - } - - try { - ODR_VERBOSE(logger, "try open as iwork"); - return std::make_unique(filesystem); - } catch (...) { - ODR_VERBOSE(logger, "failed to open as iwork"); - } - } else if (file_type == FileType::compound_file_binary_format) { - ODR_VERBOSE(logger, "open as cbf"); - - auto cfb_file = std::make_unique(file); - - auto filesystem = cfb_file->archive()->as_filesystem(); - - try { - ODR_VERBOSE(logger, "try open as legacy ms"); - return std::make_unique(filesystem); - } catch (...) { - ODR_VERBOSE(logger, "failed to open as legacy ms"); - } - - try { - ODR_VERBOSE(logger, "try open as ooxml"); - return std::make_unique(filesystem); - } catch (...) { - ODR_VERBOSE(logger, "failed to open as ooxml"); - } - } else if (file_type == FileType::rich_text_format) { - ODR_VERBOSE(logger, "open as rtf"); - return std::make_unique(file); - } else if (file_type == FileType::unknown) { - // a flat odf carries no signature, so magic cannot name it - try { - ODR_VERBOSE(logger, "try open as flat odf"); - const xml::XmlFile xml_file(std::make_shared(file)); - return std::make_unique(xml_file); - } catch (...) { - ODR_VERBOSE(logger, "failed to open as flat odf"); - } - } - - ODR_ERROR(logger, "unsupported file type for document file " - << file_type_to_string(file_type)); - throw NoDocumentFile(); -} - } // namespace odr::internal diff --git a/src/odr/internal/open_strategy.hpp b/src/odr/internal/open_strategy.hpp index b1b00bda7..b6d82f873 100644 --- a/src/odr/internal/open_strategy.hpp +++ b/src/odr/internal/open_strategy.hpp @@ -30,8 +30,4 @@ std::unique_ptr open_file(const std::shared_ptr &file, const DecodePreference &preference, const Logger &logger); -std::unique_ptr -open_document_file(const std::shared_ptr &file, - const Logger &logger); - } // namespace odr::internal::open_strategy diff --git a/src/odr/odr.cpp b/src/odr/odr.cpp index 5d14ae71c..3a6a74f34 100644 --- a/src/odr/odr.cpp +++ b/src/odr/odr.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -203,30 +204,32 @@ std::string_view odr::mimetype(const std::string &path, const Logger &logger) { } odr::DecodedFile odr::open(const File &file, const Logger &logger) { - return DecodedFile(file, logger); + return DecodedFile(internal::open_strategy::open_file(file.impl(), logger)); } odr::DecodedFile odr::open(const File &file, const FileType as, const Logger &logger) { - return {file, as, logger}; + return DecodedFile( + internal::open_strategy::open_file(file.impl(), as, logger)); } odr::DecodedFile odr::open(const File &file, const DecodePreference &preference, const Logger &logger) { - return {file, preference, logger}; + return DecodedFile( + internal::open_strategy::open_file(file.impl(), preference, logger)); } odr::DecodedFile odr::open(const std::string &path, const Logger &logger) { - return DecodedFile(path, logger); + return open(File::from_disk(path), logger); } odr::DecodedFile odr::open(const std::string &path, const FileType as, const Logger &logger) { - return {path, as, logger}; + return open(File::from_disk(path), as, logger); } odr::DecodedFile odr::open(const std::string &path, const DecodePreference &preference, const Logger &logger) { - return {path, preference, logger}; + return open(File::from_disk(path), preference, logger); } diff --git a/test/src/document_list_test.cpp b/test/src/document_list_test.cpp index 938a02c24..c71d5bf1d 100644 --- a/test/src/document_list_test.cpp +++ b/test/src/document_list_test.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include @@ -41,8 +42,8 @@ void collect_markers(const Element element, const ListType type, std::vector markers_of(const std::string &short_path) { const Logger logger = Logger::create_stdio("odr-test", LogLevel::warning); - const DocumentFile document_file(TestData::test_file_path(short_path), - logger); + const DocumentFile document_file = + open(TestData::test_file_path(short_path), logger).as_document_file(); std::vector result; collect_markers(document_file.document().root_element(), ListType::unordered, diff --git a/test/src/document_test.cpp b/test/src/document_test.cpp index 7cf5c204b..0425fd372 100644 --- a/test/src/document_test.cpp +++ b/test/src/document_test.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -71,7 +72,8 @@ Document edit_and_reload(const std::string &path, const char *diff, const std::string &output_name) { const Logger logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DocumentFile document_file(TestData::test_file_path(path), logger); + const DocumentFile document_file = + open(TestData::test_file_path(path), logger).as_document_file(); const Document document = document_file.document(); html::edit(document, diff); @@ -80,14 +82,15 @@ Document edit_and_reload(const std::string &path, const char *diff, (std::filesystem::current_path() / output_name).string(); document.save(output_path); - return DocumentFile(output_path).document(); + return open(output_path).as_document_file().document(); } /// `pages.ods` is password-protected; every test that wants its content opens /// it this way. Document decrypted_pages_ods() { const std::string path = "odr-public/ods/pages.ods"; - return DocumentFile(TestData::test_file_path(path)) + return open(TestData::test_file_path(path)) + .as_document_file() .decrypt(TestData::test_file(path).password.value()) .document(); } @@ -97,8 +100,9 @@ Document decrypted_pages_ods() { TEST(Document, odt) { const Logger logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DocumentFile document_file( - TestData::test_file_path("odr-public/odt/about.odt"), logger); + const DocumentFile document_file = + open(TestData::test_file_path("odr-public/odt/about.odt"), logger) + .as_document_file(); EXPECT_EQ(document_file.file_type(), FileType::opendocument_text); @@ -119,8 +123,9 @@ TEST(Document, odt) { TEST(Document, docx_page_layout) { const Logger logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DocumentFile document_file( - TestData::test_file_path("odr-public/docx/sample3.docx"), logger); + const DocumentFile document_file = + open(TestData::test_file_path("odr-public/docx/sample3.docx"), logger) + .as_document_file(); const Document document = document_file.document(); @@ -140,9 +145,10 @@ TEST(Document, docx_page_layout) { TEST(Document, ods_sheet_page_layout) { const Logger logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DocumentFile document_file( - TestData::test_file_path("odr-public/ods/file_example_ODS_100.ods"), - logger); + const DocumentFile document_file = + open(TestData::test_file_path("odr-public/ods/file_example_ODS_100.ods"), + logger) + .as_document_file(); const Document document = document_file.document(); const PageLayout page_layout = @@ -160,9 +166,10 @@ TEST(Document, ods_sheet_page_layout) { TEST(Document, ods_sheet_page_layout_without_a_paper_size) { const Logger logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DocumentFile document_file( - TestData::test_file_path("odr-public/ods/file_example_ODS_10.ods"), - logger); + const DocumentFile document_file = + open(TestData::test_file_path("odr-public/ods/file_example_ODS_10.ods"), + logger) + .as_document_file(); const Document document = document_file.document(); const PageLayout page_layout = @@ -176,9 +183,10 @@ TEST(Document, ods_sheet_page_layout_without_a_paper_size) { TEST(Document, xlsx_sheet_names) { const Logger logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DocumentFile document_file( - TestData::test_file_path("odr-public/xlsx/sampledatainsurance.xlsx"), - logger); + const DocumentFile document_file = + open(TestData::test_file_path("odr-public/xlsx/sampledatainsurance.xlsx"), + logger) + .as_document_file(); const Document document = document_file.document(); std::vector names; @@ -193,8 +201,9 @@ TEST(Document, xlsx_sheet_names) { TEST(Document, odt_element_path) { const Logger logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DocumentFile document_file( - TestData::test_file_path("odr-public/odt/about.odt"), logger); + const DocumentFile document_file = + open(TestData::test_file_path("odr-public/odt/about.odt"), logger) + .as_document_file(); EXPECT_EQ(document_file.file_type(), FileType::opendocument_text); @@ -216,8 +225,10 @@ TEST(Document, odt_element_path) { TEST(Document, odt_element_path2) { const Logger logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DocumentFile document_file( - TestData::test_file_path("odr-public/odt/style-various-1.odt"), logger); + const DocumentFile document_file = + open(TestData::test_file_path("odr-public/odt/style-various-1.odt"), + logger) + .as_document_file(); EXPECT_EQ(document_file.file_type(), FileType::opendocument_text); @@ -236,8 +247,10 @@ TEST(Document, odt_element_path2) { TEST(Document, odt_text_position) { const Logger logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DocumentFile document_file( - TestData::test_file_path("odr-public/odt/style-various-1.odt"), logger); + const DocumentFile document_file = + open(TestData::test_file_path("odr-public/odt/style-various-1.odt"), + logger) + .as_document_file(); const Document document = document_file.document(); const Element root = document.root_element(); @@ -263,8 +276,10 @@ TEST(Document, odt_text_position) { TEST(Document, odt_line_height_and_text_indent) { const Logger logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DocumentFile document_file( - TestData::test_file_path("odr-public/odt/file-sample_100kB.odt"), logger); + const DocumentFile document_file = + open(TestData::test_file_path("odr-public/odt/file-sample_100kB.odt"), + logger) + .as_document_file(); const Document document = document_file.document(); const Element root = document.root_element(); @@ -281,8 +296,9 @@ TEST(Document, odt_line_height_and_text_indent) { TEST(Document, odg) { const Logger logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DocumentFile document_file( - TestData::test_file_path("odr-public/odg/sample.odg"), logger); + const DocumentFile document_file = + open(TestData::test_file_path("odr-public/odg/sample.odg"), logger) + .as_document_file(); EXPECT_EQ(document_file.file_type(), FileType::opendocument_graphics); @@ -307,7 +323,8 @@ void edit_every_text_and_reload(const std::string &path, const std::string &output_name) { const Logger logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DocumentFile document_file(TestData::test_file_path(path), logger); + const DocumentFile document_file = + open(TestData::test_file_path(path), logger).as_document_file(); const Document document = document_file.document(); set_every_text(document.root_element(), "hello world!"); @@ -316,7 +333,7 @@ void edit_every_text_and_reload(const std::string &path, (std::filesystem::current_path() / output_name).string(); document.save(output_path); - const Document reloaded = DocumentFile(output_path).document(); + const Document reloaded = open(output_path).as_document_file().document(); expect_every_text(reloaded.root_element(), "hello world!"); } @@ -405,19 +422,21 @@ constexpr const char *flat_odt = } // namespace TEST(Document, save_to_memory_round_trips_a_flat_document) { - const Document document = DocumentFile::from_memory(flat_odt).document(); + const Document document = + open(File::from_memory(flat_odt)).as_document_file().document(); set_every_text(document.root_element(), "hello world!"); const File saved = document.save_to_memory(); EXPECT_EQ(FileLocation::memory, saved.location()); - const Document reloaded = DocumentFile(saved).document(); + const Document reloaded = open(saved).as_document_file().document(); expect_every_text(reloaded.root_element(), "hello world!"); } TEST(Document, save_to_a_stream_writes_what_save_to_memory_holds) { - const Document document = DocumentFile::from_memory(flat_odt).document(); + const Document document = + open(File::from_memory(flat_odt)).as_document_file().document(); std::ostringstream out; document.save(out); @@ -427,19 +446,21 @@ TEST(Document, save_to_a_stream_writes_what_save_to_memory_holds) { TEST(Document, save_to_memory_round_trips_a_package) { const Document document = - DocumentFile(TestData::test_file_path("odr-public/odt/about.odt")) + open(TestData::test_file_path("odr-public/odt/about.odt")) + .as_document_file() .document(); set_every_text(document.root_element(), "hello world!"); - const Document reloaded = DocumentFile(document.save_to_memory()).document(); + const Document reloaded = + open(document.save_to_memory()).as_document_file().document(); expect_every_text(reloaded.root_element(), "hello world!"); } TEST(Document, saving_an_unsavable_format_leaves_no_file) { const Document document = - DocumentFile( - TestData::test_file_path("odr-public/pptx/style-various-1.pptx")) + open(TestData::test_file_path("odr-public/pptx/style-various-1.pptx")) + .as_document_file() .document(); ASSERT_FALSE(document.is_savable()); diff --git a/test/src/file_test.cpp b/test/src/file_test.cpp index d3997bc7e..2ccb307f8 100644 --- a/test/src/file_test.cpp +++ b/test/src/file_test.cpp @@ -62,8 +62,8 @@ TEST(File, opening_as_the_wrong_document_type_throws) { for (const auto &[path, is, is_not] : cases) { const std::string file_path = TestData::test_file_path(path); - EXPECT_EQ(DecodedFile(file_path, is).file_type(), is) << path; - EXPECT_THROW(std::ignore = DecodedFile(file_path, is_not), UnknownFileType) + EXPECT_EQ(open(file_path, is).file_type(), is) << path; + EXPECT_THROW(std::ignore = open(file_path, is_not), UnknownFileType) << path; } } @@ -71,9 +71,9 @@ TEST(File, opening_as_the_wrong_document_type_throws) { /// The one reading that is not its own container's: an encrypted ooxml names /// no inner type until it is decrypted, so it stands in for the one asked for. TEST(File, an_encrypted_ooxml_opens_as_the_type_asked_for) { - const DecodedFile file( - TestData::test_file_path("odr-public/docx/encrypted.docx"), - FileType::office_open_xml_document); + const DecodedFile file = + open(TestData::test_file_path("odr-public/docx/encrypted.docx"), + FileType::office_open_xml_document); EXPECT_EQ(file.file_type(), FileType::office_open_xml_encrypted); EXPECT_TRUE(file.password_encrypted()); @@ -88,12 +88,12 @@ TEST(File, a_flat_document_and_a_package_answer_a_wrong_type_alike) { R"(application/vnd.oasis.opendocument.text">)" R"()"; - EXPECT_THROW(std::ignore = DecodedFile(File::from_memory(flat), - FileType::opendocument_graphics), + EXPECT_THROW(std::ignore = open(File::from_memory(flat), + FileType::opendocument_graphics), UnknownFileType); - EXPECT_THROW(std::ignore = DecodedFile( - TestData::test_file_path("odr-public/odt/about.odt"), - FileType::opendocument_graphics), + EXPECT_THROW(std::ignore = + open(TestData::test_file_path("odr-public/odt/about.odt"), + FileType::opendocument_graphics), UnknownFileType); } @@ -129,7 +129,7 @@ TEST(File, an_archive_entry_is_named_by_its_entry) { std::stringstream out; zip.save(out); - const Filesystem filesystem = DecodedFile(File::from_memory(out.str())) + const Filesystem filesystem = open(File::from_memory(out.str())) .as_archive_file() .archive() .as_filesystem(); @@ -153,9 +153,9 @@ TEST(File, from_memory_holds_its_bytes) { TEST(File, from_memory_decodes_the_same_as_from_disk) { const std::string path = TestData::test_file_path("odr-public/odt/about.odt"); - const DecodedFile from_disk(File::from_disk(path)); - const DecodedFile from_memory( - File::from_memory(internal::util::file::read(path))); + const DecodedFile from_disk = open(File::from_disk(path)); + const DecodedFile from_memory = + open(File::from_memory(internal::util::file::read(path))); EXPECT_EQ(from_memory.file_type(), from_disk.file_type()); EXPECT_EQ(from_memory.file_category(), from_disk.file_category()); @@ -200,14 +200,17 @@ TEST(File, disk_file_has_no_memory_data) { EXPECT_FALSE(file.memory_data().has_value()); } -TEST(DocumentFile, open) { EXPECT_THROW(DocumentFile("/"), FileNotFound); } +TEST(DocumentFile, open) { + EXPECT_THROW(open("/").as_document_file(), FileNotFound); +} TEST(DocumentFile, from_disk_and_from_memory_agree) { const std::string path = TestData::test_file_path("odr-public/odt/about.odt"); - const DocumentFile from_disk = DocumentFile::from_disk(path); + const DocumentFile from_disk = open(path).as_document_file(); const DocumentFile from_memory = - DocumentFile::from_memory(internal::util::file::read(path)); + open(File::from_memory(internal::util::file::read(path))) + .as_document_file(); EXPECT_EQ(from_memory.file_type(), from_disk.file_type()); EXPECT_EQ(from_memory.document_type(), from_disk.document_type()); @@ -217,24 +220,26 @@ TEST(DocumentFile, from_disk_and_from_memory_agree) { /// Not a document, so both factories have to refuse it the same way. TEST(DocumentFile, from_memory_throws_on_a_non_document) { - EXPECT_THROW(std::ignore = DocumentFile::from_memory("not a document"), + EXPECT_THROW(std::ignore = + open(File::from_memory("not a document")).as_document_file(), NoDocumentFile); } TEST(DocumentFile, odf_thumbnail) { - const DocumentFile file( - TestData::test_file_path("odr-public/ods/file_example_ODS_10.ods")); + const DocumentFile file = + open(TestData::test_file_path("odr-public/ods/file_example_ODS_10.ods")) + .as_document_file(); const std::optional thumbnail = file.thumbnail(); ASSERT_TRUE(thumbnail.has_value()); EXPECT_LT(0, thumbnail->size()); - EXPECT_EQ(DecodedFile(*thumbnail).file_type(), - FileType::portable_network_graphics); + EXPECT_EQ(open(*thumbnail).file_type(), FileType::portable_network_graphics); } TEST(DocumentFile, thumbnail_is_absent_where_the_package_has_none) { - const DocumentFile file( - TestData::test_file_path("odr-public/docx/style-various-1.docx")); + const DocumentFile file = + open(TestData::test_file_path("odr-public/docx/style-various-1.docx")) + .as_document_file(); EXPECT_FALSE(file.thumbnail().has_value()); } @@ -261,7 +266,8 @@ TEST(DocumentFile, ooxml_thumbnail_is_named_by_the_package_relationship) { std::stringstream out; zip.save(out); - const DocumentFile file = DocumentFile::from_memory(out.str()); + const DocumentFile file = + open(File::from_memory(out.str())).as_document_file(); ASSERT_EQ(file.file_type(), FileType::office_open_xml_document); const std::optional thumbnail = file.thumbnail(); @@ -276,7 +282,7 @@ TEST(DecodedFile, wpd) { const auto path = TestData::test_file_path("odr-public/wpd/Sync3 Sample Page.wpd"); try { - DecodedFile file(path, logger); + DecodedFile file = open(path, logger); FAIL(); } catch (const UnsupportedFileType &e) { EXPECT_EQ(e.file_type, FileType::word_perfect); diff --git a/test/src/html_test.cpp b/test/src/html_test.cpp index 1565a6caa..5f3293ac3 100644 --- a/test/src/html_test.cpp +++ b/test/src/html_test.cpp @@ -59,15 +59,14 @@ TEST(html, linked_resources_are_served) { EXPECT_GT(linked, 0); }; - check(DecodedFile(TestData::test_file_path("odr-public/odt/about.odt"), - FileType::zip, logger), + check(open(TestData::test_file_path("odr-public/odt/about.odt"), + FileType::zip, logger), "files.html"); - check(DecodedFile(TestData::test_file_path("odr-public/txt/lorem ipsum.txt"), - logger), - "text.html"); check( - DecodedFile(TestData::test_file_path("odr-public/pdf/empty.pdf"), logger), - "document.html"); + open(TestData::test_file_path("odr-public/txt/lorem ipsum.txt"), logger), + "text.html"); + check(open(TestData::test_file_path("odr-public/pdf/empty.pdf"), logger), + "document.html"); } // Same for a document resource, which unlike a shipped one is named by the @@ -77,7 +76,7 @@ TEST(html, linked_images_are_served) { const auto logger = Logger::create_stdio("odr-test", LogLevel::verbose); const auto check = [&](const std::string &path) { - const DecodedFile file(TestData::test_file_path(path), logger); + const DecodedFile file = open(TestData::test_file_path(path), logger); HtmlConfig config; config.embed_images = false; @@ -119,8 +118,9 @@ TEST(html, linked_images_are_served) { TEST(html, archive_entry_yields_to_a_shipped_resource) { const auto logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DecodedFile file(TestData::test_file_path("odr-public/odt/about.odt"), - FileType::zip, logger); + const DecodedFile file = + open(TestData::test_file_path("odr-public/odt/about.odt"), FileType::zip, + logger); HtmlConfig config((std::filesystem::current_path() / "collision").string()); config.embed_shipped_resources = false; @@ -153,8 +153,9 @@ TEST(html, archive_entry_yields_to_a_shipped_resource) { TEST(html, archive_listing) { const auto logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DecodedFile file(TestData::test_file_path("odr-public/odt/about.odt"), - FileType::zip, logger); + const DecodedFile file = + open(TestData::test_file_path("odr-public/odt/about.odt"), FileType::zip, + logger); ASSERT_TRUE(file.is_archive_file()); const std::string output_path = @@ -195,7 +196,7 @@ TEST(html, archive_listing) { namespace { std::string render(const std::string &path, const HtmlConfig &config) { - const DecodedFile file(TestData::test_file_path(path), Logger::null()); + const DecodedFile file = open(TestData::test_file_path(path), Logger::null()); std::ostringstream out; html::translate(file, config).list_views().at(0).write_html(out); @@ -225,14 +226,16 @@ TEST(html, min_content_margin_reaches_every_view) { HtmlConfig config; const auto render_as = [&](const std::string &path, const FileType as) { - const DecodedFile file(TestData::test_file_path(path), as, Logger::null()); + const DecodedFile file = + open(TestData::test_file_path(path), as, Logger::null()); std::ostringstream out; html::translate(file, config).list_views().at(0).write_html(out); return std::move(out).str(); }; const auto xml = [&] { - const DecodedFile file(File::from_memory("c"), FileType::xml); + const DecodedFile file = + open(File::from_memory("c"), FileType::xml); std::ostringstream out; html::translate(file, config).list_views().at(0).write_html(out); return std::move(out).str(); @@ -337,8 +340,8 @@ TEST(html, linked_dark_style_is_served) { config.embed_shipped_resources = false; config.color_scheme = HtmlColorScheme::system; - const DecodedFile file(TestData::test_file_path("odr-public/odt/about.odt"), - Logger::null()); + const DecodedFile file = open( + TestData::test_file_path("odr-public/odt/about.odt"), Logger::null()); const HtmlService service = html::translate(file, config); std::ostringstream out; @@ -364,16 +367,16 @@ TEST(html, color_scheme_reaches_every_view) { EXPECT_NE(text.find("--odr-text-gutter:#161b22"), std::string::npos); // a source view - const DecodedFile xml_file(File::from_memory("c"), - FileType::xml); + const DecodedFile xml_file = + open(File::from_memory("c"), FileType::xml); std::ostringstream xml; html::translate(xml_file, config).list_views().at(0).write_html(xml); EXPECT_NE(xml.str().find("--odr-xml-name:#7ee787"), std::string::npos); // a file listing: the archive view of a zip - const DecodedFile archive( - TestData::test_file_path("odr-public/odt/about.odt"), FileType::zip, - Logger::null()); + const DecodedFile archive = + open(TestData::test_file_path("odr-public/odt/about.odt"), FileType::zip, + Logger::null()); std::ostringstream listing; html::translate(archive, config).list_views().at(0).write_html(listing); EXPECT_NE(listing.str().find("--odr-files-link:#6cb6ff"), std::string::npos); @@ -387,8 +390,9 @@ TEST(html, color_scheme_reaches_every_view) { TEST(html, views) { const auto logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DocumentFile document_file( - TestData::test_file_path("odr-public/ods/Senza nome 1.ods"), logger); + const DocumentFile document_file = + open(TestData::test_file_path("odr-public/ods/Senza nome 1.ods"), logger) + .as_document_file(); const Document document = document_file.document(); @@ -408,7 +412,7 @@ TEST(html, views) { TEST(html, paged_output_fits_the_viewport) { const auto logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DecodedFile file( + const DecodedFile file = open( TestData::test_file_path("odr-public/odp/style-various-1.odp"), logger); const auto render = [&](const HtmlConfig &config) { @@ -495,7 +499,7 @@ TEST(html, each_view_fits_the_page_it_renders) { HtmlConfig config; config.viewport_width = 400; - const DecodedFile file{path}; + const DecodedFile file = open(path); const HtmlService service = html::translate(file, config); const auto factor_of = [&](const std::size_t view) { @@ -525,9 +529,9 @@ TEST(html, each_view_fits_the_page_it_renders) { TEST(html, an_image_fits_the_viewport) { const auto logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DecodedFile file( - TestData::test_file_path("odr-public/png/tango-example-icons.png"), - logger); + const DecodedFile file = + open(TestData::test_file_path("odr-public/png/tango-example-icons.png"), + logger); const auto render = [&](const HtmlConfig &config) { const std::string cache = @@ -570,7 +574,8 @@ TEST(html, an_image_no_browser_decodes_is_not_translated) { namespace { std::string render_markdown(const std::string &markdown) { - const DecodedFile file(File::from_memory(markdown), FileType::markdown); + const DecodedFile file = + open(File::from_memory(markdown), FileType::markdown); std::ostringstream out; html::translate(file, HtmlConfig()).list_views().at(0).write_html(out); return std::move(out).str(); @@ -585,7 +590,7 @@ DecodedFile csv_file(const std::uint32_t rows, const std::uint32_t columns) { } csv += "\n"; } - return DecodedFile(File::from_memory(csv), FileType::comma_separated_values); + return open(File::from_memory(csv), FileType::comma_separated_values); } /// A flat ODF sheet holding @p rows, each a `table:table-row`, under the @@ -618,8 +623,7 @@ DecodedFile fods_file(const std::string &rows, columns + rows + R"()" R"()"; - return DecodedFile(File::from_memory(fods), - FileType::opendocument_spreadsheet); + return open(File::from_memory(fods), FileType::opendocument_spreadsheet); } /// A cell holding @p text, styled by `ce1`, or by `ce2` where it wraps. @@ -726,12 +730,12 @@ TEST(html, no_view_declares_a_document_wide_link_target) { }; const std::array views{ - render(DecodedFile(File::from_memory("a,b\n1,2\n"), - FileType::comma_separated_values)), - render(DecodedFile(File::from_memory("c"), FileType::xml)), - render(DecodedFile(File::from_memory("plain text"), FileType::text_file)), - render(DecodedFile(File::from_memory("[a](https://x.example)\n"), - FileType::markdown)), + render(open(File::from_memory("a,b\n1,2\n"), + FileType::comma_separated_values)), + render(open(File::from_memory("c"), FileType::xml)), + render(open(File::from_memory("plain text"), FileType::text_file)), + render(open(File::from_memory("[a](https://x.example)\n"), + FileType::markdown)), }; for (const std::string &view : views) { @@ -970,8 +974,8 @@ std::string flat_ods_sheet(const std::string &width) { } std::optional flat_ods_fit(const std::string &width) { - const DecodedFile file(File::from_memory(flat_ods_sheet(width)), - FileType::opendocument_spreadsheet); + const DecodedFile file = open(File::from_memory(flat_ods_sheet(width)), + FileType::opendocument_spreadsheet); std::ostringstream out; html::translate(file, HtmlConfig()).list_views().at(0).write_html(out); return print_fit_of(std::move(out).str()); @@ -990,7 +994,8 @@ TEST(html, a_sheet_is_only_ever_fitted_down) { } TEST(html, a_view_that_renders_no_sheet_has_no_cut) { - const DecodedFile file(File::from_memory("c"), FileType::xml); + const DecodedFile file = + open(File::from_memory("c"), FileType::xml); const HtmlService service = html::translate(file, HtmlConfig()); EXPECT_FALSE(service.list_views().at(0).sheet_cut().has_value()); diff --git a/test/src/internal/csv/csv_file_test.cpp b/test/src/internal/csv/csv_file_test.cpp index b4e686a1d..7fce41734 100644 --- a/test/src/internal/csv/csv_file_test.cpp +++ b/test/src/internal/csv/csv_file_test.cpp @@ -278,7 +278,7 @@ TEST(CsvOptions, with_options_derives_another_handle) { TEST(CsvOptions, a_decoded_csv_is_reachable_as_one) { const File file( TestData::test_file_path("odr-public/csv/file_example_ODS_5000.csv")); - const DecodedFile decoded(file, FileType::comma_separated_values); + const DecodedFile decoded = open(file, FileType::comma_separated_values); EXPECT_TRUE(decoded.is_csv_file()); EXPECT_EQ(decoded.as_csv_file().options().separator, ','); @@ -461,7 +461,7 @@ TEST(CsvDocument, a_cell_path_round_trips) { /// line list. TEST(CsvDocument, translating_the_decoded_file_yields_a_table) { const File bytes = File::from_memory("a,b\n1,2\n"); - const DecodedFile decoded(bytes, FileType::comma_separated_values); + const DecodedFile decoded = open(bytes, FileType::comma_separated_values); // a csv stays a text file and is rendered as a table anyway EXPECT_TRUE(decoded.is_text_file()); diff --git a/test/src/internal/html/image_file_test.cpp b/test/src/internal/html/image_file_test.cpp index 5fed622b6..c07b14daa 100644 --- a/test/src/internal/html/image_file_test.cpp +++ b/test/src/internal/html/image_file_test.cpp @@ -44,7 +44,7 @@ std::string write_path(const HtmlService &service, const std::string &path) { std::string image_src(const File &file) { std::ostringstream out; - internal::html::translate_image_src(DecodedFile(file).as_image_file(), out, + internal::html::translate_image_src(open(file).as_image_file(), out, HtmlConfig(), Logger::null()); return out.str(); } @@ -95,7 +95,7 @@ TEST(image_file, xml_that_is_not_an_svg_stops_at_xml) { } TEST(image_file, svg_is_detected_and_opens_as_an_image) { - const DecodedFile file{svg_file()}; + const DecodedFile file = open(svg_file()); EXPECT_EQ(file.file_type(), FileType::scalable_vector_graphics); EXPECT_EQ(file.file_category(), FileCategory::image); @@ -108,7 +108,7 @@ TEST(image_file, svg_is_detected_and_opens_as_an_image) { } TEST(image_file, svg_translates_to_an_image_page) { - const DecodedFile file{svg_file()}; + const DecodedFile file = open(svg_file()); const HtmlService service = html::translate(file, HtmlConfig()); ASSERT_EQ(service.list_views().size(), 1); @@ -120,7 +120,7 @@ TEST(image_file, svg_translates_to_an_image_page) { } TEST(image_file, ico_is_named_by_its_own_mime_type) { - const DecodedFile file{ico_file()}; + const DecodedFile file = open(ico_file()); EXPECT_EQ(file.file_type(), FileType::windows_icon); EXPECT_TRUE(file.is_image_file()); @@ -135,7 +135,7 @@ TEST(image_file, ico_is_named_by_its_own_mime_type) { /// wrappers all filled theirs in, so a png reported no type and no mimetype. TEST(image_file, every_image_reports_its_meta) { for (const File &file : {png_file(), ico_file(), svg_file()}) { - const DecodedFile decoded{file}; + const DecodedFile decoded = open(file); const FileMeta meta = decoded.file_meta(); EXPECT_EQ(meta.type, decoded.file_type()); diff --git a/test/src/internal/html/media_file_test.cpp b/test/src/internal/html/media_file_test.cpp index c0b3e5136..a2eda7bff 100644 --- a/test/src/internal/html/media_file_test.cpp +++ b/test/src/internal/html/media_file_test.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include @@ -44,7 +45,7 @@ std::string write_path(const HtmlService &service, const std::string &path) { } // namespace TEST(media_file, audio_is_decoded_without_a_wrapper_type) { - const DecodedFile file{mp3_file()}; + const DecodedFile file = open(mp3_file()); EXPECT_EQ(file.file_type(), FileType::mpeg_audio); EXPECT_EQ(file.file_category(), FileCategory::audio); @@ -58,7 +59,7 @@ TEST(media_file, audio_is_decoded_without_a_wrapper_type) { } TEST(media_file, audio_translates_to_a_player) { - const DecodedFile file{mp3_file()}; + const DecodedFile file = open(mp3_file()); const HtmlService service = html::translate(file, HtmlConfig()); ASSERT_EQ(service.list_views().size(), 1); @@ -72,7 +73,7 @@ TEST(media_file, audio_translates_to_a_player) { } TEST(media_file, video_translates_to_a_player) { - const DecodedFile file{mp4_file()}; + const DecodedFile file = open(mp4_file()); const HtmlService service = html::translate(file, HtmlConfig()); ASSERT_EQ(service.list_views().size(), 1); @@ -87,7 +88,7 @@ TEST(media_file, video_translates_to_a_player) { /// The point of the resource: a video is served and copied as bytes, never /// base64'd into the markup the way an image is. TEST(media_file, the_media_is_served_as_a_resource) { - const DecodedFile file{mp4_file()}; + const DecodedFile file = open(mp4_file()); const HtmlService service = html::translate(file, HtmlConfig()); EXPECT_TRUE(service.exists("video.mp4")); @@ -104,7 +105,7 @@ TEST(media_file, bring_offline_writes_the_media_next_to_the_page) { const std::string output_path = temp_path("media_offline"); std::filesystem::remove_all(output_path); - const DecodedFile file{mp4_file()}; + const DecodedFile file = open(mp4_file()); const HtmlService service = html::translate(file, HtmlConfig()); const Html html = service.bring_offline(output_path); @@ -135,7 +136,7 @@ TEST(media_file, a_webm_keeps_its_own_name_and_mime) { const std::filesystem::path file_path = directory / path; std::ofstream(file_path, std::ios::binary) << "\x1a\x45\xdf\xa3payload"; - const DecodedFile file{File(file_path.string())}; + const DecodedFile file = open(File(file_path.string())); ASSERT_EQ(file.file_type(), FileType::matroska_video) << path; const HtmlService service = html::translate(file, HtmlConfig()); @@ -154,7 +155,7 @@ TEST(media_file, a_webm_keeps_its_own_name_and_mime) { TEST(media_file, webp_opens_as_an_image) { const File file(std::make_shared( std::string("RIFF\x24\x00\x00\x00WEBPdata", 16))); - const DecodedFile decoded{file}; + const DecodedFile decoded = open(file); EXPECT_EQ(decoded.file_type(), FileType::webp); EXPECT_TRUE(decoded.is_image_file()); diff --git a/test/src/internal/iwork/keynote_test.cpp b/test/src/internal/iwork/keynote_test.cpp index 3fe252f28..ee0fc89fa 100644 --- a/test/src/internal/iwork/keynote_test.cpp +++ b/test/src/internal/iwork/keynote_test.cpp @@ -76,7 +76,7 @@ TEST(IworkKeynote, is_detected_by_content) { EXPECT_THAT(list_file_types(path, logger), testing::Contains(FileType::iwork_keynote)); - const DecodedFile file(path, logger); + const DecodedFile file = open(path, logger); EXPECT_EQ(file.file_type(), FileType::iwork_keynote); EXPECT_EQ(file.file_category(), FileCategory::document); EXPECT_EQ(file.as_document_file().document_type(), @@ -89,8 +89,9 @@ TEST(IworkKeynote, is_detected_by_content) { TEST(IworkKeynote, empty) { const Logger logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DocumentFile document_file( - TestData::test_file_path("odr-public/key/empty.key"), logger); + const DocumentFile document_file = + open(TestData::test_file_path("odr-public/key/empty.key"), logger) + .as_document_file(); EXPECT_EQ(document_file.file_type(), FileType::iwork_keynote); const Document document = document_file.document(); @@ -105,8 +106,10 @@ TEST(IworkKeynote, empty) { TEST(IworkKeynote, slide_text) { const Logger logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DocumentFile document_file( - TestData::test_file_path("odr-public/key/style-various-1.key"), logger); + const DocumentFile document_file = + open(TestData::test_file_path("odr-public/key/style-various-1.key"), + logger) + .as_document_file(); const Document document = document_file.document(); const std::vector> text = @@ -127,9 +130,10 @@ TEST(IworkKeynote, slide_text) { } TEST(IworkKeynote, slides_are_named_in_presentation_order) { - const DocumentFile document_file( - TestData::test_file_path("odr-public/key/style-various-1.key"), - Logger::null()); + const DocumentFile document_file = + open(TestData::test_file_path("odr-public/key/style-various-1.key"), + Logger::null()) + .as_document_file(); const Document document = document_file.document(); @@ -145,8 +149,9 @@ TEST(IworkKeynote, slides_are_named_in_presentation_order) { // The show archive carries the slide size in points; the fixtures are the // 1024x768 Keynote has defaulted to since the 13 era. TEST(IworkKeynote, slide_page_layout_comes_from_the_show) { - const DocumentFile document_file( - TestData::test_file_path("odr-public/key/empty.key"), Logger::null()); + const DocumentFile document_file = + open(TestData::test_file_path("odr-public/key/empty.key"), Logger::null()) + .as_document_file(); const Document document = document_file.document(); const Slide slide = (*document.root_element().children().begin()).as_slide(); diff --git a/test/src/internal/iwork/numbers_test.cpp b/test/src/internal/iwork/numbers_test.cpp index e7f0107a9..3df6206c6 100644 --- a/test/src/internal/iwork/numbers_test.cpp +++ b/test/src/internal/iwork/numbers_test.cpp @@ -84,7 +84,7 @@ TEST(IworkNumbers, is_detected_by_content) { EXPECT_THAT(list_file_types(path, logger), testing::Contains(FileType::iwork_numbers)); - const DecodedFile file(path, logger); + const DecodedFile file = open(path, logger); EXPECT_EQ(file.file_type(), FileType::iwork_numbers); EXPECT_EQ(file.file_category(), FileCategory::document); EXPECT_EQ(file.as_document_file().document_type(), DocumentType::spreadsheet); @@ -93,9 +93,10 @@ TEST(IworkNumbers, is_detected_by_content) { // The blank template's one sheet holds one table with nothing in it, which // must come back as a sheet of its declared extent and no content. TEST(IworkNumbers, empty) { - const DocumentFile document_file( - TestData::test_file_path("odr-public/numbers/empty.numbers"), - Logger::null()); + const DocumentFile document_file = + open(TestData::test_file_path("odr-public/numbers/empty.numbers"), + Logger::null()) + .as_document_file(); EXPECT_EQ(document_file.file_type(), FileType::iwork_numbers); const Document document = document_file.document(); @@ -115,9 +116,11 @@ TEST(IworkNumbers, empty) { // A Numbers sheet holds many tables and our `Sheet` is one grid, so each // table is a sheet of its own rather than only the first one surviving. TEST(IworkNumbers, one_sheet_per_table) { - const DocumentFile document_file( - TestData::test_file_path("odr-public/numbers/style-various-1.numbers"), - Logger::null()); + const DocumentFile document_file = + open(TestData::test_file_path( + "odr-public/numbers/style-various-1.numbers"), + Logger::null()) + .as_document_file(); const Document document = document_file.document(); EXPECT_EQ(sheet_names(document.root_element()), @@ -126,9 +129,11 @@ TEST(IworkNumbers, one_sheet_per_table) { } TEST(IworkNumbers, cell_values) { - const DocumentFile document_file( - TestData::test_file_path("odr-public/numbers/style-various-1.numbers"), - Logger::null()); + const DocumentFile document_file = + open(TestData::test_file_path( + "odr-public/numbers/style-various-1.numbers"), + Logger::null()) + .as_document_file(); const Document document = document_file.document(); EXPECT_EQ(grid(sheet_at(document.root_element(), 0)), @@ -145,9 +150,11 @@ TEST(IworkNumbers, cell_values) { // Rows and columns cannot be confused: this table is three rows of six // columns, and holds cells only at its corners. TEST(IworkNumbers, a_table_wider_than_it_is_tall) { - const DocumentFile document_file( - TestData::test_file_path("odr-public/numbers/style-various-1.numbers"), - Logger::null()); + const DocumentFile document_file = + open(TestData::test_file_path( + "odr-public/numbers/style-various-1.numbers"), + Logger::null()) + .as_document_file(); const Document document = document_file.document(); const Sheet sheet = sheet_at(document.root_element(), 1); @@ -162,9 +169,11 @@ TEST(IworkNumbers, a_table_wider_than_it_is_tall) { } TEST(IworkNumbers, every_cell_type_the_fixtures_hold) { - const DocumentFile document_file( - TestData::test_file_path("odr-public/numbers/style-various-1.numbers"), - Logger::null()); + const DocumentFile document_file = + open(TestData::test_file_path( + "odr-public/numbers/style-various-1.numbers"), + Logger::null()) + .as_document_file(); const Document document = document_file.document(); EXPECT_EQ(grid(sheet_at(document.root_element(), 2)), @@ -185,9 +194,11 @@ TEST(IworkNumbers, every_cell_type_the_fixtures_hold) { // A number cell is right-aligned by the renderer; nothing else is. TEST(IworkNumbers, only_a_number_reports_a_float_value_type) { - const DocumentFile document_file( - TestData::test_file_path("odr-public/numbers/style-various-1.numbers"), - Logger::null()); + const DocumentFile document_file = + open(TestData::test_file_path( + "odr-public/numbers/style-various-1.numbers"), + Logger::null()) + .as_document_file(); const Document document = document_file.document(); const Sheet sheet = sheet_at(document.root_element(), 2); diff --git a/test/src/internal/iwork/pages_test.cpp b/test/src/internal/iwork/pages_test.cpp index fab2fc3e4..79a1d8402 100644 --- a/test/src/internal/iwork/pages_test.cpp +++ b/test/src/internal/iwork/pages_test.cpp @@ -77,7 +77,7 @@ TEST(Iwork, pages_is_detected_by_content) { EXPECT_THAT(list_file_types(path, logger), testing::Contains(FileType::iwork_pages)); - const DecodedFile file(path, logger); + const DecodedFile file = open(path, logger); EXPECT_EQ(file.file_type(), FileType::iwork_pages); EXPECT_EQ(file.file_category(), FileCategory::document); EXPECT_EQ(file.as_document_file().document_type(), DocumentType::text); @@ -88,8 +88,9 @@ TEST(Iwork, pages_is_detected_by_content) { TEST(Iwork, pages_empty) { const Logger logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DocumentFile document_file( - TestData::test_file_path("odr-public/pages/empty.pages"), logger); + const DocumentFile document_file = + open(TestData::test_file_path("odr-public/pages/empty.pages"), logger) + .as_document_file(); EXPECT_EQ(document_file.file_type(), FileType::iwork_pages); const Document document = document_file.document(); @@ -104,9 +105,10 @@ TEST(Iwork, pages_empty) { TEST(Iwork, pages_body_text) { const Logger logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DocumentFile document_file( - TestData::test_file_path("odr-public/pages/style-various-1.pages"), - logger); + const DocumentFile document_file = + open(TestData::test_file_path("odr-public/pages/style-various-1.pages"), + logger) + .as_document_file(); const Document document = document_file.document(); const std::vector text = paragraphs(document.root_element()); @@ -131,9 +133,10 @@ TEST(Iwork, pages_body_text) { // names. The one that is a table becomes a `Table` after the paragraph its // anchor sits in; its cells hold rich text, one storage each. TEST(Iwork, pages_table) { - const DocumentFile document_file( - TestData::test_file_path("odr-public/pages/style-various-1.pages"), - Logger::null()); + const DocumentFile document_file = + open(TestData::test_file_path("odr-public/pages/style-various-1.pages"), + Logger::null()) + .as_document_file(); const Document document = document_file.document(); std::vector tables; diff --git a/test/src/internal/markdown/markdown_file_test.cpp b/test/src/internal/markdown/markdown_file_test.cpp index 3d6c79caf..ed35443a8 100644 --- a/test/src/internal/markdown/markdown_file_test.cpp +++ b/test/src/internal/markdown/markdown_file_test.cpp @@ -28,7 +28,8 @@ namespace { /// An `Element` holds a bare pointer into its document, so every test binds the /// document to a local before walking it. Document document(const std::string &markdown) { - const DecodedFile file(File::from_memory(markdown), FileType::markdown); + const DecodedFile file = + open(File::from_memory(markdown), FileType::markdown); return file.as_markdown_file().document(); } @@ -87,7 +88,8 @@ std::vector types_of(const std::vector &elements) { /// Like a csv, markdown stays a text file — the document is the other view of /// the same bytes. TEST(MarkdownFile, a_markdown_file_is_a_text_file_that_loads_as_a_document) { - const DecodedFile file(File::from_memory("# hello"), FileType::markdown); + const DecodedFile file = + open(File::from_memory("# hello"), FileType::markdown); const Document md = document("# hello"); EXPECT_EQ(file.file_type(), FileType::markdown); @@ -104,8 +106,8 @@ TEST(MarkdownFile, a_markdown_file_is_a_text_file_that_loads_as_a_document) { /// The whole point: a markdown file handed to the renderer comes out as prose, /// not as the line list a text file renders to. TEST(MarkdownFile, translating_the_decoded_file_yields_the_document) { - const DecodedFile file(File::from_memory("# hello\n\ntext\n"), - FileType::markdown); + const DecodedFile file = + open(File::from_memory("# hello\n\ntext\n"), FileType::markdown); const HtmlService service = html::translate(file, HtmlConfig()); std::ostringstream out; @@ -122,7 +124,7 @@ TEST(MarkdownFile, it_is_not_detected_by_content) { EXPECT_THAT(list_file_types(file), testing::Not(testing::Contains(FileType::markdown))); - EXPECT_EQ(DecodedFile(file).file_type(), FileType::text_file); + EXPECT_EQ(open(file).file_type(), FileType::text_file); } /// Nothing rejects: any UTF-8 byte sequence is some markdown document. diff --git a/test/src/internal/odf/odf_flat_file_test.cpp b/test/src/internal/odf/odf_flat_file_test.cpp index b03f4b4dc..b0ffe608b 100644 --- a/test/src/internal/odf/odf_flat_file_test.cpp +++ b/test/src/internal/odf/odf_flat_file_test.cpp @@ -99,8 +99,8 @@ TEST(FlatOpenDocumentFile, the_root_mimetype_names_the_document_type) { }; for (const auto &[mimetype, file_type, document_type] : cases) { - const DecodedFile file( - File::from_memory(flat_document(mimetype, ""))); + const DecodedFile file = + open(File::from_memory(flat_document(mimetype, ""))); EXPECT_EQ(file.file_type(), file_type); EXPECT_EQ(file.file_category(), FileCategory::document); @@ -112,7 +112,7 @@ TEST(FlatOpenDocumentFile, the_root_mimetype_names_the_document_type) { /// The `-flat-xml` mimetypes are what a caller names the file, not what the /// root carries. TEST(FlatOpenDocumentFile, the_flat_mimetype_is_read_too_and_reported_back) { - const DecodedFile file(File::from_memory( + const DecodedFile file = open(File::from_memory( flat_document("application/vnd.oasis.opendocument.spreadsheet-flat-xml", ""))); @@ -122,19 +122,19 @@ TEST(FlatOpenDocumentFile, the_flat_mimetype_is_read_too_and_reported_back) { } TEST(FlatOpenDocumentFile, other_xml_is_left_to_the_source_view) { - EXPECT_EQ(DecodedFile(File::from_memory("")).file_type(), + EXPECT_EQ(open(File::from_memory("")).file_type(), FileType::xml); - EXPECT_EQ( - DecodedFile(File::from_memory( - R"()")) - .file_type(), - FileType::xml); - EXPECT_EQ(DecodedFile(File::from_memory("")).file_type(), FileType::xml); + EXPECT_EQ(open(File::from_memory( + R"()")) + .file_type(), + FileType::xml); + EXPECT_EQ(open(File::from_memory("")).file_type(), FileType::xml); } TEST(FlatOpenDocumentFile, opening_it_as_a_document_file_works) { const DocumentFile file = - DocumentFile::from_memory(flat_text("Hello")); + open(File::from_memory(flat_text("Hello"))) + .as_document_file(); EXPECT_EQ(file.file_type(), FileType::opendocument_text); EXPECT_FALSE(file.password_encrypted()); @@ -143,18 +143,19 @@ TEST(FlatOpenDocumentFile, opening_it_as_a_document_file_works) { TEST(FlatOpenDocumentFile, opening_it_as_a_named_type_works) { const std::string source = flat_text("Hello"); - EXPECT_EQ(DecodedFile(File::from_memory(source), FileType::opendocument_text) - .file_type(), - FileType::opendocument_text); - EXPECT_THROW(std::ignore = DecodedFile(File::from_memory(source), - FileType::opendocument_graphics), + EXPECT_EQ( + open(File::from_memory(source), FileType::opendocument_text).file_type(), + FileType::opendocument_text); + EXPECT_THROW(std::ignore = open(File::from_memory(source), + FileType::opendocument_graphics), UnknownFileType); } TEST(FlatOpenDocumentFile, the_body_decodes_to_the_same_tree_as_a_package) { const Document document = - DocumentFile::from_memory( - flat_text("Hello flat")) + open(File::from_memory( + flat_text("Hello flat"))) + .as_document_file() .document(); EXPECT_EQ(document.document_type(), DocumentType::text); @@ -169,20 +170,20 @@ TEST(FlatOpenDocumentFile, the_body_decodes_to_the_same_tree_as_a_package) { /// has both under its one root. TEST(FlatOpenDocumentFile, styles_resolve_from_the_single_root) { const Document document = - DocumentFile::from_memory( - flat_text( - R"(Hello)", - R"()" - R"()" - R"()" - R"()" - R"()" - R"()" - R"()" - R"()" - R"()" - R"()")) + open(File::from_memory(flat_text( + R"(Hello)", + R"()" + R"()" + R"()" + R"()" + R"()" + R"()" + R"()" + R"()" + R"()" + R"()"))) + .as_document_file() .document(); const Element paragraph = @@ -220,7 +221,7 @@ std::string render(const std::string &source) { config.text_document_margin = true; std::ostringstream out; - html::translate(DecodedFile(File::from_memory(source)), config) + html::translate(open(File::from_memory(source)), config) .list_views() .at(0) .write_html(out); @@ -230,7 +231,8 @@ std::string render(const std::string &source) { /// `break_before` of every top-level paragraph, in document order. std::vector> breaks_before_of(const std::string &source) { - const Document document = DocumentFile::from_memory(source).document(); + const Document document = + open(File::from_memory(source)).as_document_file().document(); std::vector> result; for (const Element child : document.root_element().children()) { @@ -299,7 +301,8 @@ TEST(FlatOpenDocumentFile, a_soft_page_break_is_not_content) { const std::string source = flat_text(R"(onetwo)"); - const Document document = DocumentFile::from_memory(source).document(); + const Document document = + open(File::from_memory(source)).as_document_file().document(); const Element paragraph = first_of_type(document.root_element(), ElementType::paragraph); ASSERT_TRUE(paragraph); @@ -316,7 +319,7 @@ TEST(FlatOpenDocumentFile, a_reflowed_document_states_the_break_in_css_only) { config.text_document_margin = false; std::ostringstream out; - html::translate(DecodedFile(File::from_memory( + html::translate(open(File::from_memory( three_paragraphs("P1", R"(fo:break-before="page")"))), config) .list_views() @@ -330,11 +333,12 @@ TEST(FlatOpenDocumentFile, a_reflowed_document_states_the_break_in_css_only) { /// Without a package there is nowhere to put an image but the markup. TEST(FlatOpenDocumentFile, an_embedded_image_is_internal_and_decodes) { const Document document = - DocumentFile::from_memory( - flat_text(std::string("" - "") + - png_base64 + - "")) + open(File::from_memory(flat_text( + std::string("" + "") + + png_base64 + + ""))) + .as_document_file() .document(); const Element element = @@ -347,17 +351,17 @@ TEST(FlatOpenDocumentFile, an_embedded_image_is_internal_and_decodes) { const std::optional file = image.file(); ASSERT_TRUE(file.has_value()); - EXPECT_EQ(DecodedFile(*file).file_type(), - FileType::portable_network_graphics); + EXPECT_EQ(open(*file).file_type(), FileType::portable_network_graphics); } /// A flat document has no package, so a linked image stays a plain link. TEST(FlatOpenDocumentFile, a_linked_image_is_not_internal) { const Document document = - DocumentFile::from_memory( - flat_text(R"()" - R"()")) + open(File::from_memory( + flat_text(R"()" + R"()"))) + .as_document_file() .document(); const Element element = @@ -375,18 +379,18 @@ TEST(FlatOpenDocumentFile, the_statistics_give_the_entry_count) { "/>"; }; - const DecodedFile text(File::from_memory( + const DecodedFile text = open(File::from_memory( flat_document("application/vnd.oasis.opendocument.text", "", meta(R"(meta:page-count="7")")))); EXPECT_EQ(text.file_meta().entry_count, 7); - const DecodedFile spreadsheet(File::from_memory( + const DecodedFile spreadsheet = open(File::from_memory( flat_document("application/vnd.oasis.opendocument.spreadsheet", "", meta(R"(meta:table-count="3")")))); EXPECT_EQ(spreadsheet.file_meta().entry_count, 3); // the statistic a text document does not count - const DecodedFile mismatched(File::from_memory( + const DecodedFile mismatched = open(File::from_memory( flat_document("application/vnd.oasis.opendocument.text", "", meta(R"(meta:table-count="3")")))); EXPECT_FALSE(mismatched.file_meta().entry_count.has_value()); @@ -405,7 +409,9 @@ TEST(FlatOpenDocumentFile, it_is_listed_next_to_the_source_view) { /// There is no package behind a flat document; asking for one answers empty. TEST(FlatOpenDocumentFile, it_has_an_empty_filesystem) { const Document document = - DocumentFile::from_memory(flat_text("Hello")).document(); + open(File::from_memory(flat_text("Hello"))) + .as_document_file() + .document(); const Filesystem filesystem = document.as_filesystem(); EXPECT_FALSE(filesystem.exists("/content.xml")); @@ -418,10 +424,10 @@ TEST(FlatOpenDocumentFile, embedded_images_get_distinct_hrefs) { "") + png_base64 + ""; - const Document document = - DocumentFile::from_memory( - flat_text("" + image + image + "")) - .document(); + const Document document = open(File::from_memory(flat_text( + "" + image + image + ""))) + .as_document_file() + .document(); std::vector hrefs; for (const Element child : @@ -442,13 +448,14 @@ TEST(FlatOpenDocumentFile, embedded_images_get_distinct_hrefs) { TEST(FlatOpenDocumentFile, an_embedded_image_does_not_take_its_href_from_the_markup) { const Document document = - DocumentFile::from_memory( - flat_text(std::string(R"()") - .append(R"()") - .append("") - .append(png_base64) - .append("") - .append(""))) + open(File::from_memory(flat_text( + std::string(R"()") + .append(R"()") + .append("") + .append(png_base64) + .append("") + .append("")))) + .as_document_file() .document(); const Element element = @@ -469,7 +476,7 @@ TEST(FlatOpenDocumentFile, a_packaged_embedded_image_decodes_as_well) { .append(png_base64) .append("")); - const Document document = DocumentFile(path).document(); + const Document document = open(path).as_document_file().document(); const Element element = first_of_type(document.root_element(), ElementType::image); @@ -480,8 +487,7 @@ TEST(FlatOpenDocumentFile, a_packaged_embedded_image_decodes_as_well) { const std::optional file = image.file(); ASSERT_TRUE(file.has_value()); - EXPECT_EQ(DecodedFile(*file).file_type(), - FileType::portable_network_graphics); + EXPECT_EQ(open(*file).file_type(), FileType::portable_network_graphics); } TEST(FlatOpenDocumentFile, packaged_markup_bytes_beat_the_href) { @@ -496,7 +502,7 @@ TEST(FlatOpenDocumentFile, packaged_markup_bytes_beat_the_href) { // the element holds a bare pointer into the document, so the document has // to outlive it - const Document document = DocumentFile(path).document(); + const Document document = open(path).as_document_file().document(); const Element element = first_of_type(document.root_element(), ElementType::image); @@ -522,7 +528,7 @@ TEST(FlatOpenDocumentFile, it_renders_its_embedded_image_embedded_or_linked) { config.embed_images = true; std::ostringstream out; - html::translate(DecodedFile(File::from_memory(source)), config) + html::translate(open(File::from_memory(source)), config) .list_views() .at(0) .write_html(out); @@ -535,7 +541,7 @@ TEST(FlatOpenDocumentFile, it_renders_its_embedded_image_embedded_or_linked) { config.embed_images = false; const HtmlService service = - html::translate(DecodedFile(File::from_memory(source)), config); + html::translate(open(File::from_memory(source)), config); std::ostringstream out; const HtmlResources resources = service.list_views().at(0).write_html(out); @@ -565,7 +571,8 @@ namespace { /// `direction` of every top-level paragraph, in document order. std::vector> directions_of(const std::string &source) { - const Document document = DocumentFile::from_memory(source).document(); + const Document document = + open(File::from_memory(source)).as_document_file().document(); std::vector> result; for (const Element child : document.root_element().children()) { @@ -668,7 +675,8 @@ TEST(FlatOpenDocumentFile, start_and_end_alignment_are_the_sides_they_name) { const std::string properties = R"(fo:text-align=")" + std::string(value) + "\""; const Document document = - DocumentFile::from_memory(three_paragraphs("P1", properties)) + open(File::from_memory(three_paragraphs("P1", properties))) + .as_document_file() .document(); // the middle one is the one carrying `P1` @@ -692,14 +700,16 @@ TEST(FlatOpenDocumentFile, start_and_end_alignment_are_the_sides_they_name) { TEST(FlatOpenDocumentFile, it_saves_back_as_one_xml_file) { const Document document = - DocumentFile::from_memory(flat_text("Hello")).document(); + open(File::from_memory(flat_text("Hello"))) + .as_document_file() + .document(); const std::string path = (std::filesystem::current_path() / "flat_save_test.fodt").string(); ASSERT_TRUE(document.is_savable()); document.save(path); - const DocumentFile saved(path); + const DocumentFile saved = open(path).as_document_file(); EXPECT_EQ(saved.file_type(), FileType::opendocument_text); EXPECT_EQ(first_of_type(saved.document().root_element(), ElementType::text) .as_text() diff --git a/test/src/internal/odf/odf_sheet_repeat_test.cpp b/test/src/internal/odf/odf_sheet_repeat_test.cpp index d3cb872fb..ba6cf90b8 100644 --- a/test/src/internal/odf/odf_sheet_repeat_test.cpp +++ b/test/src/internal/odf/odf_sheet_repeat_test.cpp @@ -47,10 +47,11 @@ std::string repeated_rows(const std::uint32_t rows_repeated, } std::shared_ptr document_of(const std::string &source) { - const std::unique_ptr file = - open_strategy::open_document_file(std::make_shared(source), - Logger::null()); - return file->document(); + const DocumentFile file = + DecodedFile(open_strategy::open_file(std::make_shared(source), + Logger::null())) + .as_document_file(); + return file.impl()->document(); } } // namespace diff --git a/test/src/internal/oldms/ppt_test.cpp b/test/src/internal/oldms/ppt_test.cpp index e044a6ee7..41605bdae 100644 --- a/test/src/internal/oldms/ppt_test.cpp +++ b/test/src/internal/oldms/ppt_test.cpp @@ -68,8 +68,9 @@ TEST(OldMs, ppt_parse_style_text_prop_atom) { TEST(OldMs, ppt_empty) { const Logger logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DocumentFile document_file( - TestData::test_file_path("odr-public/ppt/empty.ppt"), logger); + const DocumentFile document_file = + open(TestData::test_file_path("odr-public/ppt/empty.ppt"), logger) + .as_document_file(); EXPECT_EQ(document_file.file_type(), FileType::legacy_powerpoint_presentation); @@ -88,8 +89,10 @@ TEST(OldMs, ppt_empty) { TEST(OldMs, ppt_style_various) { const Logger logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DocumentFile document_file( - TestData::test_file_path("odr-public/ppt/style-various-1.ppt"), logger); + const DocumentFile document_file = + open(TestData::test_file_path("odr-public/ppt/style-various-1.ppt"), + logger) + .as_document_file(); EXPECT_EQ(document_file.file_type(), FileType::legacy_powerpoint_presentation); diff --git a/test/src/internal/oldms/xls_test.cpp b/test/src/internal/oldms/xls_test.cpp index 374cb2e2a..747b32f1f 100644 --- a/test/src/internal/oldms/xls_test.cpp +++ b/test/src/internal/oldms/xls_test.cpp @@ -299,8 +299,9 @@ TEST(OldMs, xls_palette_record) { TEST(OldMs, xls_empty) { const Logger logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DocumentFile document_file( - TestData::test_file_path("odr-public/xls/empty.xls"), logger); + const DocumentFile document_file = + open(TestData::test_file_path("odr-public/xls/empty.xls"), logger) + .as_document_file(); EXPECT_EQ(document_file.file_type(), FileType::legacy_excel_worksheets); @@ -323,9 +324,10 @@ TEST(OldMs, xls_empty) { TEST(OldMs, xls_file_example_10) { const Logger logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DocumentFile document_file( - TestData::test_file_path("odr-public/xls/file_example_XLS_10.xls"), - logger); + const DocumentFile document_file = + open(TestData::test_file_path("odr-public/xls/file_example_XLS_10.xls"), + logger) + .as_document_file(); EXPECT_EQ(document_file.file_type(), FileType::legacy_excel_worksheets); @@ -367,9 +369,10 @@ TEST(OldMs, xls_file_example_10) { TEST(OldMs, xls_file_example_5000) { const Logger logger = Logger::create_stdio("odr-test", LogLevel::verbose); - const DocumentFile document_file( - TestData::test_file_path("odr-public/xls/file_example_XLS_5000.xls"), - logger); + const DocumentFile document_file = + open(TestData::test_file_path("odr-public/xls/file_example_XLS_5000.xls"), + logger) + .as_document_file(); const Document document = document_file.document(); diff --git a/test/src/internal/ooxml/ooxml_spreadsheet_merge_test.cpp b/test/src/internal/ooxml/ooxml_spreadsheet_merge_test.cpp index fb037c9a2..3245d288e 100644 --- a/test/src/internal/ooxml/ooxml_spreadsheet_merge_test.cpp +++ b/test/src/internal/ooxml/ooxml_spreadsheet_merge_test.cpp @@ -73,8 +73,9 @@ Sheet first_sheet(const Document &document) { } Document decode(const std::shared_ptr &file) { - return Document( - open_strategy::open_document_file(file, Logger::null())->document()); + return Document(DecodedFile(open_strategy::open_file(file, Logger::null())) + .as_document_file() + .document()); } constexpr const char *two_cells = diff --git a/test/src/internal/rtf/rtf_document_test.cpp b/test/src/internal/rtf/rtf_document_test.cpp index b19cf6f9c..a39f35433 100644 --- a/test/src/internal/rtf/rtf_document_test.cpp +++ b/test/src/internal/rtf/rtf_document_test.cpp @@ -224,22 +224,22 @@ TEST(RtfDocument, the_open_strategy_opens_an_rtf) { const File file(memory_file(R"({\rtf1\ansi Hello\par})")); // magic names the type and the strategy decodes it - const DecodedFile detected(file); + const DecodedFile detected = open(file); EXPECT_EQ(detected.file_type(), FileType::rich_text_format); EXPECT_TRUE(detected.is_document_file()); // as does asking for the type outright - EXPECT_EQ(DecodedFile(file, FileType::rich_text_format).file_type(), + EXPECT_EQ(open(file, FileType::rich_text_format).file_type(), FileType::rich_text_format); // the branch's `NoRtfFile` is what `open_file` catches to move on to the // next candidate type, so a caller asking for an rtf that is not one sees // the strategy's own answer - EXPECT_THROW(DecodedFile(File(memory_file("Hello, World!")), - FileType::rich_text_format), - UnknownFileType); + EXPECT_THROW( + open(File(memory_file("Hello, World!")), FileType::rich_text_format), + UnknownFileType); // and the document-file path, which a caller reaches through `DocumentFile` - const DocumentFile document_file(file); + const DocumentFile document_file = open(file).as_document_file(); EXPECT_EQ(document_file.file_type(), FileType::rich_text_format); EXPECT_EQ(document_file.document_type(), DocumentType::text); } diff --git a/test/src/internal/svg/svg_file_test.cpp b/test/src/internal/svg/svg_file_test.cpp index 986d29bde..6a168fd33 100644 --- a/test/src/internal/svg/svg_file_test.cpp +++ b/test/src/internal/svg/svg_file_test.cpp @@ -33,7 +33,8 @@ std::shared_ptr svg_file(const std::string &content) { } // namespace TEST(SvgFile, an_svg_opens_as_an_image_that_knows_it_is_one) { - const DecodedFile file(File::from_memory(std::string(svg_open) + "")); + const DecodedFile file = + open(File::from_memory(std::string(svg_open) + "")); EXPECT_EQ(file.file_type(), FileType::scalable_vector_graphics); EXPECT_EQ(file.file_category(), FileCategory::image); diff --git a/test/src/internal/text/text_file_test.cpp b/test/src/internal/text/text_file_test.cpp index 95449c7d0..934ee4ba0 100644 --- a/test/src/internal/text/text_file_test.cpp +++ b/test/src/internal/text/text_file_test.cpp @@ -63,9 +63,9 @@ TEST(TextFile, unrecognised_bytes_do_not_open) { const File junk = File::from_memory(std::string(512, '\0')); EXPECT_THROW(std::ignore = mimetype(junk), UnknownFileType); - EXPECT_THROW(DecodedFile{junk}, UnknownFileType); + EXPECT_THROW(open(junk), UnknownFileType); // asking for text by name is no way around it - EXPECT_THROW(DecodedFile(junk, FileType::text_file), UnknownFileType); + EXPECT_THROW(open(junk, FileType::text_file), UnknownFileType); } TEST(TextFile, encoding_comes_from_the_byte_order_mark) { diff --git a/test/src/internal/xml/xml_file_test.cpp b/test/src/internal/xml/xml_file_test.cpp index dfb152242..c576432d1 100644 --- a/test/src/internal/xml/xml_file_test.cpp +++ b/test/src/internal/xml/xml_file_test.cpp @@ -45,7 +45,7 @@ std::string declared_encoding(const std::string &content) { } // namespace TEST(XmlFile, an_xml_file_opens_as_xml) { - const DecodedFile file(File::from_memory("")); + const DecodedFile file = open(File::from_memory("")); EXPECT_EQ(file.file_type(), FileType::xml); EXPECT_EQ(file.file_meta().mimetype, "application/xml"); @@ -59,8 +59,8 @@ TEST(XmlFile, an_xml_file_opens_as_xml) { /// Xml is the last resort: anything with a more specific reading keeps it. TEST(XmlFile, an_svg_still_opens_as_an_image) { - const DecodedFile file( - File::from_memory(R"()")); + const DecodedFile file = + open(File::from_memory(R"()")); EXPECT_EQ(file.file_type(), FileType::scalable_vector_graphics); EXPECT_TRUE(file.is_image_file()); @@ -70,7 +70,7 @@ TEST(XmlFile, malformed_xml_is_no_xml_file_and_stays_text) { EXPECT_THROW(std::ignore = xml_file(""), NoXmlFile); // which is what leaves the line list in place for it - const DecodedFile file(File::from_memory("")); + const DecodedFile file = open(File::from_memory("")); EXPECT_EQ(file.file_type(), FileType::text_file); } @@ -91,8 +91,7 @@ TEST(XmlFile, an_encoding_we_cannot_decode_has_no_source_view) { ""; EXPECT_THROW(std::ignore = xml_file(content), UnsupportedTextEncoding); - EXPECT_EQ(DecodedFile(File::from_memory(content)).file_type(), - FileType::text_file); + EXPECT_EQ(open(File::from_memory(content)).file_type(), FileType::text_file); } TEST(XmlDeclaration, the_encoding_pseudo_attribute_is_read_off_the_bytes) { diff --git a/test/src/odr_test.cpp b/test/src/odr_test.cpp index 7d716ef15..6e369109c 100644 --- a/test/src/odr_test.cpp +++ b/test/src/odr_test.cpp @@ -92,7 +92,8 @@ TEST(odr, a_misnamed_file_is_what_its_bytes_are) { EXPECT_EQ(open(path, logger).file_type(), FileType::opendocument_text); // no name at all, so no hint: the same bytes come back as plain text - const DecodedFile from_memory(File::from_memory("# heading\n"), logger); + const DecodedFile from_memory = + open(File::from_memory("# heading\n"), logger); EXPECT_EQ(from_memory.file_type(), FileType::text_file); } @@ -108,7 +109,7 @@ TEST(odr, a_named_file_in_memory_is_offered_its_type) { EXPECT_EQ(types.front(), FileType::text_file); EXPECT_EQ(types.back(), FileType::markdown); - EXPECT_EQ(DecodedFile(file, logger).file_type(), FileType::markdown); + EXPECT_EQ(open(file, logger).file_type(), FileType::markdown); EXPECT_EQ(mimetype(file, logger), "text/markdown"); } From 25dd861ac26e63bcaaf3df590ef249876abbae91 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Sun, 6 Sep 2026 14:24:47 +0200 Subject: [PATCH 2/2] fixup: the wasm binding constructed a DecodedFile too Its open() and openAs() built the handle directly rather than going through odr::open. Qualified, because the file has an open() of its own. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_016hxDa2rev11eLUEJZJ5nmz --- python/tests/test_file.py | 4 +++- src/odr/file.hpp | 3 +-- test/src/file_test.cpp | 2 +- test/src/internal/rtf/rtf_document_test.cpp | 7 ++++--- test/src/internal/text/text_file_test.cpp | 4 ++-- test/src/internal/xml/xml_file_test.cpp | 4 ++-- wasm/src/wasm_file.cpp | 6 +++--- 7 files changed, 16 insertions(+), 14 deletions(-) diff --git a/python/tests/test_file.py b/python/tests/test_file.py index b28c6310c..3dc7c59d2 100644 --- a/python/tests/test_file.py +++ b/python/tests/test_file.py @@ -172,7 +172,9 @@ def test_document_file_from_file(odt_path): def test_document_file_from_disk_and_from_memory(odt_path): from_disk = pyodr.open(str(odt_path)).as_document_file() - from_memory = pyodr.open(pyodr.File.from_memory(odt_path.read_bytes())).as_document_file() + from_memory = pyodr.open( + pyodr.File.from_memory(odt_path.read_bytes()) + ).as_document_file() assert from_disk.file_type() == pyodr.FileType.opendocument_text assert from_memory.file_type() == from_disk.file_type() diff --git a/src/odr/file.hpp b/src/odr/file.hpp index 79daf5409..53dda5f90 100644 --- a/src/odr/file.hpp +++ b/src/odr/file.hpp @@ -497,8 +497,7 @@ class ArchiveFile final : public DecodedFile { /// @brief Represents a document file. class DocumentFile final : public DecodedFile { public: - /// Reached through @ref DecodedFile::as_document_file, on what @ref - /// odr::open produced; this wraps what that narrowed to. + /// Narrowing is @ref DecodedFile::as_document_file; this wraps its result. explicit DocumentFile(std::shared_ptr); [[nodiscard]] DocumentType document_type() const; diff --git a/test/src/file_test.cpp b/test/src/file_test.cpp index 2ccb307f8..d213df435 100644 --- a/test/src/file_test.cpp +++ b/test/src/file_test.cpp @@ -201,7 +201,7 @@ TEST(File, disk_file_has_no_memory_data) { } TEST(DocumentFile, open) { - EXPECT_THROW(open("/").as_document_file(), FileNotFound); + EXPECT_THROW(std::ignore = open("/").as_document_file(), FileNotFound); } TEST(DocumentFile, from_disk_and_from_memory_agree) { diff --git a/test/src/internal/rtf/rtf_document_test.cpp b/test/src/internal/rtf/rtf_document_test.cpp index a39f35433..74015c897 100644 --- a/test/src/internal/rtf/rtf_document_test.cpp +++ b/test/src/internal/rtf/rtf_document_test.cpp @@ -16,6 +16,7 @@ #include #include #include +#include using namespace odr; using namespace odr::internal; @@ -234,9 +235,9 @@ TEST(RtfDocument, the_open_strategy_opens_an_rtf) { // the branch's `NoRtfFile` is what `open_file` catches to move on to the // next candidate type, so a caller asking for an rtf that is not one sees // the strategy's own answer - EXPECT_THROW( - open(File(memory_file("Hello, World!")), FileType::rich_text_format), - UnknownFileType); + EXPECT_THROW(std::ignore = open(File(memory_file("Hello, World!")), + FileType::rich_text_format), + UnknownFileType); // and the document-file path, which a caller reaches through `DocumentFile` const DocumentFile document_file = open(file).as_document_file(); diff --git a/test/src/internal/text/text_file_test.cpp b/test/src/internal/text/text_file_test.cpp index 934ee4ba0..89667d865 100644 --- a/test/src/internal/text/text_file_test.cpp +++ b/test/src/internal/text/text_file_test.cpp @@ -63,9 +63,9 @@ TEST(TextFile, unrecognised_bytes_do_not_open) { const File junk = File::from_memory(std::string(512, '\0')); EXPECT_THROW(std::ignore = mimetype(junk), UnknownFileType); - EXPECT_THROW(open(junk), UnknownFileType); + EXPECT_THROW(std::ignore = open(junk), UnknownFileType); // asking for text by name is no way around it - EXPECT_THROW(open(junk, FileType::text_file), UnknownFileType); + EXPECT_THROW(std::ignore = open(junk, FileType::text_file), UnknownFileType); } TEST(TextFile, encoding_comes_from_the_byte_order_mark) { diff --git a/test/src/internal/xml/xml_file_test.cpp b/test/src/internal/xml/xml_file_test.cpp index c576432d1..953595c90 100644 --- a/test/src/internal/xml/xml_file_test.cpp +++ b/test/src/internal/xml/xml_file_test.cpp @@ -112,8 +112,8 @@ TEST(XmlDeclaration, the_encoding_pseudo_attribute_is_read_off_the_bytes) { /// Opening the same bytes as a text file is how to ask for the line list. TEST(XmlHtml, opening_it_as_a_text_file_writes_the_line_list) { const HtmlService service = html::translate( - DecodedFile(File::from_memory(""), FileType::text_file), - HtmlConfig(), Logger::null()); + open(File::from_memory(""), FileType::text_file), HtmlConfig(), + Logger::null()); std::ostringstream out; service.write("text.html", out); diff --git a/wasm/src/wasm_file.cpp b/wasm/src/wasm_file.cpp index ae7963a26..0fe432fb4 100644 --- a/wasm/src/wasm_file.cpp +++ b/wasm/src/wasm_file.cpp @@ -52,7 +52,7 @@ emscripten::val open(const std::string &bytes, std::string name, const emscripten::val &config) { return guarded([&] { return opened( - DecodedFile(from_bytes(bytes, std::move(name)), default_logger()), + odr::open(from_bytes(bytes, std::move(name)), default_logger()), config); }); } @@ -60,8 +60,8 @@ emscripten::val open(const std::string &bytes, std::string name, emscripten::val open_as(const std::string &bytes, std::string name, const int as, const emscripten::val &config) { return guarded([&] { - return opened(DecodedFile(from_bytes(bytes, std::move(name)), - static_cast(as), default_logger()), + return opened(odr::open(from_bytes(bytes, std::move(name)), + static_cast(as), default_logger()), config); }); }