mirror of
https://github.com/mlua-rs/mlua
synced 2026-06-08 16:05:43 +00:00
27f91dfd1b
Previously wrapped functions were required to return `mlua::Result`. Now it's possible to wrap functions returning any errors as long as they implement `std::error::Error`. Existing code remains compatible with `mlua::Result` as this type is not converted to an external error.
115 lines
3.8 KiB
Rust
115 lines
3.8 KiB
Rust
use std::error::Error as _;
|
|
use std::{fmt, io};
|
|
|
|
use mlua::{Error, ErrorContext, Lua, Result};
|
|
|
|
#[test]
|
|
fn test_error_context() -> Result<()> {
|
|
let lua = Lua::new();
|
|
|
|
let func =
|
|
lua.create_function(|_, ()| Err::<(), _>(Error::runtime("runtime error")).context("some context"))?;
|
|
lua.globals().set("func", func)?;
|
|
|
|
let msg = lua
|
|
.load("local _, err = pcall(func); return tostring(err)")
|
|
.eval::<String>()?;
|
|
assert!(msg.contains("some context"));
|
|
assert!(msg.contains("runtime error"));
|
|
|
|
let func2 = lua.create_function(|lua, ()| {
|
|
lua.globals()
|
|
.get::<String>("nonextant")
|
|
.with_context(|_| "failed to find global")
|
|
})?;
|
|
lua.globals().set("func2", func2)?;
|
|
|
|
let msg2 = lua
|
|
.load("local _, err = pcall(func2); return tostring(err)")
|
|
.eval::<String>()?;
|
|
assert!(msg2.contains("failed to find global"));
|
|
assert!(msg2.contains("error converting Lua nil to String"));
|
|
|
|
// Rewrite context message and test `downcast_ref`
|
|
let func3 = lua.create_function(|_, ()| {
|
|
Err::<(), _>(Error::external(io::Error::new(io::ErrorKind::Other, "other")))
|
|
.context("some context")
|
|
.context("some new context")
|
|
})?;
|
|
let err = func3.call::<()>(()).unwrap_err();
|
|
let err = err.parent().unwrap();
|
|
assert!(!err.to_string().contains("some context"));
|
|
assert!(err.to_string().contains("some new context"));
|
|
assert!(err.downcast_ref::<io::Error>().is_some());
|
|
assert!(err.downcast_ref::<fmt::Error>().is_none());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_error_chain() -> Result<()> {
|
|
let lua = Lua::new();
|
|
|
|
// Check that `Error::ExternalError` creates a chain with a single element
|
|
let io_err = io::Error::new(io::ErrorKind::Other, "other");
|
|
assert_eq!(Error::external(io_err).chain().count(), 1);
|
|
|
|
let func = lua.create_function(|_, ()| {
|
|
let err = Error::external(io::Error::new(io::ErrorKind::Other, "other")).context("io error");
|
|
Err::<(), _>(err)
|
|
})?;
|
|
let err = func.call::<()>(()).unwrap_err();
|
|
assert_eq!(err.chain().count(), 3);
|
|
for (i, err) in err.chain().enumerate() {
|
|
match i {
|
|
0 => assert!(matches!(err.downcast_ref(), Some(Error::CallbackError { .. }))),
|
|
1 => assert!(matches!(err.downcast_ref(), Some(Error::WithContext { .. }))),
|
|
2 => assert!(matches!(err.downcast_ref(), Some(io::Error { .. }))),
|
|
_ => unreachable!(),
|
|
}
|
|
}
|
|
|
|
let err = err.parent().unwrap();
|
|
assert!(err.source().is_none()); // The source is included to the `Display` output
|
|
assert!(err.to_string().contains("io error"));
|
|
assert!(err.to_string().contains("other"));
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_external_error() {
|
|
// `Error::external` should preserve `mlua::Error`
|
|
let runtime_err = Error::runtime("test error");
|
|
let converted = Error::external(runtime_err);
|
|
assert!(matches!(converted, Error::RuntimeError(ref msg) if msg == "test error"));
|
|
|
|
// Other errors should become `ExternalError`
|
|
let converted = Error::external(io::Error::other("other error"));
|
|
assert!(matches!(converted, Error::ExternalError(_)));
|
|
assert!(converted.downcast_ref::<io::Error>().is_some());
|
|
}
|
|
|
|
#[cfg(feature = "anyhow")]
|
|
#[test]
|
|
fn test_error_anyhow() -> Result<()> {
|
|
use mlua::IntoLua;
|
|
|
|
let lua = Lua::new();
|
|
|
|
let err = anyhow::Error::msg("anyhow error");
|
|
let val = err.into_lua(&lua)?;
|
|
assert!(val.is_error());
|
|
assert_eq!(val.as_error().unwrap().to_string(), "anyhow error");
|
|
|
|
// Try Error -> anyhow::Error -> Error roundtrip
|
|
let err = Error::runtime("runtime error");
|
|
let err = anyhow::Error::new(err);
|
|
let err = err.into_lua(&lua)?;
|
|
assert!(err.is_error());
|
|
let err = err.as_error().unwrap();
|
|
assert!(matches!(err, Error::RuntimeError(msg) if msg == "runtime error"));
|
|
|
|
Ok(())
|
|
}
|