1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124

use dev_prefix::*;
use super::types::*;

lazy_static!{
    pub static ref VALID_SEARCH_FIELDS: HashSet<char> = HashSet::from_iter(
        ['N', 'D', 'P', 'O', 'L', 'R', 'T', 'A'].iter().cloned());
}

impl FromStr for SearchSettings {
    type Err = Error;

    fn from_str(s: &str) -> Result<SearchSettings> {
        let pattern = HashSet::from_iter(s.chars());
        debug!("got search pattern: {:?}", pattern);
        let invalid: HashSet<char> = pattern.difference(&VALID_SEARCH_FIELDS)
            .cloned()
            .collect();
        if !invalid.is_empty() {
            return Err(ErrorKind::CmdError(format!("Unknown search fields in pattern: {:?}",
                                                   invalid))
                .into());
        }
        let mut set = SearchSettings {
            use_regex: true,
            name: pattern.contains(&'N'),
            path: pattern.contains(&'D'),
            parts: pattern.contains(&'P'),
            partof: pattern.contains(&'O'),
            loc: pattern.contains(&'L'),
            text: pattern.contains(&'T'),
            ..SearchSettings::default()
        };
        if pattern.contains(&'A') {
            set.name = !set.name;
            set.path = !set.path;
            set.parts = !set.parts;
            set.partof = !set.partof;
            set.loc = !set.loc;
            set.text = !set.text;
        }
        Ok(set)
    }
}

fn matches_name(pat: &Regex, names: &ArtNames) -> bool {
    for n in names.iter() {
        if pat.is_match(&n.raw) {
            return true;
        }
    }
    false
}

/// return true if the artifact meets the criteria
pub fn show_artifact(name: &ArtName,
                     art: &Artifact,
                     pat_case: &Regex,
                     search_settings: &SearchSettings)
                     -> bool {
    let ss = search_settings;
    let completed = (art.completed * 100.0).round() as i8;
    let tested = (art.tested * 100.0).round() as i8;
    if (ss.completed.lt && completed > ss.completed.perc) ||
       (!ss.completed.lt && completed < ss.completed.perc) ||
       (ss.tested.lt && tested > ss.tested.perc) ||
       (!ss.tested.lt && tested < ss.tested.perc) {
        false
    } else {
        !ss.use_regex || (ss.name && pat_case.is_match(&name.raw)) ||
        (ss.parts && matches_name(pat_case, &art.parts)) ||
        (ss.partof && matches_name(pat_case, &art.partof)) ||
        (ss.loc &&
         match art.loc.as_ref() {
            None => false,
            Some(l) => pat_case.is_match(l.path.to_string_lossy().as_ref()),
        }) || (ss.text && pat_case.is_match(&art.text))
    }
}

#[test]
fn test_show_artfact() {
    let mut req_one = Artifact::from_str("[REQ-one]
            partof = 'REQ-base'
            text = 'hello bob'")
        .unwrap();
    let req_two = Artifact::from_str("[REQ-two]\ntext = 'goodbye joe'").unwrap();
    req_one.1.tested = 0.2;
    req_one.1.completed = 0.8;

    let search_bob = &Regex::new("bob").unwrap();
    let search_two = &Regex::new("two").unwrap();

    // test percentage search
    let mut settings_little_tested = SearchSettings::default();
    settings_little_tested.tested = PercentSearch {
        lt: false,
        perc: 10,
    };
    assert!(show_artifact(&req_one.0, &req_one.1, &search_bob, &settings_little_tested));

    let mut settings_ct = SearchSettings::default();
    settings_ct.completed = PercentSearch {
        lt: false,
        perc: 50,
    };
    settings_ct.tested = PercentSearch {
        lt: false,
        perc: 50,
    };
    assert!(!show_artifact(&req_one.0, &req_one.1, &search_bob, &settings_ct));

    // test regex search
    let settings_name = SearchSettings::from_str("N").unwrap();
    let settings_text = SearchSettings::from_str("T").unwrap();
    let settings_nt = SearchSettings::from_str("NT").unwrap();

    assert!(show_artifact(&req_one.0, &req_one.1, &search_bob, &settings_text));
    assert!(show_artifact(&req_one.0, &req_one.1, &search_bob, &settings_nt));
    assert!(show_artifact(&req_two.0, &req_two.1, &search_two, &settings_nt));

    assert!(!show_artifact(&req_one.0, &req_one.1, &search_bob, &settings_name));
    assert!(!show_artifact(&req_one.0, &req_one.1, &search_two, &settings_nt));
}