• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gengteng / axum-valid / 6588897796

20 Oct 2023 02:14PM UTC coverage: 86.699% (+2.2%) from 84.518%
6588897796

push

github

gengteng
update README.md

1258 of 1451 relevant lines covered (86.7%)

12.47 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.24
/src/validify/test.rs
1
#![cfg(feature = "validify")]
2

3
use crate::tests::{ValidTest, ValidTestParameter};
4
use crate::{
5
    HasValidate, Modified, Validated, Validified, ValidifiedByRef, VALIDATION_ERROR_STATUS,
6
};
7
use axum::extract::{Path, Query};
8
use axum::routing::{get, post};
9
use axum::{Form, Json, Router};
10
use hyper::Method;
11
use once_cell::sync::Lazy;
12
use reqwest::{StatusCode, Url};
13
use serde::{Deserialize, Serialize};
14
use std::any::type_name;
15
use std::net::SocketAddr;
16
use std::ops::Deref;
17
use validify::{Modify, Validate, Validify};
18

19
#[derive(Clone, Deserialize, Serialize, Validify, Eq, PartialEq)]
20
#[cfg_attr(feature = "extra_protobuf", derive(prost::Message))]
21
#[cfg_attr(
22
    feature = "typed_multipart",
23
    derive(axum_typed_multipart::TryFromMultipart)
24
)]
25
pub struct ParametersValidify {
26
    #[validate(range(min = 5.0, max = 10.0))]
27
    #[cfg_attr(feature = "extra_protobuf", prost(int32, tag = "1"))]
28
    v0: i32,
29
    #[modify(lowercase)]
30
    #[validate(length(min = 1, max = 10))]
31
    #[cfg_attr(feature = "extra_protobuf", prost(string, tag = "2"))]
32
    v1: String,
33
}
34

35
trait IsModified: Modify + Clone + PartialEq + Eq {
36
    fn modified(&self) -> bool {
9✔
37
        let mut cloned = self.clone();
9✔
38
        cloned.modify();
9✔
39
        cloned == *self
9✔
40
    }
41
}
42

43
impl<T> IsModified for T where T: Modify + Clone + PartialEq + Eq {}
44

45
static VALID_PARAMETERS: Lazy<ParametersValidify> = Lazy::new(|| ParametersValidify {
6✔
46
    v0: 5,
47
    v1: String::from("ABCDEFG"),
3✔
48
});
49

50
static INVALID_PARAMETERS: Lazy<ParametersValidify> = Lazy::new(|| ParametersValidify {
6✔
51
    v0: 6,
52
    v1: String::from("ABCDEFGHIJKLMN"),
3✔
53
});
54

55
impl ValidTestParameter for ParametersValidify {
56
    fn valid() -> &'static Self {
3✔
57
        VALID_PARAMETERS.deref()
3✔
58
    }
59

60
    fn error() -> &'static [(&'static str, &'static str)] {
61
        &[("not_v0_or_v1", "value")]
62
    }
63

64
    fn invalid() -> &'static Self {
3✔
65
        INVALID_PARAMETERS.deref()
3✔
66
    }
67
}
68

69
impl HasValidate for ParametersValidify {
70
    type Validate = ParametersValidify;
71

72
    fn get_validate(&self) -> &Self::Validate {
3✔
73
        self
74
    }
75
}
76

