Skip to main content

rocketmq_admin_core/ui/
progress.rs

1// Copyright 2023 The RocketMQ Rust Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Progress indicators for long-running operations
16
17use indicatif::ProgressBar;
18use indicatif::ProgressStyle;
19
20/// Create a spinner for indeterminate operations
21pub fn create_spinner(message: &str) -> ProgressBar {
22    let pb = ProgressBar::new_spinner();
23    pb.set_style(
24        ProgressStyle::default_spinner()
25            .tick_strings(&["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"])
26            .template("{spinner:.blue} {msg}")
27            .unwrap(),
28    );
29    pb.set_message(message.to_string());
30    pb.enable_steady_tick(std::time::Duration::from_millis(80));
31    pb
32}
33
34/// Create a progress bar for determinate operations
35pub fn create_progress_bar(total: u64, message: &str) -> ProgressBar {
36    let pb = ProgressBar::new(total);
37    pb.set_style(
38        ProgressStyle::default_bar()
39            .template("{msg} [{bar:40.cyan/blue}] {pos}/{len} ({eta})")
40            .unwrap()
41            .progress_chars("=>-"),
42    );
43    pb.set_message(message.to_string());
44    pb
45}
46
47/// Finish progress with success message
48pub fn finish_progress_success(pb: &ProgressBar, message: &str) {
49    pb.finish_with_message(format!("[OK] {}", message));
50}
51
52/// Finish progress with error message
53pub fn finish_progress_error(pb: &ProgressBar, message: &str) {
54    pb.finish_with_message(format!("[ERROR] {}", message));
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60
61    #[test]
62    fn test_spinner_creation() {
63        let spinner = create_spinner("Testing...");
64        spinner.finish();
65    }
66
67    #[test]
68    fn test_progress_bar_creation() {
69        let pb = create_progress_bar(100, "Processing");
70        pb.finish();
71    }
72
73    #[test]
74    fn test_spinner_with_different_messages() {
75        let spinner1 = create_spinner("Connecting...");
76        let spinner2 = create_spinner("Fetching data...");
77        let spinner3 = create_spinner("Processing...");
78
79        spinner1.finish();
80        spinner2.finish();
81        spinner3.finish();
82    }
83
84    #[test]
85    fn test_progress_bar_with_different_totals() {
86        let pb1 = create_progress_bar(10, "Small task");
87        let pb2 = create_progress_bar(1000, "Large task");
88        let pb3 = create_progress_bar(0, "Empty task");
89
90        pb1.finish();
91        pb2.finish();
92        pb3.finish();
93    }
94
95    #[test]
96    fn test_finish_progress_success() {
97        let pb = create_progress_bar(100, "Task");
98        finish_progress_success(&pb, "Completed successfully");
99    }
100
101    #[test]
102    fn test_finish_progress_error() {
103        let pb = create_progress_bar(100, "Task");
104        finish_progress_error(&pb, "Failed with error");
105    }
106
107    #[test]
108    fn test_spinner_finish_and_clear() {
109        let spinner = create_spinner("Loading...");
110        spinner.finish_and_clear();
111    }
112
113    #[test]
114    fn test_progress_bar_increment() {
115        let pb = create_progress_bar(10, "Counting");
116        for _ in 0..10 {
117            pb.inc(1);
118        }
119        finish_progress_success(&pb, "Done");
120    }
121}