LCOV - code coverage report
Current view: top level - dashql-pack/src - badge.rs Coverage Total Hit
Test: DashQL 6e74948 Lines: 100.0 % 71 71
Test Date: 2026-11-06 17:46:50

            Line data    Source code
       1              : const CHARACTER_WIDTH: usize = 7;
       2              : const PERCENT_WIDTH: usize = 11;
       3              : const PADDING: usize = 10;
       4              : 
       5           10 : fn value_text_width(value: &str) -> usize {
       6           73 :     value.chars().map(|c| if c == '%' { PERCENT_WIDTH } else { CHARACTER_WIDTH }).sum()
       7           10 : }
       8              : 
       9           10 : fn build_badge(label: &str, label_text_width: usize, value: &str, color: &str) -> String {
      10           10 :     let escaped_value = value
      11           10 :         .replace('&', "&")
      12           10 :         .replace('<', "&lt;")
      13           10 :         .replace('>', "&gt;")
      14           10 :         .replace('"', "&quot;")
      15           10 :         .replace('\'', "&apos;");
      16           10 :     let label_width = label_text_width + PADDING;
      17           10 :     let value_width = value_text_width(value) + PADDING;
      18           10 :     let width = label_width + value_width;
      19           10 :     let label_center = label_width * 5;
      20           10 :     let value_center = label_width * 10 + value_width * 5;
      21           10 :     let label_text_length = label_text_width * 10;
      22           10 :     let value_text_length = (value_width - PADDING) * 10;
      23           10 :     let title = format!("{label}: {escaped_value}");
      24              : 
      25           10 :     format!(
      26              :         r##"<svg xmlns="http://www.w3.org/2000/svg" width="{width}" height="20" role="img" aria-label="{title}"><title>{title}</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="{width}" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="{label_width}" height="20" fill="#555"/><rect x="{label_width}" width="{value_width}" height="20" fill="{color}"/><rect width="{width}" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="{label_center}" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="{label_text_length}">{label}</text><text x="{label_center}" y="140" transform="scale(.1)" fill="#fff" textLength="{label_text_length}">{label}</text><text aria-hidden="true" x="{value_center}" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="{value_text_length}">{escaped_value}</text><text x="{value_center}" y="140" transform="scale(.1)" fill="#fff" textLength="{value_text_length}">{escaped_value}</text></g></svg>"##
      27              :     )
      28           10 : }
      29              : 
      30            6 : pub fn build_version_badge(version: &str) -> String {
      31            6 :     build_badge("version", 41, version, "#007ec6")
      32            6 : }
      33              : 
      34              : // The thresholds and colors of the Coveralls badges, with the green of the license badge from 90 up
      35           10 : fn coverage_color(percentage: f64) -> &'static str {
      36           10 :     if percentage < 80.0 {
      37            4 :         "#e05d44"
      38            6 :     } else if percentage < 90.0 {
      39            2 :         "#dfb317"
      40              :     } else {
      41            4 :         "#4c1"
      42              :     }
      43           10 : }
      44              : 
      45            4 : pub fn build_coverage_badge(percentage: f64) -> String {
      46              :     // The color follows the number on the badge
      47            4 :     let rounded = percentage.round();
      48            4 :     build_badge("coverage", 51, &format!("{rounded}%"), coverage_color(rounded))
      49            4 : }
      50              : 
      51              : #[cfg(test)]
      52              : mod tests {
      53              :     use super::*;
      54              : 
      55              :     #[test]
      56            1 :     fn builds_version_badge() {
      57            1 :         let badge = build_version_badge("0.0.7-dev.6");
      58              : 
      59            1 :         assert!(badge.contains("width=\"138\""));
      60            1 :         assert!(badge.contains("aria-label=\"version: 0.0.7-dev.6\""));
      61            1 :         assert!(badge.contains(">version</text>"));
      62            1 :         assert!(badge.contains("fill=\"#007ec6\""));
      63            1 :         assert_eq!(badge.matches(">0.0.7-dev.6</text>").count(), 2);
      64            1 :     }
      65              : 
      66              :     #[test]
      67            1 :     fn escapes_version_badge_text() {
      68            1 :         let badge = build_version_badge("1<&\"'>");
      69              : 
      70            1 :         assert!(badge.contains("version: 1&lt;&amp;&quot;&apos;&gt;"));
      71            1 :         assert!(!badge.contains("version: 1<&\"'>"));
      72            1 :     }
      73              : 
      74              :     #[test]
      75            1 :     fn builds_coverage_badge() {
      76            1 :         let badge = build_coverage_badge(90.53);
      77              : 
      78            1 :         assert!(badge.contains("width=\"96\""));
      79            1 :         assert!(badge.contains("aria-label=\"coverage: 91%\""));
      80            1 :         assert!(badge.contains(">coverage</text>"));
      81            1 :         assert!(badge.contains("fill=\"#4c1\""));
      82            1 :         assert_eq!(badge.matches(">91%</text>").count(), 2);
      83            1 :     }
      84              : 
      85              :     #[test]
      86            1 :     fn colors_coverage_by_thresholds() {
      87            1 :         assert_eq!(coverage_color(0.0), "#e05d44");
      88            1 :         assert_eq!(coverage_color(79.0), "#e05d44");
      89            1 :         assert_eq!(coverage_color(80.0), "#dfb317");
      90            1 :         assert_eq!(coverage_color(89.0), "#dfb317");
      91            1 :         assert_eq!(coverage_color(90.0), "#4c1");
      92            1 :         assert_eq!(coverage_color(100.0), "#4c1");
      93            1 :     }
      94              : 
      95              :     #[test]
      96            1 :     fn colors_coverage_by_the_number_on_the_badge() {
      97            1 :         let badge = build_coverage_badge(89.6);
      98            1 :         assert!(badge.contains("aria-label=\"coverage: 90%\""));
      99            1 :         assert!(badge.contains("fill=\"#4c1\""));
     100              : 
     101            1 :         let badge = build_coverage_badge(79.4);
     102            1 :         assert!(badge.contains("aria-label=\"coverage: 79%\""));
     103            1 :         assert!(badge.contains("fill=\"#e05d44\""));
     104            1 :     }
     105              : }
        

Generated by: LCOV version 2.0-1