(** Node.js test for MIME output infrastructure. This tests that the MIME output infrastructure is wired up correctly: - exec_result.mime_vals field is returned - Field is empty when no MIME output occurs - API types are correctly defined Note: The mime_printer library is used internally by the worker to capture MIME output. User code can call Mime_printer.push to produce MIME values when the mime_printer package is loaded in the toplevel. *) open Js_top_worker open Impl (* Flusher that writes to process.stdout in Node.js *) let console_flusher (s : string) : unit = let open Js_of_ocaml in let process = Js.Unsafe.get Js.Unsafe.global (Js.string "process") in let stdout = Js.Unsafe.get process (Js.string "stdout") in let write = Js.Unsafe.get stdout (Js.string "write") in ignore (Js.Unsafe.call write stdout [| Js.Unsafe.inject (Js.string s) |]) let capture : (unit -> 'a) -> unit -> Impl.captured * 'a = fun f () -> let stdout_buff = Buffer.create 1024 in let stderr_buff = Buffer.create 1024 in Js_of_ocaml.Sys_js.set_channel_flusher stdout (Buffer.add_string stdout_buff); let x = f () in let captured = { Impl.stdout = Buffer.contents stdout_buff; stderr = Buffer.contents stderr_buff; } in Js_of_ocaml.Sys_js.set_channel_flusher stdout console_flusher; (captured, x) module S : Impl.S = struct type findlib_t = Js_top_worker_web.Findlibish.t let capture = capture let sync_get f = let f = Fpath.v ("_opam/" ^ f) in try Some (In_channel.with_open_bin (Fpath.to_string f) In_channel.input_all) with _ -> None let async_get f = let f = Fpath.v ("_opam/" ^ f) in try let content = In_channel.with_open_bin (Fpath.to_string f) In_channel.input_all in Lwt.return (Ok content) with e -> Lwt.return (Error (`Msg (Printexc.to_string e))) let create_file = Js_of_ocaml.Sys_js.create_file let import_scripts urls = let open Js_of_ocaml.Js in let import_scripts_fn = Unsafe.get Unsafe.global (string "importScripts") in List.iter (fun url -> let (_ : 'a) = Unsafe.fun_call import_scripts_fn [| Unsafe.inject (string url) |] in ()) urls let init_function _ () = failwith "Not implemented" let findlib_init = Js_top_worker_web.Findlibish.init async_get let get_stdlib_dcs uri = Js_top_worker_web.Findlibish.fetch_dynamic_cmis sync_get uri |> Result.to_list let find_stdlib_dcs v = let pkg = match Js_top_worker_web.Findlibish.find_dcs_url v "stdlib" with | Some _ as r -> r | None -> Js_top_worker_web.Findlibish.find_dcs_url v "ocaml" in match pkg with | Some url -> Js_top_worker_web.Findlibish.fetch_dynamic_cmis sync_get url |> Result.to_list | None -> [] let require b v = function | [] -> [] | packages -> Js_top_worker_web.Findlibish.require ~import_scripts sync_get b v packages let path = "/static/cmis" end module U = Impl.Make (S) (* Test result tracking *) let total_tests = ref 0 let passed_tests = ref 0 let test name check message = incr total_tests; let passed = check in if passed then incr passed_tests; let status = if passed then "PASS" else "FAIL" in Printf.printf "[%s] %s: %s\n%!" status name message let _ = Printf.printf "=== Node.js MIME Infrastructure Tests ===\n\n%!"; Logs.set_reporter (Logs_fmt.reporter ()); Logs.set_level (Some Logs.Info); let ( let* ) m f = let open Lwt in m >>= function | Ok x -> f x | Error e -> return (Error e) in let run_exec code = U.execute "" code in let init_config = { stdlib_dcs = None; findlib_requires = []; findlib_index = None; execute = true } in let test_sequence = (* Initialize *) let* _ = U.init init_config in let* _ = U.setup "" in Printf.printf "--- Section 1: exec_result Has mime_vals Field ---\n%!"; (* Basic execution returns a result with mime_vals *) let* r = run_exec {|let x = 1 + 2;;|} in test "has_mime_vals_field" true "exec_result has mime_vals field"; test "mime_vals_is_list" (List.length r.mime_vals >= 0) (Printf.sprintf "mime_vals is a list (length=%d)" (List.length r.mime_vals)); test "mime_vals_empty_no_output" (List.length r.mime_vals = 0) "mime_vals is empty when no MIME output"; Printf.printf "\n--- Section 2: MIME Type Definitions ---\n%!"; (* Verify API types are accessible *) let mime_val_example : mime_val = { mime_type = "text/html"; encoding = Mime_printer.Noencoding; data = "test"; } in test "mime_type_field" (mime_val_example.mime_type = "text/html") "mime_val has mime_type field"; test "encoding_noencoding" (mime_val_example.encoding = Mime_printer.Noencoding) "Noencoding variant works"; test "data_field" (mime_val_example.data = "test") "mime_val has data field"; let mime_val_base64 : mime_val = { mime_type = "image/png"; encoding = Mime_printer.Base64; data = "iVBORw0KGgo="; } in test "encoding_base64" (mime_val_base64.encoding = Mime_printer.Base64) "Base64 variant works"; Printf.printf "\n--- Section 3: Multiple Executions ---\n%!"; (* Verify mime_vals is fresh for each execution *) let* r1 = run_exec {|let a = 1;;|} in let* r2 = run_exec {|let b = 2;;|} in let* r3 = run_exec {|let c = 3;;|} in test "r1_mime_empty" (List.length r1.mime_vals = 0) "First exec: mime_vals empty"; test "r2_mime_empty" (List.length r2.mime_vals = 0) "Second exec: mime_vals empty"; test "r3_mime_empty" (List.length r3.mime_vals = 0) "Third exec: mime_vals empty"; Printf.printf "\n--- Section 4: exec_toplevel Has mime_vals ---\n%!"; (* exec_toplevel also returns mime_vals *) let* tr = U.exec_toplevel "" "# let z = 42;;" in test "toplevel_has_mime_vals" true "exec_toplevel_result has mime_vals field"; test "toplevel_mime_vals_list" (List.length tr.mime_vals >= 0) (Printf.sprintf "toplevel mime_vals is a list (length=%d)" (List.length tr.mime_vals)); Lwt.return (Ok ()) in let promise = test_sequence in (match Lwt.state promise with | Lwt.Return (Ok ()) -> () | Lwt.Return (Error (InternalError s)) -> Printf.printf "\n[ERROR] Test failed with: %s\n%!" s | Lwt.Fail e -> Printf.printf "\n[ERROR] Exception: %s\n%!" (Printexc.to_string e) | Lwt.Sleep -> Printf.printf "\n[ERROR] Promise still pending\n%!"); Printf.printf "\n=== Results: %d/%d tests passed ===\n%!" !passed_tests !total_tests; if !passed_tests = !total_tests then Printf.printf "SUCCESS: All MIME infrastructure tests passed!\n%!" else Printf.printf "FAILURE: Some tests failed.\n%!"