From 788874151e63d3425e94a6f0a9eebbd2a5f8bec4 Mon Sep 17 00:00:00 2001 From: "carpentry-heartbeat[bot]" Date: Sat, 13 Jun 2026 20:23:03 +0200 Subject: [PATCH 1/2] Fix close() to return Result; fix dlclose error check; add tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit close() was the only function returning Maybe while open/get/get-from-module all return Result. Changed to Result for API consistency. Also fixed the dlclose error check from (= -1 ...) to (/= 0 ...) — per POSIX, dlclose returns 0 on success, non-zero on error (not -1). Added a test suite exercising open, get, close, and their error paths using the system libm. --- dynlib.carp | 6 +++--- test/dynlib.carp | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 test/dynlib.carp diff --git a/dynlib.carp b/dynlib.carp index 454a8f4..22dfc3a 100644 --- a/dynlib.carp +++ b/dynlib.carp @@ -62,10 +62,10 @@ a shared library `lib`. Returns a `Result` with the function on success, or the f (dlsym lib (cstr &fqn))] (if (valid? f) (Result.Success @f) (Result.Error (dlerror))))) - (doc close "closes a library `lib`. Either returns nothing or, if an error -occurs, it returns the error message.") + (doc close "closes a library `lib`. Returns a `Result` with `()` on success, +or the `dlerror` message on failure.") (defn close [lib] - (if (= -1 (dlclose lib)) (Maybe.Just (dlerror)) (Maybe.Nothing))) + (if (/= 0 (dlclose lib)) (Result.Error (dlerror)) (Result.Success ()))) (defmacro rebind [lib s] (list 'match diff --git a/test/dynlib.carp b/test/dynlib.carp new file mode 100644 index 0000000..c806f7d --- /dev/null +++ b/test/dynlib.carp @@ -0,0 +1,46 @@ +(load "../dynlib.carp") +(load "Test.carp") +(use Test) + +(defn main [] + (with-test test + ; open succeeds for a real library + (assert-true test + (Result.success? &(DynLib.open "libm.so.6")) + "open succeeds for libm") + + ; open fails for a nonexistent library + (assert-true test + (Result.error? &(DynLib.open "libnonexistent.so")) + "open fails for nonexistent library") + + ; get succeeds for a known symbol + (let-do [lib (Result.unsafe-from-success (DynLib.open "libm.so.6")) + result (the (Result (Fn [Double] Double) String) + (DynLib.get lib "floor")) + ok (Result.success? &result)] + (ignore result) + (ignore (DynLib.close lib)) + (assert-true test ok "get succeeds for known symbol")) + + ; get fails for a nonexistent symbol + (let-do [lib (Result.unsafe-from-success (DynLib.open "libm.so.6")) + result (the (Result (Fn [] ()) String) + (DynLib.get lib "nonexistent_symbol_xyz")) + bad (Result.error? &result)] + (ignore result) + (ignore (DynLib.close lib)) + (assert-true test bad "get fails for nonexistent symbol")) + + ; close succeeds on a valid handle + (let [lib (Result.unsafe-from-success (DynLib.open "libm.so.6"))] + (assert-true test + (Result.success? &(DynLib.close lib)) + "close succeeds on valid handle")) + + ; close returns Result.Success () on success + (let [lib (Result.unsafe-from-success (DynLib.open "libm.so.6"))] + (assert-equal test + &(Result.Success ()) + &(DynLib.close lib) + "close returns Result.Success on success")))) From fa8625faaec8c97d8cf5d643500daf629e5f91d1 Mon Sep 17 00:00:00 2001 From: carpentry-bot Date: Mon, 15 Jun 2026 01:38:08 +0200 Subject: [PATCH 2/2] Replace Result.unsafe-from-success with match in tests Fixes 4 unsafe-result-unwrap lint violations flagged by angler. Each test now pattern-matches on the Result from DynLib.open, failing explicitly if the library unexpectedly fails to load. --- test/dynlib.carp | 56 ++++++++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/test/dynlib.carp b/test/dynlib.carp index c806f7d..5cf782a 100644 --- a/test/dynlib.carp +++ b/test/dynlib.carp @@ -15,32 +15,42 @@ "open fails for nonexistent library") ; get succeeds for a known symbol - (let-do [lib (Result.unsafe-from-success (DynLib.open "libm.so.6")) - result (the (Result (Fn [Double] Double) String) - (DynLib.get lib "floor")) - ok (Result.success? &result)] - (ignore result) - (ignore (DynLib.close lib)) - (assert-true test ok "get succeeds for known symbol")) + (match (DynLib.open "libm.so.6") + (Result.Success lib) + (let-do [result (the (Result (Fn [Double] Double) String) + (DynLib.get lib "floor")) + ok (Result.success? &result)] + (ignore result) + (ignore (DynLib.close lib)) + (assert-true test ok "get succeeds for known symbol")) + (Result.Error _) (assert-true test false "get succeeds for known symbol")) ; get fails for a nonexistent symbol - (let-do [lib (Result.unsafe-from-success (DynLib.open "libm.so.6")) - result (the (Result (Fn [] ()) String) - (DynLib.get lib "nonexistent_symbol_xyz")) - bad (Result.error? &result)] - (ignore result) - (ignore (DynLib.close lib)) - (assert-true test bad "get fails for nonexistent symbol")) + (match (DynLib.open "libm.so.6") + (Result.Success lib) + (let-do [result (the (Result (Fn [] ()) String) + (DynLib.get lib "nonexistent_symbol_xyz")) + bad (Result.error? &result)] + (ignore result) + (ignore (DynLib.close lib)) + (assert-true test bad "get fails for nonexistent symbol")) + (Result.Error _) + (assert-true test false "get fails for nonexistent symbol")) ; close succeeds on a valid handle - (let [lib (Result.unsafe-from-success (DynLib.open "libm.so.6"))] - (assert-true test - (Result.success? &(DynLib.close lib)) - "close succeeds on valid handle")) + (match (DynLib.open "libm.so.6") + (Result.Success lib) + (assert-true test + (Result.success? &(DynLib.close lib)) + "close succeeds on valid handle") + (Result.Error _) (assert-true test false "close succeeds on valid handle")) ; close returns Result.Success () on success - (let [lib (Result.unsafe-from-success (DynLib.open "libm.so.6"))] - (assert-equal test - &(Result.Success ()) - &(DynLib.close lib) - "close returns Result.Success on success")))) + (match (DynLib.open "libm.so.6") + (Result.Success lib) + (assert-equal test + &(Result.Success ()) + &(DynLib.close lib) + "close returns Result.Success on success") + (Result.Error _) + (assert-true test false "close returns Result.Success on success"))))