use crate::work_stats::WorkStats;
use std::collections::HashMap;
use std::ops::{Add, AddAssign};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AnalyzedDiff {
pub stats: WorkStats,
pub tag_stats: HashMap<String, WorkStats>,
}
impl AnalyzedDiff {
pub fn empty() -> AnalyzedDiff {
Default::default()
}
pub fn add_stats(&mut self, stats: WorkStats, tags: &Vec<String>) {
self.stats += stats;
for tag in tags {
if self.tag_stats.contains_key(tag) {
let v = self.tag_stats.get_mut(tag).unwrap();
*v += stats;
} else {
self.tag_stats.insert(tag.to_string(), stats);
}
}
}
}
impl Default for AnalyzedDiff {
fn default() -> Self {
AnalyzedDiff {
stats: WorkStats::empty(),
tag_stats: HashMap::new(),
}
}
}
impl Add for AnalyzedDiff {
type Output = AnalyzedDiff;
fn add(self, other: AnalyzedDiff) -> AnalyzedDiff {
self + &other
}
}
impl<'b> Add<&'b AnalyzedDiff> for AnalyzedDiff {
type Output = AnalyzedDiff;
fn add(self, other: &'b AnalyzedDiff) -> AnalyzedDiff {
&self + other
}
}
impl<'a> Add<AnalyzedDiff> for &'a AnalyzedDiff {
type Output = AnalyzedDiff;
fn add(self, other: AnalyzedDiff) -> Self::Output {
self + &other
}
}
impl<'a, 'b> Add<&'b AnalyzedDiff> for &'a AnalyzedDiff {
type Output = AnalyzedDiff;
fn add(self, other: &'b AnalyzedDiff) -> Self::Output {
AnalyzedDiff {
stats: self.stats + other.stats,
tag_stats: merge_tag_stats(&self.tag_stats, &other.tag_stats),
}
}
}
impl AddAssign for AnalyzedDiff {
fn add_assign(&mut self, other: AnalyzedDiff) {
*self += &other;
}
}
impl<'a> AddAssign<&'a AnalyzedDiff> for AnalyzedDiff {
fn add_assign(&mut self, other: &'a AnalyzedDiff) {
self.stats += other.stats;
self.tag_stats = merge_tag_stats(&self.tag_stats, &other.tag_stats);
}
}
fn merge_tag_stats(
a: &HashMap<String, WorkStats>,
b: &HashMap<String, WorkStats>,
) -> HashMap<String, WorkStats> {
let mut res: HashMap<String, WorkStats> = HashMap::new();
for (tag, count) in a.iter().chain(b.iter()) {
let res_count = res.entry(tag.to_string()).or_insert(WorkStats::empty());
*res_count += *count;
}
res
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_addition() {
let mut tag_stats = HashMap::new();
tag_stats.insert("migration".to_string(), WorkStats::new_work());
let diff = AnalyzedDiff {
stats: WorkStats::new_work(),
tag_stats,
};
let mut tag_stats2 = HashMap::new();
tag_stats2.insert("migration".to_string(), WorkStats::new_work());
let diff2 = AnalyzedDiff {
stats: WorkStats::new_work(),
tag_stats: tag_stats2,
};
let result = diff + diff2;
assert_eq!(result.stats.new_work, 2);
assert_eq!(result.tag_stats.get("migration").unwrap().new_work, 2);
}
#[test]
fn test_add_stats() {
let mut diff = AnalyzedDiff::empty();
diff.add_stats(
WorkStats::legacy_refactor(),
&vec!["ruby".to_string(), "rspec".to_string()],
);
assert_eq!(diff.tag_stats.len(), 2);
assert_eq!(diff.tag_stats.get("ruby").unwrap().legacy_refactor, 1);
assert_eq!(diff.tag_stats.get("rspec").unwrap().legacy_refactor, 1);
}
}