77
#[tokio::test]
18✔
78
async fn test_main() -> anyhow::Result<()> {
9✔
79
    let router = Router::new()
51✔
80
        .route(route::PATH, get(extract_path))
6✔
81
        .route(route::PATH_MODIFIED, get(extract_path_modified))
6✔
82
        .route(route::PATH_VALIDIFIED, get(extract_path_validified))
6✔
83
        .route(
84
            route::PATH_VALIDIFIED_BY_REF,
85
            get(extract_path_validified_by_ref),
3✔
86
        )
87
        .route(route::QUERY, get(extract_query))
6✔
88
        .route(route::QUERY_MODIFIED, get(extract_query_modified))
6✔
89
        .route(route::QUERY_VALIDIFIED, get(extract_query_validified))
6✔
90
        .route(
91
            route::QUERY_VALIDIFIED_BY_REF,
92
            get(extract_query_validified_by_ref),
3✔
93
        )
94
        .route(route::FORM, post(extract_form))
6✔
95
        .route(route::FORM_MODIFIED, post(extract_form_modified))
6✔
96
        .route(route::FORM_VALIDIFIED, post(extract_form_validified))
6✔
97
        .route(
98
            route::FORM_VALIDIFIED_BY_REF,
99
            post(extract_form_validified_by_ref),
3✔
100
        )
101
        .route(route::JSON, post(extract_json))
6✔
102
        .route(route::JSON_MODIFIED, post(extract_json_modified))
6✔
103
        .route(route::JSON_VALIDIFIED, post(extract_json_validified))
6✔
104
        .route(
105
            route::JSON_VALIDIFIED_BY_REF,
106
            post(extract_json_validified_by_ref),
3✔
107
        );
108

109
    #[cfg(feature = "typed_header")]
110
    let router = router
12✔
111
        .route(
112
            typed_header::route::TYPED_HEADER,
113
            post(typed_header::extract_typed_header),
3✔
114
        )
115
        .route(
116
            typed_header::route::TYPED_HEADER_MODIFIED,
117
            post(typed_header::extract_typed_header_modified),
3✔
118
        )
119
        .route(
120
            typed_header::route::TYPED_HEADER_VALIDIFIED_BY_REF,
121
            post(typed_header::extract_typed_header_validified_by_ref),
3✔
122
        );
123

124
    #[cfg(feature = "typed_multipart")]
125
    let router = router
9✔
126
        .route(
127
            typed_multipart::route::TYPED_MULTIPART,
128
            post(typed_multipart::extract_typed_multipart),
3✔
129
        )
130
        .route(
131
            typed_multipart::route::BASE_MULTIPART,
132
            post(typed_multipart::extract_base_multipart),
3✔
133
        );
134

135
    #[cfg(feature = "extra")]
136
    let router = router
12✔
137
        .route(extra::route::CACHED, post(extra::extract_cached))
6✔
138
        .route(
139
            extra::route::WITH_REJECTION,
140
            post(extra::extract_with_rejection),
3✔
141
        )
142
        .route(
143
            extra::route::WITH_REJECTION_VALIDIFY,
144
            post(extra::extract_with_rejection_valid),
3✔
145
        );
146

147
    #[cfg(feature = "extra_typed_path")]
148
    let router = router
12✔
149
        .route(
150
            extra_typed_path::route::EXTRA_TYPED_PATH,
151
            get(extra_typed_path::extract_extra_typed_path),
3✔
152
        )
153
        .route(
154
            extra_typed_path::route::EXTRA_TYPED_PATH_MODIFIED,
155
            get(extra_typed_path::extract_extra_typed_path_modified),
3✔
156
        )
157
        .route(
158
            extra_typed_path::route::EXTRA_TYPED_PATH_VALIDIFIED_BY_REF,
159
            get(extra_typed_path::extract_extra_typed_path_validified_by_ref),
3✔
160
        );
161

162
    #[cfg(feature = "extra_query")]
163
    let router = router.route(
6✔
164
        extra_query::route::EXTRA_QUERY,
165
        post(extra_query::extract_extra_query),
3✔
166
    );
167

168
    #[cfg(feature = "extra_form")]
169
    let router = router.route(
6✔
170
        extra_form::route::EXTRA_FORM,
171
        post(extra_form::extract_extra_form),
3✔
172
    );
173

174
    #[cfg(feature = "extra_protobuf")]
175
    let router = router
12✔
176
        .route(
177
            extra_protobuf::route::EXTRA_PROTOBUF,
178
            post(extra_protobuf::extract_extra_protobuf),
3✔
179
        )
180
        .route(
181
            extra_protobuf::route::EXTRA_PROTOBUF_MODIFIED,
182
            post(extra_protobuf::extract_extra_protobuf_modified),
3✔
183
        )
184
        .route(
185
            extra_protobuf::route::EXTRA_PROTOBUF_VALIDIFIED_BY_REF,
186
            post(extra_protobuf::extract_extra_protobuf_validified_by_ref),
3✔
187
        );
188

189
    #[cfg(feature = "yaml")]
190
    let router = router.route(yaml::route::YAML, post(yaml::extract_yaml));
3✔
191

192
    #[cfg(feature = "msgpack")]
193
    let router = router
9✔
194
        .route(msgpack::route::MSGPACK, post(msgpack::extract_msgpack))
6✔
195
        .route(
196
            msgpack::route::MSGPACK_RAW,
197
            post(msgpack::extract_msgpack_raw),
3✔
198
        );
199

200
    let server = axum::Server::bind(&SocketAddr::from(([0u8, 0, 0, 0], 0u16)))
9✔
201
        .serve(router.into_make_service());
6✔
202
    let server_addr = server.local_addr();
3✔
203
    println!("Axum server address: {}.", server_addr);
6✔
204

205
    let (server_guard, close) = tokio::sync::oneshot::channel::<()>();
3✔
206
    let server_handle = tokio::spawn(server.with_graceful_shutdown(async move {
15✔
207
        let _ = close.await;
9✔
208
    }));
209

210
    let server_url = format!("http://{}", server_addr);
6✔
211
    let test_executor = TestExecutor::from(Url::parse(&format!("http://{}", server_addr))?);
6✔
212

213
    async fn test_extra_path(
3✔
214
        test_executor: &TestExecutor,
215
        route: &str,
216
        server_url: &str,
217
    ) -> anyhow::Result<()> {
218
        do_test_extra_path(
219
            test_executor,
220
            route,
221
            server_url,
222
            StatusCode::OK,
223
            StatusCode::BAD_REQUEST,
224
            VALIDATION_ERROR_STATUS,
225
            true,
226
        )
227
        .await
9✔
228
    }
229

230
    async fn test_extra_path_modified(
3✔
231
        test_executor: &TestExecutor,
232
        route: &str,
233
        server_url: &str,
234
    ) -> anyhow::Result<()> {
235
        do_test_extra_path(
236
            test_executor,
237
            route,
238
            server_url,
239
            StatusCode::OK,
240
            StatusCode::BAD_REQUEST,
241
            StatusCode::OK,
242
            false,
243
        )
244
        .await
9✔
245
    }
246

247
    async fn test_extra_path_validified(
3✔
248
        test_executor: &TestExecutor,
249
        route: &str,
250
        server_url: &str,
251
    ) -> anyhow::Result<()> {
252
        do_test_extra_path(
253
            test_executor,
254
            route,
255
            server_url,
256
            StatusCode::OK,
257
            StatusCode::BAD_REQUEST,
258
            VALIDATION_ERROR_STATUS,
259
            true,
260
        )
261
        .await
9✔
262
    }
263

264
    async fn do_test_extra_path(
3✔
265
        test_executor: &TestExecutor,
266
        route: &str,
267
        server_url: &str,
268
        expected_valid_status: StatusCode,
269
        expected_error_status: StatusCode,
270
        expected_invalid_status: StatusCode,
271
        should_check_json: bool,
272
    ) -> anyhow::Result<()> {
273
        let path_type_name = type_name::<Path<ParametersValidify>>();
6✔
274
        let valid_path_response = test_executor
12✔
275
            .client()
276
            .get(format!(
21✔
277
                "{}/{route}/{}/{}",
278
                server_url, VALID_PARAMETERS.v0, VALID_PARAMETERS.v1
6✔
279
            ))
280
            .send()
281
            .await?;
9✔
282
        assert_eq!(
3✔
283
            valid_path_response.status(),
6✔
284
            expected_valid_status,
285
            "Valid '{}' test failed.",
286
            path_type_name
287
        );
288

289
        let error_path_response = test_executor
12✔
290
            .client()
291
            .get(format!("{}/{route}/not_i32/path", server_url))
9✔
292
            .send()
293
            .await?;
9✔
294
        assert_eq!(
3✔
295
            error_path_response.status(),
6✔
296
            expected_error_status,
297
            "Error '{}' test failed: {}",
298
            path_type_name,
299
            error_path_response.text().await?
×
300
        );
301

302
        let invalid_path_response = test_executor
12✔
303
            .client()
304
            .get(format!(
21✔
305
                "{}/{route}/{}/{}",
306
                server_url, INVALID_PARAMETERS.v0, INVALID_PARAMETERS.v1
6✔
307
            ))
308
            .send()
309
            .await?;
9✔
310
        assert_eq!(
3✔
311
            invalid_path_response.status(),
6✔
312
            expected_invalid_status,
313
            "Invalid '{}' test failed.",
314
            path_type_name
315
        );
316
        #[cfg(feature = "into_json")]
317
        if should_check_json {
2✔
318
            check_json(path_type_name, invalid_path_response).await;
2✔
319
        }
320
        println!("All {} tests passed.", path_type_name);
6✔
321
        Ok(())
3✔
322
    }
323

324
    test_extra_path(&test_executor, "path", &server_url).await?;
6✔
325
    test_extra_path_modified(&test_executor, "path_modified", &server_url).await?;
9✔
326
    test_extra_path_validified(&test_executor, "path_validified", &server_url).await?;
9✔
327
    test_extra_path(&test_executor, "path_validified_by_ref", &server_url).await?;
9✔
328

329
    // Validated
330
    test_executor
12✔
331
        .execute::<Query<ParametersValidify>>(Method::GET, route::QUERY)
3✔
332
        .await?;
9✔
333
    // Modified
334
    test_executor
12✔
335
        .execute_modified::<Query<ParametersValidify>>(Method::GET, route::QUERY_MODIFIED)
3✔
336
        .await?;
9✔
337
    // ValidifiedByRef
338
    test_executor
12✔
339
        .execute::<Query<ParametersValidify>>(Method::GET, route::QUERY_VALIDIFIED_BY_REF)
3✔
340
        .await?;
9✔
341
    // Validified
342
    test_executor
12✔
343
        .execute_validified::<Query<ParametersValidify>>(Method::GET, route::QUERY_VALIDIFIED)
3✔
344
        .await?;
9✔
345

346
    // Validated
347
    test_executor
12✔
348
        .execute::<Form<ParametersValidify>>(Method::POST, route::FORM)
3✔
349
        .await?;
9✔
350
    // Modified
351
    test_executor
12✔
352
        .execute_modified::<Form<ParametersValidify>>(Method::POST, route::FORM_MODIFIED)
3✔
353
        .await?;
9✔
354
    // ValidifiedByRef
355
    test_executor
12✔
356
        .execute::<Form<ParametersValidify>>(Method::POST, route::FORM_VALIDIFIED_BY_REF)
3✔
357
        .await?;
9✔
358
    // Validified
359
    test_executor
12✔
360
        .execute_validified::<Form<ParametersValidify>>(Method::POST, route::FORM_VALIDIFIED)
3✔
361
        .await?;
9✔
362

363
    // Validated
364
    test_executor
12✔
365
        .execute::<Json<ParametersValidify>>(Method::POST, route::JSON)
3✔
366
        .await?;
9✔
367
    // Modified
368
    test_executor
12✔
369
        .execute_modified::<Json<ParametersValidify>>(Method::POST, route::JSON_MODIFIED)
3✔
370
        .await?;
9✔
371
    // ValidifiedByRef
372
    test_executor
12✔
373
        .execute::<Json<ParametersValidify>>(Method::POST, route::JSON_VALIDIFIED_BY_REF)
3✔
374
        .await?;
9✔
375
    // Validified
376
    test_executor
12✔
377
        .execute_validified::<Json<ParametersValidify>>(Method::POST, route::JSON_VALIDIFIED)
3✔
378
        .await?;
9✔
379

380
    #[cfg(feature = "typed_header")]
381
    {
382
        use axum::TypedHeader;
383
        // Validated
384
        test_executor
12✔
385
            .execute::<TypedHeader<ParametersValidify>>(
386
                Method::POST,
3✔
387
                typed_header::route::TYPED_HEADER,
388
            )
389
            .await?;
9✔
390
        // Modified
391
        test_executor
12✔
392
            .execute_modified::<TypedHeader<ParametersValidify>>(
393
                Method::POST,
3✔
394
                typed_header::route::TYPED_HEADER_MODIFIED,
395
            )
396
            .await?;
9✔
397
        // ValidifiedByRef
398
        test_executor
12✔
399
            .execute::<TypedHeader<ParametersValidify>>(
400
                Method::POST,
3✔
401
                typed_header::route::TYPED_HEADER_VALIDIFIED_BY_REF,
402
            )
403
            .await?;
9✔
404
    }
405

406
    #[cfg(feature = "typed_multipart")]
407
    {
408
        use axum_typed_multipart::{BaseMultipart, TypedMultipart, TypedMultipartError};
409

410
        // Validified
411
        test_executor
12✔
412
            .execute::<BaseMultipart<ParametersValidify, TypedMultipartError>>(
413
                Method::POST,
3✔
414
                typed_multipart::route::BASE_MULTIPART,
415
            )
416
            .await?;
9✔
417

418
        // Validified
419
        test_executor
12✔
420
            .execute::<TypedMultipart<ParametersValidify>>(
421
                Method::POST,
3✔
422
                typed_multipart::route::TYPED_MULTIPART,
423
            )
424
            .await?;
9✔
425
    }
426

427
    #[cfg(feature = "extra")]
428
    {
429
        use axum_extra::extract::{Cached, WithRejection};
430
        use extra::{
431
            ParametersRejection, ValidifyWithRejectionRejection, WithRejectionValidifyRejection,
432
        };
433
        test_executor
12✔
434
            .execute::<Cached<ParametersValidify>>(Method::POST, extra::route::CACHED)
3✔
435
            .await?;
9✔
436
        test_executor
12✔
437
            .execute::<WithRejection<ParametersValidify, ValidifyWithRejectionRejection>>(
438
                Method::POST,
3✔
439
                extra::route::WITH_REJECTION,
440
            )
441
            .await?;
9✔
442
        test_executor
12✔
443
            .execute::<WithRejection<
444
                Validated<ParametersValidify>,
445
                WithRejectionValidifyRejection<ParametersRejection>,
446
            >>(Method::POST, extra::route::WITH_REJECTION_VALIDIFY)
3✔
447
            .await?;
9✔
448
    }
449

450
    #[cfg(feature = "extra_typed_path")]
451
    {
452
        async fn test_extra_typed_path(
3✔
453
            test_executor: &TestExecutor,
454
            route: &str,
455
            server_url: &str,
456
        ) -> anyhow::Result<()> {
457
            do_test_extra_typed_path(
458
                test_executor,
459
                route,
460
                server_url,
461
                StatusCode::OK,
462
                StatusCode::BAD_REQUEST,
463
                VALIDATION_ERROR_STATUS,
464
                true,
465
            )
466
            .await
9✔
467
        }
468

469
        async fn test_extra_typed_path_modified(
3✔
470
            test_executor: &TestExecutor,
471
            route: &str,
472
            server_url: &str,
473
        ) -> anyhow::Result<()> {
474
            do_test_extra_typed_path(
475
                test_executor,
476
                route,
477
                server_url,
478
                StatusCode::OK,
479
                StatusCode::BAD_REQUEST,
480
                StatusCode::OK,
481
                false,
482
            )
483
            .await
9✔
484
        }
485

486
        async fn do_test_extra_typed_path(
3✔
487
            test_executor: &TestExecutor,
488
            route: &str,
489
            server_url: &str,
490
            expected_valid_status: StatusCode,
491
            expected_error_status: StatusCode,
492
            expected_invalid_status: StatusCode,
493
            should_check_json: bool,
494
        ) -> anyhow::Result<()> {
495
            let extra_typed_path_type_name = "T: TypedPath";
3✔
496
            let valid_extra_typed_path_response = test_executor
12✔
497
                .client()
498
                .get(format!(
21✔
499
                    "{}/{route}/{}/{}",
500
                    server_url, VALID_PARAMETERS.v0, VALID_PARAMETERS.v1
6✔
501
                ))
502
                .send()
503
                .await?;
9✔
504
            assert_eq!(
3✔
505
                valid_extra_typed_path_response.status(),
6✔
506
                expected_valid_status,
507
                "Validified '{}' test failed.",
508
                extra_typed_path_type_name
509
            );
510

511
            let error_extra_typed_path_response = test_executor
12✔
512
                .client()
513
                .get(format!("{}/{route}/not_i32/path", server_url))
9✔
514
                .send()
515
                .await?;
9✔
516
            assert_eq!(
3✔
517
                error_extra_typed_path_response.status(),
6✔
518
                expected_error_status,
519
                "Error '{}' test failed.",
520
                extra_typed_path_type_name
521
            );
522

523
            let invalid_extra_typed_path_response = test_executor
12✔
524
                .client()
525
                .get(format!(
21✔
526
                    "{}/{route}/{}/{}",
527
                    server_url, INVALID_PARAMETERS.v0, INVALID_PARAMETERS.v1
6✔
528
                ))
529
                .send()
530
                .await?;
9✔
531
            assert_eq!(
3✔
532
                invalid_extra_typed_path_response.status(),
6✔
533
                expected_invalid_status,
534
                "Invalid '{}' test failed.",
535
                extra_typed_path_type_name
536
            );
537
            #[cfg(feature = "into_json")]
538
            if should_check_json {
2✔
539
                check_json(
540
                    extra_typed_path_type_name,
2✔
541
                    invalid_extra_typed_path_response,
2✔
542
                )
543
                .await;
2✔
544
            }
545
            println!("All {} tests passed.", extra_typed_path_type_name);
6✔
546
            Ok(())
3✔
547
        }
548

549
        test_extra_typed_path(&test_executor, "extra_typed_path", &server_url).await?;
9✔
550
        test_extra_typed_path_modified(&test_executor, "extra_typed_path_modified", &server_url)
12✔
551
            .await?;
9✔
552
        test_extra_typed_path(
553
            &test_executor,
3✔
554
            "extra_typed_path_validified_by_ref",
555
            &server_url,
3✔
556
        )
557
        .await?;
9✔
558
    }
559

560
    #[cfg(feature = "extra_query")]
561
    {
562
        use axum_extra::extract::Query;
563
        test_executor
12✔
564
            .execute::<Query<ParametersValidify>>(Method::POST, extra_query::route::EXTRA_QUERY)
3✔
565
            .await?;
9✔
566
    }
567

568
    #[cfg(feature = "extra_form")]
569
    {
570
        use axum_extra::extract::Form;
571
        test_executor
12✔
572
            .execute::<Form<ParametersValidify>>(Method::POST, extra_form::route::EXTRA_FORM)
3✔
573
            .await?;
9✔
574
    }
575

576
    #[cfg(feature = "extra_protobuf")]
577
    {
578
        use axum_extra::protobuf::Protobuf;
579
        // Validated
580
        test_executor
12✔
581
            .execute::<Protobuf<ParametersValidify>>(
582
                Method::POST,
3✔
583
                extra_protobuf::route::EXTRA_PROTOBUF,
584
            )
585
            .await?;
9✔
586
        // Modified
587
        test_executor
12✔
588
            .execute_modified::<Protobuf<ParametersValidify>>(
589
                Method::POST,
3✔
590
                extra_protobuf::route::EXTRA_PROTOBUF_MODIFIED,
591
            )
592
            .await?;
9✔
593
        // ValidifiedByRef
594
        test_executor
12✔
595
            .execute::<Protobuf<ParametersValidify>>(
596
                Method::POST,
3✔
597
                extra_protobuf::route::EXTRA_PROTOBUF_VALIDIFIED_BY_REF,
598
            )
599
            .await?;
9✔
600
    }
601

602
    #[cfg(feature = "yaml")]
603
    {
604
        use axum_yaml::Yaml;
605
        test_executor
12✔
606
            .execute::<Yaml<ParametersValidify>>(Method::POST, yaml::route::YAML)
3✔
607
            .await?;
9✔
608
    }
609

610
    #[cfg(feature = "msgpack")]
611
    {
612
        use axum_msgpack::{MsgPack, MsgPackRaw};
613
        test_executor
12✔
614
            .execute::<MsgPack<ParametersValidify>>(Method::POST, msgpack::route::MSGPACK)
3✔
615
            .await?;
9✔
616
        test_executor
12✔
617
            .execute::<MsgPackRaw<ParametersValidify>>(Method::POST, msgpack::route::MSGPACK_RAW)
3✔
618
            .await?;
9✔
619
    }
620

621
    drop(server_guard);
3✔
622
    server_handle.await??;
6✔
623
    Ok(())
6✔
624
}
625

