Merge pull request #1001 from matthiasbeyer/imag-tag/tests
imag-tag/tests
This commit is contained in:
commit
e4f8d4ec08
8 changed files with 224 additions and 43 deletions
|
@ -35,3 +35,12 @@ path = "../libimagentrytag"
|
|||
[dependencies.libimagutil]
|
||||
path = "../libimagutil"
|
||||
|
||||
[dev-dependencies.libimagutil]
|
||||
path = "../libimagutil"
|
||||
default-features = false
|
||||
features = ["testing"]
|
||||
|
||||
[dev-dependencies]
|
||||
toml-query = "0.3.0"
|
||||
env_logger = "0.3"
|
||||
|
||||
|
|
|
@ -27,8 +27,16 @@ extern crate libimagstore;
|
|||
extern crate libimagrt;
|
||||
extern crate libimagentrytag;
|
||||
extern crate libimagerror;
|
||||
|
||||
#[macro_use]
|
||||
extern crate libimagutil;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate toml_query;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate env_logger;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use libimagrt::runtime::Runtime;
|
||||
|
@ -169,3 +177,199 @@ fn list(id: PathBuf, rt: &Runtime) {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::path::PathBuf;
|
||||
use std::ffi::OsStr;
|
||||
|
||||
use toml::value::Value;
|
||||
use toml_query::read::TomlValueReadExt;
|
||||
use toml_query::error::Result as TomlQueryResult;
|
||||
|
||||
use libimagentrytag::ui::{get_add_tags, get_remove_tags};
|
||||
use libimagrt::runtime::Runtime;
|
||||
use libimagstore::storeid::StoreId;
|
||||
use libimagstore::store::{Result as StoreResult, FileLockEntry};
|
||||
|
||||
use super::alter;
|
||||
|
||||
make_mock_app! {
|
||||
app "imag-tag";
|
||||
modulename mock;
|
||||
version "0.3.0";
|
||||
with help "imag-tag mocking app";
|
||||
}
|
||||
use self::mock::generate_test_runtime;
|
||||
use libimagutil::testing::DEFAULT_ENTRY;
|
||||
|
||||
fn create_test_default_entry<'a, S: AsRef<OsStr>>(rt: &'a Runtime, name: S) -> StoreResult<StoreId> {
|
||||
let mut path = PathBuf::new();
|
||||
path.set_file_name(name);
|
||||
|
||||
let id = StoreId::new_baseless(path)?;
|
||||
let mut entry = rt.store().create(id.clone())?;
|
||||
entry.get_content_mut().push_str(DEFAULT_ENTRY);
|
||||
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
fn get_entry_tags<'a>(entry: &'a FileLockEntry<'a>) -> TomlQueryResult<Option<&'a Value>> {
|
||||
entry.get_header().read(&"imag.tags".to_owned())
|
||||
}
|
||||
|
||||
fn tags_toml_value<'a, I: IntoIterator<Item = &'static str>>(tags: I) -> Value {
|
||||
Value::Array(tags.into_iter().map(|s| Value::String(s.to_owned())).collect())
|
||||
}
|
||||
|
||||
fn setup_logging() {
|
||||
use env_logger;
|
||||
let _ = env_logger::init().unwrap_or(());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tag_add_adds_tag() {
|
||||
setup_logging();
|
||||
debug!("Generating runtime");
|
||||
let rt = generate_test_runtime(vec!["--id", "test", "--add", "foo"]).unwrap();
|
||||
|
||||
debug!("Creating default entry");
|
||||
create_test_default_entry(&rt, "test").unwrap();
|
||||
let id = PathBuf::from(String::from("test"));
|
||||
|
||||
debug!("Getting 'add' tags");
|
||||
let add = get_add_tags(rt.cli());
|
||||
debug!("Add-tags: {:?}", add);
|
||||
|
||||
debug!("Getting 'remove' tags");
|
||||
let rem = get_remove_tags(rt.cli());
|
||||
debug!("Rem-tags: {:?}", rem);
|
||||
|
||||
debug!("Altering things");
|
||||
alter(&rt, id.clone(), add, rem);
|
||||
debug!("Altered");
|
||||
|
||||
let test_entry = rt.store().get(id).unwrap().unwrap();
|
||||
let test_tags = get_entry_tags(&test_entry).unwrap().unwrap();
|
||||
|
||||
assert_ne!(*test_tags, tags_toml_value(vec![]));
|
||||
assert_eq!(*test_tags, tags_toml_value(vec!["foo"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tag_add_more_than_remove_adds_tags() {
|
||||
setup_logging();
|
||||
debug!("Generating runtime");
|
||||
let rt = generate_test_runtime(vec!["--id", "test",
|
||||
"--add", "foo",
|
||||
"--add", "bar",
|
||||
"--add", "baz",
|
||||
"--add", "bub",
|
||||
"--remove", "foo",
|
||||
"--remove", "bar",
|
||||
"--remove", "baz",
|
||||
]).unwrap();
|
||||
|
||||
debug!("Creating default entry");
|
||||
create_test_default_entry(&rt, "test").unwrap();
|
||||
let id = PathBuf::from(String::from("test"));
|
||||
|
||||
// Manually add tags
|
||||
let add = get_add_tags(rt.cli());
|
||||
|
||||
debug!("Getting 'remove' tags");
|
||||
let rem = get_remove_tags(rt.cli());
|
||||
debug!("Rem-tags: {:?}", rem);
|
||||
|
||||
debug!("Altering things");
|
||||
alter(&rt, id.clone(), add, rem);
|
||||
debug!("Altered");
|
||||
|
||||
let test_entry = rt.store().get(id).unwrap().unwrap();
|
||||
let test_tags = get_entry_tags(&test_entry).unwrap().unwrap();
|
||||
|
||||
assert_eq!(*test_tags, tags_toml_value(vec!["bub"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tag_remove_removes_tag() {
|
||||
setup_logging();
|
||||
debug!("Generating runtime");
|
||||
let rt = generate_test_runtime(vec!["--id", "test", "--remove", "foo"]).unwrap();
|
||||
|
||||
debug!("Creating default entry");
|
||||
create_test_default_entry(&rt, "test").unwrap();
|
||||
let id = PathBuf::from(String::from("test"));
|
||||
|
||||
// Manually add tags
|
||||
let add = Some(vec![ "foo".to_owned() ]);
|
||||
|
||||
debug!("Getting 'remove' tags");
|
||||
let rem = get_remove_tags(rt.cli());
|
||||
debug!("Rem-tags: {:?}", rem);
|
||||
|
||||
debug!("Altering things");
|
||||
alter(&rt, id.clone(), add, rem);
|
||||
debug!("Altered");
|
||||
|
||||
let test_entry = rt.store().get(id).unwrap().unwrap();
|
||||
let test_tags = get_entry_tags(&test_entry).unwrap().unwrap();
|
||||
|
||||
assert_eq!(*test_tags, tags_toml_value(vec![]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tag_remove_removes_only_to_remove_tag() {
|
||||
setup_logging();
|
||||
debug!("Generating runtime");
|
||||
let rt = generate_test_runtime(vec!["--id", "test", "--remove", "foo"]).unwrap();
|
||||
|
||||
debug!("Creating default entry");
|
||||
create_test_default_entry(&rt, "test").unwrap();
|
||||
let id = PathBuf::from(String::from("test"));
|
||||
|
||||
// Manually add tags
|
||||
let add = Some(vec![ "foo".to_owned(), "bar".to_owned() ]);
|
||||
|
||||
debug!("Getting 'remove' tags");
|
||||
let rem = get_remove_tags(rt.cli());
|
||||
debug!("Rem-tags: {:?}", rem);
|
||||
|
||||
debug!("Altering things");
|
||||
alter(&rt, id.clone(), add, rem);
|
||||
debug!("Altered");
|
||||
|
||||
let test_entry = rt.store().get(id).unwrap().unwrap();
|
||||
let test_tags = get_entry_tags(&test_entry).unwrap().unwrap();
|
||||
|
||||
assert_eq!(*test_tags, tags_toml_value(vec!["bar"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tag_remove_removes_but_doesnt_crash_on_nonexistent_tag() {
|
||||
setup_logging();
|
||||
debug!("Generating runtime");
|
||||
let rt = generate_test_runtime(vec!["--id", "test", "--remove", "foo", "--remove", "bar"]).unwrap();
|
||||
|
||||
debug!("Creating default entry");
|
||||
create_test_default_entry(&rt, "test").unwrap();
|
||||
let id = PathBuf::from(String::from("test"));
|
||||
|
||||
// Manually add tags
|
||||
let add = Some(vec![ "foo".to_owned() ]);
|
||||
|
||||
debug!("Getting 'remove' tags");
|
||||
let rem = get_remove_tags(rt.cli());
|
||||
debug!("Rem-tags: {:?}", rem);
|
||||
|
||||
debug!("Altering things");
|
||||
alter(&rt, id.clone(), add, rem);
|
||||
debug!("Altered");
|
||||
|
||||
let test_entry = rt.store().get(id).unwrap().unwrap();
|
||||
let test_tags = get_entry_tags(&test_entry).unwrap().unwrap();
|
||||
|
||||
assert_eq!(*test_tags, tags_toml_value(vec![]));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,5 @@ pub mod exec;
|
|||
pub mod result;
|
||||
pub mod tag;
|
||||
pub mod tagable;
|
||||
pub mod util;
|
||||
pub mod ui;
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
use regex::Regex;
|
||||
|
||||
pub type Tag = String;
|
||||
pub type TagSlice<'a> = &'a str;
|
||||
|
||||
|
@ -31,8 +33,9 @@ pub fn is_tag_str(s: &String) -> Result<(), String> {
|
|||
let is_lower = |s: &String| s.chars().all(|c| c.is_lowercase());
|
||||
let no_whitespace = |s: &String| s.chars().all(|c| !c.is_whitespace());
|
||||
let is_alphanum = |s: &String| s.chars().all(|c| c.is_alphanumeric());
|
||||
let matches_regex = |s: &String| Regex::new("^[a-zA-Z]([a-zA-Z0-9_-]*)$").unwrap().captures(s).is_some();
|
||||
|
||||
if is_lower.and(no_whitespace).and(is_alphanum).filter(s) {
|
||||
if is_lower.and(no_whitespace).and(is_alphanum).and(matches_regex).filter(s) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!("The string '{}' is not a valid tag", s))
|
||||
|
|
|
@ -27,7 +27,7 @@ use error::TagErrorKind;
|
|||
use error::MapErrInto;
|
||||
use result::Result;
|
||||
use tag::{Tag, TagSlice};
|
||||
use util::is_tag;
|
||||
use tag::is_tag_str;
|
||||
|
||||
use toml::Value;
|
||||
|
||||
|
@ -55,7 +55,7 @@ impl Tagable for Value {
|
|||
return Err(TagErrorKind::TagTypeError.into());
|
||||
}
|
||||
if tags.iter().any(|t| match *t {
|
||||
Value::String(ref s) => !is_tag(s),
|
||||
Value::String(ref s) => !is_tag_str(s).is_ok(),
|
||||
_ => unreachable!()})
|
||||
{
|
||||
return Err(TagErrorKind::NotATag.into());
|
||||
|
@ -77,8 +77,8 @@ impl Tagable for Value {
|
|||
}
|
||||
|
||||
fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
|
||||
if ts.iter().any(|tag| !is_tag(tag)) {
|
||||
debug!("Not a tag: '{}'", ts.iter().filter(|t| !is_tag(t)).next().unwrap());
|
||||
if ts.iter().any(|tag| !is_tag_str(tag).is_ok()) {
|
||||
debug!("Not a tag: '{}'", ts.iter().filter(|t| !is_tag_str(t).is_ok()).next().unwrap());
|
||||
return Err(TagErrorKind::NotATag.into());
|
||||
}
|
||||
|
||||
|
@ -90,7 +90,7 @@ impl Tagable for Value {
|
|||
}
|
||||
|
||||
fn add_tag(&mut self, t: Tag) -> Result<()> {
|
||||
if !is_tag(&t) {
|
||||
if !try!(is_tag_str(&t).map(|_| true).map_err(|_| TagErrorKind::NotATag.into_error())) {
|
||||
debug!("Not a tag: '{}'", t);
|
||||
return Err(TagErrorKind::NotATag.into());
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ impl Tagable for Value {
|
|||
}
|
||||
|
||||
fn remove_tag(&mut self, t: Tag) -> Result<()> {
|
||||
if !is_tag(&t) {
|
||||
if !try!(is_tag_str(&t).map(|_| true).map_err(|_| TagErrorKind::NotATag.into_error())) {
|
||||
debug!("Not a tag: '{}'", t);
|
||||
return Err(TagErrorKind::NotATag.into());
|
||||
}
|
||||
|
|
|
@ -20,8 +20,7 @@
|
|||
use clap::{Arg, ArgMatches, App, SubCommand};
|
||||
|
||||
use tag::Tag;
|
||||
|
||||
use libimagutil::cli_validators::is_tag;
|
||||
use tag::is_tag;
|
||||
|
||||
/// Generates a `clap::SubCommand` to be integrated in the commandline-ui builder for building a
|
||||
/// "tags --add foo --remove bar" subcommand to do tagging action.
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
//
|
||||
// imag - the personal information management suite for the commandline
|
||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; version
|
||||
// 2.1 of the License.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
use regex::Regex;
|
||||
|
||||
pub fn is_tag(s: &str) -> bool {
|
||||
Regex::new("^[a-zA-Z]([a-zA-Z0-9_-]*)$").unwrap().captures(s).is_some()
|
||||
}
|
|
@ -47,12 +47,3 @@ pub fn is_url(s: String) -> Result<(), String> {
|
|||
Url::parse(&s).map(|_| ()).map_err(|_| format!("Not a URL: {}", s))
|
||||
}
|
||||
|
||||
pub fn is_tag(s: String) -> Result<(), String> {
|
||||
use regex::Regex;
|
||||
lazy_static! { static ref TAG_RE : Regex = Regex::new("[:alpha:][:word:]*").unwrap(); }
|
||||
|
||||
TAG_RE
|
||||
.is_match(&s)
|
||||
.as_result((), format!("Not a valid Tag: '{}' - Valid is [a-zA-Z][0-9a-zA-Z]*", s))
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue