Harden ImportBase: open read-only and fail fast on an unreadable file.

ImportBase opened the input with a default std::fstream (in|out), which had
two consequences: a missing file silently produced an empty module (no error),
and a present-but-read-only file failed to open and also loaded as empty. Open
the stream read-only (std::ios::in) instead, and expose is_open().

System::Load now builds the importer first, checks is_open(), and throws
"cannot open file: <path>" before creating the module — so a failed load
surfaces as `load failed: …` and leaves no empty module behind. A read-only
but present file now loads correctly.

Flip the test that pinned the old silent-empty behaviour to assert the clean
failure (error + no module created).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-03 20:24:11 +02:00
parent b36af3167a
commit 4ef110ab70
3 changed files with 32 additions and 18 deletions

View File

@@ -1,6 +1,7 @@
#include <doctest/doctest.h>
#include "core/app/load.hpp"
#include "core/domain/modules.hpp"
#include "core/domain/system.hpp"
#include <cstdio>
@@ -50,15 +51,13 @@ TEST_CASE("load_module imports, drops singletons and reports counts") {
std::remove(path);
}
TEST_CASE("load_module on a missing file currently succeeds empty (no throw)") {
// Pre-existing behaviour, preserved by the extraction: ImportBase opens the
// stream without checking is_open(), so a missing file yields an empty
// module rather than an error. Pinned here so any future hardening of this
// path is a deliberate, visible change.
TEST_CASE("load_module fails cleanly on a missing file") {
// ImportBase opens read-only and System::Load checks is_open(), so a missing
// file is a clean error — and no empty module is left in the system.
System sys;
app::LoadResult r = app::load_module(
&sys, "M", "/nonexistent-dir-xyz/nope.net", ImportType::IMPORT_MENTOR);
CHECK(r.ok);
CHECK(r.parts == 0);
CHECK(r.signals == 0);
CHECK_FALSE(r.ok);
CHECK(r.error.find("cannot open") != std::string::npos);
CHECK(sys.modules()->size() == 0);
}