lcov_parser/report/
branch.rs

1// Copyright (c) 2015-2016 lcov-parser developers
2//
3// Licensed under the Apache License, Version 2.0
4// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
5// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. All files in the project carrying such notice may not be copied,
7// modified, or distributed except according to those terms.
8
9use std::io;
10use std::cmp::PartialEq;
11use std::fmt:: { Display, Formatter, Result };
12use std::collections::btree_map:: { BTreeMap };
13use std::convert::{ From };
14use record:: { BranchData };
15use merger::ops:: { TryMerge, MergeResult, MergeBranch, BranchError };
16use record:: { RecordWrite };
17use report::summary:: { Summary };
18use report::attribute:: { LineNumber, ExecutionCount };
19use report::counter:: { Hit, HitFoundCounter, FoundCounter, HitCounter };
20
21/// Units of the branch
22///
23/// # Examples
24///
25/// ```
26/// use lcov_parser::branch::BranchUnit;
27///
28/// let branch1 = BranchUnit::new(1, 1);
29/// let branch2 = BranchUnit::new(1, 1);
30///
31/// assert!(branch1 == branch2);
32///
33/// let not_eq_branch1 = BranchUnit::new(1, 1);
34/// let not_eq_branch2 = BranchUnit::new(1, 2);
35///
36/// assert!(not_eq_branch1 != not_eq_branch2);
37/// ```
38#[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone)]
39pub struct BranchUnit(u32, u32);
40
41impl BranchUnit {
42    pub fn new(block: u32, branch: u32) -> BranchUnit {
43        BranchUnit(block, branch)
44    }
45    pub fn block(&self) -> &u32 {
46        &self.0
47    }
48    pub fn branch(&self) -> &u32 {
49        &self.1
50    }
51}
52
53impl Display for BranchUnit {
54    fn fmt(&self, f: &mut Formatter) -> Result {
55        write!(f, "{}-{}", self.0, self.1)
56    }
57}
58
59#[derive(Debug, Clone)]
60pub struct Branch {
61    line_number: LineNumber,
62    block: u32,
63    branch: u32,
64    execution_count: ExecutionCount
65}
66
67impl Branch {
68    pub fn new(
69        line_number: LineNumber,
70        block: u32,
71        branch: u32,
72        execution_count: ExecutionCount
73    ) -> Self {
74        Branch {
75            line_number: line_number,
76            block: block,
77            branch: branch,
78            execution_count: execution_count
79        }
80    }
81    pub fn line_number(&self) -> &LineNumber {
82        &self.line_number
83    }
84    pub fn block(&self) -> &u32 {
85        &self.block
86    }
87    pub fn branch(&self) -> &u32 {
88        &self.branch
89    }
90    pub fn execution_count(&self) -> &ExecutionCount {
91        &self.execution_count
92    }
93}
94
95impl PartialEq<BranchData> for Branch {
96    fn eq(&self, data: &BranchData) -> bool {
97        if self.line_number != data.line {
98            return false;
99        }
100        let branch_matched = self.block == data.block && self.branch == data.branch;
101
102        if !branch_matched {
103            return false;
104        }
105        return true;
106    }
107}
108
109impl PartialEq<Branch> for Branch {
110    fn eq(&self, other: &Branch) -> bool {
111        if self.line_number != *other.line_number() {
112            return false;
113        }
114        let branch_matched = self.block == *other.block() && self.branch == *other.branch();
115
116        if !branch_matched {
117            return false;
118        }
119        return true;
120    }
121}
122
123
124
125
126
127
128
129impl<'a> From<&'a BranchData> for Branch {
130    fn from(data: &'a BranchData) -> Self {
131        Branch::new(
132            data.line,
133            data.block,
134            data.branch,
135            data.taken
136        )
137    }
138}
139
140impl<'a> TryMerge<&'a BranchData> for Branch {
141    type Err = BranchError;
142
143    fn try_merge(&mut self, data: &'a BranchData) -> MergeResult<Self::Err> {
144        if self != data {
145            return Err(
146                BranchError::Mismatch(
147                    MergeBranch::from(&self.clone()),
148                    MergeBranch::from(data)
149                )
150            );
151        }
152        self.execution_count += data.taken;
153        Ok(())
154    }
155}
156
157impl<'a> TryMerge<&'a Branch> for Branch {
158    type Err = BranchError;
159
160    fn try_merge(&mut self, other: &'a Branch) -> MergeResult<Self::Err> {
161        if self != other {
162            return Err(
163                BranchError::Mismatch(
164                    MergeBranch::from(&self.clone()),
165                    MergeBranch::from(other)
166                )
167            );
168        }
169        self.execution_count += *other.execution_count();
170        Ok(())
171    }
172}
173
174impl Hit for Branch {
175    fn is_hit(&self) -> bool {
176        self.execution_count.is_hit()
177    }
178}
179
180
181
182
183#[derive(Debug, PartialEq, Clone)]
184pub struct BranchBlocks {
185    blocks: BTreeMap<BranchUnit, Branch>
186}
187
188impl BranchBlocks {
189    pub fn new() -> Self {
190        BranchBlocks {
191            blocks: BTreeMap::new()
192        }
193    }
194}
195
196impl_summary!(BranchBlocks, blocks<BranchUnit, Branch>);
197
198
199impl HitCounter for BranchBlocks {
200    fn hit_count(&self) -> usize {
201        self.iter()
202            .filter(|&(_, branch)| branch.is_hit())
203            .count()
204    }
205}
206
207impl FoundCounter for BranchBlocks {
208    fn found_count(&self) -> usize {
209        self.blocks.len()
210    }
211}
212
213impl HitFoundCounter for BranchBlocks {}
214
215
216
217impl<'a> TryMerge<&'a BranchData> for BranchBlocks {
218    type Err = BranchError;
219
220    fn try_merge(&mut self, data: &'a BranchData) -> MergeResult<Self::Err> {
221        let unit = BranchUnit::new(data.block, data.branch);
222        if !self.blocks.contains_key(&unit) {
223            self.blocks.insert(unit, Branch::from(data));
224            return Ok(());
225        }
226        let block = self.blocks.get_mut(&unit).unwrap();
227        block.try_merge(data)
228    }
229}
230
231impl_try_merge_self_summary!(BranchBlocks:blocks, BranchError);
232
233
234
235#[derive(Debug, Clone)]
236pub struct Branches {
237    branches: BTreeMap<LineNumber, BranchBlocks>
238}
239
240impl Branches {
241    pub fn new() -> Self {
242        Branches {
243            branches: BTreeMap::new()
244        }
245    }
246}
247
248impl HitCounter for Branches {
249    fn hit_count(&self) -> usize {
250        self.iter()
251            .map(|(_, blocks)| blocks.hit_count() )
252            .sum()
253    }
254}
255
256impl FoundCounter for Branches {
257    fn found_count(&self) -> usize {
258        self.iter()
259            .map(|(_, blocks)| blocks.found_count() )
260            .sum()
261    }
262}
263
264impl HitFoundCounter for Branches {}
265
266
267impl_summary!(Branches, branches<LineNumber, BranchBlocks>);
268
269
270impl RecordWrite for Branches {
271    fn write_records<T: io::Write>(&self, output: &mut T) -> io::Result<()> {
272        write!(output, "{}", self)
273    }
274}
275
276impl Display for Branches {
277    fn fmt(&self, f: &mut Formatter) -> Result {
278        if self.is_empty() {
279            return Ok(());
280        }
281        for (line_number, blocks) in self.iter() {
282            for (_, branch) in blocks.iter() {
283                writeln!(f, "BRDA:{},{},{},{}",
284                    line_number, branch.block(), branch.branch(), branch.execution_count())?;
285            }
286        }
287        writeln!(f, "BRF:{}", self.found_count())?;
288        writeln!(f, "BRH:{}", self.hit_count())?;
289        Ok(())
290    }
291}
292
293impl_try_merge_self_summary!(Branches:branches, BranchError);
294
295
296impl<'a> TryMerge<&'a BranchData> for Branches {
297    type Err = BranchError;
298
299    fn try_merge(&mut self, data: &'a BranchData) -> MergeResult<Self::Err> {
300        if self.branches.contains_key(&data.line) {
301            let blocks = self.branches.get_mut(&data.line).unwrap();
302            blocks.try_merge(data)
303        } else {
304            let blocks = {
305                let mut blocks = BranchBlocks::new();
306                let _ = blocks.try_merge(data)?;
307                blocks
308            };
309            self.branches.insert(
310                data.line.clone(),
311                blocks
312            );
313            Ok(())
314        }
315    }
316}
317
318
319#[cfg(test)]
320mod tests {
321    use std::collections:: { HashMap };
322    use merger::ops::*;
323    use record:: { BranchData };
324    use report::branch:: { Branch, BranchUnit, Branches, BranchBlocks };
325    use report::summary:: { Summary };
326    use report::counter:: { FoundCounter, HitCounter };
327
328    #[test]
329    fn branch_unit() {
330        let branch1 = BranchUnit(1, 1);
331        let branch2 = BranchUnit(1, 2);
332
333        assert!(branch1 != branch2);
334
335        let same_branch1 = BranchUnit(1, 1);
336        let same_branch2 = BranchUnit(1, 1);
337    
338        assert_eq!(same_branch1, same_branch2);
339    }
340
341    #[test]
342    fn branch_unit_as_hash_key() {
343        let mut container = HashMap::new();
344        container.insert(BranchUnit(1, 1), 1);
345
346        assert!( container.contains_key(&BranchUnit(1, 1)) );
347    }
348
349    #[test]
350    fn add_branch_data() {
351        let mut branches = BranchBlocks::new();
352        let b1 = &BranchData { line: 1, block: 0, branch: 1, taken: 1 };
353        let b2 = &BranchData { line: 1, block: 0, branch: 1, taken: 1 };
354
355        branches.try_merge(b1).unwrap();
356        branches.try_merge(b2).unwrap();
357
358        let branch = Branch::new(1, 0, 1, 2);
359        assert_eq!(branches.get(&BranchUnit::new(0, 1)), Some(&branch));
360    }
361
362    #[test]
363    fn append_branches() {
364        let mut branches = BranchBlocks::new();
365        let b1 = &BranchData { line: 1, block: 0, branch: 1, taken: 1 };
366        let b2 = &BranchData { line: 1, block: 0, branch: 1, taken: 1 };
367
368        branches.try_merge(b1).unwrap();
369        branches.try_merge(b2).unwrap();
370
371        let cloned_branches = branches.clone();
372        branches.try_merge(&cloned_branches).unwrap();
373
374        let branch = Branch::new(1, 0, 1, 2);
375        assert_eq!(branches.get(&BranchUnit::new(0, 1)), Some(&branch));
376    }
377
378    #[test]
379    fn branch_blocks_hit_count_and_found_count() {
380        let mut branches = BranchBlocks::new();
381        let b1 = &BranchData { line: 1, block: 0, branch: 1, taken: 1 };
382        let b2 = &BranchData { line: 1, block: 0, branch: 2, taken: 0 };
383
384        branches.try_merge(b1).unwrap();
385        branches.try_merge(b2).unwrap();
386
387        assert_eq!(branches.hit_count(), 1);
388        assert_eq!(branches.found_count(), 2);
389    }
390
391    #[test]
392    fn branches_hit_count_and_found_count() {
393        let mut branches = Branches::new();
394        branches.try_merge(&BranchData { line: 1, block: 0, branch: 1, taken: 1 }).unwrap();
395        branches.try_merge(&BranchData { line: 1, block: 0, branch: 2, taken: 0 }).unwrap();
396
397        assert_eq!(branches.hit_count(), 1);
398        assert_eq!(branches.found_count(), 2);
399    }
400}