spikard 0.8.2 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +19 -10
  3. data/ext/spikard_rb/Cargo.lock +234 -162
  4. data/ext/spikard_rb/Cargo.toml +3 -3
  5. data/ext/spikard_rb/extconf.rb +4 -3
  6. data/lib/spikard/config.rb +88 -12
  7. data/lib/spikard/testing.rb +3 -1
  8. data/lib/spikard/version.rb +1 -1
  9. data/lib/spikard.rb +11 -0
  10. data/vendor/crates/spikard-bindings-shared/Cargo.toml +11 -6
  11. data/vendor/crates/spikard-bindings-shared/examples/config_extraction.rs +8 -8
  12. data/vendor/crates/spikard-bindings-shared/src/config_extractor.rs +63 -25
  13. data/vendor/crates/spikard-bindings-shared/src/conversion_traits.rs +20 -4
  14. data/vendor/crates/spikard-bindings-shared/src/di_traits.rs +10 -4
  15. data/vendor/crates/spikard-bindings-shared/src/error_response.rs +25 -22
  16. data/vendor/crates/spikard-bindings-shared/src/grpc_metadata.rs +14 -12
  17. data/vendor/crates/spikard-bindings-shared/src/handler_base.rs +24 -10
  18. data/vendor/crates/spikard-bindings-shared/src/json_conversion.rs +829 -0
  19. data/vendor/crates/spikard-bindings-shared/src/lazy_cache.rs +587 -0
  20. data/vendor/crates/spikard-bindings-shared/src/lib.rs +7 -0
  21. data/vendor/crates/spikard-bindings-shared/src/lifecycle_base.rs +17 -11
  22. data/vendor/crates/spikard-bindings-shared/src/lifecycle_executor.rs +51 -73
  23. data/vendor/crates/spikard-bindings-shared/src/response_builder.rs +442 -4
  24. data/vendor/crates/spikard-bindings-shared/src/response_interpreter.rs +944 -0
  25. data/vendor/crates/spikard-bindings-shared/src/test_client_base.rs +22 -10
  26. data/vendor/crates/spikard-bindings-shared/src/validation_helpers.rs +28 -10
  27. data/vendor/crates/spikard-bindings-shared/tests/config_extractor_behavior.rs +3 -2
  28. data/vendor/crates/spikard-bindings-shared/tests/error_response_edge_cases.rs +13 -13
  29. data/vendor/crates/spikard-bindings-shared/tests/{comprehensive_coverage.rs → full_coverage.rs} +10 -5
  30. data/vendor/crates/spikard-bindings-shared/tests/handler_base_integration.rs +14 -14
  31. data/vendor/crates/spikard-bindings-shared/tests/integration_tests.rs +669 -0
  32. data/vendor/crates/spikard-core/Cargo.toml +11 -3
  33. data/vendor/crates/spikard-core/src/bindings/response.rs +6 -9
  34. data/vendor/crates/spikard-core/src/debug.rs +2 -2
  35. data/vendor/crates/spikard-core/src/di/container.rs +2 -2
  36. data/vendor/crates/spikard-core/src/di/error.rs +1 -1
  37. data/vendor/crates/spikard-core/src/di/factory.rs +9 -5
  38. data/vendor/crates/spikard-core/src/di/graph.rs +1 -0
  39. data/vendor/crates/spikard-core/src/di/resolved.rs +25 -2
  40. data/vendor/crates/spikard-core/src/di/value.rs +2 -1
  41. data/vendor/crates/spikard-core/src/errors.rs +3 -0
  42. data/vendor/crates/spikard-core/src/http.rs +94 -18
  43. data/vendor/crates/spikard-core/src/lifecycle.rs +85 -61
  44. data/vendor/crates/spikard-core/src/parameters.rs +75 -54
  45. data/vendor/crates/spikard-core/src/problem.rs +19 -5
  46. data/vendor/crates/spikard-core/src/request_data.rs +16 -24
  47. data/vendor/crates/spikard-core/src/router.rs +26 -6
  48. data/vendor/crates/spikard-core/src/schema_registry.rs +25 -11
  49. data/vendor/crates/spikard-core/src/type_hints.rs +14 -7
  50. data/vendor/crates/spikard-core/src/validation/error_mapper.rs +30 -16
  51. data/vendor/crates/spikard-core/src/validation/mod.rs +46 -33
  52. data/vendor/crates/spikard-core/tests/di_dependency_defaults.rs +1 -1
  53. data/vendor/crates/spikard-core/tests/error_mapper.rs +2 -2
  54. data/vendor/crates/spikard-core/tests/parameters_edge_cases.rs +1 -1
  55. data/vendor/crates/spikard-core/tests/parameters_full.rs +1 -1
  56. data/vendor/crates/spikard-core/tests/parameters_schema_and_formats.rs +1 -1
  57. data/vendor/crates/spikard-core/tests/validation_coverage.rs +4 -4
  58. data/vendor/crates/spikard-http/Cargo.toml +11 -2
  59. data/vendor/crates/spikard-http/src/cors.rs +32 -11
  60. data/vendor/crates/spikard-http/src/di_handler.rs +12 -8
  61. data/vendor/crates/spikard-http/src/grpc/framing.rs +469 -0
  62. data/vendor/crates/spikard-http/src/grpc/handler.rs +887 -25
  63. data/vendor/crates/spikard-http/src/grpc/mod.rs +114 -22
  64. data/vendor/crates/spikard-http/src/grpc/service.rs +232 -2
  65. data/vendor/crates/spikard-http/src/grpc/streaming.rs +80 -2
  66. data/vendor/crates/spikard-http/src/handler_trait.rs +204 -27
  67. data/vendor/crates/spikard-http/src/handler_trait_tests.rs +15 -15
  68. data/vendor/crates/spikard-http/src/jsonrpc/http_handler.rs +2 -2
  69. data/vendor/crates/spikard-http/src/jsonrpc/router.rs +2 -2
  70. data/vendor/crates/spikard-http/src/lib.rs +1 -1
  71. data/vendor/crates/spikard-http/src/lifecycle/adapter.rs +2 -2
  72. data/vendor/crates/spikard-http/src/lifecycle.rs +4 -4
  73. data/vendor/crates/spikard-http/src/openapi/spec_generation.rs +2 -0
  74. data/vendor/crates/spikard-http/src/server/fast_router.rs +186 -0
  75. data/vendor/crates/spikard-http/src/server/grpc_routing.rs +324 -23
  76. data/vendor/crates/spikard-http/src/server/handler.rs +33 -22
  77. data/vendor/crates/spikard-http/src/server/lifecycle_execution.rs +21 -2
  78. data/vendor/crates/spikard-http/src/server/mod.rs +125 -20
  79. data/vendor/crates/spikard-http/src/server/request_extraction.rs +126 -44
  80. data/vendor/crates/spikard-http/src/server/routing_factory.rs +80 -69
  81. data/vendor/crates/spikard-http/tests/common/handlers.rs +2 -2
  82. data/vendor/crates/spikard-http/tests/common/test_builders.rs +12 -12
  83. data/vendor/crates/spikard-http/tests/di_handler_error_responses.rs +2 -2
  84. data/vendor/crates/spikard-http/tests/di_integration.rs +6 -6
  85. data/vendor/crates/spikard-http/tests/grpc_bidirectional_streaming.rs +430 -0
  86. data/vendor/crates/spikard-http/tests/grpc_client_streaming.rs +738 -0
  87. data/vendor/crates/spikard-http/tests/grpc_integration_test.rs +13 -9
  88. data/vendor/crates/spikard-http/tests/grpc_server_streaming.rs +974 -0
  89. data/vendor/crates/spikard-http/tests/lifecycle_execution.rs +2 -2
  90. data/vendor/crates/spikard-http/tests/request_extraction_full.rs +4 -4
  91. data/vendor/crates/spikard-http/tests/server_config_builder.rs +2 -2
  92. data/vendor/crates/spikard-http/tests/server_cors_preflight.rs +1 -0
  93. data/vendor/crates/spikard-http/tests/server_openapi_jsonrpc_static.rs +140 -0
  94. data/vendor/crates/spikard-rb/Cargo.toml +11 -1
  95. data/vendor/crates/spikard-rb/build.rs +1 -0
  96. data/vendor/crates/spikard-rb/src/conversion.rs +138 -4
  97. data/vendor/crates/spikard-rb/src/grpc/handler.rs +706 -229
  98. data/vendor/crates/spikard-rb/src/grpc/mod.rs +6 -2
  99. data/vendor/crates/spikard-rb/src/gvl.rs +2 -2
  100. data/vendor/crates/spikard-rb/src/handler.rs +169 -91
  101. data/vendor/crates/spikard-rb/src/lib.rs +502 -62
  102. data/vendor/crates/spikard-rb/src/lifecycle.rs +31 -3
  103. data/vendor/crates/spikard-rb/src/metadata/route_extraction.rs +108 -43
  104. data/vendor/crates/spikard-rb/src/request.rs +117 -20
  105. data/vendor/crates/spikard-rb/src/runtime/server_runner.rs +52 -25
  106. data/vendor/crates/spikard-rb/src/server.rs +23 -14
  107. data/vendor/crates/spikard-rb/src/testing/client.rs +5 -4
  108. data/vendor/crates/spikard-rb/src/testing/sse.rs +1 -36
  109. data/vendor/crates/spikard-rb/src/testing/websocket.rs +3 -38
  110. data/vendor/crates/spikard-rb/src/websocket.rs +32 -23
  111. data/vendor/crates/spikard-rb-macros/Cargo.toml +9 -1
  112. data/vendor/crates/spikard-rb-macros/src/lib.rs +4 -5
  113. metadata +14 -4
  114. data/vendor/bundle/ruby/3.4.0/gems/diff-lcs-1.6.2/mise.toml +0 -5
  115. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.10.0/build/buildkitd.toml +0 -2
