diff --git a/apps/chat2db-web/src/legacy.rs b/apps/chat2db-web/src/legacy.rs index 1084c75..1f07ee2 100644 --- a/apps/chat2db-web/src/legacy.rs +++ b/apps/chat2db-web/src/legacy.rs @@ -11186,12 +11186,12 @@ mod tests { let column = &request.new_table.column_list[0]; assert_eq!(column.primary_key_order, 0); - assert!(column.comment.is_empty()); - assert!(column.char_set_name.is_empty()); + assert_eq!(column.comment, ""); + assert_eq!(column.char_set_name, ""); let index = &request.new_table.index_list[0]; - assert!(index.index_type.is_empty()); - assert!(index.comment.is_empty()); - assert!(index.column_list[0].index_name.is_empty()); + assert_eq!(index.index_type, ""); + assert_eq!(index.comment, ""); + assert_eq!(index.column_list[0].index_name, ""); } #[test] diff --git a/apps/chat2db-web/tests/native_mysql_editable_ddl_docker.rs b/apps/chat2db-web/tests/native_mysql_editable_ddl_docker.rs index b9960b1..494fd97 100644 --- a/apps/chat2db-web/tests/native_mysql_editable_ddl_docker.rs +++ b/apps/chat2db-web/tests/native_mysql_editable_ddl_docker.rs @@ -1597,7 +1597,7 @@ async fn verify_transfer_routes( entry .read_to_string(&mut contents) .expect("generated class entry must be UTF-8"); - assert!(!contents.is_empty()); + assert_ne!(contents, ""); } let generated = directory.join("generated-classes"); diff --git a/crates/chat2db-agent/src/context.rs b/crates/chat2db-agent/src/context.rs index d229186..4cdf4bd 100644 --- a/crates/chat2db-agent/src/context.rs +++ b/crates/chat2db-agent/src/context.rs @@ -42,6 +42,9 @@ impl fmt::Debug for SummaryError { } /// Optional summarization boundary used only for complete historical turns. +// `async_trait` stamps `#[must_use]` on the generated boxed futures, which +// `clippy::double_must_use` rejects because the type is already `#[must_use]`. +#[allow(clippy::double_must_use)] #[async_trait] pub trait ContextCompactor: Send + Sync { async fn summarize( @@ -475,7 +478,7 @@ mod tests { #[test] fn adjacent_users_are_not_a_complete_compaction_turn() { let messages = vec![Message::system("s"), Message::user("a"), Message::user("b")]; - assert!(compactable_turns(&messages).is_empty()); + assert_eq!(compactable_turns(&messages).len(), 0); } #[test] @@ -491,7 +494,7 @@ mod tests { ), Message::user("latest"), ]; - assert!(compactable_turns(&messages).is_empty()); + assert_eq!(compactable_turns(&messages).len(), 0); } #[test] @@ -524,7 +527,7 @@ mod tests { Message::text(Role::Assistant, "terminal"), Message::user("latest"), ]; - assert!(compactable_turns(&missing).is_empty()); + assert_eq!(compactable_turns(&missing).len(), 0); let duplicate_call = ToolCall::new("duplicate", "query", serde_json::json!({})).expect("valid call"); @@ -548,7 +551,7 @@ mod tests { Message::text(Role::Assistant, "terminal"), Message::user("latest"), ]; - assert!(compactable_turns(&duplicate).is_empty()); + assert_eq!(compactable_turns(&duplicate).len(), 0); } #[test] diff --git a/crates/chat2db-agent/src/provider.rs b/crates/chat2db-agent/src/provider.rs index 933ce5b..c6c82f3 100644 --- a/crates/chat2db-agent/src/provider.rs +++ b/crates/chat2db-agent/src/provider.rs @@ -13,6 +13,9 @@ pub type ProviderEventStream = Pin> + Send + 'static>>; /// Direct model-provider boundary used by the agent loop. +// `async_trait` stamps `#[must_use]` on the generated boxed futures, which +// `clippy::double_must_use` rejects because the type is already `#[must_use]`. +#[allow(clippy::double_must_use)] #[async_trait] pub trait Provider: Send + Sync { /// Identifies the wire family without exposing its DTOs. diff --git a/crates/chat2db-agent/src/runner.rs b/crates/chat2db-agent/src/runner.rs index a320686..196bb2f 100644 --- a/crates/chat2db-agent/src/runner.rs +++ b/crates/chat2db-agent/src/runner.rs @@ -107,6 +107,9 @@ impl Default for AgentLimits { } /// Host boundary for executing one already-validated tool call. +// `async_trait` stamps `#[must_use]` on the generated boxed futures, which +// `clippy::double_must_use` rejects because the type is already `#[must_use]`. +#[allow(clippy::double_must_use)] #[async_trait] pub trait ToolExecutor: Send + Sync { /// Implementations receive cancellation and must return one bounded diff --git a/crates/chat2db-contract/src/community_dashboard.rs b/crates/chat2db-contract/src/community_dashboard.rs index 1e533c2..c309988 100644 --- a/crates/chat2db-contract/src/community_dashboard.rs +++ b/crates/chat2db-contract/src/community_dashboard.rs @@ -186,7 +186,7 @@ mod tests { "refreshCycle": {"unit": "seconds", "value": 30} })) .expect("dashboard request decodes"); - assert!(request.chart_ids.is_empty()); + assert_eq!(request.chart_ids.len(), 0); let encoded = serde_json::to_value(request).expect("dashboard request encodes"); assert_eq!(encoded["name"], "Sales"); assert_eq!(encoded["refreshCycle"]["value"], 30); diff --git a/crates/chat2db-core/src/agent/catalog.rs b/crates/chat2db-core/src/agent/catalog.rs index 4dc4267..85feb2d 100644 --- a/crates/chat2db-core/src/agent/catalog.rs +++ b/crates/chat2db-core/src/agent/catalog.rs @@ -545,7 +545,8 @@ mod tests { .await .expect("sessions list after delete") .items - .is_empty() + .is_empty(), + "a deleted session must not be listed" ); let missing = application .list_agent_messages(&updated.id, "0", "10") diff --git a/crates/chat2db-core/src/agent/hub.rs b/crates/chat2db-core/src/agent/hub.rs index 0597c01..60073fb 100644 --- a/crates/chat2db-core/src/agent/hub.rs +++ b/crates/chat2db-core/src/agent/hub.rs @@ -504,6 +504,9 @@ impl AgentRunHub { async fn mark_terminal(&self, entry: &AgentRunEntry) { cancel_current_permission(entry).await; + // `AtomicU64::fetch_update` is deprecated in favour of `try_update`, + // which is unstable before Rust 1.95 while the workspace MSRV is 1.88. + #[allow(deprecated)] let order = self .inner .next_terminal_order diff --git a/crates/chat2db-core/src/datasource_compatibility.rs b/crates/chat2db-core/src/datasource_compatibility.rs index 0b0f741..7af690a 100644 --- a/crates/chat2db-core/src/datasource_compatibility.rs +++ b/crates/chat2db-core/src/datasource_compatibility.rs @@ -791,7 +791,7 @@ mod tests { .expect("JDBC-only registry is valid"); let application = Application::with_native_drivers_for_test(registry); - assert!(application.list_drivers().items.is_empty()); + assert_eq!(application.list_drivers().items.len(), 0); let compatibility = application .native_driver_compatibility("JDBC_ONLY", NativeDriverAction::Download) .expect("JDBC-only compatibility resolves"); diff --git a/crates/chat2db-core/src/driver_pack.rs b/crates/chat2db-core/src/driver_pack.rs index 4bbf8e1..390ddcc 100644 --- a/crates/chat2db-core/src/driver_pack.rs +++ b/crates/chat2db-core/src/driver_pack.rs @@ -753,7 +753,7 @@ mod tests { let directory = TempDir::new().expect("temporary directory"); let prepared = discover_test(&directory.path().join("missing")).expect("missing root is optional"); - assert!(prepared.inventory().is_empty()); + assert_eq!(prepared.inventory().len(), 0); } #[test] diff --git a/crates/chat2db-core/src/native_dm.rs b/crates/chat2db-core/src/native_dm.rs index 2bd1079..e74b0cf 100644 --- a/crates/chat2db-core/src/native_dm.rs +++ b/crates/chat2db-core/src/native_dm.rs @@ -594,7 +594,7 @@ mod tests { database_query.sql, "SELECT NAME AS DATABASE_NAME FROM V$DATABASE" ); - assert!(database_query.parameters.is_empty()); + assert_eq!(database_query.parameters.len(), 0); let table_query = list_tables_query("APP' OR 1=1 --", "Order_%") .expect("quoted schema names are valid metadata values"); diff --git a/crates/chat2db-core/src/native_driver.rs b/crates/chat2db-core/src/native_driver.rs index c5164fe..3f2cdbe 100644 --- a/crates/chat2db-core/src/native_driver.rs +++ b/crates/chat2db-core/src/native_driver.rs @@ -1,3 +1,7 @@ +// `async_trait` stamps `#[must_use]` on the generated boxed futures, which +// `clippy::double_must_use` rejects because the type is already `#[must_use]`. +#![allow(clippy::double_must_use)] + use std::{ collections::{HashMap, HashSet}, sync::Arc, diff --git a/crates/chat2db-core/src/operation.rs b/crates/chat2db-core/src/operation.rs index d84c6ec..c82c07f 100644 --- a/crates/chat2db-core/src/operation.rs +++ b/crates/chat2db-core/src/operation.rs @@ -313,6 +313,9 @@ impl OperationHub { state.journal.push_back(envelope.clone()); let _ = entry.live.send(envelope); if state.status != OperationStatus::Running { + // `AtomicU64::fetch_update` is deprecated in favour of `try_update`, + // which is unstable before Rust 1.95 while the workspace MSRV is 1.88. + #[allow(deprecated)] let terminal_order = self .inner .next_terminal_order diff --git a/crates/chat2db-core/src/query.rs b/crates/chat2db-core/src/query.rs index 3451962..9189e48 100644 --- a/crates/chat2db-core/src/query.rs +++ b/crates/chat2db-core/src/query.rs @@ -1034,7 +1034,7 @@ mod tests { assert!(request.error_continue); assert_eq!(request.result_set_id, None); - assert!(request.database_name.is_empty()); + assert_eq!(request.database_name, ""); } #[test] diff --git a/crates/chat2db-core/tests/java_community_mysql_product.rs b/crates/chat2db-core/tests/java_community_mysql_product.rs index 4c257d2..e484c73 100644 --- a/crates/chat2db-core/tests/java_community_mysql_product.rs +++ b/crates/chat2db-core/tests/java_community_mysql_product.rs @@ -691,7 +691,10 @@ async fn verify_sql_tools(application: &Application, datasource_id: &str, databa .await .expect("Core must invoke real MySQL SQL validation"); assert!(!validation.valid); - assert!(!validation.diagnostics.is_empty()); + assert!( + !validation.diagnostics.is_empty(), + "invalid SQL must report diagnostics" + ); let source_sql = "select id,label from items where id=1"; let formatted = application diff --git a/crates/chat2db-core/tests/java_community_product.rs b/crates/chat2db-core/tests/java_community_product.rs index c7d7da3..c2fbe05 100644 --- a/crates/chat2db-core/tests/java_community_product.rs +++ b/crates/chat2db-core/tests/java_community_product.rs @@ -48,7 +48,10 @@ async fn product_services_invoke_the_fixed_community_h2_compatibility_slice() { .await .expect("Core SQL validation must not require a datasource or JDBC session"); assert!(!validation.valid); - assert!(!validation.diagnostics.is_empty()); + assert!( + !validation.diagnostics.is_empty(), + "invalid SQL must report diagnostics" + ); let formatted = application .format_community_sql(FormatCommunitySqlRequest { @@ -1095,7 +1098,7 @@ async fn verify_trigger_metadata( }) .await .expect("escaped H2 trigger-list identifiers must remain a safe metadata query"); - assert!(injected_list.items.is_empty()); + assert_eq!(injected_list.items.len(), 0); for trigger_name in ["MISSING_TRIGGER", "AUDIT_TRIGGER' OR '1'='1"] { let error = application .get_community_trigger(GetCommunityTriggerRequest { diff --git a/crates/chat2db-core/tests/large_value.rs b/crates/chat2db-core/tests/large_value.rs index 11ffc28..61d5d3b 100644 --- a/crates/chat2db-core/tests/large_value.rs +++ b/crates/chat2db-core/tests/large_value.rs @@ -282,7 +282,7 @@ fn binary_chunks_round_trip_and_range_validation_is_closed() { .read_chunk("execution-1", token(&preview), 13, 1) .expect("offset at the end should be valid"); assert!(eof.eof); - assert!(eof.value.is_empty()); + assert_eq!(eof.value.len(), 0); } #[test] diff --git a/crates/chat2db-core/tests/native_mysql_product.rs b/crates/chat2db-core/tests/native_mysql_product.rs index f2823a5..c150573 100644 --- a/crates/chat2db-core/tests/native_mysql_product.rs +++ b/crates/chat2db-core/tests/native_mysql_product.rs @@ -490,7 +490,8 @@ async fn verify_native_workspace_metadata( .await .expect("table pins must relist") .items - .is_empty() + .is_empty(), + "an unpinned table must disappear from the listing" ); assert_java_dormant(application); } @@ -530,7 +531,7 @@ async fn verify_native_metadata( }) .await .expect("MySQL schema route must stay native"); - assert!(schemas.items.is_empty()); + assert_eq!(schemas.items.len(), 0); let tables = application .list_community_tables(ListCommunityTablesRequest { diff --git a/crates/chat2db-core/tests/native_oracle_smoke.rs b/crates/chat2db-core/tests/native_oracle_smoke.rs index a07b101..e78434d 100644 --- a/crates/chat2db-core/tests/native_oracle_smoke.rs +++ b/crates/chat2db-core/tests/native_oracle_smoke.rs @@ -261,8 +261,8 @@ async fn verify_database_and_schema_metadata( .items .first() .expect("Oracle must expose its current database"); - assert!(!database.name.is_empty()); - assert!(!database.owner.is_empty()); + assert_ne!(database.name, ""); + assert_ne!(database.owner, ""); let schemas = application .list_community_schemas(ListCommunitySchemasRequest { diff --git a/crates/chat2db-core/tests/native_postgres_smoke.rs b/crates/chat2db-core/tests/native_postgres_smoke.rs index bf2a37b..90d338e 100644 --- a/crates/chat2db-core/tests/native_postgres_smoke.rs +++ b/crates/chat2db-core/tests/native_postgres_smoke.rs @@ -198,7 +198,7 @@ async fn verify_oversized_scalar_cleanup( datasource_id: &str, data_dir: &Path, ) { - assert!(retained_result_files(data_dir).is_empty()); + assert_eq!(retained_result_files(data_dir).len(), 0); let scalar_bytes = wire::JdbcProtocolLimit::MaxScalarBytes as usize + 1; let query = application .start_query(StartQueryRequest { diff --git a/crates/chat2db-java-bridge/src/supervisor/community.rs b/crates/chat2db-java-bridge/src/supervisor/community.rs index 427962b..4788391 100644 --- a/crates/chat2db-java-bridge/src/supervisor/community.rs +++ b/crates/chat2db-java-bridge/src/supervisor/community.rs @@ -344,7 +344,10 @@ impl CommunityClasspath { } /// Returns the canonical JARs in deterministic classpath order. - #[must_use] + // A bare `#[must_use]` satisfies `clippy::must_use_candidate` on Rust 1.88 + // but fails `clippy::double_must_use` on Rust 1.99; the explicit reason + // satisfies both. + #[must_use = "the canonical classpath order must be consumed"] pub fn artifacts(&self) -> impl ExactSizeIterator { self.artifacts .iter() @@ -2777,6 +2780,9 @@ fn validate_metadata_session( Ok(()) } +// `AtomicU64::fetch_update` is deprecated in favour of `try_update`, which is +// unstable before Rust 1.95 while the workspace MSRV is 1.88. +#[allow(deprecated)] fn next_sql_completion_datasource_scope() -> Result { NEXT_SQL_COMPLETION_DATASOURCE_SCOPE .fetch_update(Ordering::Relaxed, Ordering::Relaxed, next_java_long_scope) diff --git a/crates/chat2db-java-bridge/tests/java_community_h2.rs b/crates/chat2db-java-bridge/tests/java_community_h2.rs index 9b2843b..749afe3 100644 --- a/crates/chat2db-java-bridge/tests/java_community_h2.rs +++ b/crates/chat2db-java-bridge/tests/java_community_h2.rs @@ -780,7 +780,7 @@ async fn verify_programmability_metadata( .list_function_parameters(session, "H2", database_name, "APP", "ADD_ONE", None) .await .expect("H2Meta must list function parameters"); - assert!(function_parameters.is_empty()); + assert_eq!(function_parameters.len(), 0); let procedures = community .list_procedures(session, "H2", database_name, "APP", None) @@ -971,14 +971,17 @@ async fn verify_parser(community: &CommunityClient) { .expect("Community parser must validate well-formed SQL"); assert!(valid.valid); assert_eq!(valid.statements.len(), 1); - assert!(valid.diagnostics.is_empty()); + assert_eq!(valid.diagnostics.len(), 0); let invalid = community .validate_sql("H2", "SELECT FROM;") .await .expect("Community parser must return bounded syntax diagnostics"); assert!(!invalid.valid); - assert!(!invalid.diagnostics.is_empty()); + assert!( + !invalid.diagnostics.is_empty(), + "invalid SQL must report diagnostics" + ); assert!( invalid .diagnostics diff --git a/crates/chat2db-java-bridge/tests/java_jdbc_h2.rs b/crates/chat2db-java-bridge/tests/java_jdbc_h2.rs index da0fbf7..35cee5f 100644 --- a/crates/chat2db-java-bridge/tests/java_jdbc_h2.rs +++ b/crates/chat2db-java-bridge/tests/java_jdbc_h2.rs @@ -522,7 +522,10 @@ async fn collect_rows(session: &Session, sql: &str) -> Vec { match next_event(&mut stream).await { QueryEvent::Started(metadata) => { assert!(!started, "query metadata must be emitted once"); - assert!(!metadata.columns.is_empty()); + assert!( + !metadata.columns.is_empty(), + "query metadata must carry columns" + ); started = true; } QueryEvent::Batch(batch) => rows.extend(batch.rows), diff --git a/crates/chat2db-storage/src/agent.rs b/crates/chat2db-storage/src/agent.rs index 3cce6e2..5fcff2e 100644 --- a/crates/chat2db-storage/src/agent.rs +++ b/crates/chat2db-storage/src/agent.rs @@ -4377,7 +4377,7 @@ mod tests { assert_eq!(messages[0].ordinal, 0); assert_eq!(messages[0].role, AgentMessageRole::System); assert_eq!(messages[0].content_json, message_json("rules")); - assert!(!messages[0].id.is_empty()); + assert_ne!(messages[0].id, ""); assert!(messages[0].run_id.is_none()); let appended = storage @@ -4870,7 +4870,8 @@ mod tests { storage .list_agent_messages(&session.id, 0, 10) .expect("messages list") - .is_empty() + .is_empty(), + "rejected messages must not be persisted" ); } @@ -6175,7 +6176,8 @@ mod tests { storage .list_agent_messages(&session.id, 0, 10) .expect("messages list") - .is_empty() + .is_empty(), + "rejected messages must not be persisted" ); storage diff --git a/crates/chat2db-storage/src/community_dashboard.rs b/crates/chat2db-storage/src/community_dashboard.rs index c2d5827..701fc03 100644 --- a/crates/chat2db-storage/src/community_dashboard.rs +++ b/crates/chat2db-storage/src/community_dashboard.rs @@ -1193,7 +1193,8 @@ mod tests { .expect("dashboard reads") .expect("dashboard exists") .chart_ids - .is_empty() + .is_empty(), + "a default dashboard must not define charts" ); assert!( storage diff --git a/crates/chat2db-storage/src/datasource.rs b/crates/chat2db-storage/src/datasource.rs index dc4cf9b..7f1c159 100644 --- a/crates/chat2db-storage/src/datasource.rs +++ b/crates/chat2db-storage/src/datasource.rs @@ -1130,7 +1130,8 @@ mod tests { storage .list_datasources() .expect("datasources list") - .is_empty() + .is_empty(), + "a rolled back create must not leave datasources behind" ); assert!(vault.values.lock().expect("vault lock").is_empty()); assert_eq!(storage.reconcile_secrets().expect("queue reads").pending, 0); diff --git a/crates/chat2db-storage/src/result_store.rs b/crates/chat2db-storage/src/result_store.rs index 7ad7d49..2ccab09 100644 --- a/crates/chat2db-storage/src/result_store.rs +++ b/crates/chat2db-storage/src/result_store.rs @@ -1827,7 +1827,7 @@ mod tests { .read_result_page(&metadata.id, PageRequest::default()) .expect("empty page reads"); assert_eq!(page.schema, schema()); - assert!(page.rows.is_empty()); + assert_eq!(page.rows.len(), 0); assert!(!page.has_more); }