1
1
use log:: LevelFilter ;
2
+ use std:: error:: Error ;
3
+ use std:: fmt:: { Display , Formatter } ;
2
4
3
5
use crate :: Directive ;
4
6
use crate :: FilterOp ;
@@ -22,8 +24,36 @@ impl ParseResult {
22
24
fn add_error ( & mut self , message : String ) {
23
25
self . errors . push ( message) ;
24
26
}
27
+
28
+ pub ( crate ) fn ok ( self ) -> Result < ( Vec < Directive > , Option < FilterOp > ) , ParseError > {
29
+ if self . errors . is_empty ( ) {
30
+ Ok ( ( self . directives , self . filter ) )
31
+ } else {
32
+ Err ( ParseError {
33
+ details : self . errors ,
34
+ } )
35
+ }
36
+ }
25
37
}
26
38
39
+ /// Error during logger directive parsing process.
40
+ #[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
41
+ pub struct ParseError {
42
+ details : Vec < String > ,
43
+ }
44
+
45
+ impl Display for ParseError {
46
+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
47
+ write ! (
48
+ f,
49
+ "error parsing logger filter: {}" ,
50
+ self . details. join( ", " )
51
+ )
52
+ }
53
+ }
54
+
55
+ impl Error for ParseError { }
56
+
27
57
/// Parse a logging specification string (e.g: `crate1,crate2::mod3,crate3::x=error/foo`)
28
58
/// and return a vector with log directives.
29
59
pub ( crate ) fn parse_spec ( spec : & str ) -> ParseResult {
@@ -376,11 +406,117 @@ mod tests {
376
406
let ParseResult {
377
407
directives : dirs,
378
408
filter,
379
- ..
409
+ errors ,
380
410
} = parse_spec ( "crate1/a*c" ) ;
381
411
assert_eq ! ( dirs. len( ) , 1 ) ;
382
412
assert_eq ! ( dirs[ 0 ] . name, Some ( "crate1" . to_owned( ) ) ) ;
383
413
assert_eq ! ( dirs[ 0 ] . level, LevelFilter :: max( ) ) ;
384
414
assert ! ( filter. is_some( ) && filter. unwrap( ) . to_string( ) == "a*c" ) ;
415
+ assert ! ( errors. is_empty( ) ) ;
416
+ }
417
+
418
+ #[ test]
419
+ fn parse_spec_with_multiple_filters ( ) {
420
+ let ParseResult {
421
+ directives : dirs,
422
+ filter,
423
+ errors,
424
+ } = parse_spec ( "debug/abc/a.c" ) ;
425
+ assert ! ( dirs. is_empty( ) ) ;
426
+ assert ! ( filter. is_none( ) ) ;
427
+
428
+ assert_eq ! ( errors. len( ) , 1 ) ;
429
+ assert_data_eq ! (
430
+ & errors[ 0 ] ,
431
+ str ![ "invalid logging spec 'debug/abc/a.c' (too many '/'s)" ]
432
+ ) ;
433
+ }
434
+
435
+ #[ test]
436
+ fn parse_spec_multiple_invalid_crates ( ) {
437
+ // test parse_spec with multiple = in specification
438
+ let ParseResult {
439
+ directives : dirs,
440
+ filter,
441
+ errors,
442
+ } = parse_spec ( "crate1::mod1=warn=info,crate2=debug,crate3=error=error" ) ;
443
+
444
+ assert_eq ! ( dirs. len( ) , 1 ) ;
445
+ assert_eq ! ( dirs[ 0 ] . name, Some ( "crate2" . to_owned( ) ) ) ;
446
+ assert_eq ! ( dirs[ 0 ] . level, LevelFilter :: Debug ) ;
447
+ assert ! ( filter. is_none( ) ) ;
448
+
449
+ assert_eq ! ( errors. len( ) , 2 ) ;
450
+ assert_data_eq ! (
451
+ & errors[ 0 ] ,
452
+ str ![ "invalid logging spec 'crate1::mod1=warn=info'" ]
453
+ ) ;
454
+ assert_data_eq ! (
455
+ & errors[ 1 ] ,
456
+ str ![ "invalid logging spec 'crate3=error=error'" ]
457
+ ) ;
458
+ }
459
+
460
+ #[ test]
461
+ fn parse_spec_multiple_invalid_levels ( ) {
462
+ // test parse_spec with 'noNumber' as log level
463
+ let ParseResult {
464
+ directives : dirs,
465
+ filter,
466
+ errors,
467
+ } = parse_spec ( "crate1::mod1=noNumber,crate2=debug,crate3=invalid" ) ;
468
+
469
+ assert_eq ! ( dirs. len( ) , 1 ) ;
470
+ assert_eq ! ( dirs[ 0 ] . name, Some ( "crate2" . to_owned( ) ) ) ;
471
+ assert_eq ! ( dirs[ 0 ] . level, LevelFilter :: Debug ) ;
472
+ assert ! ( filter. is_none( ) ) ;
473
+
474
+ assert_eq ! ( errors. len( ) , 2 ) ;
475
+ assert_data_eq ! ( & errors[ 0 ] , str ![ "invalid logging spec 'noNumber'" ] ) ;
476
+ assert_data_eq ! ( & errors[ 1 ] , str ![ "invalid logging spec 'invalid'" ] ) ;
477
+ }
478
+
479
+ #[ test]
480
+ fn parse_spec_invalid_crate_and_level ( ) {
481
+ // test parse_spec with 'noNumber' as log level
482
+ let ParseResult {
483
+ directives : dirs,
484
+ filter,
485
+ errors,
486
+ } = parse_spec ( "crate1::mod1=debug=info,crate2=debug,crate3=invalid" ) ;
487
+
488
+ assert_eq ! ( dirs. len( ) , 1 ) ;
489
+ assert_eq ! ( dirs[ 0 ] . name, Some ( "crate2" . to_owned( ) ) ) ;
490
+ assert_eq ! ( dirs[ 0 ] . level, LevelFilter :: Debug ) ;
491
+ assert ! ( filter. is_none( ) ) ;
492
+
493
+ assert_eq ! ( errors. len( ) , 2 ) ;
494
+ assert_data_eq ! (
495
+ & errors[ 0 ] ,
496
+ str ![ "invalid logging spec 'crate1::mod1=debug=info'" ]
497
+ ) ;
498
+ assert_data_eq ! ( & errors[ 1 ] , str ![ "invalid logging spec 'invalid'" ] ) ;
499
+ }
500
+
501
+ #[ test]
502
+ fn parse_error_message_single_error ( ) {
503
+ let error = parse_spec ( "crate1::mod1=debug=info,crate2=debug" )
504
+ . ok ( )
505
+ . unwrap_err ( ) ;
506
+ assert_data_eq ! (
507
+ error,
508
+ str ![ "error parsing logger filter: invalid logging spec 'crate1::mod1=debug=info'" ]
509
+ ) ;
510
+ }
511
+
512
+ #[ test]
513
+ fn parse_error_message_multiple_errors ( ) {
514
+ let error = parse_spec ( "crate1::mod1=debug=info,crate2=debug,crate3=invalid" )
515
+ . ok ( )
516
+ . unwrap_err ( ) ;
517
+ assert_data_eq ! (
518
+ error,
519
+ str ![ "error parsing logger filter: invalid logging spec 'crate1::mod1=debug=info', invalid logging spec 'invalid'" ]
520
+ ) ;
385
521
}
386
522
}
0 commit comments