626
#[derive(Debug, Clone)]
627
pub struct TestExecutor {
628
    client: reqwest::Client,
629
    server_url: Url,
630
}
631

632
impl From<Url> for TestExecutor {
633
    fn from(server_url: Url) -> Self {
3✔
634
        Self {
635
            client: Default::default(),
3✔
636
            server_url,
637
        }
638
    }
639
}
640

641
impl TestExecutor {
642
    /// Execute all tests
643
    pub async fn execute<T: ValidTest>(&self, method: Method, route: &str) -> anyhow::Result<()> {
225✔
644
        self.do_execute::<T>(
90✔
645
            method,
×
646
            route,
×
647
            StatusCode::OK,
×
648
            T::ERROR_STATUS_CODE,
×
649
            T::INVALID_STATUS_CODE,
×
650
            true,
651
        )
652
        .await
135✔
653
    }
654

655
    /// Execute all tests for `Modified` without validation
656
    pub async fn execute_modified<T: ValidTest>(
15✔
657
        &self,
658
        method: Method,
659
        route: &str,
660
    ) -> anyhow::Result<()> {
661
        self.do_execute::<T>(
30✔
662
            method,
×
663
            route,
×
664
            StatusCode::OK,
×
665
            T::ERROR_STATUS_CODE,
×
666
            StatusCode::OK,
×
667
            false,
668
        )
669
        .await
45✔
670
    }
671

672
    /// Execute all tests for `Modified` without validation
673
    pub async fn execute_validified<T: ValidTest>(
9✔
674
        &self,
675
        method: Method,
676
        route: &str,
677
    ) -> anyhow::Result<()> {
678
        self.do_execute::<T>(
18✔
679
            method,
×
680
            route,
×
681
            StatusCode::OK,
×
682
            T::INVALID_STATUS_CODE,
×
683
            T::INVALID_STATUS_CODE,
×
684
            false,
685
        )
686
        .await
27✔
687
    }
688

689
    async fn do_execute<T: ValidTest>(
45✔
690
        &self,
691
        method: Method,
692
        route: &str,
693
        expected_valid_status: StatusCode,
694
        expected_error_status: StatusCode,
695
        expected_invalid_status: StatusCode,
696
        should_check_json: bool,
697
    ) -> anyhow::Result<()> {
698
        let url = {
×
699
            let mut url_builder = self.server_url.clone();
45✔
700
            url_builder.set_path(route);
45✔
701
            url_builder
45✔
702
        };
703

704
        let type_name = type_name::<T>();
90✔
705

706
        let valid_builder = self.client.request(method.clone(), url.clone());
90✔
707
        let valid_response = T::set_valid_request(valid_builder).send().await?;
135✔
708
        assert_eq!(
45✔
709
            valid_response.status(),
90✔
710
            expected_valid_status,
×
711
            "Validified '{}' test failed: {}.",
712
            type_name,
×
713
            valid_response.text().await?
×
714
        );
715

716
        let error_builder = self.client.request(method.clone(), url.clone());
90✔
717
        let error_response = T::set_error_request(error_builder).send().await?;
135✔
718
        assert_eq!(
45✔
719
            error_response.status(),
90✔
720
            expected_error_status,
×
721
            "Error '{}' test failed: {}.",
722
            type_name,
×
723
            error_response.text().await?
×
724
        );
725

726
        let invalid_builder = self.client.request(method, url);
45✔
727
        let invalid_response = T::set_invalid_request(invalid_builder).send().await?;
135✔
728
        assert_eq!(
45✔
729
            invalid_response.status(),
90✔
730
            expected_invalid_status,
×
731
            "Invalid '{}' test failed: {}.",
732
            type_name,
×
733
            invalid_response.text().await?
×
734
        );
735
        #[cfg(feature = "into_json")]
×
736
        if should_check_json && T::JSON_SERIALIZABLE {
40✔
737
            check_json(type_name, invalid_response).await;
28✔
738
        }
739

740
        println!("All '{}' tests passed.", type_name);
90✔
741
        Ok(())
45✔
742
    }
743

744
    pub fn client(&self) -> &reqwest::Client {
3✔
745
        &self.client
3✔
746
    }
747
}
748

