use mlua::StdLib;
use mlua::prelude::*;
use pasta_lua::loader::LuaConfig;
use pasta_lua::runtime::lua_require;
use pasta_lua::{ConfigError, RuntimeConfig};
#[test]
fn test_runtime_config_new_returns_default_libs() {
let config = RuntimeConfig::new();
assert!(config.libs.contains(&"std_all".to_string()));
assert!(config.libs.contains(&"assertions".to_string()));
assert!(config.libs.contains(&"testing".to_string()));
assert!(config.libs.contains(&"regex".to_string()));
assert!(config.libs.contains(&"json".to_string()));
assert!(config.libs.contains(&"yaml".to_string()));
assert!(!config.libs.contains(&"env".to_string()));
}
#[test]
fn test_runtime_config_full_includes_unsafe() {
let config = RuntimeConfig::full();
assert!(config.libs.contains(&"std_all_unsafe".to_string()));
assert!(config.libs.contains(&"env".to_string()));
}
#[test]
fn test_runtime_config_minimal_is_std_all_only() {
let config = RuntimeConfig::minimal();
assert_eq!(config.libs, vec!["std_all".to_string()]);
}
#[test]
fn test_runtime_config_from_libs() {
let config = RuntimeConfig::from_libs(vec!["std_table".into(), "regex".into()]);
assert_eq!(config.libs.len(), 2);
assert!(config.libs.contains(&"std_table".to_string()));
assert!(config.libs.contains(&"regex".to_string()));
}
#[test]
fn test_to_stdlib_std_all() {
let config = RuntimeConfig::from_libs(vec!["std_all".into()]);
let stdlib = config.to_stdlib().unwrap();
assert_eq!(stdlib, StdLib::ALL_SAFE);
}
#[test]
fn test_to_stdlib_std_all_unsafe() {
let config = RuntimeConfig::from_libs(vec!["std_all_unsafe".into()]);
let stdlib = config.to_stdlib().unwrap();
assert_eq!(stdlib, StdLib::ALL);
}
#[test]
fn test_to_stdlib_individual_libs() {
let config = RuntimeConfig::from_libs(vec![
"std_table".into(),
"std_string".into(),
"std_math".into(),
]);
let stdlib = config.to_stdlib().unwrap();
assert_eq!(stdlib, StdLib::TABLE | StdLib::STRING | StdLib::MATH);
}
#[test]
fn test_to_stdlib_luajit_specific_libs() {
let config =
RuntimeConfig::from_libs(vec!["std_jit".into(), "std_ffi".into(), "std_bit".into()]);
let stdlib = config.to_stdlib().unwrap();
assert_eq!(stdlib, StdLib::JIT | StdLib::FFI | StdLib::BIT);
}
#[test]
fn test_to_stdlib_rejects_removed_std_utf8() {
let config = RuntimeConfig::from_libs(vec!["std_utf8".into()]);
let result = config.to_stdlib();
match result {
Err(ConfigError::UnknownLibrary(name)) => {
assert_eq!(name, "std_utf8");
let message = ConfigError::UnknownLibrary(name).to_string();
let valid_libraries = message
.split_once("Valid libraries: ")
.map(|(_, libraries)| libraries)
.expect("UnknownLibrary message should list valid libraries");
assert!(!valid_libraries.contains("std_utf8"));
assert!(valid_libraries.contains("std_jit"));
assert!(valid_libraries.contains("std_ffi"));
assert!(valid_libraries.contains("std_bit"));
}
Ok(_) => panic!("Expected error for removed std_utf8 library"),
}
}
#[test]
fn test_to_stdlib_subtraction() {
let config = RuntimeConfig::from_libs(vec!["std_all".into(), "-std_io".into()]);
let stdlib = config.to_stdlib().unwrap();
let expected = StdLib::ALL_SAFE ^ (StdLib::ALL_SAFE & StdLib::IO);
assert_eq!(stdlib, expected);
}
#[test]
fn test_to_stdlib_order_independent() {
let config1 = RuntimeConfig::from_libs(vec!["-std_io".into(), "std_all".into()]);
let config2 = RuntimeConfig::from_libs(vec!["std_all".into(), "-std_io".into()]);
let stdlib1 = config1.to_stdlib().unwrap();
let stdlib2 = config2.to_stdlib().unwrap();
assert_eq!(stdlib1, stdlib2);
}
#[test]
fn test_to_stdlib_empty_libs() {
let config = RuntimeConfig::from_libs(vec![]);
let stdlib = config.to_stdlib().unwrap();
assert_eq!(stdlib, StdLib::NONE);
}
#[test]
fn test_to_stdlib_unknown_library_error() {
let config = RuntimeConfig::from_libs(vec!["std_nonexistent".into()]);
let result = config.to_stdlib();
assert!(result.is_err());
match result {
Err(ConfigError::UnknownLibrary(name)) => {
assert_eq!(name, "std_nonexistent");
}
Ok(_) => panic!("Expected error for unknown library"),
}
}
#[test]
fn test_to_stdlib_ignores_mlua_stdlib_modules() {
let config = RuntimeConfig::from_libs(vec![
"std_table".into(),
"assertions".into(),
"regex".into(),
]);
let stdlib = config.to_stdlib().unwrap();
assert_eq!(stdlib, StdLib::TABLE);
}
#[test]
fn test_should_enable_module_positive() {
let config = RuntimeConfig::from_libs(vec!["testing".into(), "regex".into()]);
assert!(config.should_enable_module("testing"));
assert!(config.should_enable_module("regex"));
assert!(!config.should_enable_module("assertions"));
}
#[test]
fn test_should_enable_module_with_subtraction() {
let config = RuntimeConfig::from_libs(vec!["testing".into(), "-testing".into()]);
assert!(!config.should_enable_module("testing"));
}
#[test]
fn test_should_enable_module_subtraction_without_positive() {
let config = RuntimeConfig::from_libs(vec!["-testing".into()]);
assert!(!config.should_enable_module("testing"));
}
#[test]
fn test_from_lua_config() {
let lua_config = LuaConfig {
libs: vec!["std_all".into(), "testing".into()],
};
let runtime_config: RuntimeConfig = lua_config.into();
assert_eq!(runtime_config.libs, vec!["std_all", "testing"]);
}
#[test]
fn test_default_equals_new() {
let default_config = RuntimeConfig::default();
let new_config = RuntimeConfig::new();
assert_eq!(default_config.libs, new_config.libs);
}
#[test]
fn test_validate_and_warn_safe_config() {
let config = RuntimeConfig::new();
config.validate_and_warn();
}
#[test]
fn test_validate_and_warn_unsafe_config() {
let config = RuntimeConfig::full();
config.validate_and_warn();
}
#[test]
fn test_validate_and_warn_detects_std_debug() {
let config = RuntimeConfig::from_libs(vec!["std_debug".into()]);
config.validate_and_warn();
assert!(config.libs.contains(&"std_debug".to_string()));
}
#[test]
fn test_validate_and_warn_detects_std_all_unsafe() {
let config = RuntimeConfig::from_libs(vec!["std_all_unsafe".into()]);
config.validate_and_warn();
assert!(config.libs.contains(&"std_all_unsafe".to_string()));
}
#[test]
fn test_validate_and_warn_detects_env_module() {
let config = RuntimeConfig::from_libs(vec!["std_all".into(), "env".into()]);
config.validate_and_warn();
assert!(config.should_enable_module("env"));
}
#[test]
fn test_validate_and_warn_respects_debug_subtraction() {
let config = RuntimeConfig::from_libs(vec!["std_all_unsafe".into(), "-std_debug".into()]);
config.validate_and_warn();
assert!(config.libs.iter().any(|lib| lib == "-std_debug"));
}
#[test]
fn test_validate_and_warn_respects_env_subtraction() {
let config = RuntimeConfig::from_libs(vec!["env".into(), "-env".into()]);
config.validate_and_warn();
assert!(!config.should_enable_module("env"));
}
#[test]
fn test_validate_and_warn_empty_libs() {
let config = RuntimeConfig::from_libs(vec![]);
config.validate_and_warn();
}
#[test]
fn test_validate_and_warn_minimal() {
let config = RuntimeConfig::minimal();
config.validate_and_warn();
assert!(!config.libs.contains(&"std_debug".to_string()));
assert!(!config.libs.contains(&"std_all_unsafe".to_string()));
assert!(!config.should_enable_module("env"));
}
#[test]
fn test_lua_require_existing_module() {
let lua = unsafe { Lua::unsafe_new_with(StdLib::ALL_SAFE, mlua::LuaOptions::default()) };
let test_module = lua.create_table().unwrap();
test_module.set("name", "test_module").unwrap();
let package: LuaTable = lua.globals().get("package").unwrap();
let loaded: LuaTable = package.get("loaded").unwrap();
loaded.set("test_module", test_module).unwrap();
let result = lua_require(&lua, "test_module");
assert!(result.is_ok(), "Should successfully require test_module");
let value = result.unwrap();
if let LuaValue::Table(t) = value {
let name: String = t.get("name").unwrap();
assert_eq!(name, "test_module");
} else {
panic!("Expected table from require");
}
}
#[test]
fn test_lua_require_nonexistent_module() {
let lua = unsafe { Lua::unsafe_new_with(StdLib::ALL_SAFE, mlua::LuaOptions::default()) };
let result = lua_require(&lua, "nonexistent_module_xyz123");
assert!(result.is_err(), "Should fail for non-existent module");
let err = result.unwrap_err();
let err_str = err.to_string();
assert!(
err_str.contains("nonexistent_module_xyz123"),
"Error message should contain module name: {}",
err_str
);
}
#[test]
fn test_lua_require_dotted_module_name() {
let lua = unsafe { Lua::unsafe_new_with(StdLib::ALL_SAFE, mlua::LuaOptions::default()) };
let entry_module = lua.create_table().unwrap();
entry_module.set("initialized", true).unwrap();
let package: LuaTable = lua.globals().get("package").unwrap();
let loaded: LuaTable = package.get("loaded").unwrap();
loaded.set("pasta.shiori.entry", entry_module).unwrap();
let result = lua_require(&lua, "pasta.shiori.entry");
assert!(
result.is_ok(),
"Should successfully require pasta.shiori.entry"
);
let value = result.unwrap();
if let LuaValue::Table(t) = value {
let initialized: bool = t.get("initialized").unwrap();
assert!(initialized);
} else {
panic!("Expected table from require");
}
}