Skip to main content

test_lua_module/
test_lua_module.rs

1//! Testing a Lua module loaded into an existing VM.
2//!
3//! Demonstrates the pattern used in orcs-cli: register the
4//! framework on a pre-existing Lua VM that already has custom
5//! globals, then run tests against those globals.
6
7use mlua::prelude::*;
8
9/// Simulates an application that exposes Rust APIs to Lua.
10fn setup_app_globals(lua: &Lua) -> LuaResult<()> {
11    let app = lua.create_table()?;
12
13    // app.add(a, b) -> number
14    app.set(
15        "add",
16        lua.create_function(|_, (a, b): (f64, f64)| Ok(a + b))?,
17    )?;
18
19    // app.greet(name) -> string
20    app.set(
21        "greet",
22        lua.create_function(|_, name: String| Ok(format!("Hello, {name}!")))?,
23    )?;
24
25    // app.validate_email(email) -> bool
26    app.set(
27        "validate_email",
28        lua.create_function(|_, email: String| Ok(email.contains('@') && email.contains('.')))?,
29    )?;
30
31    // app.config -> table
32    let config = lua.create_table()?;
33    config.set("max_retries", 3)?;
34    config.set("timeout_ms", 5000)?;
35    config.set("debug", false)?;
36    app.set("config", config)?;
37
38    lua.globals().set("app", app)?;
39    Ok(())
40}
41
42fn main() {
43    let lua = Lua::new();
44
45    // 1. Set up application globals
46    setup_app_globals(&lua).expect("failed to set up app globals");
47
48    // 2. Register mlua-lspec
49    mlua_lspec::register(&lua).expect("failed to register lspec");
50    mlua_lspec::register_doubles(&lua).expect("failed to register doubles");
51
52    // 3. Run tests against the app API
53    lua.load(
54        r#"
55        local describe, it, expect = lust.describe, lust.it, lust.expect
56
57        describe('app', function()
58
59            describe('add', function()
60                it('adds two positive numbers', function()
61                    expect(app.add(2, 3)).to.equal(5)
62                end)
63
64                it('handles negative numbers', function()
65                    expect(app.add(-1, 1)).to.equal(0)
66                end)
67
68                it('handles floating point', function()
69                    expect(app.add(0.1, 0.2)).to.equal(0.3, 1e-10)
70                end)
71            end)
72
73            describe('greet', function()
74                it('creates greeting message', function()
75                    expect(app.greet("World")).to.equal("Hello, World!")
76                end)
77
78                it('handles empty name', function()
79                    expect(app.greet("")).to.equal("Hello, !")
80                end)
81            end)
82
83            describe('validate_email', function()
84                it('accepts valid email', function()
85                    expect(app.validate_email("user@example.com")).to.be.truthy()
86                end)
87
88                it('rejects missing @', function()
89                    expect(app.validate_email("userexample.com")).to_not.be.truthy()
90                end)
91
92                it('rejects missing dot', function()
93                    expect(app.validate_email("user@examplecom")).to_not.be.truthy()
94                end)
95            end)
96
97            describe('config', function()
98                it('has expected defaults', function()
99                    expect(app.config.max_retries).to.equal(3)
100                    expect(app.config.timeout_ms).to.equal(5000)
101                    expect(app.config.debug).to_not.be.truthy()
102                end)
103            end)
104        end)
105    "#,
106    )
107    .exec()
108    .expect("test execution failed");
109
110    let summary = mlua_lspec::collect_results(&lua).expect("failed to collect results");
111
112    println!(
113        "{} passed, {} failed out of {} tests",
114        summary.passed, summary.failed, summary.total
115    );
116
117    assert_eq!(summary.failed, 0, "all tests should pass");
118}