use pos_tagger::Tagger;
use std::collections::HashMap;
fn pairs(input: &[(&str, &str)]) -> Vec<(String, String)> {
input
.iter()
.map(|(w, t)| (w.to_string(), t.to_string()))
.collect()
}
fn tag(words: &[&str]) -> Vec<(String, String)> {
Tagger::new().tag(words)
}
#[test]
fn extends_lexicon_with_new_word() {
let mut tagger = Tagger::new();
let mut entries = HashMap::new();
entries.insert("Obama".to_string(), vec!["NNP".to_string()]);
tagger.extend_lexicon(entries);
assert_eq!(
tagger.tag(&["Mr", "Obama"]),
pairs(&[("Mr", "NNP"), ("Obama", "NNP")])
);
}
#[test]
fn tag_accepts_owned_strings_from_lexer() {
use pos_tagger::Lexer;
let tokens = Lexer::new().lex("the dog");
let tagged = Tagger::new().tag(&tokens);
assert_eq!(tagged, pairs(&[("the", "DT"), ("dog", "NN")]));
}
#[test]
fn extend_lexicon_accepts_an_array_of_pairs() {
let mut tagger = Tagger::new();
tagger.extend_lexicon([("Obama".to_string(), vec!["NNP".to_string()])]);
assert_eq!(tagger.tag(&["Obama"]), pairs(&[("Obama", "NNP")]));
}
#[test]
fn fresh_tagger_does_not_know_extended_word() {
assert_eq!(tag(&["Obama"]), pairs(&[("Obama", "NN")]));
}
#[test]
fn extend_lexicon_never_overrides_existing() {
let mut tagger = Tagger::new();
let mut entries = HashMap::new();
entries.insert("Mr".to_string(), vec!["XX".to_string()]);
tagger.extend_lexicon(entries);
assert_eq!(tagger.tag(&["Mr"]), pairs(&[("Mr", "NNP")]));
}
#[test]
fn unknown_word_defaults_to_nn() {
assert_eq!(tag(&["Zzqxxw"]), pairs(&[("Zzqxxw", "NN")]));
}
#[test]
fn single_unknown_char_defaults_to_nn() {
assert_eq!(tag(&["~"]), pairs(&[("~", "NN")]));
assert_eq!(tag(&["z"]), pairs(&[("z", "NN")]));
}
#[test]
fn at_sign_is_a_lexicon_entry() {
assert_eq!(tag(&["@"]), pairs(&[("@", "IN")]));
}
#[test]
fn object_property_names_are_not_lexicon_hits() {
assert_eq!(tag(&["constructor"]), pairs(&[("constructor", "NN")]));
assert_eq!(tag(&["hasOwnProperty"]), pairs(&[("hasOwnProperty", "NN")]));
assert_eq!(tag(&["toString"]), pairs(&[("toString", "VBG")]));
}
#[test]
fn word_in_lexicon_is_false_for_object_member_names() {
let tagger = Tagger::new();
for name in [
"constructor",
"valueOf",
"hasOwnProperty",
"toString",
"__proto__",
] {
assert!(
!tagger.word_in_lexicon(name),
"{name:?} should not be a lexicon hit"
);
}
}
#[test]
fn mixed_case_falls_back_to_lowercase() {
assert_eq!(tag(&["THE"]), pairs(&[("THE", "DT")]));
assert_eq!(tag(&["the"]), pairs(&[("the", "DT")]));
}
#[test]
fn empty_input_returns_empty() {
assert_eq!(tag(&[]), Vec::<(String, String)>::new());
}
#[test]
fn empty_token_tags_as_nn() {
assert_eq!(tag(&[""]), pairs(&[("", "NN")]));
}
#[test]
fn rule1_determiner_then_verb_becomes_noun() {
assert_eq!(tag(&["the", "run"]), pairs(&[("the", "DT"), ("run", "NN")]));
}
#[test]
fn rule2_noun_with_dot_and_letters_becomes_url() {
assert_eq!(tag(&["example.com"]), pairs(&[("example.com", "URL")]));
assert_eq!(tag(&["google.com"]), pairs(&[("google.com", "URL")]));
}
#[test]
fn rule2_numeric_becomes_cd() {
assert_eq!(tag(&["5.42"]), pairs(&[("5.42", "CD")]));
assert_eq!(tag(&["3.14"]), pairs(&[("3.14", "CD")]));
}
#[test]
fn rule2_parsefloat_prefix_becomes_cd() {
assert_eq!(tag(&["5abc"]), pairs(&[("5abc", "CD")]));
}
#[test]
fn rule2_dotted_non_numeric_becomes_cd() {
assert_eq!(tag(&["v1.2.3"]), pairs(&[("v1.2.3", "CD")]));
}
#[test]
fn rule3_noun_ending_ed_becomes_past_participle() {
assert_eq!(tag(&["Foobared"]), pairs(&[("Foobared", "VBN")]));
}
#[test]
fn rule4_ly_becomes_adverb() {
assert_eq!(tag(&["quickly"]), pairs(&[("quickly", "RB")]));
}
#[test]
fn rule5_noun_ending_al_becomes_adjective() {
assert_eq!(tag(&["Zzqxxwal"]), pairs(&[("Zzqxxwal", "JJ")]));
}
#[test]
fn rule6_noun_after_would_becomes_verb() {
assert_eq!(
tag(&["would", "Zzqxxw"]),
pairs(&[("would", "MD"), ("Zzqxxw", "VB")])
);
}
#[test]
fn rule7_noun_ending_s_becomes_plural() {
assert_eq!(tag(&["Zzqxxws"]), pairs(&[("Zzqxxws", "NNS")]));
}
#[test]
fn rule8_noun_ending_ing_becomes_gerund() {
assert_eq!(tag(&["Zzqxxwing"]), pairs(&[("Zzqxxwing", "VBG")]));
}
#[test]
fn buggy_ends_with_keeps_boss_and_class_singular() {
assert_eq!(tag(&["boss"]), pairs(&[("boss", "NN")]));
assert_eq!(tag(&["class"]), pairs(&[("class", "NN")]));
assert_eq!(tag(&["dogs"]), pairs(&[("dogs", "NNS")]));
}
#[test]
fn first_occurrence_ends_with_across_all_suffixes() {
let non_firing: &[(&str, &str)] = &[
("Zzedzzed", "NN"), ("Zzlyzzly", "NN"), ("lyrically", "NN"), ("Zzalzzal", "NN"), ("Zzinging", "NN"), ];
for (word, expected) in non_firing {
assert_eq!(tag(&[*word]), pairs(&[(word, expected)]));
}
let firing: &[(&str, &str)] = &[
("Zzaling", "VBG"), ("Zzlying", "VBG"), ];
for (word, expected) in firing {
assert_eq!(tag(&[*word]), pairs(&[(word, expected)]));
}
}
#[test]
fn word_in_lexicon() {
let tagger = Tagger::new();
assert!(tagger.word_in_lexicon("Mr"));
assert!(tagger.word_in_lexicon("THE")); assert!(tagger.word_in_lexicon("")); assert!(!tagger.word_in_lexicon("Zzqxxw"));
}