;; Phase 8 FFI BIF tests — one round-trip per BIF. ;; Each BIF lives in lib/erlang/runtime.sx (registered with ;; er-bif-registry) and wraps an SX-host primitive. (define er-ffi-test-count 0) (define er-ffi-test-pass 0) (define er-ffi-test-fails (list)) (define er-ffi-test (fn (name actual expected) (set! er-ffi-test-count (+ er-ffi-test-count 1)) (if (= actual expected) (set! er-ffi-test-pass (+ er-ffi-test-pass 1)) (append! er-ffi-test-fails {:name name :expected expected :actual actual})))) (define ffi-ev erlang-eval-ast) (define ffi-nm (fn (v) (get v :name))) ;; ── file:read_file/1 + file:write_file/2 ──────────────────────── (er-ffi-test "file:write_file ok" (ffi-nm (ffi-ev "file:write_file(\"/tmp/er-ffi-1.txt\", \"hello\")")) "ok") (er-ffi-test "file:read_file ok tag" (ffi-nm (ffi-ev "element(1, file:read_file(\"/tmp/er-ffi-1.txt\"))")) "ok") (er-ffi-test "file:read_file payload is binary" (ffi-nm (ffi-ev "case file:read_file(\"/tmp/er-ffi-1.txt\") of {ok, B} -> is_binary(B) end")) "true") (er-ffi-test "file:read_file content byte_size" (ffi-ev "case file:read_file(\"/tmp/er-ffi-1.txt\") of {ok, B} -> byte_size(B) end") 5) (er-ffi-test "file:read_file missing enoent" (ffi-nm (ffi-ev "element(2, file:read_file(\"/tmp/er-ffi-no-such-xyz\"))")) "enoent") (er-ffi-test "file:write_file bad path enoent" (ffi-nm (ffi-ev "element(2, file:write_file(\"/tmp/er-ffi-no-dir-xyz/x\", \"y\"))")) "enoent") (er-ffi-test "file:write_file binary payload" (ffi-ev "file:write_file(\"/tmp/er-ffi-2.bin\", <<1, 2, 3, 4, 5>>), case file:read_file(\"/tmp/er-ffi-2.bin\") of {ok, B} -> byte_size(B) end") 5) ;; ── file:delete/1 ──────────────────────────────────────────────── (er-ffi-test "file:delete ok" (ffi-nm (ffi-ev "file:write_file(\"/tmp/er-ffi-del.txt\", \"x\"), file:delete(\"/tmp/er-ffi-del.txt\")")) "ok") (er-ffi-test "file:read_file after delete enoent" (ffi-nm (ffi-ev "file:write_file(\"/tmp/er-ffi-del2.txt\", \"x\"), file:delete(\"/tmp/er-ffi-del2.txt\"), element(2, file:read_file(\"/tmp/er-ffi-del2.txt\"))")) "enoent") ;; ── Blocked BIFs (placeholder asserts so the suite documents intent) ── ;; crypto:hash/2, cid:from_bytes/1, cid:to_string/1, file:list_dir/1, ;; httpc:request/4, sqlite:* — documented in plans/erlang-on-sx.md ;; under Blockers. When the host runtime gains the underlying primitive, ;; the wrappers land in runtime.sx and tests appear here. For now we ;; assert each is NOT registered, so a future iteration that adds them ;; without updating this file fails fast. (er-ffi-test "crypto:hash unregistered" (er-lookup-bif "crypto" "hash" 2) nil) (er-ffi-test "cid:from_bytes unregistered" (er-lookup-bif "cid" "from_bytes" 1) nil) (er-ffi-test "file:list_dir unregistered" (er-lookup-bif "file" "list_dir" 1) nil) (er-ffi-test "httpc:request unregistered" (er-lookup-bif "httpc" "request" 4) nil) (er-ffi-test "sqlite:exec unregistered" (er-lookup-bif "sqlite" "exec" 2) nil) (define er-ffi-test-summary (str "ffi " er-ffi-test-pass "/" er-ffi-test-count))