749
/// Check if the response is a json response
750
#[cfg(feature = "into_json")]
751
pub async fn check_json(type_name: &'static str, response: reqwest::Response) {
12✔
752
    assert_eq!(
2✔
753
        response.headers()[axum::http::header::CONTENT_TYPE],
4✔
754
        axum::http::HeaderValue::from_static(mime::APPLICATION_JSON.as_ref()),
2✔
755
        "'{}' rejection into json test failed",
756
        type_name
757
    );
758
    assert!(response.json::<serde_json::Value>().await.is_ok());
2✔
759
}
760

761
mod route {
762
    pub const PATH: &str = "/path/:v0/:v1";
763
    pub const PATH_MODIFIED: &str = "/path_modified/:v0/:v1";
764
    pub const PATH_VALIDIFIED: &str = "/path_validified/:v0/:v1";
765
    pub const PATH_VALIDIFIED_BY_REF: &str = "/path_validified_by_ref/:v0/:v1";
766
    pub const QUERY: &str = "/query";
767
    pub const QUERY_MODIFIED: &str = "/query_modified/:v0/:v1";
768

769
    pub const QUERY_VALIDIFIED: &str = "/query_validified/:v0/:v1";
770
    pub const QUERY_VALIDIFIED_BY_REF: &str = "/query_validified_by_ref/:v0/:v1";
771
    pub const FORM: &str = "/form";
772
    pub const FORM_MODIFIED: &str = "/form_modified/:v0/:v1";
773
    pub const FORM_VALIDIFIED: &str = "/form_validified/:v0/:v1";
774
    pub const FORM_VALIDIFIED_BY_REF: &str = "/form_validified_by_ref/:v0/:v1";
775
    pub const JSON: &str = "/json";
776
    pub const JSON_MODIFIED: &str = "/json_modified/:v0/:v1";
777
    pub const JSON_VALIDIFIED: &str = "/json_validified/:v0/:v1";
778
    pub const JSON_VALIDIFIED_BY_REF: &str = "/json_validified_by_ref/:v0/:v1";
779
}
780