@@ -23,13 +23,15 @@ impl TestClientConfig {
23
23
  }
24
24
 
25
25
  /// Set the timeout in milliseconds
26
- pub fn with_timeout(mut self, timeout_ms: u64) -> Self {
26
+ #[must_use]
27
+ pub const fn with_timeout(mut self, timeout_ms: u64) -> Self {
27
28
  self.timeout_ms = timeout_ms;
28
29
  self
29
30
  }
30
31
 
31
32
  /// Set whether to follow redirects
32
- pub fn with_follow_redirects(mut self, follow_redirects: bool) -> Self {
33
+ #[must_use]
34
+ pub const fn with_follow_redirects(mut self, follow_redirects: bool) -> Self {
33
35
  self.follow_redirects = follow_redirects;
34
36
  self
35
37
  }
@@ -60,7 +62,13 @@ pub struct TestResponseMetadata {
60
62
 
61
63
  impl TestResponseMetadata {
62
64
  /// Create a new test response metadata
63
- pub fn new(status_code: u16, headers: HashMap<String, String>, body_size: usize, response_time_ms: u64) -> Self {
65
+ #[must_use]
66
+ pub const fn new(
67
+ status_code: u16,
68
+ headers: HashMap<String, String>,
69
+ body_size: usize,
70
+ response_time_ms: u64,
71
+ ) -> Self {
64
72
  Self {
65
73
  status_code,
66
74
  headers,
@@ -70,6 +78,7 @@ impl TestResponseMetadata {
70
78
  }
71
79
 
72
80
  /// Get a header value by name (case-insensitive)
81
+ #[must_use]
73
82
  pub fn get_header(&self, name: &str) -> Option<&String> {
74
83
  let lower_name = name.to_lowercase();
75
84
  self.headers
@@ -79,17 +88,20 @@ impl TestResponseMetadata {
79
88
  }
80
89
 
81
90
  /// Check if response was successful (2xx status code)
82
- pub fn is_success(&self) -> bool {
91
+ #[must_use]
92
+ pub const fn is_success(&self) -> bool {
83
93
  self.status_code >= 200 && self.status_code < 300
84
94
  }
85
95
 
86
96
  /// Check if response was a client error (4xx status code)
87
- pub fn is_client_error(&self) -> bool {
97
+ #[must_use]
98
+ pub const fn is_client_error(&self) -> bool {
88
99
  self.status_code >= 400 && self.status_code < 500
89
100
  }
90
101
 
91
102
  /// Check if response was a server error (5xx status code)
92
- pub fn is_server_error(&self) -> bool {
103
+ #[must_use]
104
+ pub const fn is_server_error(&self) -> bool {
93
105
  self.status_code >= 500 && self.status_code < 600
94
106
  }
95
107
  }
@@ -194,7 +206,7 @@ mod tests {
194
206
  let metadata_204 = TestResponseMetadata::new(204, headers.clone(), 0, 50);
195
207
  let metadata_299 = TestResponseMetadata::new(299, headers.clone(), 100, 50);
196
208
  let metadata_300 = TestResponseMetadata::new(300, headers.clone(), 100, 50);
197
- let metadata_400 = TestResponseMetadata::new(400, headers.clone(), 100, 50);
209
+ let metadata_400 = TestResponseMetadata::new(400, headers, 100, 50);
198
210
 
199
211
  assert!(metadata_200.is_success());
200
212
  assert!(metadata_201.is_success());
@@ -211,7 +223,7 @@ mod tests {
211
223
  let metadata_400 = TestResponseMetadata::new(400, headers.clone(), 100, 50);
212
224
  let metadata_404 = TestResponseMetadata::new(404, headers.clone(), 100, 50);
213
225
  let metadata_499 = TestResponseMetadata::new(499, headers.clone(), 100, 50);
214
- let metadata_500 = TestResponseMetadata::new(500, headers.clone(), 100, 50);
226
+ let metadata_500 = TestResponseMetadata::new(500, headers, 100, 50);
215
227
 
216
228
  assert!(!metadata_399.is_client_error());
217
229
  assert!(metadata_400.is_client_error());
@@ -227,7 +239,7 @@ mod tests {
227
239
  let metadata_500 = TestResponseMetadata::new(500, headers.clone(), 100, 50);
228
240
  let metadata_502 = TestResponseMetadata::new(502, headers.clone(), 100, 50);
229
241
  let metadata_599 = TestResponseMetadata::new(599, headers.clone(), 100, 50);
230
- let metadata_600 = TestResponseMetadata::new(600, headers.clone(), 100, 50);
242
+ let metadata_600 = TestResponseMetadata::new(600, headers, 100, 50);
231
243
 
232
244
  assert!(!metadata_499.is_server_error());
233
245
  assert!(metadata_500.is_server_error());
@@ -240,7 +252,7 @@ mod tests {
240
252
  fn test_response_metadata_debug() {
241
253
  let headers = HashMap::new();
242
254
  let metadata = TestResponseMetadata::new(200, headers, 100, 50);
243
- let debug_str = format!("{:?}", metadata);
255
+ let debug_str = format!("{metadata:?}");
244
256
  assert!(debug_str.contains("200"));
245
257
  assert!(debug_str.contains("100"));
246
258
  assert!(debug_str.contains("50"));
@@ -7,29 +7,37 @@ pub struct HeaderValidator;
7
7
 
8
8
  impl HeaderValidator {
9
9
  /// Validate that required headers are present
10
+ ///
11
+ /// # Errors
12
+ ///
13
+ /// Returns an error if required headers are missing.
10
14
  pub fn validate_required(headers: &[(String, String)], required: &[&str]) -> Result<(), String> {
11
15
  let header_names: std::collections::HashSet<_> = headers.iter().map(|(k, _)| k.to_lowercase()).collect();
12
16
 
13
17
  for req in required {
14
18
  if !header_names.contains(&req.to_lowercase()) {
15
- return Err(format!("Missing required header: {}", req));
19
+ return Err(format!("Missing required header: {req}"));
16
20
  }
17
21
  }
18
22
  Ok(())
19
23
  }
20
24
 
21
25
  /// Validate header format
26
+ ///
27
+ /// # Errors
28
+ ///
29
+ /// Returns an error if the header format is invalid.
22
30
  pub fn validate_format(key: &str, value: &str, format: HeaderFormat) -> Result<(), String> {
23
31
  match format {
24
32
  HeaderFormat::Bearer => {
25
33
  if !value.starts_with("Bearer ") {
26
- return Err(format!("{}: must start with 'Bearer '", key));
34
+ return Err(format!("{key}: must start with 'Bearer '"));
27
35
  }
28
36
  Ok(())
29
37
  }
30
38
  HeaderFormat::Json => {
31
39
  if !value.starts_with("application/json") {
32
- return Err(format!("{}: must be 'application/json'", key));
40
+ return Err(format!("{key}: must be 'application/json'"));
33
41
  }
34
42
  Ok(())
35
43
  }
@@ -38,6 +46,7 @@ impl HeaderValidator {
38
46
  }
39
47
 
40
48
  /// Header validation formats
49
+ #[derive(Copy, Clone)]
41
50
  pub enum HeaderFormat {
42
51
  /// Bearer token format
43
52
  Bearer,
@@ -50,6 +59,10 @@ pub struct BodyValidator;
50
59
 
51
60
  impl BodyValidator {
52
61
  /// Validate that required fields are present in a JSON object
62
+ ///
63
+ /// # Errors
64
+ ///
65
+ /// Returns an error if required fields are missing.
53
66
  pub fn validate_required_fields(body: &Value, required: &[&str]) -> Result<(), String> {
54
67
  let obj = body
55
68
  .as_object()
@@ -57,44 +70,48 @@ impl BodyValidator {
57
70
 
58
71
  for field in required {
59
72
  if !obj.contains_key(*field) {
60
- return Err(format!("Missing required field: {}", field));
73
+ return Err(format!("Missing required field: {field}"));
61
74
  }
62
75
  }
63
76
  Ok(())
64
77
  }
65
78
 
66
79
  /// Validate field type
80
+ ///
81
+ /// # Errors
82
+ ///
83
+ /// Returns an error if the field type doesn't match.
67
84
  pub fn validate_field_type(body: &Value, field: &str, expected_type: FieldType) -> Result<(), String> {
68
85
  let obj = body
69
86
  .as_object()
70
87
  .ok_or_else(|| "Body must be a JSON object".to_string())?;
71
88
 
72
- let value = obj.get(field).ok_or_else(|| format!("Field not found: {}", field))?;
89
+ let value = obj.get(field).ok_or_else(|| format!("Field not found: {field}"))?;
73
90
 
74
91
  match expected_type {
75
92
  FieldType::String => {
76
93
  if !value.is_string() {
77
- return Err(format!("{}: expected string", field));
94
+ return Err(format!("{field}: expected string"));
78
95
  }
79
96
  }
80
97
  FieldType::Number => {
81
98
  if !value.is_number() {
82
- return Err(format!("{}: expected number", field));
99
+ return Err(format!("{field}: expected number"));
83
100
  }
84
101
  }
85
102
  FieldType::Boolean => {
86
103
  if !value.is_boolean() {
87
- return Err(format!("{}: expected boolean", field));
104
+ return Err(format!("{field}: expected boolean"));
88
105
  }
89
106
  }
90
107
  FieldType::Object => {
91
108
  if !value.is_object() {
92
- return Err(format!("{}: expected object", field));
109
+ return Err(format!("{field}: expected object"));
93
110
  }
94
111
  }
95
112
  FieldType::Array => {
96
113
  if !value.is_array() {
97
- return Err(format!("{}: expected array", field));
114
+ return Err(format!("{field}: expected array"));
98
115
  }
99
116
  }
100
117
  }
@@ -103,6 +120,7 @@ impl BodyValidator {
103
120
  }
104
121
 
105
122
  /// Field types for validation
123
+ #[derive(Copy, Clone)]
106
124
  pub enum FieldType {
107
125
  String,
108
126
  Number,
@@ -7,6 +7,7 @@ struct JsonSource {
7
7
  }
8
8
 
9
9
  impl JsonSource {
10
+ #[allow(clippy::missing_const_for_fn)]
10
11
  fn new(value: serde_json::Value) -> Self {
11
12
  Self { value }
12
13
  }
@@ -44,7 +45,7 @@ impl ConfigSource for JsonSource {
44
45
 
45
46
  fn get_nested(&self, key: &str) -> Option<Box<dyn ConfigSource + '_>> {
46
47
  let nested = self.get(key)?.as_object()?;
47
- Some(Box::new(JsonSource {
48
+ Some(Box::new(Self {
48
49
  value: serde_json::Value::Object(nested.clone()),
49
50
  }))
50
51
  }
@@ -60,7 +61,7 @@ impl ConfigSource for JsonSource {
60
61
  fn get_array_element(&self, key: &str, index: usize) -> Option<Box<dyn ConfigSource + '_>> {
61
62
  let array = self.get(key)?.as_array()?;
62
63
  let element = array.get(index)?.as_object()?;
63
- Some(Box::new(JsonSource {
64
+ Some(Box::new(Self {
64
65
  value: serde_json::Value::Object(element.clone()),
65
66
  }))
66
67
  }
@@ -2,6 +2,12 @@
2
2
  //!
3
3
  //! These tests cover serialization edge cases and ensure fallback
4
4
  //! behavior works correctly when serialization fails.
5
+ #![allow(
6
+ clippy::redundant_clone,
7
+ clippy::uninlined_format_args,
8
+ clippy::doc_markdown,
9
+ reason = "Edge case tests for error handling"
10
+ )]
5
11
 
6
12
  use axum::http::StatusCode;
7
13
  use pretty_assertions::assert_eq;
@@ -99,7 +105,7 @@ fn test_from_structured_error_with_details() {
99
105
  json!({"field": "username", "reason": "already_exists"}),
100
106
  );
101
107
 
102
- let (status, body) = ErrorResponseBuilder::from_structured_error(error);
108
+ let (status, body) = ErrorResponseBuilder::from_structured_error(&error);
103
109
  assert_eq!(status, StatusCode::INTERNAL_SERVER_ERROR);
104
110
  let parsed: Value = serde_json::from_str(&body).unwrap();
105
111
  assert_eq!(parsed["code"], "custom_error");
@@ -201,23 +207,17 @@ fn test_all_convenience_methods_return_valid_json() {
201
207
  ];
202
208
 
203
209
  for (status, body) in test_cases {
204
- let parsed: Value = serde_json::from_str(&body)
205
- .unwrap_or_else(|_| panic!("Failed to parse JSON for status {}: {}", status, body));
210
+ let parsed: Value =
211
+ serde_json::from_str(&body).unwrap_or_else(|_| panic!("Failed to parse JSON for status {status}: {body}"));
206
212
 
207
213
  assert!(
208
214
  parsed.get("error").is_some(),
209
- "Missing 'error' field for status {}",
210
- status
211
- );
212
- assert!(
213
- parsed.get("code").is_some(),
214
- "Missing 'code' field for status {}",
215
- status
215
+ "Missing 'error' field for status {status}"
216
216
  );
217
+ assert!(parsed.get("code").is_some(), "Missing 'code' field for status {status}");
217
218
  assert!(
218
219
  parsed.get("details").is_some(),
219
- "Missing 'details' field for status {}",
220
- status
220
+ "Missing 'details' field for status {status}"
221
221
  );
222
222
  }
223
223
  }
@@ -336,7 +336,7 @@ fn test_error_message_types() {
336
336
  let (_, body) = ErrorResponseBuilder::bad_request("test");
337
337
  assert!(body.contains("test"));
338
338
 
339
- let (_, body) = ErrorResponseBuilder::bad_request(format!("Error: {}", 123));
339
+ let (_, body) = ErrorResponseBuilder::bad_request(format!("Error: {0}", 123));
340
340
  assert!(body.contains("Error: 123"));
341
341
  }
342
342
 
@@ -2,6 +2,13 @@
2
2
  //!
3
3
  //! This test file ensures full code coverage across all modules in the crate,
4
4
  //! testing edge cases, error paths, and integration scenarios.
5
+ #![allow(
6
+ clippy::doc_markdown,
7
+ clippy::items_after_statements,
8
+ clippy::uninlined_format_args,
9
+ clippy::redundant_clone,
10
+ reason = "Integration test with many coverage scenarios"
11
+ )]
5
12
 
6
13
  use axum::http::{Request, StatusCode};
7
14
  use pretty_assertions::assert_eq;
@@ -201,12 +208,10 @@ fn test_lifecycle_hook_types() {
201
208
  }
202
209
 
203
210
  let continue_result = HookResult::Continue;
204
- let cloned_continue = continue_result.clone();
205
- assert!(matches!(cloned_continue, HookResult::Continue));
211
+ assert!(matches!(continue_result.clone(), HookResult::Continue));
206
212
 
207
213
  let short_circuit = HookResult::ShortCircuit(json!({"status": "error"}));
208
- let cloned_short = short_circuit.clone();
209
- assert!(matches!(cloned_short, HookResult::ShortCircuit(_)));
214
+ assert!(matches!(short_circuit.clone(), HookResult::ShortCircuit(_)));
210
215
  }
211
216
 
212
217
  #[test]
@@ -413,7 +418,7 @@ fn test_conversion_traits_comprehensive() {
413
418
  fn from_any(value: &(dyn std::any::Any + Send + Sync)) -> Result<Self, Self::Error> {
414
419
  value
415
420
  .downcast_ref::<i32>()
416
- .map(|&v| CustomType { value: v })
421
+ .map(|&v| Self { value: v })
417
422
  .ok_or_else(|| "Type mismatch".to_string())
418
423
  }
419
424
  }
@@ -1,4 +1,4 @@
1
- //! Integration tests for handler_base module
1
+ //! Integration tests for `handler_base` module
2
2
  //!
3
3
  //! These tests cover the validation paths and error handling that aren't
4
4
  //! covered by unit tests in the module itself.
@@ -41,7 +41,7 @@ impl LanguageHandler for MockHandler {
41
41
  if should_fail {
42
42
  Err(HandlerError::Execution("Handler failed".to_string()))
43
43
  } else {
44
- Ok(format!("output:{}", input))
44
+ Ok(format!("output:{input}"))
45
45
  }
46
46
  })
47
47
  }
@@ -81,10 +81,10 @@ async fn test_handler_executor_with_validation_error() {
81
81
  let request = Request::builder().body(Body::empty()).unwrap();
82
82
  let request_data = RequestData {
83
83
  path_params: Arc::new(HashMap::new()),
84
- query_params: json!({}),
84
+ query_params: Arc::new(json!({})),
85
85
  validated_params: None,
86
86
  raw_query_params: Arc::new(HashMap::new()),
87
- body: json!({"username": "john"}),
87
+ body: Arc::new(json!({"username": "john"})),
88
88
  raw_body: None,
89
89
  headers: Arc::new(HashMap::new()),
90
90
  cookies: Arc::new(HashMap::new()),
@@ -110,10 +110,10 @@ async fn test_handler_executor_prepare_failure() {
110
110
  let request = Request::builder().body(Body::empty()).unwrap();
111
111
  let request_data = RequestData {
112
112
  path_params: Arc::new(HashMap::new()),
113
- query_params: json!({}),
113
+ query_params: Arc::new(json!({})),
114
114
  validated_params: None,
115
115
  raw_query_params: Arc::new(HashMap::new()),
116
- body: json!({}),
116
+ body: Arc::new(json!({})),
117
117
  raw_body: None,
118
118
  headers: Arc::new(HashMap::new()),
119
119
  cookies: Arc::new(HashMap::new()),
@@ -139,10 +139,10 @@ async fn test_handler_executor_invoke_failure() {
139
139
  let request = Request::builder().body(Body::empty()).unwrap();
140
140
  let request_data = RequestData {
141
141
  path_params: Arc::new(HashMap::new()),
142
- query_params: json!({}),
142
+ query_params: Arc::new(json!({})),
143
143
  validated_params: None,
144
144
  raw_query_params: Arc::new(HashMap::new()),
145
- body: json!({}),
145
+ body: Arc::new(json!({})),
146
146
  raw_body: None,
147
147
  headers: Arc::new(HashMap::new()),
148
148
  cookies: Arc::new(HashMap::new()),
@@ -168,10 +168,10 @@ async fn test_handler_executor_interpret_failure() {
168
168
  let request = Request::builder().body(Body::empty()).unwrap();
169
169
  let request_data = RequestData {
170
170
  path_params: Arc::new(HashMap::new()),
171
- query_params: json!({}),
171
+ query_params: Arc::new(json!({})),
172
172
  validated_params: None,
173
173
  raw_query_params: Arc::new(HashMap::new()),
174
- body: json!({}),
174
+ body: Arc::new(json!({})),
175
175
  raw_body: None,
176
176
  headers: Arc::new(HashMap::new()),
177
177
  cookies: Arc::new(HashMap::new()),
@@ -210,10 +210,10 @@ async fn test_handler_executor_with_request_validator() {
210
210
 
211
211
  let request_data = RequestData {
212
212
  path_params: Arc::new(HashMap::new()),
213
- query_params: json!({}),
213
+ query_params: Arc::new(json!({})),
214
214
  validated_params: None,
215
215
  raw_query_params: Arc::new(HashMap::new()),
216
- body: json!({"name": "test"}),
216
+ body: Arc::new(json!({"name": "test"})),
217
217
  raw_body: None,
218
218
  headers: Arc::new(headers),
219
219
  cookies: Arc::new(HashMap::new()),
@@ -263,10 +263,10 @@ async fn test_handler_executor_builder_pattern() {
263
263
  let request = Request::builder().body(Body::empty()).unwrap();
264
264
  let request_data = RequestData {
265
265
  path_params: Arc::new(HashMap::new()),
266
- query_params: json!({}),
266
+ query_params: Arc::new(json!({})),
267
267
  validated_params: None,
268
268
  raw_query_params: Arc::new(HashMap::new()),
269
- body: json!({"email": "test@example.com"}),
269
+ body: Arc::new(json!({"email": "test@example.com"})),
270
270
  raw_body: None,
271
271
  headers: Arc::new(HashMap::new()),
272
272
  cookies: Arc::new(HashMap::new()),