|
7 | 7 |
|
8 | 8 | #![allow(dead_code)] // Some functions are for future use |
9 | 9 |
|
| 10 | +use auths_verifier::AssuranceLevel; |
10 | 11 | use console::{Style, Term}; |
11 | 12 | use serde::Serialize; |
12 | 13 | use std::io::IsTerminal; |
@@ -270,6 +271,59 @@ impl Output { |
270 | 271 | } |
271 | 272 | } |
272 | 273 |
|
| 274 | + /// Format an assurance level badge with a visual strength meter. |
| 275 | + /// |
| 276 | + /// With colors enabled: |
| 277 | + /// `████ Sovereign` (green) |
| 278 | + /// `███░ Authenticated` (cyan) |
| 279 | + /// `██░░ Token-Verified`(yellow) |
| 280 | + /// `█░░░ Self-Asserted` (dim) |
| 281 | + /// |
| 282 | + /// Without colors: `[4/4 Sovereign]`, `[3/4 Authenticated]`, etc. |
| 283 | + pub fn assurance_badge(&self, level: AssuranceLevel) -> String { |
| 284 | + let score = level.score(); |
| 285 | + let label = level.label(); |
| 286 | + |
| 287 | + if !self.colors_enabled { |
| 288 | + return format!("[{}/4 {}]", score, label); |
| 289 | + } |
| 290 | + |
| 291 | + let filled = "\u{2588}".repeat(score as usize); |
| 292 | + let empty = "\u{2591}".repeat(4 - score as usize); |
| 293 | + let bar = format!("{}{}", filled, empty); |
| 294 | + |
| 295 | + match level { |
| 296 | + AssuranceLevel::Sovereign => { |
| 297 | + format!( |
| 298 | + "{} {}", |
| 299 | + self.success_style.apply_to(&bar), |
| 300 | + self.success_style.apply_to(label) |
| 301 | + ) |
| 302 | + } |
| 303 | + AssuranceLevel::Authenticated => { |
| 304 | + format!( |
| 305 | + "{} {}", |
| 306 | + self.info_style.apply_to(&bar), |
| 307 | + self.info_style.apply_to(label) |
| 308 | + ) |
| 309 | + } |
| 310 | + AssuranceLevel::TokenVerified => { |
| 311 | + format!( |
| 312 | + "{} {}", |
| 313 | + self.warn_style.apply_to(&bar), |
| 314 | + self.warn_style.apply_to(label) |
| 315 | + ) |
| 316 | + } |
| 317 | + AssuranceLevel::SelfAsserted | _ => { |
| 318 | + format!( |
| 319 | + "{} {}", |
| 320 | + self.dim_style.apply_to(&bar), |
| 321 | + self.dim_style.apply_to(label) |
| 322 | + ) |
| 323 | + } |
| 324 | + } |
| 325 | + } |
| 326 | + |
273 | 327 | /// Format a status indicator. |
274 | 328 | pub fn status(&self, passed: bool) -> &'static str { |
275 | 329 | if passed { |
@@ -339,4 +393,25 @@ mod tests { |
339 | 393 | let kv = output.key_value("name", "value"); |
340 | 394 | assert_eq!(kv, "name: value"); |
341 | 395 | } |
| 396 | + |
| 397 | + #[test] |
| 398 | + fn test_assurance_badge_no_colors() { |
| 399 | + let output = Output::new_without_colors(); |
| 400 | + assert_eq!( |
| 401 | + output.assurance_badge(AssuranceLevel::Sovereign), |
| 402 | + "[4/4 Sovereign]" |
| 403 | + ); |
| 404 | + assert_eq!( |
| 405 | + output.assurance_badge(AssuranceLevel::Authenticated), |
| 406 | + "[3/4 Authenticated]" |
| 407 | + ); |
| 408 | + assert_eq!( |
| 409 | + output.assurance_badge(AssuranceLevel::TokenVerified), |
| 410 | + "[2/4 Token-Verified]" |
| 411 | + ); |
| 412 | + assert_eq!( |
| 413 | + output.assurance_badge(AssuranceLevel::SelfAsserted), |
| 414 | + "[1/4 Self-Asserted]" |
| 415 | + ); |
| 416 | + } |
342 | 417 | } |
0 commit comments