1use tailwind_rs_core::responsive::{Breakpoint, ResponsiveConfig, ResponsiveValue};
4
5#[derive(Debug, Clone)]
7pub struct ResponsiveTestResult {
8 pub success: bool,
9 pub message: String,
10 pub expected_value: Option<String>,
11 pub actual_value: Option<String>,
12}
13
14impl ResponsiveTestResult {
15 pub fn success(message: impl Into<String>) -> Self {
16 Self {
17 success: true,
18 message: message.into(),
19 expected_value: None,
20 actual_value: None,
21 }
22 }
23
24 pub fn failure(message: impl Into<String>) -> Self {
25 Self {
26 success: false,
27 message: message.into(),
28 expected_value: None,
29 actual_value: None,
30 }
31 }
32
33 pub fn with_values(mut self, expected: impl Into<String>, actual: impl Into<String>) -> Self {
34 self.expected_value = Some(expected.into());
35 self.actual_value = Some(actual.into());
36 self
37 }
38}
39
40pub fn test_responsive_breakpoint(
42 breakpoint: Breakpoint,
43 expected_min_width: u32,
44) -> ResponsiveTestResult {
45 let actual_min_width = breakpoint.min_width();
46
47 if actual_min_width == expected_min_width {
48 ResponsiveTestResult::success(format!("Breakpoint {:?} has correct min width", breakpoint))
49 } else {
50 ResponsiveTestResult::failure(format!(
51 "Breakpoint {:?} has incorrect min width",
52 breakpoint
53 ))
54 .with_values(expected_min_width.to_string(), actual_min_width.to_string())
55 }
56}
57
58pub fn test_responsive_value<T: PartialEq + std::fmt::Debug>(
60 responsive_value: &ResponsiveValue<T>,
61 breakpoint: Breakpoint,
62 expected_value: &T,
63) -> ResponsiveTestResult {
64 let actual_value = responsive_value.get_breakpoint(breakpoint);
65
66 if actual_value == expected_value {
67 ResponsiveTestResult::success(format!(
68 "Responsive value at {:?} matches expected",
69 breakpoint
70 ))
71 } else {
72 ResponsiveTestResult::failure(format!(
73 "Responsive value at {:?} does not match expected",
74 breakpoint
75 ))
76 .with_values(
77 format!("{:?}", expected_value),
78 format!("{:?}", actual_value),
79 )
80 }
81}
82
83pub fn test_responsive_config(
85 config: &ResponsiveConfig,
86 expected_breakpoints: &[(&str, u32)],
87) -> ResponsiveTestResult {
88 let mut missing_breakpoints = Vec::new();
89 let mut incorrect_breakpoints = Vec::new();
90
91 for (name, expected_value) in expected_breakpoints {
92 match config.get_breakpoint(name) {
93 Ok(actual_value) => {
94 if actual_value != *expected_value {
95 incorrect_breakpoints.push(format!(
96 "{}: expected {}, got {}",
97 name, expected_value, actual_value
98 ));
99 }
100 }
101 Err(_) => {
102 missing_breakpoints.push(name.to_string());
103 }
104 }
105 }
106
107 if missing_breakpoints.is_empty() && incorrect_breakpoints.is_empty() {
108 ResponsiveTestResult::success("All breakpoints match expected values")
109 } else {
110 let mut message = String::new();
111 if !missing_breakpoints.is_empty() {
112 message.push_str(&format!("Missing breakpoints: {:?}", missing_breakpoints));
113 }
114 if !incorrect_breakpoints.is_empty() {
115 if !message.is_empty() {
116 message.push_str("; ");
117 }
118 message.push_str(&format!(
119 "Incorrect breakpoints: {:?}",
120 incorrect_breakpoints
121 ));
122 }
123 ResponsiveTestResult::failure(message)
124 }
125}
126
127pub fn test_responsive_classes(
129 classes: &std::collections::HashSet<String>,
130 expected_responsive: &[(&str, &str)],
131) -> ResponsiveTestResult {
132 let mut missing_classes = Vec::new();
133 let mut found_classes = Vec::new();
134
135 for (breakpoint, class) in expected_responsive {
136 let responsive_class = format!("{}:{}", breakpoint, class);
137 if classes.contains(&responsive_class) {
138 found_classes.push(responsive_class);
139 } else {
140 missing_classes.push(responsive_class);
141 }
142 }
143
144 if missing_classes.is_empty() {
145 ResponsiveTestResult::success(format!("All responsive classes found: {:?}", found_classes))
146 } else {
147 ResponsiveTestResult::failure(format!("Missing responsive classes: {:?}", missing_classes))
148 }
149}
150
151pub fn assert_responsive_value<T: PartialEq + std::fmt::Debug>(
153 responsive_value: &ResponsiveValue<T>,
154 breakpoint: Breakpoint,
155 expected_value: &T,
156) {
157 let result = test_responsive_value(responsive_value, breakpoint, expected_value);
158 if !result.success {
159 panic!("Responsive assertion failed: {}", result.message);
160 }
161}
162
163pub fn assert_responsive_breakpoint(breakpoint: Breakpoint, expected_min_width: u32) {
165 let result = test_responsive_breakpoint(breakpoint, expected_min_width);
166 if !result.success {
167 panic!("Responsive assertion failed: {}", result.message);
168 }
169}
170
171pub fn assert_responsive_config(config: &ResponsiveConfig, expected_breakpoints: &[(&str, u32)]) {
173 let result = test_responsive_config(config, expected_breakpoints);
174 if !result.success {
175 panic!("Responsive assertion failed: {}", result.message);
176 }
177}
178
179pub fn assert_responsive_classes(
181 classes: &std::collections::HashSet<String>,
182 expected_responsive: &[(&str, &str)],
183) {
184 let result = test_responsive_classes(classes, expected_responsive);
185 if !result.success {
186 panic!("Responsive assertion failed: {}", result.message);
187 }
188}
189
190#[cfg(test)]
191mod tests {
192 use super::*;
193
194 #[test]
195 fn test_responsive_breakpoint_testing() {
196 let result = test_responsive_breakpoint(Breakpoint::Sm, 640);
197 assert!(result.success);
198
199 let result = test_responsive_breakpoint(Breakpoint::Sm, 768);
200 assert!(!result.success);
201 }
202
203 #[test]
204 fn test_responsive_value_testing() {
205 let responsive_value = ResponsiveValue::new(10);
206 let result = test_responsive_value(&responsive_value, Breakpoint::Base, &10);
207 assert!(result.success);
208
209 let result = test_responsive_value(&responsive_value, Breakpoint::Base, &20);
210 assert!(!result.success);
211 }
212
213 #[test]
214 fn test_responsive_config_testing() {
215 let config = ResponsiveConfig::new();
216 let expected_breakpoints = [
217 ("sm", 640),
218 ("md", 768),
219 ("lg", 1024),
220 ("xl", 1280),
221 ("2xl", 1536),
222 ];
223
224 let result = test_responsive_config(&config, &expected_breakpoints);
225 assert!(result.success);
226 }
227
228 #[test]
229 fn test_responsive_classes_testing() {
230 let classes: std::collections::HashSet<String> =
231 ["sm:text-sm".to_string(), "md:text-md".to_string()]
232 .iter()
233 .cloned()
234 .collect();
235
236 let expected_responsive = [("sm", "text-sm"), ("md", "text-md")];
237
238 let result = test_responsive_classes(&classes, &expected_responsive);
239 assert!(result.success);
240 }
241}