Refactor application structure and simplify implementation

This commit is contained in:
2026-07-22 00:08:09 +03:00
parent dbba3806cc
commit 90b2eb507c
74 changed files with 11362 additions and 6814 deletions
+88
View File
@@ -121,3 +121,91 @@ fn rejects_malformed_target_fields() {
assert!(error.iter().any(|item| item.field == "protocol"));
assert!(error.iter().any(|item| item.field == "requires_component"));
}
#[test]
fn unicode_names_receive_distinct_stable_ids() {
let profile = normalize_profile(ProfileInput {
id: None,
name: "Игры".to_string(),
enabled: true,
target_id: "main-proxy".to_string(),
protocols: vec!["TCP".to_string()],
items: vec![ProfileItemInput {
item_type: "process".to_string(),
value: "game.exe".to_string(),
recursive: None,
}],
})
.expect("unicode profile should normalize");
let other = normalize_profile(ProfileInput {
id: None,
name: "Работа".to_string(),
enabled: true,
target_id: "main-proxy".to_string(),
protocols: vec!["TCP".to_string()],
items: vec![ProfileItemInput {
item_type: "process".to_string(),
value: "work.exe".to_string(),
recursive: None,
}],
})
.expect("second unicode profile should normalize");
assert!(profile.id.starts_with("profile-"));
assert!(other.id.starts_with("profile-"));
assert_ne!(profile.id, other.id);
}
#[test]
fn rejects_host_with_scheme_credentials_or_path() {
for host in [
"socks5://proxy.example.test",
"user@proxy.example.test",
"proxy.example.test/path",
] {
let error = normalize_target(TargetInput {
id: None,
name: "Invalid host".to_string(),
kind: "external".to_string(),
protocol: "socks5".to_string(),
host: host.to_string(),
port: 1080,
requires_component: None,
})
.expect_err("host must not contain URL syntax");
assert!(error.iter().any(|item| item.field == "host"));
}
}
#[test]
fn rejects_relative_or_non_executable_profile_paths() {
let error = normalize_profile(ProfileInput {
id: None,
name: "Invalid paths".to_string(),
enabled: true,
target_id: "main-proxy".to_string(),
protocols: vec!["TCP".to_string()],
items: vec![
ProfileItemInput {
item_type: "folder".to_string(),
value: r"relative\folder".to_string(),
recursive: None,
},
ProfileItemInput {
item_type: "exe".to_string(),
value: r"C:\Games\game.txt".to_string(),
recursive: None,
},
],
})
.expect_err("unsafe path shapes should fail validation");
assert_eq!(
error
.iter()
.filter(|item| item.field == "items.value")
.count(),
2
);
}