From 3bc3251eb81022b9b17b4ae5ce2dd50292f1e3bb Mon Sep 17 00:00:00 2001 From: Stefan Steiner Date: Mon, 5 Oct 2026 12:04:54 -0700 Subject: [PATCH] fix(ci): satisfy Rust 1.99 clippy lints CI tracks the moving stable toolchain, and 1.99 added/tightened lints that fail the -D warnings clippy gate: - must_use_candidate on six accessor methods in hyperdb-api - assert_is_empty on assert!(x.is_empty()) in tests (use assert_eq!/assert_ne!) - unfulfilled #[expect(clippy::float_cmp)] in hyperdb-api-core tests, which 1.99 no longer triggers No behaviour change. --- hyperdb-api-core/src/client/auth.rs | 2 +- hyperdb-api-core/src/client/prepare.rs | 10 +--------- hyperdb-api-core/src/protocol/copy.rs | 2 +- hyperdb-api-core/src/protocol/types.rs | 4 ---- hyperdb-api-core/src/types/special.rs | 10 +--------- hyperdb-api/src/grpc_connection.rs | 2 ++ hyperdb-api/src/inserter.rs | 1 + hyperdb-api/src/names.rs | 5 ++++- hyperdb-api/tests/arrow_reader_tests.rs | 22 +++++++++++----------- hyperdb-api/tests/async_kv_store_tests.rs | 2 +- hyperdb-api/tests/kv_store_in_tests.rs | 4 ++-- hyperdb-api/tests/kv_store_tests.rs | 5 ++++- hyperdb-api/tests/process_tests.rs | 4 ++-- hyperdb-api/tests/type_tests.rs | 2 +- hyperdb-bootstrap/src/release.rs | 2 +- hyperdb-mcp/tests/attach_tests.rs | 2 +- hyperdb-mcp/tests/diagnostics_tests.rs | 10 ++++++++-- hyperdb-mcp/tests/inspect_tests.rs | 5 ++++- hyperdb-mcp/tests/subscription_tests.rs | 6 +++--- 19 files changed, 49 insertions(+), 51 deletions(-) diff --git a/hyperdb-api-core/src/client/auth.rs b/hyperdb-api-core/src/client/auth.rs index b32d1c8b..9b6dc60e 100644 --- a/hyperdb-api-core/src/client/auth.rs +++ b/hyperdb-api-core/src/client/auth.rs @@ -390,6 +390,6 @@ mod tests { let nonce1 = generate_nonce(); let nonce2 = generate_nonce(); assert_ne!(nonce1, nonce2); - assert!(!nonce1.is_empty()); + assert_ne!(nonce1, ""); } } diff --git a/hyperdb-api-core/src/client/prepare.rs b/hyperdb-api-core/src/client/prepare.rs index 319b7a31..e51710c4 100644 --- a/hyperdb-api-core/src/client/prepare.rs +++ b/hyperdb-api-core/src/client/prepare.rs @@ -692,10 +692,6 @@ mod tests { } #[test] - #[expect( - clippy::float_cmp, - reason = "1.5 is exactly representable; encode/decode must round-trip bit-for-bit" - )] fn test_sql_param_f32() { let encoded = 1.5_f32.encode(); assert_eq!(encoded.len(), 4); @@ -704,10 +700,6 @@ mod tests { } #[test] - #[expect( - clippy::float_cmp, - reason = "1.5 is exactly representable; encode/decode must round-trip bit-for-bit" - )] fn test_sql_param_f64() { let encoded = 1.5_f64.encode(); assert_eq!(encoded.len(), 8); @@ -748,7 +740,7 @@ mod tests { #[test] fn test_params_macro_empty() { let p = params![]; - assert!(p.is_empty()); + assert_eq!(p.len(), 0); } #[test] diff --git a/hyperdb-api-core/src/protocol/copy.rs b/hyperdb-api-core/src/protocol/copy.rs index e26bdeac..a6292f84 100644 --- a/hyperdb-api-core/src/protocol/copy.rs +++ b/hyperdb-api-core/src/protocol/copy.rs @@ -773,7 +773,7 @@ mod tests { // A zero-length value is valid: 4 bytes of length prefix, no data. let buf = [0x00, 0x00, 0x00, 0x00]; let bytes = read_varbinary(&buf).unwrap(); - assert!(bytes.is_empty()); + assert_eq!(bytes.len(), 0); } #[test] diff --git a/hyperdb-api-core/src/protocol/types.rs b/hyperdb-api-core/src/protocol/types.rs index b9f62ce4..4a17cd39 100644 --- a/hyperdb-api-core/src/protocol/types.rs +++ b/hyperdb-api-core/src/protocol/types.rs @@ -423,10 +423,6 @@ mod tests { } #[test] - #[expect( - clippy::float_cmp, - reason = "bit-for-bit round-trip through fixed-width binary encoding; epsilon compare would mask a decode regression" - )] fn test_f64_roundtrip() { let mut buf = BytesMut::new(); f64_to_hyper_binary(std::f64::consts::PI, &mut buf); diff --git a/hyperdb-api-core/src/types/special.rs b/hyperdb-api-core/src/types/special.rs index 05d58e62..2fbcde9f 100644 --- a/hyperdb-api-core/src/types/special.rs +++ b/hyperdb-api-core/src/types/special.rs @@ -2182,7 +2182,7 @@ mod geo_impl { let wkb_geo = Geography::from_wkt("POINT(1 2)").expect("wkt to wkb"); match wkb_geo.format().expect("format detection") { GeographyFormat::Wkb(bytes) => { - assert!(!bytes.is_empty()); + assert_ne!(bytes.len(), 0); assert!(bytes[0] == 0 || bytes[0] == 1); } GeographyFormat::Legacy(_) => panic!("expected WKB format"), @@ -2460,10 +2460,6 @@ mod tests { } #[test] - #[expect( - clippy::float_cmp, - reason = "42.0 is exactly representable; scale=0 conversion must be bit-exact" - )] fn test_numeric_from_binary_with_scale_zero() { // Unscaled value 42 with scale 0 = 42 let mut bytes = [0u8; 16]; @@ -2571,10 +2567,6 @@ mod tests { } #[test] - #[expect( - clippy::float_cmp, - reason = "123.0 is exactly representable; scale=0 conversion must be bit-exact" - )] fn test_numeric_from_binary_with_scale_required() { // FromHyperBinary is intentionally NOT implemented for Numeric because // the scale must be obtained from type metadata - it cannot be inferred diff --git a/hyperdb-api/src/grpc_connection.rs b/hyperdb-api/src/grpc_connection.rs index 78e75f16..5aa1ef83 100644 --- a/hyperdb-api/src/grpc_connection.rs +++ b/hyperdb-api/src/grpc_connection.rs @@ -290,6 +290,7 @@ impl GrpcConnection { } /// Returns the gRPC configuration. + #[must_use] pub fn config(&self) -> &GrpcConfig { self.client.config() } @@ -425,6 +426,7 @@ impl GrpcConnectionAsync { } /// Returns the gRPC configuration. + #[must_use] pub fn config(&self) -> &GrpcConfig { self.client.config() } diff --git a/hyperdb-api/src/inserter.rs b/hyperdb-api/src/inserter.rs index 56894647..6d5b5fb0 100644 --- a/hyperdb-api/src/inserter.rs +++ b/hyperdb-api/src/inserter.rs @@ -284,6 +284,7 @@ impl<'conn> Inserter<'conn> { } /// Returns the table definition. + #[must_use] pub fn table_definition(&self) -> &TableDefinition { &self.table_def } diff --git a/hyperdb-api/src/names.rs b/hyperdb-api/src/names.rs index 83331200..4d0225ac 100644 --- a/hyperdb-api/src/names.rs +++ b/hyperdb-api/src/names.rs @@ -314,6 +314,7 @@ impl DatabaseName { } /// Returns the name component. + #[must_use] pub fn name(&self) -> &Name { &self.name } @@ -449,6 +450,7 @@ impl SchemaName { } /// Returns the schema name component. + #[must_use] pub fn schema(&self) -> &Name { &self.schema } @@ -638,6 +640,7 @@ impl TableName { } /// Returns the table name component. + #[must_use] pub fn table(&self) -> &Name { &self.table } @@ -877,7 +880,7 @@ mod tests { let name = Name::try_new("users").unwrap(); assert_eq!(name.to_string(), "\"users\""); assert_eq!(name.unescaped(), "users"); - assert!(!name.unescaped().is_empty()); + assert_ne!(name.unescaped(), ""); } #[test] diff --git a/hyperdb-api/tests/arrow_reader_tests.rs b/hyperdb-api/tests/arrow_reader_tests.rs index 778de850..b56505da 100644 --- a/hyperdb-api/tests/arrow_reader_tests.rs +++ b/hyperdb-api/tests/arrow_reader_tests.rs @@ -56,11 +56,11 @@ fn test_arrow_reader_query() -> Result<()> { // Test query with filter let arrow_data = reader.query_to_arrow("SELECT * FROM products WHERE price > 15")?; - assert!(!arrow_data.is_empty()); + assert_ne!(arrow_data, [] as [u8; 0]); // Test query with aggregation let arrow_data = reader.query_to_arrow("SELECT COUNT(*), SUM(price) FROM products")?; - assert!(!arrow_data.is_empty()); + assert_ne!(arrow_data, [] as [u8; 0]); Ok(()) } @@ -80,7 +80,7 @@ fn test_arrow_reader_columns() -> Result<()> { // Read only specific columns let arrow_data = reader.table_columns_to_arrow("users", &["id", "name"])?; - assert!(!arrow_data.is_empty()); + assert_ne!(arrow_data, [] as [u8; 0]); Ok(()) } @@ -106,7 +106,7 @@ fn test_arrow_reader_filtered() -> Result<()> { // Read with filter let arrow_data = reader.table_filtered_to_arrow("orders", "status = 'pending'")?; - assert!(!arrow_data.is_empty()); + assert_ne!(arrow_data, [] as [u8; 0]); Ok(()) } @@ -161,7 +161,7 @@ fn test_arrow_reader_empty_table() -> Result<()> { let arrow_data = reader.table_to_arrow("empty_table")?; // Even empty result should have some data (schema at minimum) - assert!(!arrow_data.is_empty()); + assert_ne!(arrow_data, [] as [u8; 0]); Ok(()) } @@ -192,7 +192,7 @@ fn test_arrow_reader_various_types() -> Result<()> { let reader = ArrowReader::new(&conn); let arrow_data = reader.table_to_arrow("typed_data")?; - assert!(!arrow_data.is_empty()); + assert_ne!(arrow_data, [] as [u8; 0]); Ok(()) } @@ -213,7 +213,7 @@ fn test_arrow_reader_no_matching_rows() -> Result<()> { let arrow_data = reader.query_to_arrow("SELECT * FROM test_filter WHERE id > 100")?; // Should still have data (schema) - assert!(!arrow_data.is_empty()); + assert_ne!(arrow_data, [] as [u8; 0]); Ok(()) } @@ -233,7 +233,7 @@ fn test_arrow_reader_schema_qualified() -> Result<()> { let reader = ArrowReader::new(&conn); let arrow_data = reader.table_to_arrow("custom_schema.test_table")?; - assert!(!arrow_data.is_empty()); + assert_ne!(arrow_data, [] as [u8; 0]); Ok(()) } @@ -256,9 +256,9 @@ fn test_arrow_reader_multiple_reads() -> Result<()> { let data2 = reader.table_to_arrow("multi_test")?; let data3 = reader.query_to_arrow("SELECT COUNT(*) FROM multi_test")?; - assert!(!data1.is_empty()); - assert!(!data2.is_empty()); - assert!(!data3.is_empty()); + assert_ne!(data1, [] as [u8; 0]); + assert_ne!(data2, [] as [u8; 0]); + assert_ne!(data3, [] as [u8; 0]); // Same query should return same size assert_eq!(data1.len(), data2.len()); diff --git a/hyperdb-api/tests/async_kv_store_tests.rs b/hyperdb-api/tests/async_kv_store_tests.rs index c572205f..1d08fa8f 100644 --- a/hyperdb-api/tests/async_kv_store_tests.rs +++ b/hyperdb-api/tests/async_kv_store_tests.rs @@ -71,7 +71,7 @@ async fn async_kv_full_surface() -> Result<()> { #[tokio::test(flavor = "current_thread")] async fn async_list_stores_and_validation() -> Result<()> { let (_hyper, conn) = fresh_async_conn("async_kv_list").await?; - assert!(conn.kv_list_stores().await?.is_empty()); + assert_eq!(conn.kv_list_stores().await?, [] as [std::string::String; 0]); let _ = conn.kv_store("alpha").await?.set("k", "1").await?; let _ = conn.kv_store("beta").await?.set("k", "2").await?; let mut stores = conn.kv_list_stores().await?; diff --git a/hyperdb-api/tests/kv_store_in_tests.rs b/hyperdb-api/tests/kv_store_in_tests.rs index 91d5656f..354ed727 100644 --- a/hyperdb-api/tests/kv_store_in_tests.rs +++ b/hyperdb-api/tests/kv_store_in_tests.rs @@ -56,7 +56,7 @@ fn kv_store_in_targets_attached_database() -> Result<()> { // The location-aware listing sees the attached-DB store; the primary has none. assert_eq!(conn.kv_list_stores_in("aux")?, vec!["settings".to_string()]); - assert!(conn.kv_list_stores()?.is_empty()); + assert_eq!(conn.kv_list_stores()?, [] as [std::string::String; 0]); Ok(()) } @@ -108,7 +108,7 @@ async fn async_kv_store_in_targets_attached_database() -> Result<()> { conn.kv_list_stores_in("aux").await?, vec!["settings".to_string()] ); - assert!(conn.kv_list_stores().await?.is_empty()); + assert_eq!(conn.kv_list_stores().await?, [] as [std::string::String; 0]); Ok(()) } diff --git a/hyperdb-api/tests/kv_store_tests.rs b/hyperdb-api/tests/kv_store_tests.rs index a8ccd4f6..de99afd5 100644 --- a/hyperdb-api/tests/kv_store_tests.rs +++ b/hyperdb-api/tests/kv_store_tests.rs @@ -148,7 +148,10 @@ fn delete_exists_size_keys_clear() -> Result<()> { fn list_stores_and_isolation() -> Result<()> { let tc = TestConnection::new()?; // Empty before any store has keys. - assert!(tc.connection.kv_list_stores()?.is_empty()); + assert_eq!( + tc.connection.kv_list_stores()?, + [] as [std::string::String; 0] + ); let a = tc.connection.kv_store("alpha")?; let b = tc.connection.kv_store("beta")?; diff --git a/hyperdb-api/tests/process_tests.rs b/hyperdb-api/tests/process_tests.rs index 272d3509..de25b515 100644 --- a/hyperdb-api/tests/process_tests.rs +++ b/hyperdb-api/tests/process_tests.rs @@ -172,7 +172,7 @@ fn test_hyper_process_start_stop() { // Verify the endpoint is valid let endpoint = hyper.endpoint().expect("No endpoint"); let descriptor = endpoint.to_string(); - assert!(!descriptor.is_empty()); + assert_ne!(descriptor, ""); // Verify we can connect let conn = Connection::without_database(endpoint).expect("Failed to connect"); @@ -310,7 +310,7 @@ fn test_hyper_process_drop() { } // After hyper is dropped, we can't verify the server is down without // trying to connect (which would hang), so we just ensure no panic - assert!(!endpoint_str.is_empty()); + assert_ne!(endpoint_str, ""); } #[test] diff --git a/hyperdb-api/tests/type_tests.rs b/hyperdb-api/tests/type_tests.rs index f9cf621c..61a93e17 100644 --- a/hyperdb-api/tests/type_tests.rs +++ b/hyperdb-api/tests/type_tests.rs @@ -94,7 +94,7 @@ fn test_i64_type_handling() { let str_val = row.get::(0); assert!(str_val.is_some(), "Should be readable as String"); // The string might be "42" or binary representation, but should not be empty - assert!(!str_val.unwrap().is_empty()); + assert_ne!(str_val.unwrap(), ""); } } diff --git a/hyperdb-bootstrap/src/release.rs b/hyperdb-bootstrap/src/release.rs index aaeec1c3..c9cf6928 100644 --- a/hyperdb-bootstrap/src/release.rs +++ b/hyperdb-bootstrap/src/release.rs @@ -109,7 +109,7 @@ mod tests { #[test] fn builtin_parses() { let r = PinnedRelease::builtin(); - assert!(!r.version.is_empty()); + assert_ne!(r.version, ""); } #[test] diff --git a/hyperdb-mcp/tests/attach_tests.rs b/hyperdb-mcp/tests/attach_tests.rs index c5e57921..cfc983c9 100644 --- a/hyperdb-mcp/tests/attach_tests.rs +++ b/hyperdb-mcp/tests/attach_tests.rs @@ -166,7 +166,7 @@ fn detach_removes_entry_and_hides_tables() { // Should surface as a SQL error (attached database not found). We // don't pin the exact ErrorCode here — we only care that the // query is rejected. - assert!(!err.message.is_empty()); + assert_ne!(err.message, ""); } #[test] diff --git a/hyperdb-mcp/tests/diagnostics_tests.rs b/hyperdb-mcp/tests/diagnostics_tests.rs index fa5b1476..ab79bba4 100644 --- a/hyperdb-mcp/tests/diagnostics_tests.rs +++ b/hyperdb-mcp/tests/diagnostics_tests.rs @@ -57,7 +57,10 @@ fn non_utf8_os_string() -> OsString { fn launcher_identity_parsing_contract() { let absent = parse_launcher_identity(None); assert_eq!(absent.identity, None); - assert!(absent.warnings.is_empty()); + assert_eq!( + absent.warnings, + [] as [hyperdb_mcp::diagnostics::IdentityWarning; 0] + ); let secret = "UNKNOWN_SECRET_SENTINEL_4c4c08"; let valid = json!({ @@ -79,7 +82,10 @@ fn launcher_identity_parsing_contract() { .to_string(); let parsed = parse_launcher_identity(Some(OsStr::new(&valid))); - assert!(parsed.warnings.is_empty()); + assert_eq!( + parsed.warnings, + [] as [hyperdb_mcp::diagnostics::IdentityWarning; 0] + ); let identity = parsed.identity.expect("valid launcher metadata must parse"); assert_eq!( serde_json::to_value(&identity).expect("launcher identity must serialize"), diff --git a/hyperdb-mcp/tests/inspect_tests.rs b/hyperdb-mcp/tests/inspect_tests.rs index 118cca85..cb0934a0 100644 --- a/hyperdb-mcp/tests/inspect_tests.rs +++ b/hyperdb-mcp/tests/inspect_tests.rs @@ -46,7 +46,10 @@ fn inspect_csv_reports_widened_types_and_min_max() { assert_eq!(report.stats[pop].max_i128, Some(8_000_000_000)); assert_eq!(report.stats[pop].min_i128, Some(100)); assert_eq!(report.stats[pop].null_count, 0); - assert!(!report.stats[pop].sample_values.is_empty()); + assert_ne!( + report.stats[pop].sample_values, + [] as [std::string::String; 0] + ); } /// Nulls and empty cells must be counted, not silently dropped — the caller diff --git a/hyperdb-mcp/tests/subscription_tests.rs b/hyperdb-mcp/tests/subscription_tests.rs index b9c21338..3aee0f72 100644 --- a/hyperdb-mcp/tests/subscription_tests.rs +++ b/hyperdb-mcp/tests/subscription_tests.rs @@ -18,7 +18,7 @@ use hyperdb_mcp::subscriptions::{ #[test] fn empty_registry_has_no_subscribed_uris() { let reg = SubscriptionRegistry::new(); - assert!(reg.subscribed_uris().is_empty()); + assert_eq!(reg.subscribed_uris(), [] as [std::string::String; 0]); assert!(reg.subscribers_for("hyper://anything").is_empty()); } @@ -32,7 +32,7 @@ fn unsubscribe_on_empty_registry_is_a_noop() { // subscribers_for after an unsubscribe should still be empty. assert_eq!(reg.subscribers_for("hyper://workspace").len(), 0); reg.clear(); - assert!(reg.subscribed_uris().is_empty()); + assert_eq!(reg.subscribed_uris(), [] as [std::string::String; 0]); } #[test] @@ -43,7 +43,7 @@ fn notify_updated_on_empty_registry_is_safe() { reg.notify_updated("hyper://workspace"); reg.notify_list_changed(); // Should still have no subscribers after the no-op. - assert!(reg.subscribed_uris().is_empty()); + assert_eq!(reg.subscribed_uris(), [] as [std::string::String; 0]); } // --- URI fan-out helpers ----------------------------------------------------