Skip to content

Commit f0938a8

Browse files
authored
Merge pull request #15 from zjp-CN/pretty-test-example
add example: pretty-test
2 parents 22bda53 + 0679466 commit f0938a8

File tree

1 file changed

+100
-0
lines changed

1 file changed

+100
-0
lines changed

examples/pretty-test.rs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
//! Make the output of `cargo test` prettier in tree style.
2+
//! To see the complete demo coupling with rust-script, you can refer to
3+
//! https://users.rust-lang.org/t/cargo-test-output-with-indentation/100149/2
4+
5+
use std::collections::{btree_map::Entry, BTreeMap};
6+
use termtree::{GlyphPalette, Tree};
7+
8+
fn main() {
9+
let text = "
10+
test a::b::c ... FAILED
11+
test a::d ... ok
12+
test works ... ok
13+
";
14+
assert_eq!(
15+
pretty_test(text.trim().lines()).unwrap().to_string(),
16+
"\
17+
test
18+
├── a
19+
│ ├── b
20+
│ │ └─ ❌ c
21+
│ └─ ✅ d
22+
└─ ✅ works\n"
23+
);
24+
}
25+
26+
#[derive(Debug)]
27+
enum Node<'s> {
28+
Path(BTreeMap<&'s str, Node<'s>>),
29+
Status(&'s str),
30+
}
31+
32+
fn pretty_test<'s>(lines: impl Iterator<Item = &'s str>) -> Option<Tree<&'s str>> {
33+
let mut path = BTreeMap::new();
34+
for line in lines {
35+
let mut iter = line.splitn(3, ' ');
36+
let mut split = iter.nth(1)?.split("::");
37+
let next = split.next();
38+
let status = iter.next()?;
39+
make_node(split, status, &mut path, next);
40+
}
41+
let mut tree = Tree::new("test");
42+
for (root, child) in path {
43+
make_tree(root, &child, &mut tree);
44+
}
45+
Some(tree)
46+
}
47+
48+
// Add paths to Node
49+
fn make_node<'s>(
50+
mut split: impl Iterator<Item = &'s str>,
51+
status: &'s str,
52+
path: &mut BTreeMap<&'s str, Node<'s>>,
53+
key: Option<&'s str>,
54+
) {
55+
let Some(key) = key else { return };
56+
let next = split.next();
57+
match path.entry(key) {
58+
Entry::Vacant(empty) => {
59+
if next.is_some() {
60+
let mut btree = BTreeMap::new();
61+
make_node(split, status, &mut btree, next);
62+
empty.insert(Node::Path(btree));
63+
} else {
64+
empty.insert(Node::Status(status));
65+
}
66+
}
67+
Entry::Occupied(mut btree) => {
68+
if let Node::Path(btree) = btree.get_mut() {
69+
make_node(split, status, btree, next)
70+
}
71+
}
72+
}
73+
}
74+
75+
// Add Node to Tree
76+
fn make_tree<'s>(root: &'s str, node: &Node<'s>, parent: &mut Tree<&'s str>) {
77+
match node {
78+
Node::Path(btree) => {
79+
let mut t = Tree::new(root);
80+
for (path, child) in btree {
81+
make_tree(path, child, &mut t);
82+
}
83+
parent.push(t);
84+
}
85+
Node::Status(s) => {
86+
parent.push(Tree::new(root).with_glyphs(set_status(s)));
87+
}
88+
}
89+
}
90+
91+
// Display with a status icon
92+
fn set_status(status: &str) -> GlyphPalette {
93+
let mut glyph = GlyphPalette::new();
94+
glyph.item_indent = if status.ends_with("ok") {
95+
"─ ✅ "
96+
} else {
97+
"─ ❌ "
98+
};
99+
glyph
100+
}

0 commit comments

Comments
 (0)