781
async fn extract_path(
3✔
782
    Validated(Path(parameters)): Validated<Path<ParametersValidify>>,
783
) -> StatusCode {
784
    check_validated(&parameters)
3✔
785
}
786

787
async fn extract_path_modified(
3✔
788
    Modified(Path(parameters)): Modified<Path<ParametersValidify>>,
789
) -> StatusCode {
790
    check_modified(&parameters)
3✔
791
}
792

793
async fn extract_path_validified(
3✔
794
    Validified(Path(parameters)): Validified<Path<ParametersValidify>>,
795
) -> StatusCode {
796
    check_validified(&parameters)
3✔
797
}
798

799
async fn extract_path_validified_by_ref(
3✔
800
    ValidifiedByRef(Path(parameters)): ValidifiedByRef<Path<ParametersValidify>>,
801
) -> StatusCode {
802
    check_validified(&parameters)
3✔
803
}
804

805
async fn extract_query(
3✔
806
    Validated(Query(parameters)): Validated<Query<ParametersValidify>>,
807
) -> StatusCode {
808
    check_validated(&parameters)
3✔
809
}
810

811
async fn extract_query_modified(
3✔
812
    Modified(Query(parameters)): Modified<Query<ParametersValidify>>,
813
) -> StatusCode {
814
    check_modified(&parameters)
3✔
815
}
816

817
async fn extract_query_validified(
3✔
818
    Validified(Query(parameters)): Validified<Query<ParametersValidify>>,
819
) -> StatusCode {
820
    check_validified(&parameters)
3✔
821
}
822

823
async fn extract_query_validified_by_ref(
3✔
824
    ValidifiedByRef(Query(parameters)): ValidifiedByRef<Query<ParametersValidify>>,
825
) -> StatusCode {
826
    check_validified(&parameters)
3✔
827
}
828

829
async fn extract_form(
3✔
830
    Validated(Form(parameters)): Validated<Form<ParametersValidify>>,
831
) -> StatusCode {
832
    check_validated(&parameters)
3✔
833
}
834

835
async fn extract_form_modified(
3✔
836
    Modified(Form(parameters)): Modified<Form<ParametersValidify>>,
837
) -> StatusCode {
838
    check_modified(&parameters)
3✔
839
}
840

841
async fn extract_form_validified(
3✔
842
    Validified(Form(parameters)): Validified<Form<ParametersValidify>>,
843
) -> StatusCode {
844
    check_validified(&parameters)
3✔
845
}
846

847
async fn extract_form_validified_by_ref(
3✔
848
    ValidifiedByRef(Form(parameters)): ValidifiedByRef<Form<ParametersValidify>>,
849
) -> StatusCode {
850
    check_validified(&parameters)
3✔
851
}
852

853
async fn extract_json(
3✔
854
    Validated(Json(parameters)): Validated<Json<ParametersValidify>>,
855
) -> StatusCode {
856
    check_validated(&parameters)
3✔
857
}
858

859
async fn extract_json_modified(
3✔
860
    Modified(Json(parameters)): Modified<Json<ParametersValidify>>,
861
) -> StatusCode {
862
    check_modified(&parameters)
3✔
863
}
864

865
async fn extract_json_validified(
3✔
866
    Validified(Json(parameters)): Validified<Json<ParametersValidify>>,
867
) -> StatusCode {
868
    check_validified(&parameters)
3✔
869
}
870

871
async fn extract_json_validified_by_ref(
3✔
872
    ValidifiedByRef(Json(parameters)): ValidifiedByRef<Json<ParametersValidify>>,
873
) -> StatusCode {
874
    check_validified(&parameters)
3✔
875
}
876

