use mlua::{Lua, Result, Table, Value};
pub const LSHAPE_SOURCES: &[(&str, &str)] = &[
("lshape", include_str!("../lua/lshape/init.lua")),
("lshape.t", include_str!("../lua/lshape/t.lua")),
("lshape.check", include_str!("../lua/lshape/check.lua")),
("lshape.reflect", include_str!("../lua/lshape/reflect.lua")),
("lshape.luacats", include_str!("../lua/lshape/luacats.lua")),
];
pub fn install(lua: &Lua) -> Result<()> {
let package: Table = lua.globals().get("package")?;
let preload: Table = package.get("preload")?;
for (name, src) in LSHAPE_SOURCES {
let name_owned = (*name).to_owned();
let src_owned = (*src).to_owned();
let loader = lua.create_function(move |lua, ()| -> Result<Value> {
let chunk = lua
.load(&src_owned)
.set_name(&format!("@{}", name_owned));
chunk.eval::<Value>()
})?;
preload.set(*name, loader)?;
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn install_and_require_lshape() {
let lua = Lua::new();
install(&lua).unwrap();
lua.load(
r#"
local lshape = require("lshape")
assert(type(lshape) == "table")
assert(type(lshape.t) == "table")
assert(type(lshape.check) == "table")
assert(type(lshape.reflect) == "table")
assert(type(lshape.luacats) == "table")
"#,
)
.exec()
.unwrap();
}
#[test]
fn check_validates_shape() {
let lua = Lua::new();
install(&lua).unwrap();
lua.load(
r#"
local lshape = require("lshape")
local T = lshape.t
local Voted = T.shape({ answer = T.string })
local ok, _ = lshape.check.check({ answer = "42" }, Voted)
assert(ok)
local ok2, why = lshape.check.check({ answer = 42 }, Voted)
assert(not ok2)
assert(why:find("shape violation"))
"#,
)
.exec()
.unwrap();
}
#[test]
fn vendored_version_matches() {
let lua = Lua::new();
install(&lua).unwrap();
lua.load(
r#"
local lshape = require("lshape")
assert(lshape._VERSION == "0.1.0",
"expected lshape._VERSION == '0.1.0', got " .. tostring(lshape._VERSION))
local T = lshape.t
-- v0.1.0 surface smoke: any_of, pattern, partial, literal
local U = T.any_of({ T.string, T.number })
assert(lshape.check.check("x", U))
assert(lshape.check.check(1, U))
assert(not (lshape.check.check(true, U)))
local Slug = T.pattern("^[a-z]+$")
assert(lshape.check.check("abc", Slug))
assert(not (lshape.check.check("ABC", Slug)))
local P = T.partial({ a = T.string, b = T.number })
assert(lshape.check.check({}, P))
assert(lshape.check.check({ a = "x" }, P))
local L = T.literal("yes")
assert(lshape.check.check("yes", L))
assert(not (lshape.check.check("no", L)))
"#,
)
.exec()
.unwrap();
}
}