Compare commits

...

3 Commits

Author SHA1 Message Date
grimhilt
e66dc8d408 tests(add): introduce basics tests for add 2024-09-08 17:59:39 +02:00
grimhilt
baeef1a33a feat(reset): introduce reset and fix ROOT_PATH 2024-09-08 17:59:22 +02:00
grimhilt
bc6a23b76b feat(structs): set wrappers to path 2024-09-08 15:56:20 +02:00
21 changed files with 343 additions and 98 deletions

View File

@ -1,3 +1,4 @@
pub mod add; pub mod add;
pub mod init; pub mod init;
pub mod status; pub mod status;
pub mod reset;

View File

@ -3,7 +3,10 @@ use crate::store::{
ignorer::Ignorer, ignorer::Ignorer,
indexer::Indexer, indexer::Indexer,
nsobject::{self, NsObject}, nsobject::{self, NsObject},
structs::{self, to_obj_path},
}; };
use crate::utils::path::to_repo_relative;
use colored::Colorize;
use std::fs; use std::fs;
// use glob::glob; // use glob::glob;
use std::path::PathBuf; use std::path::PathBuf;
@ -18,6 +21,8 @@ pub struct AddArgs {
} }
pub fn exec(args: AddArgs, config: Config) { pub fn exec(args: AddArgs, config: Config) {
structs::init(config.get_root());
// Init ignorer // Init ignorer
let mut ignorer = Ignorer::new(config.get_root_unsafe()); let mut ignorer = Ignorer::new(config.get_root_unsafe());
ignorer.active_nsignore(!args.force); ignorer.active_nsignore(!args.force);
@ -26,8 +31,6 @@ pub fn exec(args: AddArgs, config: Config) {
let mut indexer = Indexer::new(config.get_root_unsafe()); let mut indexer = Indexer::new(config.get_root_unsafe());
let _ = indexer.load(); let _ = indexer.load();
nsobject::init(config.get_root_unsafe());
if args.all { if args.all {
return add_dir(config.get_root_unsafe(), &mut ignorer, &mut indexer); return add_dir(config.get_root_unsafe(), &mut ignorer, &mut indexer);
} }
@ -37,13 +40,18 @@ pub fn exec(args: AddArgs, config: Config) {
path_to_add.push(PathBuf::from(obj_to_add)); path_to_add.push(PathBuf::from(obj_to_add));
if path_to_add.exists() { if path_to_add.exists() {
// ignore object if it is ns config file or nsignored
if ignorer.should_ignore(&path_to_add) {
continue;
}
if path_to_add.is_dir() { if path_to_add.is_dir() {
indexer.index_dir(path_to_add.clone()); indexer.index_dir(path_to_add.clone());
add_dir(&path_to_add, &mut ignorer, &mut indexer); add_dir(&path_to_add, &mut ignorer, &mut indexer);
} else { } else {
indexer.index_file(path_to_add); indexer.index_file(path_to_add);
} }
} else if NsObject::from_local_path(&path_to_add).exists() { } else if NsObject::from_local_path(&to_obj_path(&path_to_add)).exists() {
indexer.index_file(path_to_add); indexer.index_file(path_to_add);
} else { } else {
// try globbing // try globbing
@ -53,17 +61,31 @@ pub fn exec(args: AddArgs, config: Config) {
} }
} }
// print all path ignored
if ignorer.ignored_paths.len() > 0 {
println!("The following paths are ignored by one of your .nsignore files:");
for ignored_path in ignorer.ignored_paths {
println!("{}", to_repo_relative(&ignored_path).display());
}
println!(
"{}",
"hint: Use -f if you really want to add them.".bright_red()
);
// hint: Turn this message off by running
// hint: "git config advice.addIgnoredFile false"
}
dbg!(indexer.save()); dbg!(indexer.save());
/* /*
for all files for all files
if globbing if globbing
take all match glob nextsyncignore take all match glob nextsyncignore
else else
if dir if dir
add dir add dir
add all childs with nextsyncignore add all childs with nextsyncignore
else else
add files add files
*/ */
} }

11
src/commands/reset.rs Normal file
View File

@ -0,0 +1,11 @@
use crate::config::config::Config;
use crate::store::indexer::Indexer;
pub struct ResetArgs {
}
pub fn exec(args: ResetArgs, config: Config) {
// Init ignorer
let indexer = Indexer::new(config.get_root_unsafe());
let _ = indexer.save();
}

View File

@ -3,6 +3,8 @@ use crate::store::{
indexer::Indexer, indexer::Indexer,
nsobject::NsObject, nsobject::NsObject,
object::{Obj, ObjStatus, ObjType}, object::{Obj, ObjStatus, ObjType},
structs,
structs::to_obj_path,
}; };
use crate::utils::path; use crate::utils::path;
use colored::{ColoredString, Colorize}; use colored::{ColoredString, Colorize};
@ -108,6 +110,8 @@ pub fn exec(args: StatusArgs, config: Config) {
} }
pub fn get_obj_changes(args: &StatusArgs, config: &Config) -> ObjStaged { pub fn get_obj_changes(args: &StatusArgs, config: &Config) -> ObjStaged {
structs::init(config.get_root());
// use root of repo if no custom path has been set by the command // use root of repo if no custom path has been set by the command
let root = if config.is_custom_execution_path { let root = if config.is_custom_execution_path {
config.execution_path.clone() config.execution_path.clone()
@ -235,14 +239,13 @@ fn compare_dir(
} }
}; };
let repo_relative_entry = path::to_repo_relative(&entry.path(), root_path); if entry.path().ends_with(".nextsync") {
let local_obj = Obj::from_local_path(&repo_relative_entry); continue;
}
let local_obj = Obj::from_local_path(&entry.path().into());
if entry.path().is_dir() { if entry.path().is_dir() {
if entry.path().ends_with(".nextsync") {
continue;
}
if local_obj.is_new() { if local_obj.is_new() {
// TODO: opti move files in new directory // TODO: opti move files in new directory
if indexer.is_staged_parent(&local_obj) { if indexer.is_staged_parent(&local_obj) {
@ -280,7 +283,7 @@ fn compare_dir(
} }
// Read ns objects to find deleted // Read ns objects to find deleted
let entries = NsObject::from_local_path(&path); let entries = NsObject::from_local_path(&to_obj_path(&path));
for entry in entries.iter() { for entry in entries.iter() {
if entry.is_file() { if entry.is_file() {
match local_files.get(entry.get_obj_path().to_str().unwrap()) { match local_files.get(entry.get_obj_path().to_str().unwrap()) {
@ -324,8 +327,7 @@ fn add_childs(root_path: &PathBuf, path: &PathBuf, res: Arc<ObjStatuses>) {
} }
}; };
let repo_relative_entry = path::to_repo_relative(&entry.path(), root_path); let local_obj = Obj::from_local_path(&entry.path().into());
let local_obj = Obj::from_local_path(&repo_relative_entry);
if entry.path().is_dir() { if entry.path().is_dir() {
if entry.path().ends_with(".nextsync") { if entry.path().ends_with(".nextsync") {
continue; continue;

View File

@ -1,6 +1,7 @@
use std::env; use std::env;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::OnceLock; use std::sync::OnceLock;
use crate::store::structs;
/// ///
/// # Parameters /// # Parameters

View File

@ -15,6 +15,7 @@ fn main() {
subcommands::init::create(), subcommands::init::create(),
subcommands::add::create(), subcommands::add::create(),
subcommands::status::create(), subcommands::status::create(),
subcommands::reset::create(),
]); ]);
// .setting(clap::AppSettings::SubcommandRequiredElseHelp); // .setting(clap::AppSettings::SubcommandRequiredElseHelp);
@ -24,6 +25,7 @@ fn main() {
Some(("init", args)) => subcommands::init::handler(args), Some(("init", args)) => subcommands::init::handler(args),
Some(("add", args)) => subcommands::add::handler(args), Some(("add", args)) => subcommands::add::handler(args),
Some(("status", args)) => subcommands::status::handler(args), Some(("status", args)) => subcommands::status::handler(args),
Some(("reset", args)) => subcommands::reset::handler(args),
Some((_, _)) => {} Some((_, _)) => {}
None => {} None => {}
}; };

View File

@ -3,3 +3,4 @@ pub mod indexer;
pub mod nsignore; pub mod nsignore;
pub mod nsobject; pub mod nsobject;
pub mod object; pub mod object;
pub mod structs;

View File

@ -9,6 +9,8 @@ pub struct Ignorer {
use_nsignore: bool, use_nsignore: bool,
/// Nsignore's rules /// Nsignore's rules
rules: OnceLock<Vec<String>>, rules: OnceLock<Vec<String>>,
/// Path that have been ignored by should_ignore function
pub ignored_paths: Vec<PathBuf>,
childs: Option<Vec<Box<Ignorer>>>, childs: Option<Vec<Box<Ignorer>>>,
} }
@ -18,6 +20,7 @@ impl Ignorer {
path: path.to_path_buf(), path: path.to_path_buf(),
use_nsignore: true, use_nsignore: true,
rules: OnceLock::new(), rules: OnceLock::new(),
ignored_paths: Vec::new(),
childs: None, childs: None,
} }
} }
@ -52,6 +55,11 @@ impl Ignorer {
/// ///
/// * `path`: /// * `path`:
pub fn should_ignore(&mut self, path: &PathBuf) -> bool { pub fn should_ignore(&mut self, path: &PathBuf) -> bool {
self.is_config_file(path) || (self.use_nsignore && self.is_ignored(path)) let should = self.is_config_file(path) || (self.use_nsignore && self.is_ignored(path));
if should {
self.ignored_paths.push(path.clone());
}
should
} }
} }

View File

@ -27,9 +27,9 @@ fn sort_paths_hierarchically(paths: &mut Vec<PathBuf>) {
} }
#[derive(Debug)] #[derive(Debug)]
struct IndexedObj { pub struct IndexedObj {
obj_type: ObjType, obj_type: ObjType,
path: PathBuf, pub path: PathBuf,
} }
pub struct Indexer { pub struct Indexer {
@ -76,6 +76,14 @@ impl Indexer {
dbg!(&self.indexed_objs); dbg!(&self.indexed_objs);
} }
pub fn clear(&mut self) {
self.indexed_objs.clear();
}
pub fn get_indexed_objs(&self) -> &Vec<IndexedObj> {
&self.indexed_objs
}
fn is_indexed(&self, obj: &IndexedObj) -> bool { fn is_indexed(&self, obj: &IndexedObj) -> bool {
self.indexed_objs self.indexed_objs
.iter() .iter()

View File

@ -1,66 +1,28 @@
use crate::store::object::{Obj, ObjMetadata, ObjType}; use crate::store::{
use crypto::digest::Digest; object::{Obj, ObjMetadata, ObjType},
use crypto::sha1::Sha1; structs::{NsObjPath, ObjPath},
};
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::OnceLock; use std::sync::OnceLock;
pub static REPO_ROOT: OnceLock<PathBuf> = OnceLock::new();
pub fn init(repo_root: &PathBuf) {
REPO_ROOT.set(repo_root.clone());
}
type NsObjectChilds = Vec<Box<NsObject>>; type NsObjectChilds = Vec<Box<NsObject>>;
struct NsObjectPath {
path: PathBuf,
}
impl From<&str> for NsObjectPath {
fn from(hash: &str) -> Self {
let (dir, res) = hash.split_at(2);
let mut ns_obj_path = match REPO_ROOT.get() {
Some(path) => path.clone(),
None => {
panic!("fatal: 'REPO_ROOT' not set, you must initialize nsobject before using it!")
}
};
ns_obj_path.push(dir);
ns_obj_path.push(res);
NsObjectPath { path: ns_obj_path }
}
}
impl From<&PathBuf> for NsObjectPath {
fn from(obj_path: &PathBuf) -> Self {
let mut hasher = Sha1::new();
hasher.input_str(
obj_path
.to_str()
.expect("Cannot contains non UTF-8 char in path"),
);
NsObjectPath::from(hasher.result_str().as_str())
}
}
pub struct NsObject { pub struct NsObject {
pub obj_type: ObjType, pub obj_type: ObjType,
obj_path: OnceLock<PathBuf>, /// path of the obj in the repo
nsobj_path: OnceLock<PathBuf>, obj_path: OnceLock<ObjPath>,
/// path of the nsobj file in the store
nsobj_path: OnceLock<NsObjPath>,
childs: OnceLock<NsObjectChilds>, childs: OnceLock<NsObjectChilds>,
index: usize,
} }
impl NsObject { impl NsObject {
pub fn from_local_path(path: &PathBuf) -> Self { pub fn from_local_path(path: &ObjPath) -> Self {
NsObject { NsObject {
obj_type: ObjType::Obj, obj_type: ObjType::Obj,
obj_path: OnceLock::from(path.to_path_buf()), obj_path: OnceLock::from(path.clone()),
nsobj_path: OnceLock::new(), nsobj_path: OnceLock::new(),
childs: OnceLock::new(), childs: OnceLock::new(),
index: 0,
} }
} }
@ -68,19 +30,18 @@ impl NsObject {
NsObject { NsObject {
obj_type: ObjType::Obj, obj_type: ObjType::Obj,
obj_path: OnceLock::new(), obj_path: OnceLock::new(),
nsobj_path: OnceLock::from(NsObjectPath::from(hash).path), nsobj_path: OnceLock::from(NsObjPath::from(hash)),
childs: OnceLock::new(), childs: OnceLock::new(),
index: 0,
} }
} }
pub fn get_obj_path(&self) -> &PathBuf { pub fn get_obj_path(&self) -> &ObjPath {
self.obj_path.get_or_init(|| todo!()) self.obj_path.get_or_init(|| todo!())
} }
fn get_nsobj_path(&self) -> &PathBuf { fn get_nsobj_path(&self) -> &NsObjPath {
self.nsobj_path self.nsobj_path
.get_or_init(|| NsObjectPath::from(self.get_obj_path()).path) .get_or_init(|| NsObjPath::from(self.get_obj_path()))
} }
/// Return the existence of the nsobj in the store /// Return the existence of the nsobj in the store

View File

@ -1,4 +1,4 @@
use crate::store::nsobject::NsObject; use crate::store::{structs::ObjPath, nsobject::NsObject};
use crate::utils::path; use crate::utils::path;
use std::fs; use std::fs;
use std::path::PathBuf; use std::path::PathBuf;
@ -55,16 +55,16 @@ pub struct Obj {
obj_type: ObjType, obj_type: ObjType,
status: OnceLock<ObjStatus>, status: OnceLock<ObjStatus>,
/// path of the object from root /// path of the object from root
obj_path: PathBuf, obj_path: ObjPath,
} }
impl Obj { impl Obj {
pub fn from_local_path(path: &PathBuf) -> Self { pub fn from_local_path(path: &ObjPath) -> Self {
// todo set state // todo set state
Obj { Obj {
obj_type: ObjType::Obj, obj_type: ObjType::Obj,
status: OnceLock::new(), status: OnceLock::new(),
obj_path: path.to_path_buf(), obj_path: path.clone(),
} }
} }
@ -101,7 +101,7 @@ impl Obj {
} }
pub fn get_metadata(&self) -> Option<ObjMetadata> { pub fn get_metadata(&self) -> Option<ObjMetadata> {
let metadata = match fs::metadata(&self.obj_path) { let metadata = match fs::metadata(&*self.obj_path) {
Ok(m) => m, Ok(m) => m,
Err(err) => { Err(err) => {
eprintln!( eprintln!(

120
src/store/structs.rs Normal file
View File

@ -0,0 +1,120 @@
use crate::utils::{path, tests};
use crypto::digest::Digest;
use crypto::sha1::Sha1;
use std::ops::{Deref, DerefMut};
use std::path::PathBuf;
use std::sync::{LazyLock, Mutex, OnceLock};
// for tests only as it is mutable
static REPO_ROOT_DEV: LazyLock<Mutex<Vec<PathBuf>>> =
LazyLock::new(|| Mutex::new(vec![PathBuf::new()]));
static REPO_ROOT: OnceLock<PathBuf> = OnceLock::new();
pub fn init(repo_root: &Option<PathBuf>) {
if tests::is_var_setup() {
REPO_ROOT_DEV.lock().unwrap()[0] = repo_root.clone().unwrap();
return;
}
if let Some(repo_root) = repo_root {
if REPO_ROOT.get().is_none() {
let _ = REPO_ROOT.set(repo_root.clone());
}
} else {
eprintln!("REPO_ROOT failed to initialize");
}
}
pub fn get_repo_root() -> PathBuf {
if tests::is_var_setup() {
return REPO_ROOT_DEV.lock().unwrap()[0].clone();
}
match REPO_ROOT.get() {
Some(path) => path.clone(),
None => {
panic!("fatal: 'REPO_ROOT' not set, you must initialize nsobject before using it!")
}
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct ObjPath {
path: PathBuf,
}
impl Deref for ObjPath {
type Target = PathBuf;
fn deref(&self) -> &PathBuf {
&self.path
}
}
impl DerefMut for ObjPath {
fn deref_mut(&mut self) -> &mut PathBuf {
&mut self.path
}
}
pub fn to_obj_path(path: &PathBuf) -> ObjPath {
ObjPath { path: path.clone() }
}
impl Into<ObjPath> for &PathBuf {
fn into(self) -> ObjPath {
ObjPath {
path: path::to_repo_relative(self),
}
}
}
impl Into<ObjPath> for PathBuf {
fn into(self) -> ObjPath {
ObjPath {
path: path::to_repo_relative(&self),
}
}
}
#[derive(Debug, PartialEq)]
pub struct NsObjPath {
path: PathBuf,
}
impl Deref for NsObjPath {
type Target = PathBuf;
fn deref(&self) -> &PathBuf {
&self.path
}
}
impl DerefMut for NsObjPath {
fn deref_mut(&mut self) -> &mut PathBuf {
&mut self.path
}
}
impl From<&str> for NsObjPath {
fn from(hash: &str) -> Self {
let (dir, res) = hash.split_at(2);
let mut ns_obj_path = get_repo_root();
ns_obj_path.push(dir);
ns_obj_path.push(res);
NsObjPath { path: ns_obj_path }
}
}
impl From<&ObjPath> for NsObjPath {
fn from(obj_path: &ObjPath) -> Self {
let mut hasher = Sha1::new();
hasher.input_str(
obj_path
.to_str()
.expect("Cannot contains non UTF-8 char in path"),
);
NsObjPath::from(hasher.result_str().as_str())
}
}

View File

@ -1,3 +1,4 @@
pub mod add; pub mod add;
pub mod init; pub mod init;
pub mod reset;
pub mod status; pub mod status;

17
src/subcommands/reset.rs Normal file
View File

@ -0,0 +1,17 @@
use clap::{Arg, ArgAction, ArgMatches, Command};
use crate::commands;
use crate::commands::reset::ResetArgs;
use crate::config::config::Config;
pub fn create() -> Command {
Command::new("reset")
.about("Clear the index")
}
pub fn handler(args: &ArgMatches) {
commands::reset::exec(
ResetArgs {},
Config::new(),
);
}

View File

@ -1 +1,2 @@
pub mod path; pub mod path;
pub mod tests;

View File

@ -1,7 +1,15 @@
use std::path::{Path, PathBuf, Component}; use std::path::{Component, Path, PathBuf};
use crate::store::structs;
pub fn to_repo_relative(path: &PathBuf, root: &PathBuf) -> PathBuf { pub fn to_repo_relative(path: &PathBuf) -> PathBuf {
path.strip_prefix(root).unwrap().to_path_buf() let root = structs::get_repo_root();
path.strip_prefix(&root)
.expect(&format!(
"Expect '{}' to be in the repo '{}'",
path.display(),
root.display()
))
.to_path_buf()
} }
pub fn to_string(path: &PathBuf) -> String { pub fn to_string(path: &PathBuf) -> String {
@ -18,9 +26,7 @@ pub fn to_string(path: &PathBuf) -> String {
/// This function ensures a given path ending with '/' still /// This function ensures a given path ending with '/' still
/// ends with '/' after normalization. /// ends with '/' after normalization.
pub fn normalize_path<P: AsRef<Path>>(path: P) -> PathBuf { pub fn normalize_path<P: AsRef<Path>>(path: P) -> PathBuf {
let ends_with_slash = path.as_ref() let ends_with_slash = path.as_ref().to_str().map_or(false, |s| s.ends_with('/'));
.to_str()
.map_or(false, |s| s.ends_with('/'));
let mut normalized = PathBuf::new(); let mut normalized = PathBuf::new();
for component in path.as_ref().components() { for component in path.as_ref().components() {
match &component { match &component {

15
src/utils/tests.rs Normal file
View File

@ -0,0 +1,15 @@
use std::env;
#[cfg(test)]
pub fn is_running() -> bool {
true
}
#[cfg(not(test))]
pub fn is_running() -> bool {
false
}
pub fn is_var_setup() -> bool {
env::var("RUNNING_TESTS").is_ok()
}

49
tests/add_test.rs Normal file
View File

@ -0,0 +1,49 @@
mod common;
use common::client::ClientTest;
use nextsync::store::indexer::Indexer;
use nextsync::commands::status::{get_obj_changes, StatusArgs};
use nextsync::config::config::Config;
use std::io;
use std::path::PathBuf;
const DEFAULT_STATUS_ARG: StatusArgs = StatusArgs { nostyle: false };
fn indexed_expected(indexer: &Indexer, expected: Vec<&str>) {
let objs = indexer.get_indexed_objs();
assert_eq!(objs.len(), expected.len());
for obj in expected {
assert!(objs
.iter()
.position(|e| { e.path == PathBuf::from(obj) })
.is_some());
}
}
#[test]
fn add_ignored_file() -> io::Result<()> {
let mut client = ClientTest::new("add__simple_file").init();
client.add_ignore_rule("foo");
client.add_file("foo", "foo")?;
let mut indexer = Indexer::new(client.get_config().get_root_unsafe());
client.exec_ok("add foo");
let _ = indexer.load();
indexed_expected(&indexer, vec![]);
client.exec_ok("add foo -f");
let _ = indexer.load();
indexed_expected(&indexer, vec!["foo"]);
client.ok()
}
// add double globbing
// add all
// add folders
// add part of folders
// add all folder
// add automatic ignored if is tracked

View File

@ -1,4 +1,5 @@
use nextsync::config::config::Config; use nextsync::config::config::Config;
use std::fs::OpenOptions;
use rand::{distributions::Alphanumeric, Rng}; use rand::{distributions::Alphanumeric, Rng};
use std::env; use std::env;
use std::fs::{self, File}; use std::fs::{self, File};
@ -125,6 +126,18 @@ impl ClientTest {
Ok(()) Ok(())
} }
pub fn add_ignore_rule(&self, rule: &str) {
let mut nsignore_path = self.volume.clone();
nsignore_path.push_str("/.nsignore");
let mut file = OpenOptions::new()
.write(true)
.create(true)
.append(true)
.open(nsignore_path).unwrap();
let _ = writeln!(file, "{rule}").unwrap();
}
// pub fn has_file(&mut self, file: &str, content: &str) -> bool { // pub fn has_file(&mut self, file: &str, content: &str) -> bool {
// let full_path = PathBuf::from(self.volume.clone()).join(file); // let full_path = PathBuf::from(self.volume.clone()).join(file);

4
tests/reset_test.rs Normal file
View File

@ -0,0 +1,4 @@
// reset all
// reset file
// reset folder
// reset unknown

View File

@ -8,7 +8,7 @@ use std::path::PathBuf;
const DEFAULT_STATUS_ARG: StatusArgs = StatusArgs { nostyle: false }; const DEFAULT_STATUS_ARG: StatusArgs = StatusArgs { nostyle: false };
fn status_exepected(config: &Config, staged: Vec<&str>, not_staged: Vec<&str>) { fn status_expected(config: &Config, staged: Vec<&str>, not_staged: Vec<&str>) {
let res = get_obj_changes(&DEFAULT_STATUS_ARG, config); let res = get_obj_changes(&DEFAULT_STATUS_ARG, config);
assert_eq!(res.staged.len(), staged.len()); assert_eq!(res.staged.len(), staged.len());
@ -36,16 +36,15 @@ fn simple_file() -> io::Result<()> {
let mut client = ClientTest::new("status__simple_file").init(); let mut client = ClientTest::new("status__simple_file").init();
client.add_file("foo", "foo")?; client.add_file("foo", "foo")?;
status_exepected(&client.get_config(), vec![], vec!["foo"]); status_expected(&client.get_config(), vec![], vec!["foo"]);
client.exec_ok("add foo"); client.exec_ok("add foo");
status_exepected(&client.get_config(), vec!["foo"], vec![]); status_expected(&client.get_config(), vec!["foo"], vec![]);
client.ok() client.ok()
} }
#[test] #[test]
#[ignore]
fn all_folder() -> io::Result<()> { fn all_folder() -> io::Result<()> {
let mut client = ClientTest::new("status__all_folder").init(); let mut client = ClientTest::new("status__all_folder").init();
@ -53,10 +52,10 @@ fn all_folder() -> io::Result<()> {
client.add_file("dir/foo", "foo")?; client.add_file("dir/foo", "foo")?;
client.add_file("dir/bar", "bar")?; client.add_file("dir/bar", "bar")?;
client.add_file("foo", "foo")?; client.add_file("foo", "foo")?;
status_exepected(&client.get_config(), vec![], vec!["foo", "dir"]); status_expected(&client.get_config(), vec![], vec!["foo", "dir"]);
client.exec_ok("add dir"); client.exec_ok("add dir");
status_exepected(&client.get_config(), vec!["dir"], vec!["foo"]); status_expected(&client.get_config(), vec!["dir/foo", "dir/bar"], vec!["foo"]);
client.ok() client.ok()
} }
@ -70,10 +69,10 @@ fn all_folder_current() -> io::Result<()> {
client.add_file("dir/foo", "foo")?; client.add_file("dir/foo", "foo")?;
client.add_file("dir/bar", "bar")?; client.add_file("dir/bar", "bar")?;
client.add_file("foor", "foor")?; client.add_file("foor", "foor")?;
status_exepected(&client.get_config(), vec![], vec!["foor", "dir"]); status_expected(&client.get_config(), vec![], vec!["foor", "dir"]);
client.exec_ok("add dir"); client.exec_ok("add dir");
status_exepected( status_expected(
&Config::from(Some(&String::from("./dir"))), &Config::from(Some(&String::from("./dir"))),
vec!["foor", "bar"], vec!["foor", "bar"],
vec!["../foo"], vec!["../foo"],
@ -90,10 +89,10 @@ fn part_of_folder() -> io::Result<()> {
client.add_file("dir/foo", "foo")?; client.add_file("dir/foo", "foo")?;
client.add_file("dir/bar", "bar")?; client.add_file("dir/bar", "bar")?;
client.add_file("foor", "foor")?; client.add_file("foor", "foor")?;
status_exepected(&client.get_config(), vec![], vec!["foor", "dir"]); status_expected(&client.get_config(), vec![], vec!["foor", "dir"]);
client.exec_ok("add dir/foo"); client.exec_ok("add dir/foo");
status_exepected( status_expected(
&client.get_config(), &client.get_config(),
vec!["dir/foo"], vec!["dir/foo"],
vec!["foor", "dir/bar"], vec!["foor", "dir/bar"],
@ -103,3 +102,6 @@ fn part_of_folder() -> io::Result<()> {
} }
// ../folder/file add // ../folder/file add
// force add ignored file
// status without ignored file
// all folder without ignored file