877
fn check_validated<V: Validate>(validate: &V) -> StatusCode {
9✔
878
    // The `Validified` extractor has validated the `parameters` once,
879
    // it should have returned `400 BAD REQUEST` if the `parameters` were invalid,
880
    // Let's validate them again to check if the `Validified` extractor works well.
881
    // If it works properly, this function will never return `500 INTERNAL SERVER ERROR`
882
    match validate.validate() {
9✔
883
        Ok(_) => StatusCode::OK,
9✔
884
        Err(_) => StatusCode::INTERNAL_SERVER_ERROR,
×
885
    }
886
}
887

888
fn check_modified<M: IsModified>(modify: &M) -> StatusCode {
9✔
889
    if modify.modified() {
9✔
890
        StatusCode::OK
9✔
891
    } else {
892
        StatusCode::INTERNAL_SERVER_ERROR
×
893
    }
894
}
895

896
fn check_validified<D: IsModified + Validate>(data: &D) -> StatusCode {
6✔
897
    let status = check_modified(data);
6✔
898
    if status != StatusCode::OK {
6✔
899
        return status;
×
900
    }
901

902
    check_validated(data)
6✔
903
}
904

905
#[cfg(feature = "typed_header")]
906
mod typed_header {
907

908
    pub(crate) mod route {
909
        pub const TYPED_HEADER: &str = "/typed_header";
910
        pub const TYPED_HEADER_MODIFIED: &str = "/typed_header_modified";
911
        pub const TYPED_HEADER_VALIDIFIED_BY_REF: &str = "/typed_header_validified_be_ref";
912
    }
913

914
    use super::{check_modified, check_validated, check_validified, ParametersValidify};
915
    use crate::{Modified, Validated, ValidifiedByRef};
916
    use axum::headers::{Error, Header, HeaderName, HeaderValue};
917
    use axum::http::StatusCode;
918
    use axum::TypedHeader;
919

920
    pub static AXUM_VALID_PARAMETERS: HeaderName = HeaderName::from_static("axum-valid-parameters");
921

922
    pub(super) async fn extract_typed_header(
3✔
923
        Validated(TypedHeader(parameters)): Validated<TypedHeader<ParametersValidify>>,
924
    ) -> StatusCode {
925
        check_validated(&parameters)
3✔
926
    }
927

928
    pub(super) async fn extract_typed_header_modified(
3✔
929
        Modified(TypedHeader(parameters)): Modified<TypedHeader<ParametersValidify>>,
930
    ) -> StatusCode {
931
        check_modified(&parameters)
3✔
932
    }
933

934
    pub(super) async fn extract_typed_header_validified_by_ref(
3✔
935
        ValidifiedByRef(TypedHeader(parameters)): ValidifiedByRef<TypedHeader<ParametersValidify>>,
936
    ) -> StatusCode {
937
        check_validified(&parameters)
3✔
938
    }
939

940
    impl Header for ParametersValidify {
941
        fn name() -> &'static HeaderName {
942
            &AXUM_VALID_PARAMETERS
943
        }
944

945
        fn decode<'i, I>(values: &mut I) -> Result<Self, Error>
6✔
946
        where
947
            Self: Sized,
948
            I: Iterator<Item = &'i HeaderValue>,
949
        {
950
            let value = values.next().ok_or_else(Error::invalid)?;
9✔
951
            let src = std::str::from_utf8(value.as_bytes()).map_err(|_| Error::invalid())?;
12✔
952
            let split = src.split(',').collect::<Vec<_>>();
6✔
953
            match split.as_slice() {
6✔
954
                [v0, v1] => Ok(ParametersValidify {
18✔
955
                    v0: v0.parse().map_err(|_| Error::invalid())?,
18✔
956
                    v1: v1.to_string(),
6✔
957
                }),
958
                _ => Err(Error::invalid()),
×
959
            }
960
        }
961

962
        fn encode<E: Extend<HeaderValue>>(&self, values: &mut E) {
6✔
963
            let v0 = self.v0.to_string();
6✔
964
            let mut vec = Vec::with_capacity(v0.len() + 1 + self.v1.len());
12✔
965
            vec.extend_from_slice(v0.as_bytes());
12✔
966
            vec.push(b',');
6✔
967
            vec.extend_from_slice(self.v1.as_bytes());
6✔
968
            let value = HeaderValue::from_bytes(&vec).expect("Failed to build header");
6✔
969
            values.extend(::std::iter::once(value));
6✔
970
        }
971
    }
972

973
    #[test]
974
    fn parameter_is_header() -> anyhow::Result<()> {
975
        let parameter = ParametersValidify {
976
            v0: 123456,
977
            v1: "111111".to_string(),
978
        };
979
        let mut vec = Vec::new();
980
        parameter.encode(&mut vec);
981
        let mut iter = vec.iter();
982
        assert_eq!(parameter, ParametersValidify::decode(&mut iter)?);
983
        Ok(())
984
    }
985
}
986

987
#[cfg(feature = "typed_multipart")]
988
mod typed_multipart {
989
    use super::{check_validated, ParametersValidify};
990
    use crate::Validated;
991
    use axum::http::StatusCode;
992
    use axum_typed_multipart::{BaseMultipart, TypedMultipart, TypedMultipartError};
993

994
    pub mod route {
995
        pub const TYPED_MULTIPART: &str = "/typed_multipart";
996
        pub const BASE_MULTIPART: &str = "/base_multipart";
997
    }
998

999
    impl From<&ParametersValidify> for reqwest::multipart::Form {
1000
        fn from(value: &ParametersValidify) -> Self {
3✔
1001
            reqwest::multipart::Form::new()
9✔
1002
                .text("v0", value.v0.to_string())
6✔
1003
                .text("v1", value.v1.clone())
6✔
1004
        }
1005
    }
1006

1007
    pub(super) async fn extract_typed_multipart(
3✔
1008
        Validated(TypedMultipart(parameters)): Validated<TypedMultipart<ParametersValidify>>,
1009
    ) -> StatusCode {
1010
        check_validated(&parameters)
3✔
1011
    }
1012

1013
    pub(super) async fn extract_base_multipart(
3✔
1014
        Validated(BaseMultipart { data, .. }): Validated<
1015
            BaseMultipart<ParametersValidify, TypedMultipartError>,
1016
        >,
1017
    ) -> StatusCode {
1018
        check_validated(&data)
3✔
1019
    }
1020
}
1021

