Seregon/StratoSDK

StratoSDK is a framework with a declarative approach similar to Flutter/React, written and designed entirely for Rust.

Rust/27.3 KB/No license
crates/strato-ui-renderer/src/windowing/winit/linux/clipboard_tests.rs
StratoSDK / crates / strato-ui-renderer / src / windowing / winit / linux / clipboard_tests.rs
1/// Linux-specific clipboard tests.
2///
3/// Note: Most image processing functionality is tested in ui/src/clipboard_utils_tests.rs
4/// to avoid duplication. These tests focus on Linux-specific clipboard behavior.
5#[cfg(target_os = "linux")]
6mod clipboard_tests {
7 use crate::clipboard::{Clipboard, ClipboardContent};
8 use crate::windowing::winit::linux::LinuxClipboard;
9 
10 fn create_test_clipboard() -> Option<LinuxClipboard> {
11 LinuxClipboard::new().ok()
12 }
13 
14 /// Helper function to avoid repetitive clipboard creation and early return logic.
15 fn with_test_clipboard<F>(test_fn: F)
16 where
17 F: FnOnce(&mut LinuxClipboard),
18 {
19 let mut clipboard = match create_test_clipboard() {
20 Some(clipboard) => clipboard,
21 None => {
22 eprintln!("Skipping test - no clipboard available (headless environment)");
23 return;
24 }
25 };
26 test_fn(&mut clipboard);
27 }
28 
29 /// Helper to assert that paths are correctly extracted from clipboard text.
30 fn assert_paths_extracted(
31 clipboard: &mut LinuxClipboard,
32 input: &str,
33 expected_paths: &[&str],
34 ) {
35 let content = ClipboardContent::plain_text(input.to_string());
36 clipboard.write(content);
37 let read_content = clipboard.read();
38 
39 if let Some(paths) = read_content.paths {
40 assert_eq!(paths.len(), expected_paths.len());
41 for expected_path in expected_paths {
42 assert!(
43 paths.contains(&expected_path.to_string()),
44 "Expected path '{expected_path}' not found in: {paths:?}"
45 );
46 }
47 } else {
48 panic!("Expected to extract paths from: '{input}'");
49 }
50 }
51 
52 /// Helper to assert that no paths are extracted from clipboard text.
53 fn assert_no_paths_extracted(clipboard: &mut LinuxClipboard, input: &str) {
54 let content = ClipboardContent::plain_text(input.to_string());
55 clipboard.write(content);
56 let read_content = clipboard.read();
57 assert!(
58 read_content.paths.is_none(),
59 "Expected no paths to be extracted from: '{}', but got: {:?}",
60 input,
61 read_content.paths
62 );
63 }
64 
65 #[test]
66 fn test_clipboard_round_trip() {
67 with_test_clipboard(|clipboard| {
68 let test_content = ClipboardContent::plain_text("Linux clipboard test".to_string());
69 
70 // Write content
71 clipboard.write(test_content.clone());
72 
73 // Read it back
74 let read_content = clipboard.read();
75 
76 // Should get the same text back (in environments where clipboard works)
77 if !read_content.plain_text.is_empty() {
78 assert_eq!(read_content.plain_text, test_content.plain_text);
79 }
80 });
81 }
82 
83 #[test]
84 fn test_html_content_handling() {
85 with_test_clipboard(|clipboard| {
86 let test_content = ClipboardContent {
87 plain_text: "Test text".to_string(),
88 html: Some("<div>Test HTML</div>".to_string()),
89 images: None,
90 paths: None,
91 };
92 
93 // Write HTML content
94 clipboard.write(test_content.clone());
95 
96 // Read it back
97 let read_content = clipboard.read();
98 
99 // In environments where clipboard works, we should get content back
100 // (the exact HTML may not be preserved depending on the system)
101 if !read_content.is_empty() {
102 assert!(!read_content.plain_text.is_empty());
103 }
104 });
105 }
106 
107 #[test]
108 fn test_primary_clipboard_operations() {
109 with_test_clipboard(|clipboard| {
110 let test_content = ClipboardContent::plain_text("Primary clipboard test".to_string());
111 
112 // Test primary clipboard write (should not panic)
113 clipboard.write_to_primary_clipboard(test_content.clone());
114 
115 // Test primary clipboard read (should return valid ClipboardContent)
116 let read_content = clipboard.read_from_primary_clipboard();
117 
118 // Should always return a ClipboardContent struct, even if empty
119 // (this tests the fallback behavior when primary clipboard isn't supported)
120 assert!(matches!(read_content.images, None | Some(_)));
121 assert!(matches!(read_content.html, None | Some(_)));
122 });
123 }
124 
125 #[test]
126 fn test_empty_content_handling() {
127 with_test_clipboard(|clipboard| {
128 let empty_content = ClipboardContent::plain_text("".to_string());
129 
130 // Writing empty content should not panic
131 clipboard.write(empty_content);
132 
133 // Reading should return valid ClipboardContent (may be empty or have previous content)
134 let read_content = clipboard.read();
135 
136 // Should always return a valid ClipboardContent struct
137 assert!(matches!(read_content.images, None | Some(_)));
138 });
139 }
140 
141 #[test]
142 fn test_absolute_paths_extracted() {
143 with_test_clipboard(|clipboard| {
144 // Test single path
145 assert_paths_extracted(
146 clipboard,
147 "/home/user/document.txt",
148 &["/home/user/document.txt"],
149 );
150 
151 // Test multiple paths
152 assert_paths_extracted(
153 clipboard,
154 "/home/user/file1.txt\n/home/user/file2.pdf",
155 &["/home/user/file1.txt", "/home/user/file2.pdf"],
156 );
157 });
158 }
159 
160 #[test]
161 fn test_file_uri_decoded() {
162 with_test_clipboard(|clipboard| {
163 // Test basic file:// URI
164 assert_paths_extracted(
165 clipboard,
166 "file:///home/user/document.txt",
167 &["/home/user/document.txt"],
168 );
169 
170 // Test URL-encoded URI with spaces
171 assert_paths_extracted(
172 clipboard,
173 "file:///home/user/My%20Documents/file.txt",
174 &["/home/user/My Documents/file.txt"],
175 );
176 });
177 }
178 
179 #[test]
180 fn test_non_absolute_paths_rejected() {
181 with_test_clipboard(|clipboard| {
182 // Relative paths should be rejected
183 assert_no_paths_extracted(clipboard, "./relative.txt\n../another.txt");
184 
185 // Regular text should be rejected
186 assert_no_paths_extracted(clipboard, "Hello world\nThis is text");
187 
188 // Mixed content should be rejected (strict policy)
189 assert_no_paths_extracted(
190 clipboard,
191 "/home/user/file.txt\nSome text\n/another/file.txt",
192 );
193 });
194 }
195}
196