From 9b8a8f49dc7a691ca198716d556a674f50e57d38 Mon Sep 17 00:00:00 2001 From: Yijun Yu Date: Sun, 20 Dec 2020 23:01:18 +0000 Subject: [PATCH 1/4] Add new Ratio output type --output-format=Ratio: report safe ratio rather than unsafe count --- cargo-geiger/src/args.rs | 2 +- cargo-geiger/src/format/print_config.rs | 1 + cargo-geiger/src/format/table.rs | 89 +++++++++++++------ .../src/format/table/handle_text_tree_line.rs | 2 +- cargo-geiger/src/scan/default/table.rs | 18 ++-- 5 files changed, 80 insertions(+), 32 deletions(-) diff --git a/cargo-geiger/src/args.rs b/cargo-geiger/src/args.rs index 00b31eaf..44131faa 100644 --- a/cargo-geiger/src/args.rs +++ b/cargo-geiger/src/args.rs @@ -31,7 +31,7 @@ OPTIONS: --format Format string used for printing dependencies [default: {p}]. --output-format Output format for the report: Ascii, GitHubMarkdown, - Json, Utf8 [default: Utf8] + Json, Utf8, Ratio [default: Utf8] --update-readme Writes output to ./README.md. Looks for a Safety Report section, replaces if found, adds if not. Throws an error if no README.md exists. diff --git a/cargo-geiger/src/format/print_config.rs b/cargo-geiger/src/format/print_config.rs index aa56637e..4e1d63aa 100644 --- a/cargo-geiger/src/format/print_config.rs +++ b/cargo-geiger/src/format/print_config.rs @@ -22,6 +22,7 @@ pub enum OutputFormat { Json, GitHubMarkdown, Utf8, + Ratio, } impl Default for OutputFormat { diff --git a/cargo-geiger/src/format/table.rs b/cargo-geiger/src/format/table.rs index 330d0967..82033122 100644 --- a/cargo-geiger/src/format/table.rs +++ b/cargo-geiger/src/format/table.rs @@ -107,32 +107,71 @@ fn table_footer( output_format: OutputFormat, status: CrateDetectionStatus, ) -> ColoredString { - let fmt = |used: &Count, not_used: &Count| { - format!("{}/{}", used.unsafe_, used.unsafe_ + not_used.unsafe_) - }; - let output = format!( - "{: <10} {: <12} {: <6} {: <7} {: <7}", - fmt(&used.functions, ¬_used.functions), - fmt(&used.exprs, ¬_used.exprs), - fmt(&used.item_impls, ¬_used.item_impls), - fmt(&used.item_traits, ¬_used.item_traits), - fmt(&used.methods, ¬_used.methods), - ); - colorize(&status, output_format, output) + match output_format { + OutputFormat::Ratio => { // print safe ratio + let fmt = |used: &Count, not_used: &Count| { + format!("{:>5}/{:<}={:.2}%", (used.safe + not_used.safe), (used.safe + used.unsafe_ + not_used.unsafe_ + not_used.safe), + if used.safe + used.unsafe_ + not_used.unsafe_ + not_used.safe == 0 { 100.0 } + else {(100.00*(used.safe + not_used.safe) as f32)/((used.safe + used.unsafe_ + not_used.unsafe_ + not_used.safe) as f32)} + ) + }; + let output = format!( + "{: <12} {: <18} {: <18} {: <12} {: <12}", + fmt(&used.functions, ¬_used.functions), + fmt(&used.exprs, ¬_used.exprs), + fmt(&used.item_impls, ¬_used.item_impls), + fmt(&used.item_traits, ¬_used.item_traits), + fmt(&used.methods, ¬_used.methods), + ); + colorize(&status, output_format, output) + } + _ => { + let fmt = |used: &Count, not_used: &Count| { + format!("{}/{}", used.unsafe_, used.unsafe_ + not_used.unsafe_) + }; + let output = format!( + "{: <10} {: <12} {: <6} {: <7} {: <7}", + fmt(&used.functions, ¬_used.functions), + fmt(&used.exprs, ¬_used.exprs), + fmt(&used.item_impls, ¬_used.item_impls), + fmt(&used.item_traits, ¬_used.item_traits), + fmt(&used.methods, ¬_used.methods), + ); + colorize(&status, output_format, output) + } + } } -fn table_row(used: &CounterBlock, not_used: &CounterBlock) -> String { - let fmt = |used: &Count, not_used: &Count| { - format!("{}/{}", used.unsafe_, used.unsafe_ + not_used.unsafe_) - }; - format!( - "{: <10} {: <12} {: <6} {: <7} {: <7}", - fmt(&used.functions, ¬_used.functions), - fmt(&used.exprs, ¬_used.exprs), - fmt(&used.item_impls, ¬_used.item_impls), - fmt(&used.item_traits, ¬_used.item_traits), - fmt(&used.methods, ¬_used.methods), - ) +fn table_row(used: &CounterBlock, not_used: &CounterBlock, output_format: OutputFormat) -> String { + match output_format { + OutputFormat::Ratio => { // print safe ratio + let fmt = |used: &Count, not_used: &Count| { + format!("{:>5}/{:<}={:.2}%", (used.safe + not_used.safe), (used.safe + used.unsafe_ + not_used.unsafe_ + not_used.safe), + if used.safe + used.unsafe_ + not_used.unsafe_ + not_used.safe == 0 { 100.0 } + else {(100.00*(used.safe + not_used.safe) as f32)/((used.safe + used.unsafe_ + not_used.unsafe_ + not_used.safe) as f32)} + ) + }; + format!("{: <12} {: <18} {: <18} {: <12} {: <12}", + fmt(&used.functions, ¬_used.functions), + fmt(&used.exprs, ¬_used.exprs), + fmt(&used.item_impls, ¬_used.item_impls), + fmt(&used.item_traits, ¬_used.item_traits), + fmt(&used.methods, ¬_used.methods) + ) + } + _ => { + let fmt = |used: &Count, not_used: &Count| { + format!("{}/{}", used.unsafe_, used.unsafe_ + not_used.unsafe_) + }; + format!("{: <10} {: <12} {: <6} {: <7} {: <7}", + fmt(&used.functions, ¬_used.functions), + fmt(&used.exprs, ¬_used.exprs), + fmt(&used.item_impls, ¬_used.item_impls), + fmt(&used.item_traits, ¬_used.item_traits), + fmt(&used.methods, ¬_used.methods) + ) + } + } } fn table_row_empty() -> String { @@ -142,7 +181,7 @@ fn table_row_empty() -> String { .iter() .map(|s| s.len()) .sum::() - + headers_but_last.len() // Space after each column + + headers_but_last.len() + 4// Space after each column + 2 // Unsafety symbol width + 1; // Space after symbol " ".repeat(n) diff --git a/cargo-geiger/src/format/table/handle_text_tree_line.rs b/cargo-geiger/src/format/table/handle_text_tree_line.rs index 6ea665d3..437c1b93 100644 --- a/cargo-geiger/src/format/table/handle_text_tree_line.rs +++ b/cargo-geiger/src/format/table/handle_text_tree_line.rs @@ -104,7 +104,7 @@ pub fn handle_text_tree_line_package( let unsafe_info = colorize( &crate_detection_status, table_parameters.print_config.output_format, - table_row(&unsafe_info.used, &unsafe_info.unused), + table_row(&unsafe_info.used, &unsafe_info.unused, table_parameters.print_config.output_format), ); let shift_chars = unsafe_info.chars().count() + 4; diff --git a/cargo-geiger/src/scan/default/table.rs b/cargo-geiger/src/scan/default/table.rs index 301e3c76..9cd051d8 100644 --- a/cargo-geiger/src/scan/default/table.rs +++ b/cargo-geiger/src/scan/default/table.rs @@ -93,11 +93,19 @@ fn construct_key_lines( let mut output_key_lines = Vec::::new(); output_key_lines.push(String::new()); - output_key_lines.push(String::from("Metric output format: x/y")); - output_key_lines - .push(String::from(" x = unsafe code used by the build")); - output_key_lines - .push(String::from(" y = total unsafe code found in the crate")); + match output_format { + OutputFormat::Ratio => { // Change the prompt for Safe Ratio report: + output_key_lines.push(String::from("Metric output format: x/y=z%")); + output_key_lines.push(String::from(" x = safe code found in the crate")); + output_key_lines.push(String::from(" y = total code found in the crate")); + output_key_lines.push(String::from(" z = percentage of safe ratio as defined by x/y")); + } + _ => { + output_key_lines.push(String::from("Metric output format: x/y")); + output_key_lines.push(String::from(" x = unsafe code used by the build")); + output_key_lines.push(String::from(" y = total unsafe code found in the crate")); + } + } output_key_lines.push(String::new()); output_key_lines.push(String::from("Symbols: ")); From 15cf8f5792567fd6710a2deb5647b0f6176d3169 Mon Sep 17 00:00:00 2001 From: Yijun Yu Date: Sun, 20 Dec 2020 23:28:43 +0000 Subject: [PATCH 2/4] Add new safe ratio option --output-format=Ratio: fmt update --- cargo-geiger/src/format/table.rs | 160 +++++++++++------- .../src/format/table/handle_text_tree_line.rs | 6 +- cargo-geiger/src/scan/default/table.rs | 20 ++- 3 files changed, 122 insertions(+), 64 deletions(-) diff --git a/cargo-geiger/src/format/table.rs b/cargo-geiger/src/format/table.rs index 82033122..d3d15feb 100644 --- a/cargo-geiger/src/format/table.rs +++ b/cargo-geiger/src/format/table.rs @@ -107,71 +107,117 @@ fn table_footer( output_format: OutputFormat, status: CrateDetectionStatus, ) -> ColoredString { - match output_format { - OutputFormat::Ratio => { // print safe ratio - let fmt = |used: &Count, not_used: &Count| { - format!("{:>5}/{:<}={:.2}%", (used.safe + not_used.safe), (used.safe + used.unsafe_ + not_used.unsafe_ + not_used.safe), - if used.safe + used.unsafe_ + not_used.unsafe_ + not_used.safe == 0 { 100.0 } - else {(100.00*(used.safe + not_used.safe) as f32)/((used.safe + used.unsafe_ + not_used.unsafe_ + not_used.safe) as f32)} - ) - }; - let output = format!( - "{: <12} {: <18} {: <18} {: <12} {: <12}", - fmt(&used.functions, ¬_used.functions), - fmt(&used.exprs, ¬_used.exprs), - fmt(&used.item_impls, ¬_used.item_impls), - fmt(&used.item_traits, ¬_used.item_traits), - fmt(&used.methods, ¬_used.methods), - ); - colorize(&status, output_format, output) + match output_format { + OutputFormat::Ratio => { + // print safe ratio + let fmt = |used: &Count, not_used: &Count| { + format!( + "{:>5}/{:<}={:.2}%", + (used.safe + not_used.safe), + (used.safe + + used.unsafe_ + + not_used.unsafe_ + + not_used.safe), + if used.safe + + used.unsafe_ + + not_used.unsafe_ + + not_used.safe + == 0 + { + 100.0 + } else { + (100.00 * (used.safe + not_used.safe) as f32) + / ((used.safe + + used.unsafe_ + + not_used.unsafe_ + + not_used.safe) + as f32) + } + ) + }; + let output = format!( + "{: <12} {: <18} {: <18} {: <12} {: <12}", + fmt(&used.functions, ¬_used.functions), + fmt(&used.exprs, ¬_used.exprs), + fmt(&used.item_impls, ¬_used.item_impls), + fmt(&used.item_traits, ¬_used.item_traits), + fmt(&used.methods, ¬_used.methods), + ); + colorize(&status, output_format, output) } _ => { - let fmt = |used: &Count, not_used: &Count| { - format!("{}/{}", used.unsafe_, used.unsafe_ + not_used.unsafe_) - }; - let output = format!( - "{: <10} {: <12} {: <6} {: <7} {: <7}", - fmt(&used.functions, ¬_used.functions), - fmt(&used.exprs, ¬_used.exprs), - fmt(&used.item_impls, ¬_used.item_impls), - fmt(&used.item_traits, ¬_used.item_traits), - fmt(&used.methods, ¬_used.methods), - ); - colorize(&status, output_format, output) + let fmt = |used: &Count, not_used: &Count| { + format!("{}/{}", used.unsafe_, used.unsafe_ + not_used.unsafe_) + }; + let output = format!( + "{: <10} {: <12} {: <6} {: <7} {: <7}", + fmt(&used.functions, ¬_used.functions), + fmt(&used.exprs, ¬_used.exprs), + fmt(&used.item_impls, ¬_used.item_impls), + fmt(&used.item_traits, ¬_used.item_traits), + fmt(&used.methods, ¬_used.methods), + ); + colorize(&status, output_format, output) } } } -fn table_row(used: &CounterBlock, not_used: &CounterBlock, output_format: OutputFormat) -> String { - match output_format { - OutputFormat::Ratio => { // print safe ratio - let fmt = |used: &Count, not_used: &Count| { - format!("{:>5}/{:<}={:.2}%", (used.safe + not_used.safe), (used.safe + used.unsafe_ + not_used.unsafe_ + not_used.safe), - if used.safe + used.unsafe_ + not_used.unsafe_ + not_used.safe == 0 { 100.0 } - else {(100.00*(used.safe + not_used.safe) as f32)/((used.safe + used.unsafe_ + not_used.unsafe_ + not_used.safe) as f32)} - ) - }; - format!("{: <12} {: <18} {: <18} {: <12} {: <12}", - fmt(&used.functions, ¬_used.functions), - fmt(&used.exprs, ¬_used.exprs), - fmt(&used.item_impls, ¬_used.item_impls), - fmt(&used.item_traits, ¬_used.item_traits), - fmt(&used.methods, ¬_used.methods) - ) - } - _ => { - let fmt = |used: &Count, not_used: &Count| { - format!("{}/{}", used.unsafe_, used.unsafe_ + not_used.unsafe_) - }; - format!("{: <10} {: <12} {: <6} {: <7} {: <7}", - fmt(&used.functions, ¬_used.functions), - fmt(&used.exprs, ¬_used.exprs), - fmt(&used.item_impls, ¬_used.item_impls), - fmt(&used.item_traits, ¬_used.item_traits), - fmt(&used.methods, ¬_used.methods) +fn table_row( + used: &CounterBlock, + not_used: &CounterBlock, + output_format: OutputFormat, +) -> String { + match output_format { + OutputFormat::Ratio => { + // print safe ratio + let fmt = |used: &Count, not_used: &Count| { + format!( + "{:>5}/{:<}={:.2}%", + (used.safe + not_used.safe), + (used.safe + + used.unsafe_ + + not_used.unsafe_ + + not_used.safe), + if used.safe + + used.unsafe_ + + not_used.unsafe_ + + not_used.safe + == 0 + { + 100.0 + } else { + (100.00 * (used.safe + not_used.safe) as f32) + / ((used.safe + + used.unsafe_ + + not_used.unsafe_ + + not_used.safe) + as f32) + } ) - } + }; + format!( + "{: <12} {: <18} {: <18} {: <12} {: <12}", + fmt(&used.functions, ¬_used.functions), + fmt(&used.exprs, ¬_used.exprs), + fmt(&used.item_impls, ¬_used.item_impls), + fmt(&used.item_traits, ¬_used.item_traits), + fmt(&used.methods, ¬_used.methods) + ) + } + _ => { + let fmt = |used: &Count, not_used: &Count| { + format!("{}/{}", used.unsafe_, used.unsafe_ + not_used.unsafe_) + }; + format!( + "{: <10} {: <12} {: <6} {: <7} {: <7}", + fmt(&used.functions, ¬_used.functions), + fmt(&used.exprs, ¬_used.exprs), + fmt(&used.item_impls, ¬_used.item_impls), + fmt(&used.item_traits, ¬_used.item_traits), + fmt(&used.methods, ¬_used.methods) + ) } + } } fn table_row_empty() -> String { diff --git a/cargo-geiger/src/format/table/handle_text_tree_line.rs b/cargo-geiger/src/format/table/handle_text_tree_line.rs index 437c1b93..429dfffa 100644 --- a/cargo-geiger/src/format/table/handle_text_tree_line.rs +++ b/cargo-geiger/src/format/table/handle_text_tree_line.rs @@ -104,7 +104,11 @@ pub fn handle_text_tree_line_package( let unsafe_info = colorize( &crate_detection_status, table_parameters.print_config.output_format, - table_row(&unsafe_info.used, &unsafe_info.unused, table_parameters.print_config.output_format), + table_row( + &unsafe_info.used, + &unsafe_info.unused, + table_parameters.print_config.output_format, + ), ); let shift_chars = unsafe_info.chars().count() + 4; diff --git a/cargo-geiger/src/scan/default/table.rs b/cargo-geiger/src/scan/default/table.rs index 9cd051d8..98249ccd 100644 --- a/cargo-geiger/src/scan/default/table.rs +++ b/cargo-geiger/src/scan/default/table.rs @@ -94,16 +94,24 @@ fn construct_key_lines( output_key_lines.push(String::new()); match output_format { - OutputFormat::Ratio => { // Change the prompt for Safe Ratio report: + OutputFormat::Ratio => { + // Change the prompt for Safe Ratio report: output_key_lines.push(String::from("Metric output format: x/y=z%")); - output_key_lines.push(String::from(" x = safe code found in the crate")); - output_key_lines.push(String::from(" y = total code found in the crate")); - output_key_lines.push(String::from(" z = percentage of safe ratio as defined by x/y")); + output_key_lines + .push(String::from(" x = safe code found in the crate")); + output_key_lines + .push(String::from(" y = total code found in the crate")); + output_key_lines.push(String::from( + " z = percentage of safe ratio as defined by x/y", + )); } _ => { output_key_lines.push(String::from("Metric output format: x/y")); - output_key_lines.push(String::from(" x = unsafe code used by the build")); - output_key_lines.push(String::from(" y = total unsafe code found in the crate")); + output_key_lines + .push(String::from(" x = unsafe code used by the build")); + output_key_lines.push(String::from( + " y = total unsafe code found in the crate", + )); } } output_key_lines.push(String::new()); From cb62d497663e1b3a63243cc2595662a669453357 Mon Sep 17 00:00:00 2001 From: Yijun Yu Date: Mon, 21 Dec 2020 00:14:23 +0000 Subject: [PATCH 3/4] Add new safe ratio option --output-format=Ratio: update test case --- cargo-geiger/src/format/table.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cargo-geiger/src/format/table.rs b/cargo-geiger/src/format/table.rs index d3d15feb..9dd99dd6 100644 --- a/cargo-geiger/src/format/table.rs +++ b/cargo-geiger/src/format/table.rs @@ -317,14 +317,15 @@ mod table_tests { .collect(); let unsafety = unsafe_stats(&package_metrics, &rs_files_used); - let table_row = table_row(&unsafety.used, &unsafety.unused); + let table_row = + table_row(&unsafety.used, &unsafety.unused, OutputFormat::Ascii); assert_eq!(table_row, "4/6 8/12 12/18 16/24 20/30 "); } #[rstest] fn table_row_empty_test() { let empty_table_row = table_row_empty(); - assert_eq!(empty_table_row.len(), 51); + assert_eq!(empty_table_row.len(), 55); } #[rstest( From 697ceebad8db9115d07c84438125c417588e6efa Mon Sep 17 00:00:00 2001 From: Yijun Yu Date: Mon, 21 Dec 2020 18:57:08 +0000 Subject: [PATCH 4/4] PR#167: reorder OutputFormat alphabetically; separate OutputFormat::Ratio and _ into two functions; adding a test case for regression --- cargo-geiger/src/format/print_config.rs | 2 +- cargo-geiger/src/format/table.rs | 109 +++++++++++++----------- 2 files changed, 61 insertions(+), 50 deletions(-) diff --git a/cargo-geiger/src/format/print_config.rs b/cargo-geiger/src/format/print_config.rs index 4e1d63aa..8f9f8158 100644 --- a/cargo-geiger/src/format/print_config.rs +++ b/cargo-geiger/src/format/print_config.rs @@ -21,8 +21,8 @@ pub enum OutputFormat { Ascii, Json, GitHubMarkdown, - Utf8, Ratio, + Utf8, } impl Default for OutputFormat { diff --git a/cargo-geiger/src/format/table.rs b/cargo-geiger/src/format/table.rs index 9dd99dd6..e884370c 100644 --- a/cargo-geiger/src/format/table.rs +++ b/cargo-geiger/src/format/table.rs @@ -101,6 +101,60 @@ pub struct TableParameters<'a> { pub rs_files_used: &'a HashSet, } +fn table_footer_unsafe_counts( + used: CounterBlock, + not_used: CounterBlock, + output_format: OutputFormat, + status: CrateDetectionStatus, +) -> ColoredString { + let fmt = |used: &Count, not_used: &Count| { + format!("{}/{}", used.unsafe_, used.unsafe_ + not_used.unsafe_) + }; + let output = format!( + "{: <10} {: <12} {: <6} {: <7} {: <7}", + fmt(&used.functions, ¬_used.functions), + fmt(&used.exprs, ¬_used.exprs), + fmt(&used.item_impls, ¬_used.item_impls), + fmt(&used.item_traits, ¬_used.item_traits), + fmt(&used.methods, ¬_used.methods), + ); + colorize(&status, output_format, output) +} + +fn table_footer_safe_ratio( + used: CounterBlock, + not_used: CounterBlock, + output_format: OutputFormat, + status: CrateDetectionStatus, +) -> ColoredString { + let fmt = |used: &Count, not_used: &Count| { + format!( + "{:>5}/{:<}={:.2}%", + (used.safe + not_used.safe), + (used.safe + used.unsafe_ + not_used.unsafe_ + not_used.safe), + if used.safe + used.unsafe_ + not_used.unsafe_ + not_used.safe == 0 + { + 100.0 + } else { + (100.00 * (used.safe + not_used.safe) as f32) + / ((used.safe + + used.unsafe_ + + not_used.unsafe_ + + not_used.safe) as f32) + } + ) + }; + let output = format!( + "{: <12} {: <18} {: <18} {: <12} {: <12}", + fmt(&used.functions, ¬_used.functions), + fmt(&used.exprs, ¬_used.exprs), + fmt(&used.item_impls, ¬_used.item_impls), + fmt(&used.item_traits, ¬_used.item_traits), + fmt(&used.methods, ¬_used.methods), + ); + colorize(&status, output_format, output) +} + fn table_footer( used: CounterBlock, not_used: CounterBlock, @@ -109,56 +163,9 @@ fn table_footer( ) -> ColoredString { match output_format { OutputFormat::Ratio => { - // print safe ratio - let fmt = |used: &Count, not_used: &Count| { - format!( - "{:>5}/{:<}={:.2}%", - (used.safe + not_used.safe), - (used.safe - + used.unsafe_ - + not_used.unsafe_ - + not_used.safe), - if used.safe - + used.unsafe_ - + not_used.unsafe_ - + not_used.safe - == 0 - { - 100.0 - } else { - (100.00 * (used.safe + not_used.safe) as f32) - / ((used.safe - + used.unsafe_ - + not_used.unsafe_ - + not_used.safe) - as f32) - } - ) - }; - let output = format!( - "{: <12} {: <18} {: <18} {: <12} {: <12}", - fmt(&used.functions, ¬_used.functions), - fmt(&used.exprs, ¬_used.exprs), - fmt(&used.item_impls, ¬_used.item_impls), - fmt(&used.item_traits, ¬_used.item_traits), - fmt(&used.methods, ¬_used.methods), - ); - colorize(&status, output_format, output) - } - _ => { - let fmt = |used: &Count, not_used: &Count| { - format!("{}/{}", used.unsafe_, used.unsafe_ + not_used.unsafe_) - }; - let output = format!( - "{: <10} {: <12} {: <6} {: <7} {: <7}", - fmt(&used.functions, ¬_used.functions), - fmt(&used.exprs, ¬_used.exprs), - fmt(&used.item_impls, ¬_used.item_impls), - fmt(&used.item_traits, ¬_used.item_traits), - fmt(&used.methods, ¬_used.methods), - ); - colorize(&status, output_format, output) + table_footer_safe_ratio(used, not_used, output_format, status) } + _ => table_footer_unsafe_counts(used, not_used, output_format, status), } } @@ -256,6 +263,10 @@ mod table_tests { OutputFormat::GitHubMarkdown, String::from("2/4 4/8 6/12 8/16 10/20 ") ), + case( + OutputFormat::Ratio, + String::from(" 2/6=33.33% 6/14=42.86% 10/22=45.45% 14/30=46.67% 18/38=47.37%") + ), case( OutputFormat::Utf8, String::from("2/4 4/8 6/12 8/16 10/20 ")