1022
#[cfg(feature = "extra")]
1023
mod extra {
1024
    use super::{check_validated, ParametersValidify};
1025
    use crate::tests::{Rejection, ValidTest, ValidTestParameter};
1026
    use crate::{Validated, ValidifyRejection};
1027
    use axum::extract::FromRequestParts;
1028
    use axum::http::request::Parts;
1029
    use axum::http::StatusCode;
1030
    use axum::response::{IntoResponse, Response};
1031
    use axum_extra::extract::{Cached, WithRejection};
1032
    use reqwest::RequestBuilder;
1033

1034
    pub mod route {
1035
        pub const CACHED: &str = "/cached";
1036
        pub const WITH_REJECTION: &str = "/with_rejection";
1037
        pub const WITH_REJECTION_VALIDIFY: &str = "/with_rejection_validify";
1038
    }
1039
    pub const PARAMETERS_HEADER: &str = "parameters-header";
1040
    pub const CACHED_REJECTION_STATUS: StatusCode = StatusCode::FORBIDDEN;
1041

1042
    //  1.2. Define you own `Rejection` type and implement `IntoResponse` for it.
1043
    pub enum ParametersRejection {
1044
        Null,
1045
        InvalidJson(serde_json::error::Error),
1046
    }
1047

1048
    impl IntoResponse for ParametersRejection {
1049
        fn into_response(self) -> Response {
3✔
1050
            match self {
3✔
1051
                ParametersRejection::Null => {
1052
                    (CACHED_REJECTION_STATUS, "My-Data header is missing").into_response()
×
1053
                }
1054
                ParametersRejection::InvalidJson(e) => (
6✔
1055
                    CACHED_REJECTION_STATUS,
1056
                    format!("My-Data is not valid json string: {e}"),
3✔
1057
                )
1058
                    .into_response(),
1059
            }
1060
        }
1061
    }
1062

1063
    //  1.3. Implement your extractor (`FromRequestParts` or `FromRequest`)
1064
    #[axum::async_trait]
1065
    impl<S> FromRequestParts<S> for ParametersValidify
1066
    where
1067
        S: Send + Sync,
1068
    {
1069
        type Rejection = ParametersRejection;
1070

1071
        async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
15✔
1072
            let Some(value) = parts.headers.get(PARAMETERS_HEADER) else {
3✔
1073
                return Err(ParametersRejection::Null);
×
1074
            };
1075

1076
            serde_json::from_slice(value.as_bytes()).map_err(ParametersRejection::InvalidJson)
6✔
1077
        }
1078
    }
1079

1080
    impl ValidTest for ParametersValidify {
1081
        const ERROR_STATUS_CODE: StatusCode = CACHED_REJECTION_STATUS;
1082

1083
        fn set_valid_request(builder: RequestBuilder) -> RequestBuilder {
3✔
1084
            builder.header(
6✔
1085
                PARAMETERS_HEADER,
1086
                serde_json::to_string(ParametersValidify::valid())
6✔
1087
                    .expect("Failed to serialize parameters"),
1088
            )
1089
        }
1090

1091
        fn set_error_request(builder: RequestBuilder) -> RequestBuilder {
3✔
1092
            builder.header(
6✔
1093
                PARAMETERS_HEADER,
1094
                serde_json::to_string(ParametersValidify::error())
6✔
1095
                    .expect("Failed to serialize parameters"),
1096
            )
1097
        }
1098

1099
        fn set_invalid_request(builder: RequestBuilder) -> RequestBuilder {
3✔
1100
            builder.header(
6✔
1101
                PARAMETERS_HEADER,
1102
                serde_json::to_string(ParametersValidify::invalid())
6✔
1103
                    .expect("Failed to serialize parameters"),
1104
            )
1105
        }
1106
    }
1107

1108
    pub struct ValidifyWithRejectionRejection {
1109
        inner: ParametersRejection,
1110
    }
1111

1112
    impl Rejection for ValidifyWithRejectionRejection {
1113
        const STATUS_CODE: StatusCode = StatusCode::CONFLICT;
1114
    }
1115

1116
    impl IntoResponse for ValidifyWithRejectionRejection {
1117
        fn into_response(self) -> Response {
3✔
1118
            let mut response = self.inner.into_response();
3✔
1119
            *response.status_mut() = Self::STATUS_CODE;
6✔
1120
            response
3✔
1121
        }
1122
    }
1123

1124
    // satisfy the `WithRejection`'s extractor trait bound
1125
    // R: From<E::Rejection> + IntoResponse
1126
    impl From<ParametersRejection> for ValidifyWithRejectionRejection {
1127
        fn from(inner: ParametersRejection) -> Self {
3✔
1128
            Self { inner }
1129
        }
1130
    }
1131

1132
    pub async fn extract_cached(
3✔
1133
        Validated(Cached(parameters)): Validated<Cached<ParametersValidify>>,
1134
    ) -> StatusCode {
1135
        check_validated(&parameters)
3✔
1136
    }
1137

1138
    pub async fn extract_with_rejection(
3✔
1139
        Validated(WithRejection(parameters, _)): Validated<
1140
            WithRejection<ParametersValidify, ValidifyWithRejectionRejection>,
1141
        >,
1142
    ) -> StatusCode {
1143
        check_validated(&parameters)
3✔
1144
    }
1145

1146
    pub struct WithRejectionValidifyRejection<E> {
1147
        inner: ValidifyRejection<E>,
1148
    }
1149

1150
    impl<E> From<ValidifyRejection<E>> for WithRejectionValidifyRejection<E> {
1151
        fn from(inner: ValidifyRejection<E>) -> Self {
3✔
1152
            Self { inner }
1153
        }
1154
    }
1155

1156
    impl<E: IntoResponse> IntoResponse for WithRejectionValidifyRejection<E> {
1157
        fn into_response(self) -> Response {
3✔
1158
            let mut res = self.inner.into_response();
3✔
1159
            *res.status_mut() = StatusCode::IM_A_TEAPOT;
6✔
1160
            res
3✔
1161
        }
1162
    }
1163

1164
    pub async fn extract_with_rejection_valid(
3✔
1165
        WithRejection(Validated(parameters), _): WithRejection<
1166
            Validated<ParametersValidify>,
1167
            WithRejectionValidifyRejection<ParametersRejection>,
1168
        >,
1169
    ) -> StatusCode {
1170
        check_validated(&parameters)
3✔
1171
    }
1172
}
1173

