-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathtest_user_output.rs
More file actions
146 lines (134 loc) · 4.87 KB
/
Copy pathtest_user_output.rs
File metadata and controls
146 lines (134 loc) · 4.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
//! Test wrapper for `UserOutput` that simplifies test code
//!
//! Provides `TestUserOutput` with easy access to captured stdout and stderr content,
//! eliminating the need for manual buffer management in tests.
use std::cell::RefCell;
use std::sync::Arc;
use parking_lot::{Mutex, ReentrantMutex};
use super::TestWriter;
use crate::presentation::views::{Theme, UserOutput, VerbosityLevel};
/// Test wrapper for `UserOutput` that simplifies test code
///
/// Provides easy access to captured stdout and stderr content,
/// eliminating the need for manual buffer management in tests.
///
/// # Examples
///
/// ```rust,ignore
/// use torrust_tracker_deployer_lib::presentation::views::testing::TestUserOutput;
/// use torrust_tracker_deployer_lib::presentation::views::VerbosityLevel;
///
/// let mut test_output = TestUserOutput::new(VerbosityLevel::Normal);
/// test_output.output.progress("Processing...");
///
/// assert_eq!(test_output.stderr(), "⏳ Processing...\n");
/// assert_eq!(test_output.stdout(), "");
/// ```
pub struct TestUserOutput {
/// The `UserOutput` instance being tested
pub output: UserOutput,
/// Stdout buffer for capturing output
pub stdout_buffer: Arc<Mutex<Vec<u8>>>,
/// Stderr buffer for capturing output
pub stderr_buffer: Arc<Mutex<Vec<u8>>>,
}
impl TestUserOutput {
/// Create a new test output with the specified verbosity level and default theme
///
/// # Examples
///
/// ```rust,ignore
/// let test_output = TestUserOutput::new(VerbosityLevel::Normal);
/// ```
#[must_use]
pub fn new(verbosity: VerbosityLevel) -> Self {
Self::with_theme(verbosity, Theme::default())
}
/// Create a new test output with the specified verbosity level and theme
///
/// # Examples
///
/// ```rust,ignore
/// let test_output = TestUserOutput::with_theme(VerbosityLevel::Normal, Theme::plain());
/// ```
#[must_use]
pub fn with_theme(verbosity: VerbosityLevel, theme: Theme) -> Self {
let stdout_buffer = Arc::new(Mutex::new(Vec::new()));
let stderr_buffer = Arc::new(Mutex::new(Vec::new()));
let stdout_writer = Box::new(TestWriter::new(Arc::clone(&stdout_buffer)));
let stderr_writer = Box::new(TestWriter::new(Arc::clone(&stderr_buffer)));
let output =
UserOutput::with_theme_and_writers(verbosity, theme, stdout_writer, stderr_writer);
Self {
output,
stdout_buffer,
stderr_buffer,
}
}
/// Create wrapped `UserOutput` with `ReentrantMutex` for the new architecture
///
/// Returns a tuple containing the wrapped `UserOutput` and its output buffers.
/// This method supports the new `ReentrantMutex<RefCell<UserOutput>>` pattern.
///
/// # Examples
///
/// ```rust,ignore
/// let test_output = TestUserOutput::new(VerbosityLevel::Normal);
/// let (wrapped_output, stdout_buf, stderr_buf) = test_output.into_reentrant_wrapped();
/// // Use wrapped_output with functions that expect Arc<ReentrantMutex<RefCell<UserOutput>>>
/// // Use buffers to assert on output content
/// ```
#[must_use]
#[allow(clippy::type_complexity)]
pub fn into_reentrant_wrapped(
self,
) -> (
Arc<ReentrantMutex<RefCell<UserOutput>>>,
Arc<Mutex<Vec<u8>>>,
Arc<Mutex<Vec<u8>>>,
) {
let stdout_buf = Arc::clone(&self.stdout_buffer);
let stderr_buf = Arc::clone(&self.stderr_buffer);
(
Arc::new(ReentrantMutex::new(RefCell::new(self.output))),
stdout_buf,
stderr_buf,
)
}
/// Get the content written to stdout as a String
///
/// # Examples
///
/// ```rust,ignore
/// let mut test_output = TestUserOutput::new(VerbosityLevel::Normal);
/// test_output.output.result("Done");
/// assert_eq!(test_output.stdout(), "Done\n");
/// ```
///
/// # Panics
///
/// Panics if the mutex is poisoned or if the buffer contains invalid UTF-8.
/// These conditions indicate a test bug and should never occur in practice.
#[must_use]
pub fn stdout(&self) -> String {
String::from_utf8(self.stdout_buffer.lock().clone()).expect("stdout should be valid UTF-8")
}
/// Get the content written to stderr as a String
///
/// # Examples
///
/// ```rust,ignore
/// let mut test_output = TestUserOutput::new(VerbosityLevel::Normal);
/// test_output.output.progress("Working...");
/// assert_eq!(test_output.stderr(), "⏳ Working...\n");
/// ```
///
/// # Panics
///
/// Panics if the mutex is poisoned or if the buffer contains invalid UTF-8.
/// These conditions indicate a test bug and should never occur in practice.
#[must_use]
pub fn stderr(&self) -> String {
String::from_utf8(self.stderr_buffer.lock().clone()).expect("stderr should be valid UTF-8")
}
}