mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-11 22:50:08 +00:00
refactored file browser tree building + added tests
This commit is contained in:
+3
-1
@@ -1 +1,3 @@
|
||||
/test_dir_fetching
|
||||
/test_dir_fetching
|
||||
/test_fs_tree_with_root
|
||||
/test_fs_tree_without_root
|
||||
@@ -81,6 +81,7 @@ pub fn build_tree_item<P: AsRef<Path>>(
|
||||
ctx: &mut BuildContext,
|
||||
root_title: Option<&str>,
|
||||
) -> Handle<UiNode> {
|
||||
dbg!(path.as_ref());
|
||||
let content = GridBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_child(if path.as_ref().is_dir() {
|
||||
@@ -185,35 +186,32 @@ fn disk_letter(components: &[Component]) -> Option<u8> {
|
||||
None
|
||||
}
|
||||
|
||||
fn sanitize_path(in_path: &Path, root: Option<&PathBuf>) -> PathBuf {
|
||||
let mut out_path = PathBuf::new();
|
||||
|
||||
if let Ok(canonical_in_path) = in_path.canonicalize() {
|
||||
if let Some(canonical_root) = root.and_then(|r| r.canonicalize().ok()) {
|
||||
if let Ok(stripped) = canonical_in_path.strip_prefix(canonical_root) {
|
||||
stripped.clone_into(&mut out_path);
|
||||
}
|
||||
} else {
|
||||
out_path = canonical_in_path;
|
||||
}
|
||||
}
|
||||
|
||||
// There should be at least one component in the path. If the path is empty, this means that
|
||||
// it "points" to the current directory.
|
||||
if out_path.as_os_str().is_empty() {
|
||||
out_path.push(".");
|
||||
}
|
||||
|
||||
// Relative paths must always start from CurDir component (./), otherwise the root dir will be ignored
|
||||
// and the tree will be incorrect.
|
||||
if !out_path.is_absolute() {
|
||||
out_path = Path::new(".").join(out_path);
|
||||
}
|
||||
|
||||
out_path
|
||||
struct SanitizedPath {
|
||||
path: PathBuf,
|
||||
root_components_to_skip: usize,
|
||||
}
|
||||
|
||||
fn read_dir_entries(dir: &Path, filter: &PathFilter) -> std::io::Result<Vec<PathBuf>> {
|
||||
impl SanitizedPath {
|
||||
fn new(path: &Path, root: Option<&PathBuf>) -> std::io::Result<Self> {
|
||||
let path = path.canonicalize()?;
|
||||
if let Some(root) = root {
|
||||
let canonical_root = root.canonicalize()?;
|
||||
let root_components_to_skip = canonical_root.components().count().saturating_sub(1);
|
||||
dbg!(&path, &canonical_root, root_components_to_skip);
|
||||
Ok(Self {
|
||||
path,
|
||||
root_components_to_skip,
|
||||
})
|
||||
} else {
|
||||
Ok(Self {
|
||||
path,
|
||||
root_components_to_skip: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn read_dir_entries(dir: &Path, filter: &PathFilter) -> std::io::Result<Vec<PathBuf>> {
|
||||
#[allow(clippy::ptr_arg)]
|
||||
fn sort_dir_entries(a: &PathBuf, b: &PathBuf) -> Ordering {
|
||||
let a_is_dir = a.is_dir();
|
||||
@@ -365,24 +363,38 @@ pub fn build_single_folder(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tree_path(tree_handle: Handle<UiNode>, ui: &UserInterface) -> Option<PathBuf> {
|
||||
ui.node(tree_handle).user_data_cloned::<PathBuf>()
|
||||
}
|
||||
|
||||
pub struct FsTree {
|
||||
pub root_items: Vec<Handle<UiNode>>,
|
||||
pub path_item: Handle<UiNode>,
|
||||
}
|
||||
|
||||
impl FsTree {
|
||||
fn empty() -> Self {
|
||||
Self {
|
||||
root_items: Default::default(),
|
||||
path_item: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds entire file system tree to given final_path.
|
||||
pub fn new(
|
||||
root: Option<&PathBuf>,
|
||||
final_path: &Path,
|
||||
path: &Path,
|
||||
filter: &PathFilter,
|
||||
menu: RcUiNodeHandle,
|
||||
root_title: Option<&str>,
|
||||
ctx: &mut BuildContext,
|
||||
) -> Self {
|
||||
let dest_path = sanitize_path(final_path, root);
|
||||
) -> std::io::Result<Self> {
|
||||
let SanitizedPath {
|
||||
path,
|
||||
root_components_to_skip,
|
||||
} = SanitizedPath::new(path, root)?;
|
||||
|
||||
let dest_path_components = dest_path.components().collect::<Vec<Component>>();
|
||||
let dest_path_components = path.components().collect::<Vec<Component>>();
|
||||
|
||||
let RootsCollection {
|
||||
items: mut root_items,
|
||||
@@ -397,6 +409,10 @@ impl FsTree {
|
||||
// Concat parts of path one by one.
|
||||
full_path = full_path.join(component.as_os_str());
|
||||
|
||||
if i < root_components_to_skip {
|
||||
continue;
|
||||
}
|
||||
|
||||
let next_component = dest_path_components.get(i + 1);
|
||||
|
||||
if let Some(next_component) = next_component {
|
||||
@@ -410,12 +426,12 @@ impl FsTree {
|
||||
let next = next_component.map(|p| full_path.join(p));
|
||||
|
||||
let mut new_parent = parent;
|
||||
if let Ok(entries) = read_dir_entries(&full_path, filter) {
|
||||
for path in entries {
|
||||
let is_part_of_final_path = next.as_ref().is_some_and(|next| *next == path);
|
||||
if let Ok(dir_entries) = read_dir_entries(&full_path, filter) {
|
||||
for dir_path in dir_entries {
|
||||
let is_part_of_final_path = next.as_ref().is_some_and(|next| *next == dir_path);
|
||||
|
||||
let item = build_tree_item(
|
||||
&path,
|
||||
&dir_path,
|
||||
&full_path,
|
||||
menu.clone(),
|
||||
is_part_of_final_path,
|
||||
@@ -433,7 +449,7 @@ impl FsTree {
|
||||
new_parent = item;
|
||||
}
|
||||
|
||||
if path == dest_path {
|
||||
if dir_path == path {
|
||||
path_item = item;
|
||||
}
|
||||
}
|
||||
@@ -441,68 +457,30 @@ impl FsTree {
|
||||
parent = new_parent;
|
||||
}
|
||||
|
||||
Self {
|
||||
Ok(Self {
|
||||
root_items,
|
||||
path_item,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new_or_empty(
|
||||
root: Option<&PathBuf>,
|
||||
path: &Path,
|
||||
filter: &PathFilter,
|
||||
menu: RcUiNodeHandle,
|
||||
root_title: Option<&str>,
|
||||
ctx: &mut BuildContext,
|
||||
) -> Self {
|
||||
match Self::new(root, path, filter, menu, root_title, ctx) {
|
||||
Ok(fs_tree) => fs_tree,
|
||||
Err(err) => {
|
||||
err!(
|
||||
"Unable to rebuild FS tree for {} path! Reason: {}",
|
||||
path.display(),
|
||||
err
|
||||
);
|
||||
Self::empty()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::file_browser::{fs_tree::read_dir_entries, PathFilter};
|
||||
use std::{
|
||||
fs::File,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
fn create_dir(path: impl AsRef<Path>) {
|
||||
std::fs::create_dir_all(path).unwrap()
|
||||
}
|
||||
|
||||
fn write_empty_file(path: impl AsRef<Path>) {
|
||||
File::create(path).unwrap();
|
||||
}
|
||||
|
||||
fn create_dirs(paths: &[PathBuf]) {
|
||||
for path in paths {
|
||||
create_dir(path)
|
||||
}
|
||||
}
|
||||
|
||||
fn write_empty_files(paths: &[PathBuf]) {
|
||||
for path in paths {
|
||||
write_empty_file(path)
|
||||
}
|
||||
}
|
||||
|
||||
fn clean_or_create(path: impl AsRef<Path>) {
|
||||
if path.as_ref().exists() {
|
||||
std::fs::remove_dir_all(path).unwrap();
|
||||
} else {
|
||||
create_dir(path);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dir_fetching() {
|
||||
let path = Path::new("./test_dir_fetching");
|
||||
clean_or_create(path);
|
||||
let folders = [path.join("dir1"), path.join("dir2"), path.join("dir3")];
|
||||
let files = [path.join("file1"), path.join("file2"), path.join("file3")];
|
||||
create_dirs(&folders);
|
||||
write_empty_files(&files);
|
||||
let entries = read_dir_entries(path, &PathFilter::AllPass).unwrap();
|
||||
assert_eq!(entries[0..3], folders);
|
||||
assert_eq!(entries[3..6], files);
|
||||
let files_copy = files.clone();
|
||||
let folders_copy = folders.clone();
|
||||
let entries = read_dir_entries(
|
||||
path,
|
||||
&PathFilter::new(move |path| path != files_copy[0] && path != folders_copy[2]),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(entries[0..2], folders[0..2]);
|
||||
assert_eq!(entries[2..4], files[1..3]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,9 @@ mod fs_tree;
|
||||
mod menu;
|
||||
mod selector;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
pub use filter::*;
|
||||
pub use selector::*;
|
||||
|
||||
@@ -175,7 +178,7 @@ impl FileBrowser {
|
||||
}
|
||||
|
||||
fn rebuild_fs_tree(&mut self, ui: &mut UserInterface) {
|
||||
let fs_tree = fs_tree::FsTree::new(
|
||||
let fs_tree = fs_tree::FsTree::new_or_empty(
|
||||
self.root.as_ref(),
|
||||
&self.path,
|
||||
&self.filter,
|
||||
@@ -362,19 +365,16 @@ impl Control for FileBrowser {
|
||||
} else if let Some(TreeMessage::Expand { expand, .. }) = message.data::<TreeMessage>() {
|
||||
if *expand {
|
||||
// Look into internals of directory and build tree items.
|
||||
let parent_path = ui
|
||||
.node(message.destination())
|
||||
.user_data_cloned::<PathBuf>()
|
||||
.unwrap()
|
||||
.clone();
|
||||
fs_tree::build_single_folder(
|
||||
&parent_path,
|
||||
message.destination(),
|
||||
self.item_context_menu.clone(),
|
||||
self.root_title.as_deref(),
|
||||
&self.filter,
|
||||
ui,
|
||||
)
|
||||
if let Some(parent_path) = fs_tree::tree_path(message.destination(), ui) {
|
||||
fs_tree::build_single_folder(
|
||||
&parent_path,
|
||||
message.destination(),
|
||||
self.item_context_menu.clone(),
|
||||
self.root_title.as_deref(),
|
||||
&self.filter,
|
||||
ui,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// Nuke everything in collapsed item. This also will free some resources
|
||||
// and will speed up layout pass.
|
||||
@@ -388,60 +388,48 @@ impl Control for FileBrowser {
|
||||
}
|
||||
} else if let Some(WidgetMessage::Drop(dropped)) = message.data() {
|
||||
if !message.handled() {
|
||||
if let Some(path) = ui.node(message.destination()).user_data_cloned::<PathBuf>() {
|
||||
if let Some(path) = fs_tree::tree_path(message.destination(), ui) {
|
||||
ui.post(
|
||||
self.handle,
|
||||
FileBrowserMessage::Drop {
|
||||
dropped: *dropped,
|
||||
path_item: message.destination(),
|
||||
path: path.clone(),
|
||||
dropped_path: ui
|
||||
.node(*dropped)
|
||||
.user_data_cloned::<PathBuf>()
|
||||
.unwrap_or_default(),
|
||||
dropped_path: fs_tree::tree_path(*dropped, ui).unwrap_or_default(),
|
||||
},
|
||||
);
|
||||
message.set_handled(true);
|
||||
}
|
||||
}
|
||||
} else if let Some(TreeRootMessage::Select(selection)) = message.data::<TreeRootMessage>() {
|
||||
if message.destination() == self.tree_root
|
||||
&& message.direction() == MessageDirection::FromWidget
|
||||
{
|
||||
if let Some(&first_selected) = selection.first() {
|
||||
if let Some(first_selected_ref) = ui.try_get_node(first_selected) {
|
||||
let mut path = first_selected_ref
|
||||
.user_data_cloned::<PathBuf>()
|
||||
.unwrap()
|
||||
.clone();
|
||||
|
||||
if let FileBrowserMode::Save { .. } = self.mode {
|
||||
if path.is_file() {
|
||||
ui.send(
|
||||
self.file_name,
|
||||
TextMessage::Text(
|
||||
path.file_name()
|
||||
.map(|f| f.to_string_lossy().to_string())
|
||||
.unwrap_or_default(),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
path = path.join(&self.file_name_value);
|
||||
}
|
||||
}
|
||||
|
||||
if self.path != path {
|
||||
self.path.clone_from(&path);
|
||||
|
||||
} else if let Some(TreeRootMessage::Select(selection)) = message.data_from(self.tree_root) {
|
||||
if let Some(&first_selected) = selection.first() {
|
||||
if let Some(mut path) = fs_tree::tree_path(first_selected, ui) {
|
||||
if let FileBrowserMode::Save { .. } = self.mode {
|
||||
if path.is_file() {
|
||||
ui.send(
|
||||
self.path_text,
|
||||
TextMessage::Text(path.to_string_lossy().to_string()),
|
||||
self.file_name,
|
||||
TextMessage::Text(
|
||||
path.file_name()
|
||||
.map(|f| f.to_string_lossy().to_string())
|
||||
.unwrap_or_default(),
|
||||
),
|
||||
);
|
||||
|
||||
// Do response.
|
||||
ui.post(self.handle, FileBrowserMessage::Path(path));
|
||||
} else {
|
||||
path = path.join(&self.file_name_value);
|
||||
}
|
||||
}
|
||||
|
||||
if self.path != path {
|
||||
self.path.clone_from(&path);
|
||||
|
||||
ui.send(
|
||||
self.path_text,
|
||||
TextMessage::Text(path.to_string_lossy().to_string()),
|
||||
);
|
||||
|
||||
// Do response.
|
||||
ui.post(self.handle, FileBrowserMessage::Path(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let Some(ButtonMessage::Click) = message.data() {
|
||||
@@ -579,7 +567,7 @@ impl FileBrowserBuilder {
|
||||
|
||||
let fs_tree::FsTree {
|
||||
root_items: items, ..
|
||||
} = fs_tree::FsTree::new(
|
||||
} = fs_tree::FsTree::new_or_empty(
|
||||
self.root.as_ref(),
|
||||
self.path.as_path(),
|
||||
&self.filter,
|
||||
@@ -791,54 +779,3 @@ fn setup_filebrowser_fs_watcher(
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::file_browser::{fs_tree, FileBrowserBuilder};
|
||||
use crate::test::test_widget_deletion;
|
||||
use crate::{
|
||||
core::pool::Handle, tree::TreeRootBuilder, widget::WidgetBuilder, RcUiNodeHandle,
|
||||
UserInterface,
|
||||
};
|
||||
use fyrox_core::algebra::Vector2;
|
||||
use fyrox_core::parking_lot::Mutex;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[test]
|
||||
fn test_deletion() {
|
||||
test_widget_deletion(|ctx| FileBrowserBuilder::new(WidgetBuilder::new()).build(ctx));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_tree() {
|
||||
let mut ui = UserInterface::new(Vector2::new(100.0, 100.0));
|
||||
|
||||
let root = TreeRootBuilder::new(
|
||||
WidgetBuilder::new().with_user_data(Arc::new(Mutex::new(PathBuf::from("test")))),
|
||||
)
|
||||
.build(&mut ui.build_ctx());
|
||||
|
||||
let path = fs_tree::build_tree(
|
||||
root,
|
||||
true,
|
||||
"./test/path1",
|
||||
"./test",
|
||||
RcUiNodeHandle::new(Handle::new(0, 1), ui.sender()),
|
||||
None,
|
||||
&mut ui,
|
||||
);
|
||||
|
||||
while ui.poll_message().is_some() {}
|
||||
|
||||
// This passes.
|
||||
assert_eq!(fs_tree::find_tree_item(root, &"./test/path1", &ui), path);
|
||||
|
||||
// This expected to fail
|
||||
// https://github.com/rust-lang/rust/issues/31374
|
||||
assert_eq!(
|
||||
fs_tree::find_tree_item(root, &"test/path1", &ui),
|
||||
Handle::NONE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::test::UserInterfaceTestingExtension;
|
||||
use crate::{
|
||||
core::{algebra::Vector2, parking_lot::Mutex, pool::Handle},
|
||||
file_browser::{fs_tree, fs_tree::read_dir_entries, FileBrowserBuilder, PathFilter},
|
||||
test::test_widget_deletion,
|
||||
tree::TreeRootBuilder,
|
||||
widget::WidgetBuilder,
|
||||
RcUiNodeHandle, UiNode, UserInterface,
|
||||
};
|
||||
use fyrox_graph::SceneGraph;
|
||||
use std::{
|
||||
fs::File,
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
fn create_dir(path: impl AsRef<Path>) {
|
||||
std::fs::create_dir_all(path).unwrap()
|
||||
}
|
||||
|
||||
fn write_empty_file(path: impl AsRef<Path>) {
|
||||
if let Some(parent) = path.as_ref().parent() {
|
||||
if !parent.exists() {
|
||||
create_dir(parent)
|
||||
}
|
||||
}
|
||||
File::create(path).unwrap();
|
||||
}
|
||||
|
||||
fn create_dirs(paths: &[PathBuf]) {
|
||||
for path in paths {
|
||||
create_dir(path)
|
||||
}
|
||||
}
|
||||
|
||||
fn write_empty_files(paths: &[PathBuf]) {
|
||||
for path in paths {
|
||||
write_empty_file(path)
|
||||
}
|
||||
}
|
||||
|
||||
fn clean_or_create(path: impl AsRef<Path>) {
|
||||
if path.as_ref().exists() {
|
||||
std::fs::remove_dir_all(path).unwrap();
|
||||
} else {
|
||||
create_dir(path);
|
||||
}
|
||||
}
|
||||
|
||||
fn find_by_path(path: impl AsRef<Path>, ui: &UserInterface) -> Handle<UiNode> {
|
||||
ui.find_from_root(&mut |n| {
|
||||
n.user_data_cloned::<PathBuf>()
|
||||
.is_some_and(|p| p == path.as_ref())
|
||||
})
|
||||
.map(|(h, _)| h)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deletion() {
|
||||
test_widget_deletion(|ctx| FileBrowserBuilder::new(WidgetBuilder::new()).build(ctx));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_tree() {
|
||||
let mut ui = UserInterface::new(Vector2::new(100.0, 100.0));
|
||||
|
||||
let root = TreeRootBuilder::new(
|
||||
WidgetBuilder::new().with_user_data(Arc::new(Mutex::new(PathBuf::from("test")))),
|
||||
)
|
||||
.build(&mut ui.build_ctx());
|
||||
|
||||
let path = fs_tree::build_tree(
|
||||
root,
|
||||
true,
|
||||
"./test/path1",
|
||||
"./test",
|
||||
RcUiNodeHandle::new(Handle::new(0, 1), ui.sender()),
|
||||
None,
|
||||
&mut ui,
|
||||
);
|
||||
|
||||
while ui.poll_message().is_some() {}
|
||||
|
||||
// This passes.
|
||||
assert_eq!(fs_tree::find_tree_item(root, &"./test/path1", &ui), path);
|
||||
|
||||
// This expected to fail
|
||||
// https://github.com/rust-lang/rust/issues/31374
|
||||
assert_eq!(
|
||||
fs_tree::find_tree_item(root, &"test/path1", &ui),
|
||||
Handle::NONE
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dir_fetching() {
|
||||
let path = Path::new("./test_dir_fetching");
|
||||
clean_or_create(path);
|
||||
let folders = [path.join("dir1"), path.join("dir2"), path.join("dir3")];
|
||||
let files = [path.join("file1"), path.join("file2"), path.join("file3")];
|
||||
create_dirs(&folders);
|
||||
write_empty_files(&files);
|
||||
let entries = read_dir_entries(path, &PathFilter::AllPass).unwrap();
|
||||
assert_eq!(entries[0..3], folders);
|
||||
assert_eq!(entries[3..6], files);
|
||||
let files_copy = files.clone();
|
||||
let folders_copy = folders.clone();
|
||||
let entries = read_dir_entries(
|
||||
path,
|
||||
&PathFilter::new(move |path| path != files_copy[0] && path != folders_copy[2]),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(entries[0..2], folders[0..2]);
|
||||
assert_eq!(entries[2..4], files[1..3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fs_tree_with_root() {
|
||||
let root = PathBuf::from("./test_fs_tree_with_root");
|
||||
clean_or_create(&root);
|
||||
let paths = [
|
||||
root.join("file1"),
|
||||
root.join("file2"),
|
||||
root.join("file3"),
|
||||
root.join("subdir").join("file1"),
|
||||
root.join("subdir").join("file2"),
|
||||
root.join("subdir").join("file3"),
|
||||
];
|
||||
write_empty_files(&paths);
|
||||
let screen_size = Vector2::repeat(1000.0);
|
||||
let mut ui = UserInterface::new(screen_size);
|
||||
let ctx = &mut ui.build_ctx();
|
||||
FileBrowserBuilder::new(WidgetBuilder::new())
|
||||
.with_root(root)
|
||||
.with_path(paths.last().as_deref().unwrap())
|
||||
.build(ctx);
|
||||
ui.poll_all_messages();
|
||||
for path in paths {
|
||||
let path = path.canonicalize().unwrap();
|
||||
assert!(find_by_path(path, &ui).is_some());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fs_tree_without_root() {
|
||||
let root = PathBuf::from("./test_fs_tree_without_root");
|
||||
clean_or_create(&root);
|
||||
let paths = [
|
||||
root.join("file1"),
|
||||
root.join("file2"),
|
||||
root.join("file3"),
|
||||
root.join("subdir").join("file1"),
|
||||
root.join("subdir").join("file2"),
|
||||
root.join("subdir").join("file3"),
|
||||
];
|
||||
write_empty_files(&paths);
|
||||
let screen_size = Vector2::repeat(1000.0);
|
||||
let mut ui = UserInterface::new(screen_size);
|
||||
let ctx = &mut ui.build_ctx();
|
||||
FileBrowserBuilder::new(WidgetBuilder::new())
|
||||
.with_path(paths.last().as_deref().unwrap())
|
||||
.build(ctx);
|
||||
ui.poll_all_messages();
|
||||
for path in paths {
|
||||
let path = path.canonicalize().unwrap();
|
||||
assert!(find_by_path(path, &ui).is_some());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user