1pub mod boot;
59pub mod commands;
60pub mod error;
61pub mod plugin;
62pub mod server;
63pub mod types;
64
65pub use allframe_core::router::StreamReceiver;
66pub use boot::{BootBuilder, BootContext, BootError, BootProgress};
67pub use error::TauriServerError;
68pub use plugin::{builder, init, init_with_state, PLUGIN_NAME};
69pub use server::TauriServer;
70pub use types::{CallResponse, HandlerInfo, HandlerKind, StreamStartResponse};
71
72#[cfg(test)]
73mod tests {
74 use allframe_core::router::Router;
75
76 use super::*;
77
78 #[test]
79 fn test_server_creation() {
80 let router = Router::new();
81 let server = TauriServer::new(router);
82 assert_eq!(server.handler_count(), 0);
83 }
84
85 #[test]
86 fn test_server_discovers_handlers() {
87 let mut router = Router::new();
88 router.register("get_user", || async { "User data".to_string() });
89 router.register("create_user", || async { "Created".to_string() });
90 router.register("delete_user", || async { "Deleted".to_string() });
91
92 let server = TauriServer::new(router);
93 assert_eq!(server.handler_count(), 3);
94 }
95
96 #[test]
97 fn test_handler_info_fields() {
98 let mut router = Router::new();
99 router.register("my_handler", || async { "result".to_string() });
100
101 let server = TauriServer::new(router);
102 let handlers = server.list_handlers();
103
104 assert_eq!(handlers.len(), 1);
105 assert_eq!(handlers[0].name, "my_handler");
106 assert!(!handlers[0].description.is_empty());
107 }
108
109 #[tokio::test]
110 async fn test_call_handler_success() {
111 let mut router = Router::new();
112 router.register("echo", || async { "echoed".to_string() });
113
114 let server = TauriServer::new(router);
115 let result = server.call_handler("echo", "{}").await;
116
117 assert!(result.is_ok());
118 assert_eq!(result.unwrap().result, "echoed");
119 }
120
121 #[tokio::test]
122 async fn test_call_handler_not_found() {
123 let router = Router::new();
124 let server = TauriServer::new(router);
125
126 let result = server.call_handler("missing", "{}").await;
127 assert!(result.is_err());
128
129 let err = result.unwrap_err();
130 match err {
131 TauriServerError::HandlerNotFound(name) => {
132 assert_eq!(name, "missing");
133 }
134 other => panic!("Expected HandlerNotFound, got: {other:?}"),
135 }
136 }
137
138 #[tokio::test]
139 async fn test_multiple_calls() {
140 let mut router = Router::new();
141 router.register("a", || async { "A".to_string() });
142 router.register("b", || async { "B".to_string() });
143
144 let server = TauriServer::new(router);
145
146 let a = server.call_handler("a", "{}").await.unwrap();
147 let b = server.call_handler("b", "{}").await.unwrap();
148
149 assert_eq!(a.result, "A");
150 assert_eq!(b.result, "B");
151 }
152
153 #[tokio::test]
154 async fn test_handler_isolation() {
155 let mut router = Router::new();
156 router.register("x", || async { "X".to_string() });
157 router.register("y", || async { "Y".to_string() });
158
159 let server = TauriServer::new(router);
160
161 let _ = server.call_handler("x", "{}").await;
162 let y = server.call_handler("y", "{}").await.unwrap();
163 assert_eq!(y.result, "Y");
164 }
165
166 #[test]
167 fn test_empty_router() {
168 let router = Router::new();
169 let server = TauriServer::new(router);
170 assert_eq!(server.handler_count(), 0);
171 assert!(server.list_handlers().is_empty());
172 }
173
174 #[tokio::test]
175 async fn test_list_empty() {
176 let router = Router::new();
177 let server = TauriServer::new(router);
178 assert!(server.list_handlers().is_empty());
179 }
180
181 #[test]
182 fn test_call_response_serialization() {
183 let response = CallResponse {
184 result: r#"{"id":1}"#.to_string(),
185 };
186 let json = serde_json::to_string(&response).unwrap();
187 assert!(json.contains("id"));
188 }
189
190 #[test]
191 fn test_handler_info_serialization() {
192 let info = HandlerInfo {
193 name: "test".to_string(),
194 description: "A test handler".to_string(),
195 kind: HandlerKind::RequestResponse,
196 };
197 let json = serde_json::to_string(&info).unwrap();
198 assert!(json.contains("test"));
199 assert!(json.contains("A test handler"));
200 assert!(json.contains("request_response"));
201 }
202
203 #[test]
204 fn test_error_serialization() {
205 let err = TauriServerError::HandlerNotFound("missing".to_string());
206 let json = serde_json::to_string(&err).unwrap();
207 assert!(json.contains("missing"));
208 }
209
210 #[tokio::test]
211 async fn test_typed_args_flow_through_tauri_server() {
212 #[derive(serde::Deserialize)]
213 struct Input {
214 name: String,
215 }
216
217 let mut router = Router::new();
218 router.register_with_args("greet", |args: Input| async move {
219 format!(r#"{{"greeting":"Hello {}"}}"#, args.name)
220 });
221
222 let server = TauriServer::new(router);
223 let result = server
224 .call_handler("greet", r#"{"name":"Alice"}"#)
225 .await
226 .unwrap();
227
228 assert_eq!(result.result, r#"{"greeting":"Hello Alice"}"#);
229 }
230
231 #[tokio::test]
232 async fn test_tauri_compat_handler_through_server() {
233 use allframe_macros::tauri_compat;
234
235 #[tauri_compat]
236 async fn greet(name: String, age: u32) -> String {
237 format!(r#"{{"greeting":"Hello {}, age {}"}}"#, name, age)
238 }
239
240 let mut router = Router::new();
241 router.register_with_args::<GreetArgs, _, _>("greet", greet);
242
243 let server = TauriServer::new(router);
244 let result = server
245 .call_handler("greet", r#"{"name":"Alice","age":30}"#)
246 .await
247 .unwrap();
248
249 assert_eq!(result.result, r#"{"greeting":"Hello Alice, age 30"}"#);
250 }
251
252 #[tokio::test]
253 async fn test_tauri_compat_optional_param() {
254 use allframe_macros::tauri_compat;
255
256 #[tauri_compat]
257 async fn greet_optional(name: String, title: Option<String>) -> String {
258 match title {
259 Some(t) => format!("{} {}", t, name),
260 None => name,
261 }
262 }
263
264 let mut router = Router::new();
265 router
266 .register_with_args::<GreetOptionalArgs, _, _>("greet_optional", greet_optional);
267
268 let server = TauriServer::new(router);
269
270 let result = server
272 .call_handler("greet_optional", r#"{"name":"Alice","title":"Dr."}"#)
273 .await
274 .unwrap();
275 assert_eq!(result.result, "Dr. Alice");
276
277 let result = server
279 .call_handler("greet_optional", r#"{"name":"Bob"}"#)
280 .await
281 .unwrap();
282 assert_eq!(result.result, "Bob");
283 }
284
285 #[tokio::test]
286 async fn test_typed_return_struct() {
287 #[derive(serde::Serialize)]
288 struct UserResponse {
289 id: u32,
290 name: String,
291 }
292
293 let mut router = Router::new();
294 router.register_typed("get_user", || async {
295 UserResponse {
296 id: 1,
297 name: "Alice".to_string(),
298 }
299 });
300
301 let server = TauriServer::new(router);
302 let result = server.call_handler("get_user", "{}").await.unwrap();
303 assert_eq!(result.result, r#"{"id":1,"name":"Alice"}"#);
304 }
305
306 #[tokio::test]
307 async fn test_typed_return_with_args() {
308 #[derive(serde::Deserialize)]
309 struct Input {
310 x: i32,
311 }
312
313 #[derive(serde::Serialize)]
314 struct Output {
315 doubled: i32,
316 }
317
318 let mut router = Router::new();
319 router.register_typed_with_args("double", |args: Input| async move {
320 Output { doubled: args.x * 2 }
321 });
322
323 let server = TauriServer::new(router);
324 let result = server.call_handler("double", r#"{"x":21}"#).await.unwrap();
325 assert_eq!(result.result, r#"{"doubled":42}"#);
326 }
327
328 #[tokio::test]
329 async fn test_result_handler_ok() {
330 #[derive(serde::Serialize)]
331 struct Data {
332 value: i32,
333 }
334
335 let mut router = Router::new();
336 router.register_result("get_data", || async {
337 Ok::<_, String>(Data { value: 42 })
338 });
339
340 let server = TauriServer::new(router);
341 let result = server.call_handler("get_data", "{}").await.unwrap();
342 assert_eq!(result.result, r#"{"value":42}"#);
343 }
344
345 #[tokio::test]
346 async fn test_result_handler_err() {
347 #[derive(serde::Serialize)]
348 struct Data {
349 value: i32,
350 }
351
352 let mut router = Router::new();
353 router.register_result("fail", || async {
354 Err::<Data, String>("not found".to_string())
355 });
356
357 let server = TauriServer::new(router);
358 let result = server.call_handler("fail", "{}").await;
359 assert!(result.is_err());
360 }
361
362 #[tokio::test]
363 async fn test_typed_return_with_state() {
364 use allframe_core::router::State;
365 use std::sync::Arc;
366
367 struct AppState {
368 prefix: String,
369 }
370
371 #[derive(serde::Deserialize)]
372 struct Input {
373 name: String,
374 }
375
376 #[derive(serde::Serialize)]
377 struct Greeting {
378 message: String,
379 }
380
381 let mut router = Router::new().with_state(AppState {
382 prefix: "Hey".to_string(),
383 });
384 router.register_typed_with_state::<AppState, Input, Greeting, _, _>(
385 "greet",
386 |state: State<Arc<AppState>>, args: Input| async move {
387 Greeting {
388 message: format!("{} {}", state.prefix, args.name),
389 }
390 },
391 );
392
393 let server = TauriServer::new(router);
394 let result = server
395 .call_handler("greet", r#"{"name":"Dave"}"#)
396 .await
397 .unwrap();
398 assert_eq!(result.result, r#"{"message":"Hey Dave"}"#);
399 }
400
401 #[tokio::test]
402 async fn test_tauri_compat_no_args() {
403 use allframe_macros::tauri_compat;
404
405 #[tauri_compat]
406 async fn health_check() -> String {
407 "ok".to_string()
408 }
409
410 let mut router = Router::new();
411 router.register("health_check", health_check);
412
413 let server = TauriServer::new(router);
414 let result = server.call_handler("health_check", "{}").await.unwrap();
415 assert_eq!(result.result, "ok");
416 }
417
418 #[tokio::test]
419 async fn test_state_injection_through_tauri_server() {
420 use allframe_core::router::State;
421 use std::sync::Arc;
422
423 struct AppState {
424 prefix: String,
425 }
426
427 #[derive(serde::Deserialize)]
428 struct Input {
429 name: String,
430 }
431
432 let mut router = Router::new().with_state(AppState {
433 prefix: "Hey".to_string(),
434 });
435 router.register_with_state::<AppState, Input, _, _>(
436 "greet",
437 |state: State<Arc<AppState>>, args: Input| async move {
438 format!("{} {}", state.prefix, args.name)
439 },
440 );
441
442 let server = TauriServer::new(router);
443 let result = server
444 .call_handler("greet", r#"{"name":"Bob"}"#)
445 .await
446 .unwrap();
447
448 assert_eq!(result.result, "Hey Bob");
449 }
450
451 #[tokio::test]
452 async fn test_tauri_compat_streaming_with_args() {
453 use allframe_core::router::StreamSender;
454 use allframe_macros::tauri_compat;
455
456 #[tauri_compat(streaming)]
457 async fn stream_greet(name: String, count: u32, tx: StreamSender) -> String {
458 for i in 0..count {
459 tx.send(format!("Hello {} #{}", name, i)).await.ok();
460 }
461 "done".to_string()
462 }
463
464 let mut router = Router::new();
465 router.register_streaming_with_args::<StreamGreetArgs, _, _, _>(
466 "stream_greet",
467 stream_greet,
468 );
469
470 let server = TauriServer::new(router);
471 let (mut rx, handle) = server
472 .call_streaming_handler("stream_greet", r#"{"name":"Alice","count":2}"#)
473 .unwrap();
474
475 let msg1 = rx.recv().await.unwrap();
476 assert_eq!(msg1, "Hello Alice #0");
477 let msg2 = rx.recv().await.unwrap();
478 assert_eq!(msg2, "Hello Alice #1");
479
480 let response = handle.await.unwrap().unwrap();
481 assert_eq!(response.result, "done");
482 }
483
484 #[tokio::test]
487 async fn test_inject_state_simulates_app_handle_injection() {
488 use allframe_core::router::State;
489 use std::sync::Arc;
490
491 struct FakeAppHandle {
493 app_name: String,
494 }
495 struct DbPool {
496 url: String,
497 }
498
499 let mut router = Router::new().with_state(DbPool {
500 url: "sqlite://db".to_string(),
501 });
502
503 router.register_with_state_only::<FakeAppHandle, _, _>(
505 "emit_event",
506 |app: State<Arc<FakeAppHandle>>| async move {
507 format!("emitted from {}", app.app_name)
508 },
509 );
510
511 router.register_with_state_only::<DbPool, _, _>(
513 "db_url",
514 |db: State<Arc<DbPool>>| async move { db.url.clone() },
515 );
516
517 router.inject_state(FakeAppHandle {
519 app_name: "MyTauriApp".to_string(),
520 });
521
522 let server = TauriServer::new(router);
523
524 let result = server.call_handler("emit_event", "{}").await.unwrap();
525 assert_eq!(result.result, "emitted from MyTauriApp");
526
527 let result = server.call_handler("db_url", "{}").await.unwrap();
528 assert_eq!(result.result, "sqlite://db");
529 }
530
531 #[tokio::test]
532 async fn test_tauri_compat_streaming_no_args() {
533 use allframe_core::router::StreamSender;
534 use allframe_macros::tauri_compat;
535
536 #[tauri_compat(streaming)]
537 async fn stream_ping(tx: StreamSender) -> String {
538 tx.send("pong".to_string()).await.ok();
539 "done".to_string()
540 }
541
542 let mut router = Router::new();
543 router.register_streaming("stream_ping", stream_ping);
544
545 let server = TauriServer::new(router);
546 let (mut rx, handle) = server
547 .call_streaming_handler("stream_ping", "{}")
548 .unwrap();
549
550 let msg = rx.recv().await.unwrap();
551 assert_eq!(msg, "pong");
552
553 let response = handle.await.unwrap().unwrap();
554 assert_eq!(response.result, "done");
555 }
556}