1174
#[cfg(feature = "extra_typed_path")]
1175
mod extra_typed_path {
1176
    use super::{check_modified, check_validated, check_validified};
1177
    use crate::{HasModify, HasValidate, Modified, Validated, ValidifiedByRef};
1178
    use axum::http::StatusCode;
1179
    use axum_extra::routing::TypedPath;
1180
    use serde::Deserialize;
1181
    use validify::{Validate, Validify};
1182

1183
    pub mod route {
1184
        pub const EXTRA_TYPED_PATH: &str = "/extra_typed_path/:v0/:v1";
1185
        pub const EXTRA_TYPED_PATH_MODIFIED: &str = "/extra_typed_path_modified/:v0/:v1";
1186
        pub const EXTRA_TYPED_PATH_VALIDIFIED_BY_REF: &str =
1187
            "/extra_typed_path_validified_by_ref/:v0/:v1";
1188
    }
1189

1190
    #[derive(Validate, TypedPath, Deserialize)]
1191
    #[typed_path("/extra_typed_path/:v0/:v1")]
1192
    pub struct TypedPathParam {
1193
        #[validate(range(min = 5.0, max = 10.0))]
1194
        v0: i32,
1195
        #[validate(length(min = 1, max = 10))]
1196
        v1: String,
1197
    }
1198

1199
    impl HasValidate for TypedPathParam {
1200
        type Validate = Self;
1201

1202
        fn get_validate(&self) -> &Self::Validate {
3✔
1203
            self
1204
        }
1205
    }
1206

1207
    #[derive(Validify, TypedPath, Deserialize, Clone, PartialEq, Eq)]
1208
    #[typed_path("/extra_typed_path_validified_by_ref/:v0/:v1")]
1209
    pub struct TypedPathParamValidifiedByRef {
1210
        #[validate(range(min = 5.0, max = 10.0))]
1211
        v0: i32,
1212
        #[modify(lowercase)]
1213
        #[validate(length(min = 1, max = 10))]
1214
        v1: String,
1215
    }
1216

1217
    impl HasValidate for TypedPathParamValidifiedByRef {
1218
        type Validate = Self;
1219

1220
        fn get_validate(&self) -> &Self::Validate {
3✔
1221
            self
1222
        }
1223
    }
1224

1225
    impl HasModify for TypedPathParamValidifiedByRef {
1226
        type Modify = Self;
1227

1228
        fn get_modify(&mut self) -> &mut Self::Modify {
3✔
1229
            self
1230
        }
1231
    }
1232

1233
    #[derive(Validify, TypedPath, Deserialize, Clone, PartialEq, Eq)]
1234
    #[typed_path("/extra_typed_path_modified/:v0/:v1")]
1235
    pub struct TypedPathParamModified {
1236
        #[validate(range(min = 5.0, max = 10.0))]
1237
        v0: i32,
1238
        #[modify(lowercase)]
1239
        #[validate(length(min = 1, max = 10))]
1240
        v1: String,
1241
    }
1242

1243
    impl HasModify for TypedPathParamModified {
1244
        type Modify = Self;
1245

1246
        fn get_modify(&mut self) -> &mut Self::Modify {
3✔
1247
            self
1248
        }
1249
    }
1250

1251
    pub async fn extract_extra_typed_path(
3✔
1252
        Validated(param): Validated<TypedPathParam>,
1253
    ) -> StatusCode {
1254
        check_validated(&param)
3✔
1255
    }
1256

1257
    pub async fn extract_extra_typed_path_modified(
3✔
1258
        Modified(param): Modified<TypedPathParamModified>,
1259
    ) -> StatusCode {
1260
        check_modified(&param)
3✔
1261
    }
1262

1263
    pub async fn extract_extra_typed_path_validified_by_ref(
3✔
1264
        ValidifiedByRef(param): ValidifiedByRef<TypedPathParamValidifiedByRef>,
1265
    ) -> StatusCode {
1266
        check_validified(&param)
3✔
1267
    }
1268
}
1269

1270
#[cfg(feature = "extra_query")]
1271
mod extra_query {
1272
    use super::{check_validated, ParametersValidify};
1273
    use crate::Validated;
1274
    use axum::http::StatusCode;
1275
    use axum_extra::extract::Query;
1276

1277
    pub mod route {
1278
        pub const EXTRA_QUERY: &str = "/extra_query";
1279
    }
1280

1281
    pub async fn extract_extra_query(
3✔
1282
        Validated(Query(parameters)): Validated<Query<ParametersValidify>>,
1283
    ) -> StatusCode {
1284
        check_validated(&parameters)
3✔
1285
    }
1286
}
1287

1288
#[cfg(feature = "extra_form")]
1289
mod extra_form {
1290
    use super::{check_validated, ParametersValidify};
1291
    use crate::Validated;
1292
    use axum::http::StatusCode;
1293
    use axum_extra::extract::Form;
1294

1295
    pub mod route {
1296
        pub const EXTRA_FORM: &str = "/extra_form";
1297
    }
1298

1299
    pub async fn extract_extra_form(
3✔
1300
        Validated(Form(parameters)): Validated<Form<ParametersValidify>>,
1301
    ) -> StatusCode {
1302
        check_validated(&parameters)
3✔
1303
    }
1304
}
1305

1306
#[cfg(feature = "extra_protobuf")]
1307
mod extra_protobuf {
1308
    use super::{check_modified, check_validated, check_validified, ParametersValidify};
1309
    use crate::{Modified, Validated, ValidifiedByRef};
1310
    use axum::http::StatusCode;
1311
    use axum_extra::protobuf::Protobuf;
1312

1313
    pub mod route {
1314
        pub const EXTRA_PROTOBUF: &str = "/extra_protobuf";
1315
        pub const EXTRA_PROTOBUF_MODIFIED: &str = "/extra_protobuf_modified";
1316
        pub const EXTRA_PROTOBUF_VALIDIFIED_BY_REF: &str = "/extra_protobuf_validified_by_ref";
1317
    }
1318

1319
    pub async fn extract_extra_protobuf(
3✔
1320
        Validated(Protobuf(parameters)): Validated<Protobuf<ParametersValidify>>,
1321
    ) -> StatusCode {
1322
        check_validated(&parameters)
3✔
1323
    }
1324

1325
    pub async fn extract_extra_protobuf_modified(
3✔
1326
        Modified(Protobuf(parameters)): Modified<Protobuf<ParametersValidify>>,
1327
    ) -> StatusCode {
1328
        check_modified(&parameters)
3✔
1329
    }
1330

1331
    pub async fn extract_extra_protobuf_validified_by_ref(
3✔
1332
        ValidifiedByRef(Protobuf(parameters)): ValidifiedByRef<Protobuf<ParametersValidify>>,
1333
    ) -> StatusCode {
1334
        check_validified(&parameters)
3✔
1335
    }
1336
}
1337

1338
#[cfg(feature = "yaml")]
1339
mod yaml {
1340
    use super::{check_validated, ParametersValidify};
1341
    use crate::Validated;
1342
    use axum::http::StatusCode;
1343
    use axum_yaml::Yaml;
1344

1345
    pub mod route {
1346
        pub const YAML: &str = "/yaml";
1347
    }
1348

1349
    pub async fn extract_yaml(
3✔
1350
        Validated(Yaml(parameters)): Validated<Yaml<ParametersValidify>>,
1351
    ) -> StatusCode {
1352
        check_validated(&parameters)
3✔
1353
    }
1354
}
1355

1356
#[cfg(feature = "msgpack")]
1357
mod msgpack {
1358
    use super::{check_validated, ParametersValidify};
1359
    use crate::Validated;
1360
    use axum::http::StatusCode;
1361
    use axum_msgpack::{MsgPack, MsgPackRaw};
1362

1363
    pub mod route {
1364
        pub const MSGPACK: &str = "/msgpack";
1365
        pub const MSGPACK_RAW: &str = "/msgpack_raw";
1366
    }
1367

1368
    pub async fn extract_msgpack(
3✔
1369
        Validated(MsgPack(parameters)): Validated<MsgPack<ParametersValidify>>,
1370
    ) -> StatusCode {
1371
        check_validated(&parameters)
3✔
1372
    }
1373
    pub async fn extract_msgpack_raw(
3✔
1374
        Validated(MsgPackRaw(parameters)): Validated<MsgPackRaw<ParametersValidify>>,
1375
    ) -> StatusCode {
1376
        check_validated(&parameters)
3✔
1377
    }
1378
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc