Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,10 @@ if(BUILD_TESTING)
target_link_libraries(emscripten_eval_test ${LIBS})
add_test(NAME Emscripten_Eval_Test COMMAND emscripten_eval_test)

add_executable(emscripten_exception_test unittests/emscripten_exception_test.cpp)
target_link_libraries(emscripten_exception_test ${LIBS})
add_test(NAME Emscripten_Exception_Test COMMAND emscripten_exception_test)

add_executable(threading_config_test unittests/threading_config_test.cpp)
target_link_libraries(threading_config_test ${LIBS})
add_test(NAME Threading_Config_Test COMMAND threading_config_test)
Expand Down
5 changes: 5 additions & 0 deletions emscripten/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@ add_definitions(-DCHAISCRIPT_NO_THREADS -DCHAISCRIPT_NO_DYNLOAD)
add_executable(chaiscript chaiscript_em.cpp)
target_include_directories(chaiscript PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../include)

# Enable WASM exception handling — ChaiScript relies on C++ exceptions for
# error propagation; without this flag exceptions cause an abort in WASM.
target_compile_options(chaiscript PRIVATE -fwasm-exceptions)

# Emscripten link flags: enable embind, allow memory growth, export as ES module-compatible
target_link_options(chaiscript PRIVATE
--bind
-fwasm-exceptions
-sALLOW_MEMORY_GROWTH=1
-sEXPORT_ES6=0
-sMODULARIZE=0
Expand Down
72 changes: 72 additions & 0 deletions unittests/emscripten_exception_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Test that validates exception propagation through the Emscripten eval wrapper.
// Without proper exception support flags (-fwasm-exceptions) in the WASM build,
// C++ exceptions would cause an abort instead of being catchable.

#ifndef CHAISCRIPT_NO_THREADS
#define CHAISCRIPT_NO_THREADS
#endif

#ifndef CHAISCRIPT_NO_DYNLOAD
#define CHAISCRIPT_NO_DYNLOAD
#endif

#include <chaiscript/chaiscript.hpp>
#include "../emscripten/chaiscript_eval.hpp"
#include <cassert>
#include <iostream>
#include <stdexcept>
#include <string>

int main() {
// Verify that ChaiScript evaluation errors propagate as exceptions
// through the eval wrapper functions. In WASM builds without exception
// support, these would abort instead of throwing.

bool caught = false;

// Test 1: eval with undefined variable should throw
caught = false;
try {
chaiscript_eval("this_variable_does_not_exist");
} catch (const chaiscript::exception::eval_error &) {
caught = true;
}
assert(caught && "eval of undefined variable must throw eval_error");

// Test 2: evalString with a type mismatch should throw
caught = false;
try {
chaiscript_eval_string("1 + 2");
} catch (const chaiscript::exception::bad_boxed_cast &) {
caught = true;
}
assert(caught && "evalString with non-string result must throw bad_boxed_cast");

// Test 3: evalInt with invalid syntax should throw
caught = false;
try {
chaiscript_eval_int("def {}");
} catch (const chaiscript::exception::eval_error &) {
caught = true;
}
assert(caught && "evalInt with syntax error must throw eval_error");

// Test 4: eval with throw statement should propagate exception
caught = false;
try {
chaiscript_eval("throw(\"user exception\")");
} catch (const chaiscript::Boxed_Value &) {
caught = true;
} catch (...) {
caught = true;
}
assert(caught && "ChaiScript throw must propagate as an exception");

// Test 5: Verify normal operation still works after caught exceptions
chaiscript_eval("var post_exception_test = 100");
const int result = chaiscript_eval_int("post_exception_test");
assert(result == 100 && "normal eval must work after caught exceptions");

std::cout << "All emscripten exception tests passed.\n";
return 0;
}
Loading