diff --git a/examples/custom_channel.rs b/examples/custom_channel.rs index dbac7d1..dd3fdf8 100644 --- a/examples/custom_channel.rs +++ b/examples/custom_channel.rs @@ -54,7 +54,7 @@ impl Channel for TelegramChannel { async fn send(&self, message: &str, chat_id: &str) -> Result<()> { self.client - .post(&self.api_url("sendMessage")) + .post(self.api_url("sendMessage")) .json(&serde_json::json!({ "chat_id": chat_id, "text": message, @@ -71,7 +71,7 @@ impl Channel for TelegramChannel { loop { let resp = self .client - .get(&self.api_url("getUpdates")) + .get(self.api_url("getUpdates")) .query(&[("offset", offset.to_string()), ("timeout", "30".into())]) .send() .await? @@ -110,7 +110,7 @@ impl Channel for TelegramChannel { async fn health_check(&self) -> bool { self.client - .get(&self.api_url("getMe")) + .get(self.api_url("getMe")) .send() .await .map(|r| r.status().is_success()) diff --git a/examples/custom_memory.rs b/examples/custom_memory.rs index fcd299d..c69fad7 100644 --- a/examples/custom_memory.rs +++ b/examples/custom_memory.rs @@ -48,14 +48,20 @@ pub struct InMemoryBackend { store: Mutex>, } -impl InMemoryBackend { - pub fn new() -> Self { +impl Default for InMemoryBackend { + fn default() -> Self { Self { store: Mutex::new(HashMap::new()), } } } +impl InMemoryBackend { + pub fn new() -> Self { + Self::default() + } +} + #[async_trait] impl Memory for InMemoryBackend { fn name(&self) -> &str { diff --git a/src/channels/cli.rs b/src/channels/cli.rs index 99546e3..8b414fd 100644 --- a/src/channels/cli.rs +++ b/src/channels/cli.rs @@ -92,13 +92,13 @@ mod tests { sender: "user".into(), content: "hello".into(), channel: "cli".into(), - timestamp: 1234567890, + timestamp: 1_234_567_890, }; assert_eq!(msg.id, "test-id"); assert_eq!(msg.sender, "user"); assert_eq!(msg.content, "hello"); assert_eq!(msg.channel, "cli"); - assert_eq!(msg.timestamp, 1234567890); + assert_eq!(msg.timestamp, 1_234_567_890); } #[test] diff --git a/src/config/schema.rs b/src/config/schema.rs index 6b57f8e..96813c5 100644 --- a/src/config/schema.rs +++ b/src/config/schema.rs @@ -1013,9 +1013,9 @@ default_temperature = 0.7 #[test] fn composio_config_partial_toml() { - let toml_str = r#" + let toml_str = r" enabled = true -"#; +"; let parsed: ComposioConfig = toml::from_str(toml_str).unwrap(); assert!(parsed.enabled); assert!(parsed.api_key.is_none()); diff --git a/src/gateway/mod.rs b/src/gateway/mod.rs index 294e199..6fd27fb 100644 --- a/src/gateway/mod.rs +++ b/src/gateway/mod.rs @@ -326,6 +326,26 @@ async fn send_response( stream.write_all(response.as_bytes()).await } +async fn send_json( + stream: &mut tokio::net::TcpStream, + status: u16, + body: &serde_json::Value, +) -> std::io::Result<()> { + let reason = match status { + 200 => "OK", + 400 => "Bad Request", + 404 => "Not Found", + 500 => "Internal Server Error", + _ => "Unknown", + }; + let json = serde_json::to_string(body).unwrap_or_default(); + let response = format!( + "HTTP/1.1 {status} {reason}\r\nContent-Type: application/json\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{json}", + json.len() + ); + stream.write_all(response.as_bytes()).await +} + #[cfg(test)] mod tests { use super::*; @@ -502,23 +522,3 @@ mod tests { assert_eq!(extract_header("\r\n\r\n", "X-Webhook-Secret"), None); } } - -async fn send_json( - stream: &mut tokio::net::TcpStream, - status: u16, - body: &serde_json::Value, -) -> std::io::Result<()> { - let reason = match status { - 200 => "OK", - 400 => "Bad Request", - 404 => "Not Found", - 500 => "Internal Server Error", - _ => "Unknown", - }; - let json = serde_json::to_string(body).unwrap_or_default(); - let response = format!( - "HTTP/1.1 {status} {reason}\r\nContent-Type: application/json\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{json}", - json.len() - ); - stream.write_all(response.as_bytes()).await -} diff --git a/src/heartbeat/engine.rs b/src/heartbeat/engine.rs index 8c7d084..ee31755 100644 --- a/src/heartbeat/engine.rs +++ b/src/heartbeat/engine.rs @@ -193,7 +193,11 @@ mod tests { #[test] fn parse_tasks_many_tasks() { - let content: String = (0..100).map(|i| format!("- Task {i}\n")).collect(); + let content: String = (0..100).fold(String::new(), |mut s, i| { + use std::fmt::Write; + let _ = writeln!(s, "- Task {i}"); + s + }); let tasks = HeartbeatEngine::parse_tasks(&content); assert_eq!(tasks.len(), 100); assert_eq!(tasks[99], "Task 99"); diff --git a/src/integrations/registry.rs b/src/integrations/registry.rs index e581bdf..c85ea49 100644 --- a/src/integrations/registry.rs +++ b/src/integrations/registry.rs @@ -667,7 +667,7 @@ pub fn all_integrations() -> Vec { #[cfg(test)] mod tests { use super::*; - use crate::config::schema::{ChannelsConfig, IMessageConfig, MatrixConfig, TelegramConfig}; + use crate::config::schema::{IMessageConfig, MatrixConfig, TelegramConfig}; use crate::config::Config; #[test] @@ -685,7 +685,7 @@ mod tests { let entries = all_integrations(); for cat in IntegrationCategory::all() { let count = entries.iter().filter(|e| e.category == *cat).count(); - assert!(count > 0, "Category {:?} has no entries", cat); + assert!(count > 0, "Category {cat:?} has no entries"); } } diff --git a/src/memory/chunker.rs b/src/memory/chunker.rs index d45eb4b..97bddfa 100644 --- a/src/memory/chunker.rs +++ b/src/memory/chunker.rs @@ -206,9 +206,14 @@ mod tests { #[test] fn respects_max_tokens() { // Build multi-line text (one sentence per line) to exercise line-level splitting - let long_text: String = (0..200) - .map(|i| format!("This is sentence number {i} with some extra words to fill it up.\n")) - .collect(); + let long_text: String = (0..200).fold(String::new(), |mut s, i| { + use std::fmt::Write; + let _ = writeln!( + s, + "This is sentence number {i} with some extra words to fill it up." + ); + s + }); let chunks = chunk_markdown(&long_text, 50); // 50 tokens ≈ 200 chars assert!( chunks.len() > 1, @@ -229,7 +234,8 @@ mod tests { fn preserves_heading_in_split_sections() { let mut text = String::from("## Big Section\n"); for i in 0..100 { - text.push_str(&format!("Line {i} with some content here.\n\n")); + use std::fmt::Write; + let _ = write!(text, "Line {i} with some content here.\n\n"); } let chunks = chunk_markdown(&text, 50); assert!(chunks.len() > 1); @@ -355,7 +361,11 @@ mod tests { fn no_content_loss() { let text = "# A\nContent A line 1\nContent A line 2\n\n## B\nContent B\n\n## C\nContent C"; let chunks = chunk_markdown(text, 512); - let reassembled: String = chunks.iter().map(|c| format!("{}\n", c.content)).collect(); + let reassembled: String = chunks.iter().fold(String::new(), |mut s, c| { + use std::fmt::Write; + let _ = writeln!(s, "{}", c.content); + s + }); // All original content words should appear for word in ["Content", "line", "1", "2"] { assert!( diff --git a/src/memory/sqlite.rs b/src/memory/sqlite.rs index 8b17ed5..93e6914 100644 --- a/src/memory/sqlite.rs +++ b/src/memory/sqlite.rs @@ -763,7 +763,7 @@ mod tests { #[tokio::test] async fn sqlite_category_roundtrip() { let (_tmp, mem) = temp_sqlite(); - let categories = vec![ + let categories = [ MemoryCategory::Core, MemoryCategory::Daily, MemoryCategory::Conversation, diff --git a/src/memory/vector.rs b/src/memory/vector.rs index b7a7d79..4d39b55 100644 --- a/src/memory/vector.rs +++ b/src/memory/vector.rs @@ -132,6 +132,12 @@ pub fn hybrid_merge( } #[cfg(test)] +#[allow( + clippy::float_cmp, + clippy::approx_constant, + clippy::cast_precision_loss, + clippy::cast_possible_truncation +)] mod tests { use super::*; @@ -271,13 +277,15 @@ mod tests { let b = vec![-1.0, 0.0]; // Cosine = -1.0, clamped to 0.0 let sim = cosine_similarity(&a, &b); - assert_eq!(sim, 0.0); + assert!(sim.abs() < f32::EPSILON); } #[test] fn cosine_high_dimensional() { - let a: Vec = (0..1536).map(|i| (i as f32) * 0.001).collect(); - let b: Vec = (0..1536).map(|i| (i as f32) * 0.001 + 0.0001).collect(); + let a: Vec = (0..1536).map(|i| (f64::from(i) * 0.001) as f32).collect(); + let b: Vec = (0..1536) + .map(|i| (f64::from(i) * 0.001 + 0.0001) as f32) + .collect(); let sim = cosine_similarity(&a, &b); assert!( sim > 0.99, @@ -288,14 +296,14 @@ mod tests { #[test] fn cosine_single_element() { assert!((cosine_similarity(&[5.0], &[5.0]) - 1.0).abs() < 0.001); - assert_eq!(cosine_similarity(&[5.0], &[-5.0]), 0.0); + assert!(cosine_similarity(&[5.0], &[-5.0]).abs() < f32::EPSILON); } #[test] fn cosine_both_zero_vectors() { let a = vec![0.0, 0.0]; let b = vec![0.0, 0.0]; - assert_eq!(cosine_similarity(&a, &b), 0.0); + assert!(cosine_similarity(&a, &b).abs() < f32::EPSILON); } // ── Edge cases: vec↔bytes serialization ────────────────────── @@ -306,7 +314,7 @@ mod tests { let bytes = vec![0u8, 0, 0, 0, 0xFF]; let result = bytes_to_vec(&bytes); assert_eq!(result.len(), 1); - assert_eq!(result[0], 0.0); + assert!(result[0].abs() < f32::EPSILON); } #[test] @@ -351,7 +359,7 @@ mod tests { let merged = hybrid_merge(&vec_results, &kw_results, 0.0, 0.0, 10); // All final scores should be 0.0 for r in &merged { - assert_eq!(r.final_score, 0.0); + assert!(r.final_score.abs() < f32::EPSILON); } } diff --git a/src/observability/mod.rs b/src/observability/mod.rs index 6dbfccd..801771d 100644 --- a/src/observability/mod.rs +++ b/src/observability/mod.rs @@ -62,7 +62,9 @@ mod tests { #[test] fn factory_empty_string_falls_back_to_noop() { - let cfg = ObservabilityConfig { backend: "".into() }; + let cfg = ObservabilityConfig { + backend: String::new(), + }; assert_eq!(create_observer(&cfg).name(), "noop"); } diff --git a/src/runtime/mod.rs b/src/runtime/mod.rs index 3a5a9be..cb8abd5 100644 --- a/src/runtime/mod.rs +++ b/src/runtime/mod.rs @@ -64,7 +64,9 @@ mod tests { #[test] fn factory_empty_falls_back() { - let cfg = RuntimeConfig { kind: "".into() }; + let cfg = RuntimeConfig { + kind: String::new(), + }; let rt = create_runtime(&cfg); assert_eq!(rt.name(), "native"); } diff --git a/src/skills/mod.rs b/src/skills/mod.rs index f14730e..5b5c52b 100644 --- a/src/skills/mod.rs +++ b/src/skills/mod.rs @@ -329,6 +329,7 @@ pub fn handle_command(command: super::SkillCommands, workspace_dir: &Path) -> Re } #[cfg(test)] +#[allow(clippy::similar_names)] mod tests { use super::*; use std::fs; diff --git a/src/tools/composio.rs b/src/tools/composio.rs index 479f774..4602d5d 100644 --- a/src/tools/composio.rs +++ b/src/tools/composio.rs @@ -396,7 +396,7 @@ mod tests { #[test] fn composio_actions_response_missing_items_defaults() { - let json_str = r#"{}"#; + let json_str = r"{}"; let resp: ComposioActionsResponse = serde_json::from_str(json_str).unwrap(); assert!(resp.items.is_empty()); } diff --git a/src/tunnel/mod.rs b/src/tunnel/mod.rs index 4cb73bc..0682a1b 100644 --- a/src/tunnel/mod.rs +++ b/src/tunnel/mod.rs @@ -129,7 +129,7 @@ mod tests { CloudflareTunnelConfig, CustomTunnelConfig, NgrokTunnelConfig, TunnelConfig, }; - /// Helper: assert create_tunnel returns an error containing `needle`. + /// Helper: assert `create_tunnel` returns an error containing `needle`. fn assert_tunnel_err(cfg: &TunnelConfig, needle: &str) { match create_tunnel(cfg) { Err(e) => assert!(