component_testing/
component_testing.rs1use mlua::prelude::*;
8
9fn main() {
10 let lua = Lua::new();
11 mlua_lspec::register(&lua).expect("register lspec");
12 mlua_lspec::register_doubles(&lua).expect("register doubles");
13
14 lua.load(
15 r#"
16 local describe, it, expect = lust.describe, lust.it, lust.expect
17
18 -- ================================================================
19 -- Component definition (the code under test)
20 -- ================================================================
21 local function create_counter_component()
22 local count = 0
23 return {
24 id = "counter",
25
26 on_request = function(req)
27 if req.operation == "increment" then
28 count = count + (req.payload.amount or 1)
29 return { success = true, data = { count = count } }
30 elseif req.operation == "get" then
31 return { success = true, data = { count = count } }
32 elseif req.operation == "reset" then
33 count = 0
34 return { success = true, data = { count = 0 } }
35 end
36 return { success = false, error = "unknown: " .. req.operation }
37 end,
38
39 on_signal = function(sig)
40 if sig == "stop" then
41 count = 0
42 return "stopped"
43 end
44 return "ignored"
45 end,
46 }
47 end
48
49 -- ================================================================
50 -- Minimal harness for request/signal simulation
51 -- ================================================================
52 local function create_harness(component_fn)
53 local comp = component_fn()
54 return {
55 request = function(self, operation, payload)
56 local resp = comp.on_request({
57 operation = operation,
58 payload = payload or {},
59 })
60 if resp.success then
61 return resp.data
62 end
63 error(resp.error)
64 end,
65 signal = function(self, kind)
66 return comp.on_signal(kind)
67 end,
68 id = function(self)
69 return comp.id
70 end,
71 }
72 end
73
74 -- ================================================================
75 -- Tests
76 -- ================================================================
77
78 describe('counter component', function()
79 local h
80
81 lust.before(function()
82 h = create_harness(create_counter_component)
83 end)
84
85 describe('identity', function()
86 it('has correct id', function()
87 expect(h:id()).to.equal("counter")
88 end)
89 end)
90
91 describe('increment', function()
92 it('increments by 1 by default', function()
93 local result = h:request("increment")
94 expect(result.count).to.equal(1)
95 end)
96
97 it('increments by custom amount', function()
98 local result = h:request("increment", { amount = 5 })
99 expect(result.count).to.equal(5)
100 end)
101
102 it('accumulates across calls', function()
103 h:request("increment")
104 h:request("increment")
105 h:request("increment")
106 local result = h:request("get")
107 expect(result.count).to.equal(3)
108 end)
109 end)
110
111 describe('reset', function()
112 it('resets count to zero', function()
113 h:request("increment")
114 h:request("increment")
115 h:request("reset")
116 local result = h:request("get")
117 expect(result.count).to.equal(0)
118 end)
119 end)
120
121 describe('error handling', function()
122 it('rejects unknown operations', function()
123 expect(function()
124 h:request("unknown_op")
125 end).to.fail.with("unknown")
126 end)
127 end)
128
129 describe('signals', function()
130 it('stop signal resets state', function()
131 h:request("increment")
132 h:request("increment")
133 local response = h:signal("stop")
134 expect(response).to.equal("stopped")
135
136 local result = h:request("get")
137 expect(result.count).to.equal(0)
138 end)
139
140 it('unknown signal is ignored', function()
141 local response = h:signal("unknown")
142 expect(response).to.equal("ignored")
143 end)
144 end)
145 end)
146 "#,
147 )
148 .exec()
149 .expect("test execution failed");
150
151 let summary = mlua_lspec::collect_results(&lua).expect("collect results");
152
153 println!(
154 "{} passed, {} failed out of {} tests",
155 summary.passed, summary.failed, summary.total
156 );
157 for test in &summary.tests {
158 let icon = if test.passed { "PASS" } else { "FAIL" };
159 println!(" [{icon}] {}: {}", test.suite, test.name);
160 }
161
162 assert_eq!(summary.failed, 0, "all tests should pass");
163}