karma: reasons, milestones, no-highlight replies
All checks were successful
ci / check (push) Successful in 47s
All checks were successful
ci / check (push) Successful in 47s
This commit is contained in:
parent
af9d5eed25
commit
e801b04d6e
3 changed files with 222 additions and 87 deletions
142
tests/karma.rs
142
tests/karma.rs
|
|
@ -1,5 +1,5 @@
|
|||
use rustbot::bot::module::{Action, Chat, Command, Module};
|
||||
use rustbot::bot::modules::karma::{parse_changes, Karma};
|
||||
use rustbot::bot::modules::karma::{extract_reason, parse_changes, Karma};
|
||||
|
||||
fn chat<'a>(sender: &'a str, text: &'a str) -> Chat<'a> {
|
||||
Chat {
|
||||
|
|
@ -11,6 +11,25 @@ fn chat<'a>(sender: &'a str, text: &'a str) -> Chat<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn visible(s: &str) -> String {
|
||||
s.replace('\u{200B}', "")
|
||||
}
|
||||
|
||||
fn reply_of(k: &mut Karma, name: &str, args: &[&str]) -> String {
|
||||
let cmd = Command {
|
||||
sender: "z",
|
||||
reply_to: "#c",
|
||||
name,
|
||||
args,
|
||||
prefix: ">",
|
||||
network: "t",
|
||||
};
|
||||
match k.on_command(&cmd).as_slice() {
|
||||
[Action::Reply(s)] => visible(s),
|
||||
_ => panic!("expected one reply"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parses_increments_and_decrements() {
|
||||
assert_eq!(
|
||||
|
|
@ -40,57 +59,6 @@ fn dedupes_within_a_message() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bumps_persist_case_insensitively() {
|
||||
let path = std::env::temp_dir().join("rubot-test-karma-a.json");
|
||||
let _ = std::fs::remove_file(&path);
|
||||
let mut k = Karma::with_path(path.clone());
|
||||
k.on_message(&chat("alice", "Rust++ rust++ python--"));
|
||||
|
||||
let reloaded = Karma::with_path(path.clone());
|
||||
assert_eq!(reloaded.get("rust"), 1); // deduped to one bump
|
||||
assert_eq!(reloaded.get("RUST"), 1);
|
||||
assert_eq!(reloaded.get("python"), -1);
|
||||
let _ = std::fs::remove_file(&path);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn command_reports_karma() {
|
||||
let path = std::env::temp_dir().join("rubot-test-karma-b.json");
|
||||
let _ = std::fs::remove_file(&path);
|
||||
let mut k = Karma::with_path(path.clone());
|
||||
k.on_message(&chat("a", "foo++ foo++"));
|
||||
let cmd = Command {
|
||||
sender: "a",
|
||||
reply_to: "#c",
|
||||
name: "karma",
|
||||
args: &["foo"],
|
||||
prefix: ">",
|
||||
network: "t",
|
||||
};
|
||||
let out = match k.on_command(&cmd).as_slice() {
|
||||
[Action::Reply(s)] => s.clone(),
|
||||
_ => panic!("expected one reply"),
|
||||
};
|
||||
assert!(out.contains("foo has 1 karma"), "{out}");
|
||||
let _ = std::fs::remove_file(&path);
|
||||
}
|
||||
|
||||
fn reply_of(k: &mut Karma, name: &str, args: &[&str]) -> String {
|
||||
let cmd = Command {
|
||||
sender: "z",
|
||||
reply_to: "#c",
|
||||
name,
|
||||
args,
|
||||
prefix: ">",
|
||||
network: "t",
|
||||
};
|
||||
match k.on_command(&cmd).as_slice() {
|
||||
[Action::Reply(s)] => s.clone(),
|
||||
_ => panic!("expected one reply"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ignores_single_char_and_numeric_targets() {
|
||||
assert_eq!(
|
||||
|
|
@ -100,15 +68,52 @@ fn ignores_single_char_and_numeric_targets() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn report_shows_rank() {
|
||||
fn extract_reason_after_single_bump() {
|
||||
assert_eq!(
|
||||
extract_reason("rust++ for the clean PR").as_deref(),
|
||||
Some("the clean PR")
|
||||
);
|
||||
assert_eq!(
|
||||
extract_reason("rust++ because it's fast").as_deref(),
|
||||
Some("it's fast")
|
||||
);
|
||||
assert_eq!(
|
||||
extract_reason("rust++: solid docs").as_deref(),
|
||||
Some("solid docs")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extract_reason_none_when_ambiguous_or_absent() {
|
||||
assert_eq!(extract_reason("great work rust++"), None);
|
||||
assert_eq!(extract_reason("foo++ bar++ nice"), None);
|
||||
assert_eq!(extract_reason("just chatting"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bumps_persist_case_insensitively() {
|
||||
let path = std::env::temp_dir().join("rubot-test-karma-a.json");
|
||||
let _ = std::fs::remove_file(&path);
|
||||
let mut k = Karma::with_path(path.clone());
|
||||
k.on_message(&chat("alice", "Rust++ rust++ python--"));
|
||||
let reloaded = Karma::with_path(path.clone());
|
||||
assert_eq!(reloaded.get("rust"), 1);
|
||||
assert_eq!(reloaded.get("RUST"), 1);
|
||||
assert_eq!(reloaded.get("python"), -1);
|
||||
let _ = std::fs::remove_file(&path);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn report_shows_rank_and_reason() {
|
||||
let path = std::env::temp_dir().join("rubot-test-karma-rank.json");
|
||||
let _ = std::fs::remove_file(&path);
|
||||
let mut k = Karma::with_path(path.clone());
|
||||
k.on_message(&chat("a", "alpha++"));
|
||||
k.on_message(&chat("b", "alpha++"));
|
||||
k.on_message(&chat("c", "alpha++ beta++"));
|
||||
assert!(reply_of(&mut k, "karma", &["alpha"]).contains("alpha has 3 karma (#1 of 2)"));
|
||||
assert!(reply_of(&mut k, "karma", &["beta"]).contains("beta has 1 karma (#2 of 2)"));
|
||||
k.on_message(&chat("alice", "rust++ for the clean PR"));
|
||||
k.on_message(&chat("carol", "rust++")); // no reason -> keeps alice's
|
||||
k.on_message(&chat("bob", "beta++"));
|
||||
let r = reply_of(&mut k, "karma", &["rust"]);
|
||||
assert!(r.contains("rust has 2 karma (#1 of 2)"), "{r}");
|
||||
assert!(r.contains("last: \"the clean PR\" (alice)"), "{r}");
|
||||
let _ = std::fs::remove_file(&path);
|
||||
}
|
||||
|
||||
|
|
@ -140,3 +145,24 @@ fn leaderboard_top_and_bottom() {
|
|||
);
|
||||
let _ = std::fs::remove_file(&path);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn milestone_announced_at_ten() {
|
||||
let path = std::env::temp_dir().join("rubot-test-karma-ms.json");
|
||||
let _ = std::fs::remove_file(&path);
|
||||
let mut k = Karma::with_path(path.clone());
|
||||
for i in 0..9 {
|
||||
let s = format!("u{i}");
|
||||
assert!(
|
||||
k.on_message(&chat(&s, "rust++")).is_empty(),
|
||||
"announce at {i}"
|
||||
);
|
||||
}
|
||||
let a = k.on_message(&chat("u9", "rust++"));
|
||||
let msg = match a.as_slice() {
|
||||
[Action::Reply(s)] => visible(s),
|
||||
_ => panic!("expected a milestone announce"),
|
||||
};
|
||||
assert!(msg.contains("rust reached 10 karma"), "{msg}");
|
||||
let _ = std::fs::remove_file(&path);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue