fret_platform_native/
lib.rs1pub mod clipboard;
11pub mod external_drop;
12pub mod file_dialog;
13pub mod open_url;
14
15pub use clipboard::{DesktopClipboard, NativeClipboard};
19pub use external_drop::{DesktopExternalDrop, NativeExternalDrop};
20pub use file_dialog::{DesktopFileDialog, NativeFileDialog};
21pub use open_url::{DesktopOpenUrl, NativeOpenUrl};
22
23#[cfg(all(test, not(target_arch = "wasm32")))]
24mod tests {
25 use super::*;
26 use fret_core::{ExternalDropToken, FileDialogToken};
27 use fret_platform::external_drop::ExternalDropReadLimits;
28 use std::path::{Path, PathBuf};
29 use std::time::{SystemTime, UNIX_EPOCH};
30
31 struct TempDirGuard {
32 path: PathBuf,
33 }
34
35 impl TempDirGuard {
36 fn new(prefix: &str) -> Self {
37 let pid = std::process::id();
38 let now = SystemTime::now()
39 .duration_since(UNIX_EPOCH)
40 .expect("system time after unix epoch")
41 .as_nanos();
42 let path = std::env::temp_dir().join(format!("{prefix}-{pid}-{now}"));
43 std::fs::create_dir_all(&path).expect("create temp dir");
44 Self { path }
45 }
46
47 fn path(&self) -> &Path {
48 &self.path
49 }
50 }
51
52 impl Drop for TempDirGuard {
53 fn drop(&mut self) {
54 let _ = std::fs::remove_dir_all(&self.path);
55 }
56 }
57
58 fn write_file(dir: &Path, name: &str, bytes: &[u8]) -> PathBuf {
59 let path = dir.join(name);
60 std::fs::write(&path, bytes).expect("write temp file");
61 path
62 }
63
64 #[test]
65 fn external_drop_read_paths_enforces_max_total_bytes() {
66 let dir = TempDirGuard::new("fret-platform-native-external-drop");
67 let f1 = write_file(dir.path(), "one.txt", b"abcd");
68 let f2 = write_file(dir.path(), "two.txt", b"efgh");
69
70 let token = ExternalDropToken(1);
71 let event = NativeExternalDrop::read_paths(
72 token,
73 vec![f1.clone(), f2.clone()],
74 ExternalDropReadLimits {
75 max_total_bytes: 5,
76 max_file_bytes: 1024,
77 max_files: 10,
78 },
79 );
80
81 assert_eq!(event.token, token);
82 assert_eq!(event.files.len(), 1);
83 assert_eq!(event.files[0].name, "one.txt");
84 assert_eq!(event.files[0].bytes, b"abcd");
85
86 assert_eq!(event.errors.len(), 1);
87 assert_eq!(event.errors[0].name, "two.txt");
88 assert!(event.errors[0].message.contains("next_total"));
89 assert!(event.errors[0].message.contains("max_total_bytes"));
90 }
91
92 #[test]
93 fn file_dialog_read_paths_enforces_max_total_bytes() {
94 let dir = TempDirGuard::new("fret-platform-native-file-dialog");
95 let f1 = write_file(dir.path(), "one.txt", b"abcd");
96 let f2 = write_file(dir.path(), "two.txt", b"efgh");
97
98 let token = FileDialogToken(1);
99 let event = NativeFileDialog::read_paths(
100 token,
101 vec![f1, f2],
102 ExternalDropReadLimits {
103 max_total_bytes: 5,
104 max_file_bytes: 1024,
105 max_files: 10,
106 },
107 );
108
109 assert_eq!(event.token, token);
110 assert_eq!(event.files.len(), 1);
111 assert_eq!(event.files[0].name, "one.txt");
112 assert_eq!(event.files[0].bytes, b"abcd");
113
114 assert_eq!(event.errors.len(), 1);
115 assert_eq!(event.errors[0].name, "two.txt");
116 assert!(event.errors[0].message.contains("selection too large"));
117 assert!(event.errors[0].message.contains("max_total_bytes"));
118 }
119
120 #[test]
121 fn external_drop_read_paths_skips_oversize_files_and_continues() {
122 let dir = TempDirGuard::new("fret-platform-native-external-drop-oversize");
123 let big = write_file(dir.path(), "big.bin", &[0u8; 12]);
124 let ok = write_file(dir.path(), "ok.bin", &[1u8; 4]);
125
126 let token = ExternalDropToken(2);
127 let event = NativeExternalDrop::read_paths(
128 token,
129 vec![big, ok],
130 ExternalDropReadLimits {
131 max_total_bytes: 1024,
132 max_file_bytes: 10,
133 max_files: 10,
134 },
135 );
136
137 assert_eq!(event.token, token);
138 assert_eq!(event.files.len(), 1);
139 assert_eq!(event.files[0].name, "ok.bin");
140 assert_eq!(event.files[0].bytes, vec![1u8; 4]);
141
142 assert_eq!(event.errors.len(), 1);
143 assert_eq!(event.errors[0].name, "big.bin");
144 assert!(event.errors[0].message.contains("file too large"));
145 assert!(event.errors[0].message.contains("max_file_bytes"));
146 }
147}