use perl_workspace_folder::{
extract_workspace_folder_change, extract_workspace_folder_uris, root_path_to_file_uri,
workspace_folder_to_path,
};
use proptest::prelude::*;
use serde_json::{Value, json};
fn plain_path_strategy() -> impl Strategy<Value = String> {
prop::collection::vec("[a-z]{1,8}", 1..6).prop_map(|segments| segments.join("/"))
}
fn uri_entry_strategy() -> impl Strategy<Value = (Option<String>, Value)> {
prop_oneof![
plain_path_strategy().prop_map(|folder| {
let uri = format!("file:///{folder}");
(Some(uri.clone()), json!({"uri": uri, "name": "workspace"}))
}),
plain_path_strategy().prop_map(|folder| {
let uri = format!("file:///{folder}");
(Some(uri.clone()), json!({"uri": uri}))
}),
any::<i64>().prop_map(|value| (None, json!({"uri": value}))),
plain_path_strategy().prop_map(|folder| (None, json!({"name": folder}))),
Just((None, json!(null))),
]
}
proptest! {
#[test]
fn prop_plain_paths_are_interpreted_as_filesystem_paths(folder in plain_path_strategy()) {
let parsed = workspace_folder_to_path(&folder);
prop_assert!(!parsed.to_string_lossy().contains("file://"));
let canonical = parsed.to_string_lossy().replace('\\', "/");
prop_assert_eq!(canonical, folder);
}
#[test]
fn prop_file_uri_inputs_strip_file_scheme(folder in plain_path_strategy()) {
let uri = format!("file://{folder}");
let parsed = workspace_folder_to_path(&uri);
prop_assert!(!parsed.to_string_lossy().contains("file://"));
}
#[test]
fn prop_extract_workspace_folder_uris_preserves_only_valid_uri_strings(
entries in prop::collection::vec(uri_entry_strategy(), 0..16)
) {
let raw_entries: Vec<Value> = entries.iter().map(|(_, value)| value.clone()).collect();
let expected: Vec<String> = entries
.iter()
.filter_map(|(expected_uri, _)| expected_uri.clone())
.collect();
let extracted = extract_workspace_folder_uris(&raw_entries);
prop_assert_eq!(extracted, expected);
}
#[test]
fn prop_extract_workspace_folder_change_tracks_added_and_removed_independently(
added_entries in prop::collection::vec(uri_entry_strategy(), 0..8),
removed_entries in prop::collection::vec(uri_entry_strategy(), 0..8),
) {
let added_values: Vec<Value> = added_entries.iter().map(|(_, value)| value.clone()).collect();
let removed_values: Vec<Value> = removed_entries.iter().map(|(_, value)| value.clone()).collect();
let expected_added: Vec<String> = added_entries
.iter()
.filter_map(|(expected_uri, _)| expected_uri.clone())
.collect();
let expected_removed: Vec<String> = removed_entries
.iter()
.filter_map(|(expected_uri, _)| expected_uri.clone())
.collect();
let change = extract_workspace_folder_change(&json!({
"added": added_values,
"removed": removed_values,
}));
prop_assert_eq!(change.added, expected_added);
prop_assert_eq!(change.removed, expected_removed);
}
#[test]
fn prop_root_path_to_file_uri_produces_file_scheme_for_plain_paths(folder in plain_path_strategy()) {
let root_path = format!("/{folder}");
let uri = root_path_to_file_uri(&root_path);
prop_assert!(uri.starts_with("file://"));
prop_assert!(uri.ends_with(&folder));
prop_assert!(!uri.contains('\\'));
}
}