(env
 (_
  ;; for testing
  (env-vars
   (FOO bar))))

; [format with large precision] checks the exact decimal expansion of a
; double. The native oracle is mingw on Windows, whose printf rounds past
; ~17 significant digits and so cannot reproduce it. Both that Windows
; exclusion and the OCaml version gate live in the source as a floating
; [@@@if]; js and wasm are OS-independent and still run on every other
; platform.

(library
 (name jsoo_testsuite_floats_exact)
 (modules test_floats_exact)
 (inline_tests
  (deps
   (sandbox preserve_file_kind))
  (modes js wasm best))
 (preprocess
  (pps ppx_optcomp_light ppx_expect)))

(library
 (name jsoo_testsuite_perms)
 (modules test_unix_perms)
 (libraries unix)
 ;; WASI has no notion of file permissions (it uses capabilities instead),
 ;; and the QuickJS shim only approximates [Unix.access] / [Unix.chmod].
 (enabled_if
  (and
   (<> %{profile} wasi)
   (<> %{profile} wasi-with-native-effects)
   (<> %{profile} quickjs)))
 (inline_tests
  (deps
   (sandbox preserve_file_kind))
  (modes js wasm best))
 (preprocess
  (pps ppx_expect)))

(library
 (name jsoo_testsuite_sys_command)
 (modules test_sys_command)
 ;; [Sys.command] needs process execution, which WASI does not provide
 ;; (and the test is not run under quickjs, like the other Unix tests).
 (enabled_if
  (and
   (<> %{profile} wasi)
   (<> %{profile} wasi-with-native-effects)
   (<> %{profile} quickjs)))
 (inline_tests
  (deps
   (sandbox preserve_file_kind))
  (modes js wasm best))
 (preprocess
  (pps ppx_expect)))

(library
 (name jsoo_testsuite_float32_js)
 (modules test_marshal_float32_js)
 (libraries unix compiler-libs.common js_of_ocaml-compiler)
 (enabled_if %{oxcaml_supported})
 (inline_tests
  (modes js))
 (preprocess
  (pps ppx_expect)))

(library
 (name jsoo_testsuite_ugeint)
 (modules test_ugeint)
 (libraries unix compiler-libs.common js_of_ocaml-compiler)
 (enabled_if %{oxcaml_supported})
 (inline_tests
  (modes js wasm best))
 (preprocess
  (pps ppx_expect)))

(rule
 ; Guard against future OxCaml changes peepholing UGEINT away the same
 ; way vanilla ocamlc does. If this rule fails, [test_ugeint] still
 ; passes its assertions but no longer exercises the UGEINT code path
 ; in [parse_bytecode.ml], and the regression coverage is gone.
 (alias runtest)
 (enabled_if %{oxcaml_supported})
 (deps ugeint_bytecode_probe.ml)
 (action
  (bash
   "ocamlc %{deps} -o probe.bc && dumpobj probe.bc | grep -qE '^[[:space:]]*[0-9]+[[:space:]]+UGEINT'")))

(library
 (name jsoo_testsuite_float32)
 (modules test_marshal_float32)
 (libraries unix compiler-libs.common js_of_ocaml-compiler)
 (enabled_if %{oxcaml_supported})
 (inline_tests
  (modes wasm best))
 (preprocess
  (pps ppx_expect)))

(library
 ; The #2300 regression has to digest a >2 GiB input, which takes far longer
 ; than a normal inline test (~40s in JS). It is therefore isolated in its
 ; own library and OFF BY DEFAULT: opt in with JSOO_TEST_MD5_LARGE=true, e.g.
 ; via `make test-md5-large`.
 (name jsoo_testsuite_md5_large)
 (modules test_md5_large)
 (enabled_if
  (and
   %{env:JSOO_TEST_MD5_LARGE=false}
   ;; The sparse-file trick is not portable to the quickjs / wasi fs shims.
   (<> %{profile} wasi)
   (<> %{profile} wasi-with-native-effects)
   (<> %{profile} quickjs)))
 (inline_tests
  (deps
   (sandbox preserve_file_kind))
  (modes js wasm best))
 (preprocess
  (pps ppx_expect)))

(library
 (name jsoo_testsuite)
 (modules
  (:standard
   \
   test_floats_exact
   test_float16
   test_bigarray
   test_list_of_js_array
   test_marshal_float32
   test_marshal_float32_js
   test_md5_large
   test_ugeint
   ugeint_bytecode_probe
   test_runtime_value
   ephemeron_data
   hash_jsstring
   bigstring_kind
   wrap_exception
   meth_call_utf8
   condition
   runtime_events_register
   test_custom_name
   test_text_codec_fallback
   test_unix
   test_unix_symlink
   channel_refill
   unix_open_append
   test_promise
   test_lwt_promise
   test_unix_perms
   test_sys_command
   test_str
   test_weak_gc
   toplevel_sections
   obj_block_float))
 (libraries unix compiler-libs.common js_of_ocaml-compiler)
 (foreign_stubs
  (language c)
  (names jsoo_runtime_stubs))
 (inline_tests
  (deps
   (sandbox preserve_file_kind))
  (modes js wasm best))
 (preprocess
  ; ppx_optcomp_light lets version-specific tests (e.g. those gated with
  ; [@@@if ocaml_version >= ...]) share this single library across OCaml
  ; versions instead of living in their own enabled_if'd libraries.
  (pps ppx_optcomp_light ppx_expect)))

; test_bigarray uses the float16 kind, which requires OCaml 5.2.

(library
 (name jsoo_testsuite_bigarray)
 (modules test_bigarray)
 (enabled_if
  (>= %{ocaml_version} 5.2))
 (foreign_stubs
  (language c)
  (names bigarray_stubs))
 (inline_tests
  (deps
   (sandbox preserve_file_kind))
  (modes js wasm best))
 (preprocess
  (pps ppx_expect)))

; test_unix exercises [Unix.link], which the QuickJS shim does not
; implement, so it lives in its own library that's disabled under the
; quickjs profile.

(library
 (name jsoo_testsuite_unix)
 (enabled_if
  (<> %{profile} quickjs))
 (modules test_unix)
 (libraries unix compiler-libs.common js_of_ocaml-compiler)
 (inline_tests
  (deps
   (sandbox preserve_file_kind))
  (modes js wasm best))
 (preprocess
  (pps ppx_expect)))

; test_unix_symlink creates symlinks and stats through them. WASI rejects
; symlinks to absolute targets with EPERM (its capability model forbids
; escaping a preopen); the QuickJS shim does not implement [Unix.symlink];
; and on Windows node cannot [stat] a directory symlink without elevation.
; So it only runs on Unix-like hosts under the JS / wasm-on-unix runtimes.

(library
 (name jsoo_testsuite_symlink)
 (enabled_if
  (and
   (<> %{profile} quickjs)
   (<> %{profile} wasi)
   (<> %{profile} wasi-with-native-effects)
   (<> %{os_type} Win32)))
 (modules test_unix_symlink)
 (libraries unix)
 (inline_tests
  (deps
   (sandbox preserve_file_kind))
  (modes js wasm best))
 (preprocess
  (pps ppx_expect)))

; The Windows exclusion lives in the source as a floating [@@@if os_type
; <> "Win32"]: Windows node rejects the O_APPEND flag combination and
; positions the append offset differently.

(library
 (name jsoo_testsuite_unix_open_append)
 (modules unix_open_append)
 (libraries unix)
 (inline_tests
  (deps
   (sandbox preserve_file_kind))
  (modes js wasm best))
 (preprocess
  (pps ppx_optcomp_light ppx_expect)))

(library
 (name jsoo_testsuite_str)
 (modules test_str)
 (libraries str)
 (inline_tests
  (deps
   (sandbox preserve_file_kind))
  (modes js wasm best))
 (preprocess
  (pps ppx_expect)))

(test
 (name test_float16)
 (build_if
  (>= %{ocaml_version} 5.2))
 (modules test_float16)
 (modes js wasm native))

(test
 (name runtime_events_register)
 (build_if
  (>= %{ocaml_version} 5.1))
 (modules runtime_events_register)
 (libraries runtime_events)
 (modes js wasm native))

(test
 (name obj_block_float)
 (modules obj_block_float)
 (modes js wasm native))

(test
 (name test_runtime_value)
 (modules test_runtime_value)
 (libraries js_of_ocaml)
 (enabled_if
  (and
   (<> %{profile} wasi)
   (<> %{profile} wasi-with-native-effects)))
 (js_of_ocaml
  (javascript_files custom.js))
 (wasm_of_ocaml
  (javascript_files custom.js custom.wat))
 (modes js wasm))

; Uses [Sys_js.set_channel_filler], a js_of_ocaml runtime feature absent
; under the WASI runtime; exercised on both the JavaScript and wasm runtimes.

(library
 (name jsoo_testsuite_channel_refill)
 (modules channel_refill)
 (libraries js_of_ocaml)
 (enabled_if
  (and
   (<> %{profile} wasi)
   (<> %{profile} wasi-with-native-effects)))
 (inline_tests
  (deps
   (sandbox preserve_file_kind))
  (modes js wasm))
 (preprocess
  (pps ppx_expect)))

; Uses Js values (Js.string/Js.null), so it cannot run natively or under
; the WASI runtime; exercised on both the JavaScript and wasm runtimes.

(test
 (name ephemeron_data)
 (modules ephemeron_data)
 (libraries js_of_ocaml)
 (enabled_if
  (and
   (<> %{profile} wasi)
   (<> %{profile} wasi-with-native-effects)))
 (modes js wasm))

; JS-string hashing matches the JS runtime; uses Js values, js and wasm only.

(library
 (name hash_jsstring)
 (modules hash_jsstring)
 (enabled_if
  (and
   (<> %{profile} wasi)
   (<> %{profile} wasi-with-native-effects)))
 (inline_tests
  (modes js wasm))
 (libraries js_of_ocaml)
 (preprocess
  (pps ppx_expect)))

; Bigstring.of_arrayBuffer produces a char bigarray; uses Js, js and wasm only.

(library
 (name bigstring_kind)
 (modules bigstring_kind)
 (enabled_if
  (and
   (<> %{profile} wasi)
   (<> %{profile} wasi-with-native-effects)))
 (inline_tests
  (modes js wasm))
 (libraries js_of_ocaml)
 (preprocess
  (pps js_of_ocaml-ppx ppx_expect)))

; caml_wrap_exception wrapping of thrown JS values; uses Js, js and wasm only.

(test
 (name wrap_exception)
 (modules wrap_exception)
 (libraries js_of_ocaml)
 (enabled_if
  (and
   (<> %{profile} wasi)
   (<> %{profile} wasi-with-native-effects)))
 (modes js wasm))

; UTF-8 method-name resolution in caml_js_meth_call; uses Js values, so it
; runs on the JavaScript and wasm runtimes only.

(test
 (name meth_call_utf8)
 (modules meth_call_utf8)
 (libraries js_of_ocaml)
 (enabled_if
  (and
   (<> %{profile} wasi)
   (<> %{profile} wasi-with-native-effects)))
 (modes js wasm))

; Condition variables agree between js and wasm. Not run natively: it calls
; Condition.wait, which blocks forever there.

(test
 (name condition)
 ; The OCaml < 5 gate lives in the source as a floating [@@@if]: Condition/Mutex
 ; are in the threads library on OCaml < 5, and gating the body keeps the module
 ; compiling (empty) on older compilers without pulling in threads.
 (modules condition)
 (modes js wasm)
 (preprocess
  (pps ppx_optcomp_light)))

; The js accessor lives in the optional +toplevel.js runtime fragment, so it
; is linked explicitly; --toplevel is deliberately NOT passed, so the bytecode
; sections stay absent and the accessor raises like in a non-toplevel program.

(test
 (name toplevel_sections)
 (modules toplevel_sections)
 (enabled_if
  (and
   (<> %{profile} wasi)
   (<> %{profile} wasi-with-native-effects)))
 (modes js wasm)
 (js_of_ocaml
  (compilation_mode whole_program)
  (flags
   (:standard +toplevel.js)))
 (wasm_of_ocaml
  (compilation_mode whole_program)))

; Forces a major GC through node's v8/vm modules to observe ephemeron
; liveness, so it only runs in js mode under node.

(test
 (name test_weak_gc)
 (modules test_weak_gc)
 (enabled_if
  (and
   (<> %{profile} wasi)
   (<> %{profile} wasi-with-native-effects)
   (<> %{profile} quickjs)))
 (libraries js_of_ocaml)
 (modes js)
 (preprocess
  (pps ppx_js_internal)))

(test
 (name test_promise)
 (modules test_promise)
 (enabled_if
  (and
   (<> %{profile} wasi)
   (<> %{profile} wasi-with-native-effects)))
 (libraries js_of_ocaml)
 (modes js wasm)
 (preprocess
  (pps ppx_js_internal)))

(test
 (name test_lwt_promise)
 (package js_of_ocaml-lwt)
 (modules test_lwt_promise)
 (enabled_if
  (and
   (<> %{profile} wasi)
   (<> %{profile} wasi-with-native-effects)))
 (libraries js_of_ocaml js_of_ocaml-lwt lwt)
 (modes js wasm)
 (preprocess
  (pps ppx_js_internal)))

(library
 (name test_custom_name)
 (modules test_custom_name)
 (enabled_if
  (and
   (<> %{profile} wasi)
   (<> %{profile} wasi-with-native-effects)))
 (inline_tests
  (modes js wasm))
 (libraries js_of_ocaml)
 (preprocess
  (pps ppx_expect)))

; The TextEncoder/TextDecoder fallbacks in [runtime/js/mlBytes.js] are
; cross-checked against the host Web Encoding API. That only works on
; hosts that provide TextEncoder/TextDecoder, so skip under quickjs.

(library
 (name test_text_codec_fallback)
 (enabled_if
  (<> %{profile} quickjs))
 (modules test_text_codec_fallback)
 (inline_tests
  (modes js))
 (libraries js_of_ocaml)
 (preprocess
  (pps js_of_ocaml-ppx ppx_expect)))

(library
 (name test_list_of_js_array)
 (modules test_list_of_js_array)
 (enabled_if
  (and
   (<> %{profile} wasi)
   (<> %{profile} wasi-with-native-effects)))
 (inline_tests
  (modes js wasm))
 (libraries js_of_ocaml)
 (preprocess
  (pps ppx_expect)))

(ocamlyacc calc_parser)

(ocamllex calc_lexer)

(ocamlyacc parser_1307)

(ocamllex lexer_1307)
